Ensure that uploaded files are not reuploaded on reinstall
This commit is contained in:
parent
69e746b9c2
commit
3a2ea5014f
3 changed files with 68 additions and 35 deletions
|
@ -108,10 +108,27 @@ class DatabaseHelper {
|
|||
return _convertToPhotos(results);
|
||||
}
|
||||
|
||||
Future<int> updatePhoto(
|
||||
int generatedId, String remotePath, int syncTimestamp) async {
|
||||
Future<Photo> getMatchingPhoto(String localId, String title,
|
||||
String deviceFolder, int createTimestamp) async {
|
||||
final db = await instance.database;
|
||||
final rows = await db.query(
|
||||
table,
|
||||
where:
|
||||
'$columnLocalId=? AND $columnTitle=? AND $columnDeviceFolder=? AND $columnCreateTimestamp=?',
|
||||
whereArgs: [localId, title, deviceFolder, createTimestamp],
|
||||
);
|
||||
if (rows.isNotEmpty) {
|
||||
return _getPhotoFromRow(rows[0]);
|
||||
} else {
|
||||
throw ("No matching photo found");
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> updatePhoto(int generatedId, int uploadedId, String remotePath,
|
||||
int syncTimestamp) async {
|
||||
final db = await instance.database;
|
||||
final values = new Map<String, dynamic>();
|
||||
values[columnUploadedFileId] = uploadedId;
|
||||
values[columnRemotePath] = remotePath;
|
||||
values[columnSyncTimestamp] = syncTimestamp;
|
||||
return await db.update(
|
||||
|
@ -130,12 +147,13 @@ class DatabaseHelper {
|
|||
whereArgs: [path],
|
||||
);
|
||||
if (rows.isNotEmpty) {
|
||||
return _getPhotofromRow(rows[0]);
|
||||
return _getPhotoFromRow(rows[0]);
|
||||
} else {
|
||||
throw ("No cached photo");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove deleted photos on remote
|
||||
Future<int> markPhotoForDeletion(Photo photo) async {
|
||||
final db = await instance.database;
|
||||
var values = new Map<String, dynamic>();
|
||||
|
@ -181,7 +199,7 @@ class DatabaseHelper {
|
|||
limit: 1,
|
||||
);
|
||||
if (rows.isNotEmpty) {
|
||||
return _getPhotofromRow(rows[0]);
|
||||
return _getPhotoFromRow(rows[0]);
|
||||
} else {
|
||||
throw ("No photo found in path");
|
||||
}
|
||||
|
@ -197,7 +215,7 @@ class DatabaseHelper {
|
|||
limit: 1,
|
||||
);
|
||||
if (rows.isNotEmpty) {
|
||||
return _getPhotofromRow(rows[0]);
|
||||
return _getPhotoFromRow(rows[0]);
|
||||
} else {
|
||||
throw ("No photo found with ids " + generatedIds.join(", ").toString());
|
||||
}
|
||||
|
@ -206,7 +224,7 @@ class DatabaseHelper {
|
|||
List<Photo> _convertToPhotos(List<Map<String, dynamic>> results) {
|
||||
var photos = List<Photo>();
|
||||
for (var result in results) {
|
||||
photos.add(_getPhotofromRow(result));
|
||||
photos.add(_getPhotoFromRow(result));
|
||||
}
|
||||
return photos;
|
||||
}
|
||||
|
@ -224,7 +242,7 @@ class DatabaseHelper {
|
|||
return row;
|
||||
}
|
||||
|
||||
Photo _getPhotofromRow(Map<String, dynamic> row) {
|
||||
Photo _getPhotoFromRow(Map<String, dynamic> row) {
|
||||
Photo photo = Photo();
|
||||
photo.generatedId = row[columnGeneratedId];
|
||||
photo.localId = row[columnLocalId];
|
||||
|
|
|
@ -17,9 +17,10 @@ class Photo {
|
|||
|
||||
Photo();
|
||||
Photo.fromJson(Map<String, dynamic> json)
|
||||
: uploadedFileId = json["fileId"],
|
||||
title = json["title"],
|
||||
: uploadedFileId = json["fileID"],
|
||||
localId = json["deviceFileID"],
|
||||
deviceFolder = json["deviceFolder"],
|
||||
title = json["title"],
|
||||
remotePath = json["path"],
|
||||
createTimestamp = json["createTimestamp"],
|
||||
syncTimestamp = json["syncTimestamp"];
|
||||
|
|
|
@ -20,6 +20,7 @@ import 'package:photos/events/remote_sync_event.dart';
|
|||
class PhotoSyncManager {
|
||||
final _logger = Logger("PhotoSyncManager");
|
||||
final _dio = Dio();
|
||||
final _db = DatabaseHelper.instance;
|
||||
bool _isSyncInProgress = false;
|
||||
|
||||
static final _lastSyncTimestampKey = "last_sync_timestamp_0";
|
||||
|
@ -72,16 +73,16 @@ class PhotoSyncManager {
|
|||
}
|
||||
if (photos.isEmpty) {
|
||||
_isSyncInProgress = false;
|
||||
_syncPhotos().then((_) {
|
||||
_deletePhotos();
|
||||
_syncPhotosWithServer().then((_) {
|
||||
_deletePhotosOnServer();
|
||||
});
|
||||
} else {
|
||||
photos.sort((first, second) =>
|
||||
first.createTimestamp.compareTo(second.createTimestamp));
|
||||
_updateDatabase(photos, prefs, lastDBUpdateTimestamp).then((_) {
|
||||
_isSyncInProgress = false;
|
||||
_syncPhotos().then((_) {
|
||||
_deletePhotos();
|
||||
_syncPhotosWithServer().then((_) {
|
||||
_deletePhotosOnServer();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -99,37 +100,44 @@ class PhotoSyncManager {
|
|||
photosToBeAdded, prefs, DateTime.now().microsecondsSinceEpoch);
|
||||
}
|
||||
|
||||
_syncPhotos() async {
|
||||
_syncPhotosWithServer() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
var lastSyncTimestamp = prefs.getInt(_lastSyncTimestampKey);
|
||||
if (lastSyncTimestamp == null) {
|
||||
lastSyncTimestamp = 0;
|
||||
}
|
||||
_logger.info("Last sync timestamp: " + lastSyncTimestamp.toString());
|
||||
|
||||
await _getDiff(lastSyncTimestamp, _diffLimit).then((diff) async {
|
||||
if (diff != null) {
|
||||
await _storeDiff(diff, prefs).then((_) {
|
||||
// TODO: Recursively store diff
|
||||
_uploadDiff(prefs);
|
||||
});
|
||||
var shouldFetchDiff = true;
|
||||
while (shouldFetchDiff) {
|
||||
int lastSyncTimestamp = _getLastSyncTimestamp(prefs);
|
||||
var diff = await _getDiff(lastSyncTimestamp, _diffLimit);
|
||||
if (diff != null && diff.isNotEmpty) {
|
||||
await _storeDiff(diff, prefs);
|
||||
PhotoRepository.instance.reloadPhotos();
|
||||
}
|
||||
});
|
||||
if (diff.length < _diffLimit) {
|
||||
shouldFetchDiff = false;
|
||||
}
|
||||
}
|
||||
_uploadDiff(prefs);
|
||||
|
||||
// TODO: Fix race conditions triggered due to concurrent syncs.
|
||||
// Add device_id/last_sync_timestamp to the upload request?
|
||||
}
|
||||
|
||||
int _getLastSyncTimestamp(SharedPreferences prefs) {
|
||||
var lastSyncTimestamp = prefs.getInt(_lastSyncTimestampKey);
|
||||
if (lastSyncTimestamp == null) {
|
||||
lastSyncTimestamp = 0;
|
||||
}
|
||||
return lastSyncTimestamp;
|
||||
}
|
||||
|
||||
Future _uploadDiff(SharedPreferences prefs) async {
|
||||
List<Photo> photosToBeUploaded =
|
||||
await DatabaseHelper.instance.getPhotosToBeUploaded();
|
||||
List<Photo> photosToBeUploaded = await _db.getPhotosToBeUploaded();
|
||||
for (Photo photo in photosToBeUploaded) {
|
||||
try {
|
||||
var uploadedPhoto = await _uploadFile(photo);
|
||||
if (uploadedPhoto == null) {
|
||||
return;
|
||||
}
|
||||
await DatabaseHelper.instance.updatePhoto(photo.generatedId,
|
||||
await _db.updatePhoto(photo.generatedId, uploadedPhoto.uploadedFileId,
|
||||
uploadedPhoto.remotePath, uploadedPhoto.syncTimestamp);
|
||||
prefs.setInt(_lastSyncTimestampKey, uploadedPhoto.syncTimestamp);
|
||||
} catch (e) {
|
||||
|
@ -140,10 +148,16 @@ class PhotoSyncManager {
|
|||
|
||||
Future _storeDiff(List<Photo> diff, SharedPreferences prefs) async {
|
||||
for (Photo photo in diff) {
|
||||
await DatabaseHelper.instance.insertPhoto(photo);
|
||||
try {
|
||||
var existingPhoto = await _db.getMatchingPhoto(photo.localId,
|
||||
photo.title, photo.deviceFolder, photo.createTimestamp);
|
||||
await _db.updatePhoto(existingPhoto.generatedId, photo.uploadedFileId,
|
||||
photo.remotePath, photo.syncTimestamp);
|
||||
} catch (e) {
|
||||
await _db.insertPhoto(photo);
|
||||
}
|
||||
await prefs.setInt(_lastSyncTimestampKey, photo.syncTimestamp);
|
||||
}
|
||||
PhotoRepository.instance.reloadPhotos();
|
||||
}
|
||||
|
||||
Future<List<Photo>> _getDiff(int lastSyncTimestamp, int limit) async {
|
||||
|
@ -190,11 +204,11 @@ class PhotoSyncManager {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> _deletePhotos() async {
|
||||
DatabaseHelper.instance.getAllDeletedPhotos().then((deletedPhotos) {
|
||||
Future<void> _deletePhotosOnServer() async {
|
||||
_db.getAllDeletedPhotos().then((deletedPhotos) {
|
||||
for (Photo deletedPhoto in deletedPhotos) {
|
||||
_deletePhotoOnServer(deletedPhoto)
|
||||
.then((value) => DatabaseHelper.instance.deletePhoto(deletedPhoto));
|
||||
.then((value) => _db.deletePhoto(deletedPhoto));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -219,7 +233,7 @@ class PhotoSyncManager {
|
|||
|
||||
Future<bool> _insertPhotosToDB(
|
||||
List<Photo> photos, SharedPreferences prefs, int timestamp) async {
|
||||
await DatabaseHelper.instance.insertPhotos(photos);
|
||||
await _db.insertPhotos(photos);
|
||||
_logger.info("Inserted " + photos.length.toString() + " photos.");
|
||||
PhotoRepository.instance.reloadPhotos();
|
||||
return await prefs.setInt(_lastDBUpdateTimestampKey, timestamp);
|
||||
|
|
Loading…
Add table
Reference in a new issue