Fix issue with loading remote images

This commit is contained in:
Vishnu Mohandas 2020-08-10 04:04:59 +05:30
parent fe7225cf01
commit c7b40265c3
15 changed files with 113 additions and 98 deletions

View file

@ -16,15 +16,16 @@ class FilesDB {
static final table = 'files';
static final columnGeneratedId = '_id';
static final columnUploadedFileId = 'uploaded_file_id';
static final columnLocalId = 'local_id';
static final columnGeneratedID = '_id';
static final columnUploadedFileID = 'uploaded_file_id';
static final columnOwnerID = 'owner_id';
static final columnLocalID = 'local_id';
static final columnTitle = 'title';
static final columnDeviceFolder = 'device_folder';
static final columnLatitude = 'latitude';
static final columnLongitude = 'longitude';
static final columnFileType = 'file_type';
static final columnRemoteFolderId = 'remote_folder_id';
static final columnRemoteFolderID = 'remote_folder_id';
static final columnIsDeleted = 'is_deleted';
static final columnCreationTime = 'creation_time';
static final columnModificationTime = 'modification_time';
@ -55,15 +56,16 @@ class FilesDB {
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnGeneratedId INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
$columnLocalId TEXT,
$columnUploadedFileId INTEGER,
$columnGeneratedID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
$columnLocalID TEXT,
$columnUploadedFileID INTEGER,
$columnOwnerID INTEGER,
$columnTitle TEXT NOT NULL,
$columnDeviceFolder TEXT NOT NULL,
$columnLatitude REAL,
$columnLongitude REAL,
$columnFileType INTEGER,
$columnRemoteFolderId INTEGER,
$columnRemoteFolderID INTEGER,
$columnIsDeleted INTEGER DEFAULT 0,
$columnCreationTime TEXT NOT NULL,
$columnModificationTime TEXT NOT NULL,
@ -92,11 +94,17 @@ class FilesDB {
return await batch.commit();
}
Future<List<File>> getAllLocalFiles() async {
Future<List<File>> getOwnedFiles(int ownerID) async {
final db = await instance.database;
final whereArgs = List<dynamic>();
if (ownerID != null) {
whereArgs.add(ownerID);
}
final results = await db.query(
table,
where: '$columnLocalId IS NOT NULL AND $columnIsDeleted = 0',
// where: '$columnIsDeleted = 0' +
// (ownerID == null ? '' : ' AND $columnOwnerID = ?'),
// whereArgs: whereArgs,
orderBy: '$columnCreationTime DESC',
);
return _convertToFiles(results);
@ -107,20 +115,20 @@ class FilesDB {
final results = await db.query(
table,
where:
'$columnLocalId IS NOT NULL AND $columnFileType = 1 AND $columnIsDeleted = 0',
'$columnLocalID IS NOT NULL AND $columnFileType = 1 AND $columnIsDeleted = 0',
orderBy: '$columnCreationTime DESC',
);
return _convertToFiles(results);
}
Future<List<File>> getAllInFolder(
int folderId, int beforeCreationTime, int limit) async {
int folderID, int beforeCreationTime, int limit) async {
final db = await instance.database;
final results = await db.query(
table,
where:
'$columnRemoteFolderId = ? AND $columnIsDeleted = 0 AND $columnCreationTime < ?',
whereArgs: [folderId, beforeCreationTime],
'$columnRemoteFolderID = ? AND $columnIsDeleted = 0 AND $columnCreationTime < ?',
whereArgs: [folderID, beforeCreationTime],
orderBy: '$columnCreationTime DESC',
limit: limit,
);
@ -154,22 +162,22 @@ class FilesDB {
final db = await instance.database;
final results = await db.query(
table,
where: '$columnUploadedFileId IS NULL',
where: '$columnUploadedFileID IS NULL',
orderBy: '$columnCreationTime DESC',
);
return _convertToFiles(results);
}
Future<File> getMatchingFile(String localId, String title,
Future<File> getMatchingFile(String localID, String title,
String deviceFolder, int creationTime, int modificationTime,
{String alternateTitle}) async {
final db = await instance.database;
final rows = await db.query(
table,
where: '''$columnLocalId=? AND ($columnTitle=? OR $columnTitle=?) AND
where: '''$columnLocalID=? AND ($columnTitle=? OR $columnTitle=?) AND
$columnDeviceFolder=? AND $columnCreationTime=? AND $columnModificationTime=?''',
whereArgs: [
localId,
localID,
title,
alternateTitle,
deviceFolder,
@ -184,12 +192,12 @@ class FilesDB {
}
}
Future<File> getMatchingRemoteFile(int uploadedFileId) async {
Future<File> getMatchingRemoteFile(int uploadedFileID) async {
final db = await instance.database;
final rows = await db.query(
table,
where: '$columnUploadedFileId=?',
whereArgs: [uploadedFileId],
where: '$columnUploadedFileID=?',
whereArgs: [uploadedFileID],
);
if (rows.isNotEmpty) {
return _getFileFromRow(rows[0]);
@ -198,16 +206,16 @@ class FilesDB {
}
}
Future<int> update(int generatedId, int uploadedId, int updationTime) async {
Future<int> update(int generatedID, int uploadedID, int updationTime) async {
final db = await instance.database;
final values = new Map<String, dynamic>();
values[columnUploadedFileId] = uploadedId;
values[columnUploadedFileID] = uploadedID;
values[columnUpdationTime] = updationTime;
return await db.update(
table,
values,
where: '$columnGeneratedId = ?',
whereArgs: [generatedId],
where: '$columnGeneratedID = ?',
whereArgs: [generatedID],
);
}
@ -219,8 +227,8 @@ class FilesDB {
return db.update(
table,
values,
where: '$columnGeneratedId =?',
whereArgs: [file.generatedId],
where: '$columnGeneratedID =?',
whereArgs: [file.generatedID],
);
}
@ -228,17 +236,17 @@ class FilesDB {
final db = await instance.database;
return db.delete(
table,
where: '$columnGeneratedId =?',
whereArgs: [file.generatedId],
where: '$columnGeneratedID =?',
whereArgs: [file.generatedID],
);
}
Future<int> deleteFilesInRemoteFolder(int folderId) async {
Future<int> deleteFilesInRemoteFolder(int folderID) async {
final db = await instance.database;
return db.delete(
table,
where: '$columnRemoteFolderId =?',
whereArgs: [folderId],
where: '$columnRemoteFolderID =?',
whereArgs: [folderID],
);
}
@ -248,7 +256,7 @@ class FilesDB {
table,
columns: [columnDeviceFolder],
distinct: true,
where: '$columnRemoteFolderId IS NULL',
where: '$columnRemoteFolderID IS NULL',
);
List<String> result = List<String>();
for (final row in rows) {
@ -273,50 +281,50 @@ class FilesDB {
}
}
Future<File> getLatestFileInRemoteFolder(int folderId) async {
Future<File> getLatestFileInRemoteFolder(int folderID) async {
final db = await instance.database;
final rows = await db.query(
table,
where: '$columnRemoteFolderId =?',
whereArgs: [folderId],
where: '$columnRemoteFolderID =?',
whereArgs: [folderID],
orderBy: '$columnCreationTime DESC',
limit: 1,
);
if (rows.isNotEmpty) {
return _getFileFromRow(rows[0]);
} else {
throw ("No file found in remote folder " + folderId.toString());
throw ("No file found in remote folder " + folderID.toString());
}
}
Future<File> getLastSyncedFileInRemoteFolder(int folderId) async {
Future<File> getLastSyncedFileInRemoteFolder(int folderID) async {
final db = await instance.database;
final rows = await db.query(
table,
where: '$columnRemoteFolderId =?',
whereArgs: [folderId],
where: '$columnRemoteFolderID =?',
whereArgs: [folderID],
orderBy: '$columnUpdationTime DESC',
limit: 1,
);
if (rows.isNotEmpty) {
return _getFileFromRow(rows[0]);
} else {
throw ("No file found in remote folder " + folderId.toString());
throw ("No file found in remote folder " + folderID.toString());
}
}
Future<File> getLatestFileAmongGeneratedIds(List<String> generatedIds) async {
Future<File> getLatestFileAmongGeneratedIDs(List<String> generatedIDs) async {
final db = await instance.database;
final rows = await db.query(
table,
where: '$columnGeneratedId IN (${generatedIds.join(",")})',
where: '$columnGeneratedID IN (${generatedIDs.join(",")})',
orderBy: '$columnCreationTime DESC',
limit: 1,
);
if (rows.isNotEmpty) {
return _getFileFromRow(rows[0]);
} else {
throw ("No file found with ids " + generatedIds.join(", ").toString());
throw ("No file found with ids " + generatedIDs.join(", ").toString());
}
}
@ -330,8 +338,9 @@ class FilesDB {
Map<String, dynamic> _getRowForFile(File file) {
final row = new Map<String, dynamic>();
row[columnLocalId] = file.localId;
row[columnUploadedFileId] = file.uploadedFileId;
row[columnLocalID] = file.localID;
row[columnUploadedFileID] = file.uploadedFileID;
row[columnOwnerID] = file.ownerID;
row[columnTitle] = file.title;
row[columnDeviceFolder] = file.deviceFolder;
if (file.location != null) {
@ -348,7 +357,7 @@ class FilesDB {
default:
row[columnFileType] = -1;
}
row[columnRemoteFolderId] = file.remoteFolderId;
row[columnRemoteFolderID] = file.remoteFolderID;
row[columnCreationTime] = file.creationTime;
row[columnModificationTime] = file.modificationTime;
row[columnUpdationTime] = file.updationTime;
@ -357,16 +366,17 @@ class FilesDB {
File _getFileFromRow(Map<String, dynamic> row) {
final file = File();
file.generatedId = row[columnGeneratedId];
file.localId = row[columnLocalId];
file.uploadedFileId = row[columnUploadedFileId];
file.generatedID = row[columnGeneratedID];
file.localID = row[columnLocalID];
file.uploadedFileID = row[columnUploadedFileID];
file.ownerID = row[columnUploadedFileID];
file.title = row[columnTitle];
file.deviceFolder = row[columnDeviceFolder];
if (row[columnLatitude] != null && row[columnLongitude] != null) {
file.location = Location(row[columnLatitude], row[columnLongitude]);
}
file.fileType = getFileType(row[columnFileType]);
file.remoteFolderId = row[columnRemoteFolderId];
file.remoteFolderID = row[columnRemoteFolderID];
file.creationTime = int.parse(row[columnCreationTime]);
file.modificationTime = int.parse(row[columnModificationTime]);
file.updationTime = row[columnUpdationTime] == null

View file

@ -66,7 +66,7 @@ class MemoriesDB {
Map<String, dynamic> _getRowForSeenMemory(Memory memory, int timestamp) {
var row = new Map<String, dynamic>();
row[columnFileID] = memory.file.generatedId;
row[columnFileID] = memory.file.generatedID;
row[columnSeenTime] = timestamp;
return row;
}

View file

@ -55,7 +55,7 @@ class FaceSearchManager {
for (File file in result) {
try {
files.add(await FilesDB.instance.getMatchingFile(
file.localId,
file.localID,
file.title,
file.deviceFolder,
file.creationTime,

View file

@ -16,7 +16,7 @@ class FavoriteFilesRepository {
}
bool isLiked(File photo) {
return getLiked().contains(photo.generatedId.toString());
return getLiked().contains(photo.generatedID.toString());
}
bool hasFavorites() {
@ -26,9 +26,9 @@ class FavoriteFilesRepository {
Future<bool> setLiked(File photo, bool isLiked) {
final liked = getLiked();
if (isLiked) {
liked.add(photo.generatedId.toString());
liked.add(photo.generatedID.toString());
} else {
liked.remove(photo.generatedId.toString());
liked.remove(photo.generatedID.toString());
}
Bus.instance.fire(LocalPhotosUpdatedEvent());
return _preferences

View file

@ -1,4 +1,5 @@
import 'package:logging/logging.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/events/local_photos_updated_event.dart';
@ -16,7 +17,8 @@ class FileRepository {
}
Future<List<File>> loadFiles() async {
var files = await FilesDB.instance.getAllLocalFiles();
var files = await FilesDB.instance
.getOwnedFiles(Configuration.instance.getUserID());
_files.clear();
_files.addAll(files);

View file

@ -69,9 +69,9 @@ class FolderSharingService {
for (File file in diff) {
try {
var existingPhoto =
await FilesDB.instance.getMatchingRemoteFile(file.uploadedFileId);
await FilesDB.instance.getMatchingRemoteFile(file.uploadedFileID);
await FilesDB.instance.update(
existingPhoto.generatedId, file.uploadedFileId, file.updationTime);
existingPhoto.generatedID, file.uploadedFileID, file.updationTime);
} catch (e) {
await FilesDB.instance.insert(file);
}
@ -97,8 +97,8 @@ class FolderSharingService {
if (response != null) {
return (response.data["diff"] as List).map((p) {
File file = new File.fromJson(p);
file.localId = null;
file.remoteFolderId = folderId;
file.localID = null;
file.remoteFolderID = folderId;
return file;
}).toList();
} else {

View file

@ -57,7 +57,7 @@ class MemoriesService extends ChangeNotifier {
final memories = List<Memory>();
for (final file in files) {
if (filter.shouldInclude(file)) {
final seenTime = seenTimes[file.generatedId] ?? -1;
final seenTime = seenTimes[file.generatedID] ?? -1;
memories.add(Memory(file, seenTime));
}
}

View file

@ -10,12 +10,13 @@ import 'package:photos/models/file_type.dart';
import 'package:photos/models/location.dart';
class File {
int generatedId;
int uploadedFileId;
String localId;
int generatedID;
int uploadedFileID;
int ownerID;
String localID;
String title;
String deviceFolder;
int remoteFolderId;
int remoteFolderID;
int creationTime;
int modificationTime;
int updationTime;
@ -24,8 +25,9 @@ class File {
File();
File.fromJson(Map<String, dynamic> json) {
uploadedFileId = json["id"];
localId = json["deviceFileID"];
uploadedFileID = json["id"];
ownerID = json["ownerID"];
localID = json["deviceFileID"];
deviceFolder = json["deviceFolder"];
title = json["title"];
fileType = getFileType(json["fileType"]);
@ -37,7 +39,7 @@ class File {
static Future<File> fromAsset(
AssetPathEntity pathEntity, AssetEntity asset) async {
File file = File();
file.localId = asset.id;
file.localID = asset.id;
file.title = asset.title;
file.deviceFolder = pathEntity.name;
file.location = Location(asset.latitude, asset.longitude);
@ -70,11 +72,11 @@ class File {
}
Future<AssetEntity> getAsset() {
return AssetEntity.fromId(localId);
return AssetEntity.fromId(localID);
}
Future<Uint8List> getBytes({int quality = 100}) async {
if (localId == null) {
if (localID == null) {
return HttpClient().getUrl(Uri.parse(getDownloadUrl())).then((request) {
return request.close().then((response) {
return consolidateHttpClientResponseBytes(response);
@ -98,7 +100,7 @@ class File {
String getDownloadUrl() {
return Configuration.instance.getHttpEndpoint() +
"/files/download/" +
uploadedFileId.toString() +
uploadedFileID.toString() +
"?token=" +
Configuration.instance.getToken();
}
@ -109,22 +111,22 @@ class File {
"/streams/" +
Configuration.instance.getToken() +
"/" +
uploadedFileId.toString() +
uploadedFileID.toString() +
"/index.m3u8";
}
String getThumbnailUrl() {
return Configuration.instance.getHttpEndpoint() +
"/files/preview/" +
uploadedFileId.toString() +
uploadedFileID.toString() +
"?token=" +
Configuration.instance.getToken();
}
@override
String toString() {
return '''File(generatedId: $generatedId, uploadedFileId: $uploadedFileId,
localId: $localId, title: $title, deviceFolder: $deviceFolder,
return '''File(generatedId: $generatedID, uploadedFileId: $uploadedFileID,
localId: $localID, title: $title, deviceFolder: $deviceFolder,
location: $location, fileType: $fileType, creationTime: $creationTime,
modificationTime: $modificationTime, updationTime: $updationTime)''';
}
@ -134,22 +136,22 @@ class File {
if (identical(this, o)) return true;
return o is File &&
o.generatedId == generatedId &&
o.uploadedFileId == uploadedFileId &&
o.localId == localId;
o.generatedID == generatedID &&
o.uploadedFileID == uploadedFileID &&
o.localID == localID;
}
@override
int get hashCode {
return generatedId.hashCode ^ uploadedFileId.hashCode ^ localId.hashCode;
return generatedID.hashCode ^ uploadedFileID.hashCode ^ localID.hashCode;
}
String tag() {
return "local_" +
localId.toString() +
localID.toString() +
":remote_" +
uploadedFileId.toString() +
uploadedFileID.toString() +
":generated_" +
generatedId.toString();
generatedID.toString();
}
}

View file

@ -182,7 +182,7 @@ class PhotoSyncManager {
_logger.info("Uploading " + file.toString());
try {
final uploadedFile = await _uploadFile(file);
await _db.update(file.generatedId, uploadedFile.uploadedFileId,
await _db.update(file.generatedID, uploadedFile.uploadedFileID,
uploadedFile.updationTime);
_prefs.setInt(_lastSyncTimeKey, uploadedFile.updationTime);
@ -199,15 +199,16 @@ class PhotoSyncManager {
for (File file in diff) {
try {
final existingPhoto = await _db.getMatchingFile(
file.localId,
file.localID,
file.title,
file.deviceFolder,
file.creationTime,
file.modificationTime,
alternateTitle: getHEICFileNameForJPG(file));
await _db.update(
existingPhoto.generatedId, file.uploadedFileId, file.updationTime);
existingPhoto.generatedID, file.uploadedFileID, file.updationTime);
} catch (e) {
file.localID = null; // File uploaded from a different device
await _db.insert(file);
}
await _prefs.setInt(_lastSyncTimeKey, file.updationTime);
@ -241,7 +242,7 @@ class PhotoSyncManager {
"file": MultipartFile.fromFileSync(
(await (await localPhoto.getAsset()).originFile).path,
filename: title),
"deviceFileID": localPhoto.localId,
"deviceFileID": localPhoto.localID,
"deviceFolder": localPhoto.deviceFolder,
"title": title,
"creationTime": localPhoto.creationTime,
@ -273,7 +274,7 @@ class PhotoSyncManager {
.delete(
Configuration.instance.getHttpEndpoint() +
"/files/" +
file.uploadedFileId.toString(),
file.uploadedFileID.toString(),
options: Options(
headers: {"X-Auth-Token": Configuration.instance.getToken()}),
)

View file

@ -114,7 +114,7 @@ class _DetailPageState extends State<DetailPage> {
AppBar _buildAppBar() {
final actions = List<Widget>();
if (_files[_selectedIndex].localId != null) {
if (_files[_selectedIndex].localID != null) {
actions.add(_getFavoriteButton());
}
actions.add(PopupMenuButton(

View file

@ -86,7 +86,7 @@ class _DeviceFolderGalleryWidgetState extends State<DeviceFolderGalleryWidget> {
.compareTo(first.thumbnail.creationTime);
});
if (FavoriteFilesRepository.instance.hasFavorites()) {
final file = await FilesDB.instance.getLatestFileAmongGeneratedIds(
final file = await FilesDB.instance.getLatestFileAmongGeneratedIDs(
FavoriteFilesRepository.instance.getLiked().toList());
folders.insert(0,
DeviceFolder("Favorites", "/Favorites", file, FavoriteItemsFilter()));

View file

@ -34,7 +34,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
@override
Widget build(BuildContext context) {
if (widget.file.localId == null) {
if (widget.file.localID == null) {
return _getNetworkImage();
}
@ -120,7 +120,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
@override
void didUpdateWidget(ThumbnailWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.file.generatedId != oldWidget.file.generatedId) {
if (widget.file.generatedID != oldWidget.file.generatedID) {
setState(() {
_hasLoadedThumbnail = false;
_imageProvider = null;

View file

@ -36,7 +36,7 @@ class _VideoWidgetState extends State<VideoWidget> {
@override
void initState() {
super.initState();
if (widget.file.localId == null) {
if (widget.file.localID == null) {
_setVideoPlayerController(widget.file.getStreamUrl());
_videoPlayerController.addListener(() {
if (_videoPlayerController.value.hasError) {
@ -104,7 +104,7 @@ class _VideoWidgetState extends State<VideoWidget> {
}
Widget _getThumbnail() {
final thumbnail = widget.file.localId == null
final thumbnail = widget.file.localID == null
? CachedNetworkImage(
imageUrl: widget.file.getThumbnailUrl(),
fit: BoxFit.contain,

View file

@ -51,7 +51,7 @@ class _ZoomableImageState extends State<ZoomableImage>
@override
Widget build(BuildContext context) {
if (widget.photo.localId == null) {
if (widget.photo.localID == null) {
_loadNetworkImage();
} else {
_loadLocalImage(context);

View file

@ -9,7 +9,7 @@ import 'package:photos/models/file_type.dart';
Future<void> deleteFiles(List<File> files,
{bool deleteEveryWhere = false}) async {
await PhotoManager.editor
.deleteWithIds(files.map((file) => file.localId).toList());
.deleteWithIds(files.map((file) => file.localID).toList());
for (File file in files) {
deleteEveryWhere
? await FilesDB.instance.markForDeletion(file)
@ -21,7 +21,7 @@ void preloadFile(File file) {
if (file.fileType == FileType.video) {
return;
}
if (file.localId == null) {
if (file.localID == null) {
if (BytesLruCache.get(file) == null) {
file.getBytes().then((data) {
BytesLruCache.put(file, data);
@ -39,7 +39,7 @@ void preloadFile(File file) {
}
void preloadLocalFileThumbnail(File file) {
if (file.localId == null ||
if (file.localID == null ||
ThumbnailLruCache.get(file, THUMBNAIL_SMALL_SIZE) != null) {
return;
}