mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-25 00:14:42 +01:00
Fix startup sync results not propagated to main isolate
This commit is contained in:
parent
a04ecefed9
commit
f97476e4f0
13 changed files with 229 additions and 45 deletions
|
@ -13,6 +13,7 @@ import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||||
import 'package:nc_photos/progress_util.dart';
|
import 'package:nc_photos/progress_util.dart';
|
||||||
import 'package:nc_photos/rx_extension.dart';
|
import 'package:nc_photos/rx_extension.dart';
|
||||||
import 'package:nc_photos/use_case/file/list_file.dart';
|
import 'package:nc_photos/use_case/file/list_file.dart';
|
||||||
|
import 'package:nc_photos/use_case/find_file_descriptor.dart';
|
||||||
import 'package:nc_photos/use_case/remove.dart';
|
import 'package:nc_photos/use_case/remove.dart';
|
||||||
import 'package:nc_photos/use_case/sync_dir.dart';
|
import 'package:nc_photos/use_case/sync_dir.dart';
|
||||||
import 'package:nc_photos/use_case/update_property.dart';
|
import 'package:nc_photos/use_case/update_property.dart';
|
||||||
|
@ -20,6 +21,7 @@ import 'package:np_codegen/np_codegen.dart';
|
||||||
import 'package:np_common/lazy.dart';
|
import 'package:np_common/lazy.dart';
|
||||||
import 'package:np_common/object_util.dart';
|
import 'package:np_common/object_util.dart';
|
||||||
import 'package:np_common/or_null.dart';
|
import 'package:np_common/or_null.dart';
|
||||||
|
import 'package:np_db/np_db.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:to_string/to_string.dart';
|
import 'package:to_string/to_string.dart';
|
||||||
|
|
||||||
|
@ -233,6 +235,69 @@ class FilesController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> applySyncResult({
|
||||||
|
DbSyncIdResult? favorites,
|
||||||
|
List<int>? fileExifs,
|
||||||
|
}) async {
|
||||||
|
if (favorites?.isNotEmpty != true && fileExifs?.isNotEmpty != true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do async ops first
|
||||||
|
final fileExifFiles =
|
||||||
|
await fileExifs?.letFuture((e) async => await FindFileDescriptor(_c)(
|
||||||
|
account,
|
||||||
|
e,
|
||||||
|
onFileNotFound: (id) {
|
||||||
|
_log.warning("[applySyncResult] File id not found: $id");
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
final next = LinkedHashMap.of(_dataStreamController.value.files);
|
||||||
|
if (favorites != null && favorites.isNotEmpty) {
|
||||||
|
_applySyncFavoriteResult(next, favorites);
|
||||||
|
}
|
||||||
|
if (fileExifFiles != null && fileExifFiles.isNotEmpty) {
|
||||||
|
_applySyncFileExifResult(next, fileExifFiles);
|
||||||
|
}
|
||||||
|
_dataStreamController.addWithValue((value) => value.copyWith(files: next));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _applySyncFavoriteResult(
|
||||||
|
Map<int, FileDescriptor> next, DbSyncIdResult result) {
|
||||||
|
for (final id in result.insert) {
|
||||||
|
final f = next[id];
|
||||||
|
if (f == null) {
|
||||||
|
_log.warning("[_applySyncFavoriteResult] File id not found: $id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (f is File) {
|
||||||
|
next[id] = f.copyWith(isFavorite: true);
|
||||||
|
} else {
|
||||||
|
next[id] = f.copyWith(fdIsFavorite: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final id in result.delete) {
|
||||||
|
final f = next[id];
|
||||||
|
if (f == null) {
|
||||||
|
_log.warning("[_applySyncFavoriteResult] File id not found: $id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (f is File) {
|
||||||
|
next[id] = f.copyWith(isFavorite: false);
|
||||||
|
} else {
|
||||||
|
next[id] = f.copyWith(fdIsFavorite: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _applySyncFileExifResult(
|
||||||
|
Map<int, FileDescriptor> next, List<FileDescriptor> results) {
|
||||||
|
for (final f in results) {
|
||||||
|
next[f.fdId] = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _load() async {
|
Future<void> _load() async {
|
||||||
var lastData = _FilesStreamEvent(
|
var lastData = _FilesStreamEvent(
|
||||||
files: const {},
|
files: const {},
|
||||||
|
|
|
@ -2,6 +2,8 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
|
import 'package:nc_photos/controller/files_controller.dart';
|
||||||
|
import 'package:nc_photos/controller/persons_controller.dart';
|
||||||
import 'package:nc_photos/entity/person.dart';
|
import 'package:nc_photos/entity/person.dart';
|
||||||
import 'package:nc_photos/use_case/startup_sync.dart';
|
import 'package:nc_photos/use_case/startup_sync.dart';
|
||||||
|
|
||||||
|
@ -15,14 +17,19 @@ class SyncController {
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> requestSync(
|
Future<void> requestSync({
|
||||||
Account account, PersonProvider personProvider) async {
|
required Account account,
|
||||||
|
required FilesController filesController,
|
||||||
|
required PersonsController personsController,
|
||||||
|
required PersonProvider personProvider,
|
||||||
|
}) async {
|
||||||
if (_isDisposed) {
|
if (_isDisposed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_syncCompleter == null) {
|
if (_syncCompleter == null) {
|
||||||
_syncCompleter = Completer();
|
_syncCompleter = Completer();
|
||||||
final result = await StartupSync.runInIsolate(account, personProvider);
|
final result = await StartupSync.runInIsolate(
|
||||||
|
account, filesController, personsController, personProvider);
|
||||||
if (!_isDisposed && result.isSyncPersonUpdated) {
|
if (!_isDisposed && result.isSyncPersonUpdated) {
|
||||||
onPeopleUpdated?.call();
|
onPeopleUpdated?.call();
|
||||||
}
|
}
|
||||||
|
@ -32,15 +39,23 @@ class SyncController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> requestResync(
|
Future<void> requestResync({
|
||||||
Account account, PersonProvider personProvider) async {
|
required Account account,
|
||||||
|
required FilesController filesController,
|
||||||
|
required PersonsController personsController,
|
||||||
|
required PersonProvider personProvider,
|
||||||
|
}) async {
|
||||||
if (_syncCompleter?.isCompleted == true) {
|
if (_syncCompleter?.isCompleted == true) {
|
||||||
_syncCompleter = null;
|
_syncCompleter = null;
|
||||||
return requestSync(account, personProvider);
|
|
||||||
} else {
|
} else {
|
||||||
// already syncing
|
// already syncing
|
||||||
return requestSync(account, personProvider);
|
|
||||||
}
|
}
|
||||||
|
return requestSync(
|
||||||
|
account: account,
|
||||||
|
filesController: filesController,
|
||||||
|
personsController: personsController,
|
||||||
|
personProvider: personProvider,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Account account;
|
final Account account;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:nc_photos/db/entity_converter.dart';
|
||||||
import 'package:nc_photos/di_container.dart';
|
import 'package:nc_photos/di_container.dart';
|
||||||
import 'package:nc_photos/event/event.dart';
|
import 'package:nc_photos/event/event.dart';
|
||||||
import 'package:np_codegen/np_codegen.dart';
|
import 'package:np_codegen/np_codegen.dart';
|
||||||
|
import 'package:np_db/np_db.dart';
|
||||||
|
|
||||||
part 'cache_favorite.g.dart';
|
part 'cache_favorite.g.dart';
|
||||||
|
|
||||||
|
@ -15,18 +16,18 @@ class CacheFavorite {
|
||||||
|
|
||||||
/// Cache favorites using results from remote
|
/// Cache favorites using results from remote
|
||||||
///
|
///
|
||||||
/// Return number of files updated
|
/// Return the fileIds of the affected files
|
||||||
Future<int> call(Account account, Iterable<int> remoteFileIds) async {
|
Future<DbSyncIdResult> call(
|
||||||
|
Account account, Iterable<int> remoteFileIds) async {
|
||||||
_log.info("[call] Cache favorites");
|
_log.info("[call] Cache favorites");
|
||||||
final result = await _c.npDb.syncFavoriteFiles(
|
final result = await _c.npDb.syncFavoriteFiles(
|
||||||
account: account.toDb(),
|
account: account.toDb(),
|
||||||
favoriteFileIds: remoteFileIds.toList(),
|
favoriteFileIds: remoteFileIds.toList(),
|
||||||
);
|
);
|
||||||
final count = result.insert + result.delete + result.update;
|
if (result.isNotEmpty) {
|
||||||
if (count > 0) {
|
|
||||||
KiwiContainer().resolve<EventBus>().fire(FavoriteResyncedEvent(account));
|
KiwiContainer().resolve<EventBus>().fire(FavoriteResyncedEvent(account));
|
||||||
}
|
}
|
||||||
return count;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
final DiContainer _c;
|
final DiContainer _c;
|
||||||
|
|
|
@ -7,6 +7,8 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/app_init.dart' as app_init;
|
import 'package:nc_photos/app_init.dart' as app_init;
|
||||||
|
import 'package:nc_photos/controller/files_controller.dart';
|
||||||
|
import 'package:nc_photos/controller/persons_controller.dart';
|
||||||
import 'package:nc_photos/di_container.dart';
|
import 'package:nc_photos/di_container.dart';
|
||||||
import 'package:nc_photos/entity/person.dart';
|
import 'package:nc_photos/entity/person.dart';
|
||||||
import 'package:nc_photos/event/event.dart';
|
import 'package:nc_photos/event/event.dart';
|
||||||
|
@ -14,8 +16,11 @@ import 'package:nc_photos/use_case/person/sync_person.dart';
|
||||||
import 'package:nc_photos/use_case/sync_favorite.dart';
|
import 'package:nc_photos/use_case/sync_favorite.dart';
|
||||||
import 'package:nc_photos/use_case/sync_tag.dart';
|
import 'package:nc_photos/use_case/sync_tag.dart';
|
||||||
import 'package:np_codegen/np_codegen.dart';
|
import 'package:np_codegen/np_codegen.dart';
|
||||||
|
import 'package:np_common/object_util.dart';
|
||||||
import 'package:np_common/type.dart';
|
import 'package:np_common/type.dart';
|
||||||
|
import 'package:np_db/np_db.dart';
|
||||||
import 'package:np_platform_util/np_platform_util.dart';
|
import 'package:np_platform_util/np_platform_util.dart';
|
||||||
|
import 'package:to_string/to_string.dart';
|
||||||
|
|
||||||
part 'startup_sync.g.dart';
|
part 'startup_sync.g.dart';
|
||||||
|
|
||||||
|
@ -28,7 +33,11 @@ class StartupSync {
|
||||||
|
|
||||||
/// Sync in a background isolate
|
/// Sync in a background isolate
|
||||||
static Future<SyncResult> runInIsolate(
|
static Future<SyncResult> runInIsolate(
|
||||||
Account account, PersonProvider personProvider) async {
|
Account account,
|
||||||
|
FilesController filesController,
|
||||||
|
PersonsController personsController,
|
||||||
|
PersonProvider personProvider,
|
||||||
|
) async {
|
||||||
return _mutex.protect(() async {
|
return _mutex.protect(() async {
|
||||||
if (getRawPlatform() == NpPlatform.web) {
|
if (getRawPlatform() == NpPlatform.web) {
|
||||||
// not supported on web
|
// not supported on web
|
||||||
|
@ -42,7 +51,7 @@ class StartupSync {
|
||||||
final result = SyncResult.fromJson(resultJson);
|
final result = SyncResult.fromJson(resultJson);
|
||||||
// events fired in background isolate won't be noticed by the main isolate,
|
// events fired in background isolate won't be noticed by the main isolate,
|
||||||
// so we fire them again here
|
// so we fire them again here
|
||||||
_broadcastResult(account, result);
|
_broadcastResult(account, filesController, personsController, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -52,16 +61,16 @@ class StartupSync {
|
||||||
Account account, PersonProvider personProvider) async {
|
Account account, PersonProvider personProvider) async {
|
||||||
_log.info("[_run] Begin sync");
|
_log.info("[_run] Begin sync");
|
||||||
final stopwatch = Stopwatch()..start();
|
final stopwatch = Stopwatch()..start();
|
||||||
late final int syncFavoriteCount;
|
DbSyncIdResult? syncFavoriteResult;
|
||||||
late final bool isSyncPersonUpdated;
|
DbSyncIdResult? syncTagResult;
|
||||||
|
var isSyncPersonUpdated = false;
|
||||||
try {
|
try {
|
||||||
syncFavoriteCount = await SyncFavorite(_c)(account);
|
syncFavoriteResult = await SyncFavorite(_c)(account);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
_log.shout("[_run] Failed while SyncFavorite", e, stackTrace);
|
_log.shout("[_run] Failed while SyncFavorite", e, stackTrace);
|
||||||
syncFavoriteCount = -1;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await SyncTag(_c)(account);
|
syncTagResult = await SyncTag(_c)(account);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
_log.shout("[_run] Failed while SyncTag", e, stackTrace);
|
_log.shout("[_run] Failed while SyncTag", e, stackTrace);
|
||||||
}
|
}
|
||||||
|
@ -72,16 +81,28 @@ class StartupSync {
|
||||||
}
|
}
|
||||||
_log.info("[_run] Elapsed time: ${stopwatch.elapsedMilliseconds}ms");
|
_log.info("[_run] Elapsed time: ${stopwatch.elapsedMilliseconds}ms");
|
||||||
return SyncResult(
|
return SyncResult(
|
||||||
syncFavoriteCount: syncFavoriteCount,
|
syncFavoriteResult: syncFavoriteResult,
|
||||||
|
syncTagResult: syncTagResult,
|
||||||
isSyncPersonUpdated: isSyncPersonUpdated,
|
isSyncPersonUpdated: isSyncPersonUpdated,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _broadcastResult(Account account, SyncResult result) {
|
static void _broadcastResult(
|
||||||
final eventBus = KiwiContainer().resolve<EventBus>();
|
Account account,
|
||||||
if (result.syncFavoriteCount > 0) {
|
FilesController filesController,
|
||||||
|
PersonsController personsController,
|
||||||
|
SyncResult result,
|
||||||
|
) {
|
||||||
|
_$StartupSyncNpLog.log.info('[_broadcastResult] $result');
|
||||||
|
if (result.syncFavoriteResult != null) {
|
||||||
|
filesController.applySyncResult(favorites: result.syncFavoriteResult!);
|
||||||
|
// legacy
|
||||||
|
final eventBus = KiwiContainer().resolve<EventBus>();
|
||||||
eventBus.fire(FavoriteResyncedEvent(account));
|
eventBus.fire(FavoriteResyncedEvent(account));
|
||||||
}
|
}
|
||||||
|
if (result.isSyncPersonUpdated) {
|
||||||
|
personsController.reload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final DiContainer _c;
|
final DiContainer _c;
|
||||||
|
@ -89,23 +110,35 @@ class StartupSync {
|
||||||
static final _mutex = Mutex();
|
static final _mutex = Mutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@toString
|
||||||
class SyncResult {
|
class SyncResult {
|
||||||
const SyncResult({
|
const SyncResult({
|
||||||
required this.syncFavoriteCount,
|
required this.syncFavoriteResult,
|
||||||
|
required this.syncTagResult,
|
||||||
required this.isSyncPersonUpdated,
|
required this.isSyncPersonUpdated,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SyncResult.fromJson(JsonObj json) => SyncResult(
|
factory SyncResult.fromJson(JsonObj json) => SyncResult(
|
||||||
syncFavoriteCount: json["syncFavoriteCount"],
|
syncFavoriteResult: (json["syncFavoriteResult"] as Map?)
|
||||||
|
?.cast<String, dynamic>()
|
||||||
|
.let(DbSyncIdResult.fromJson),
|
||||||
|
syncTagResult: (json["syncTagResult"] as Map?)
|
||||||
|
?.cast<String, dynamic>()
|
||||||
|
.let(DbSyncIdResult.fromJson),
|
||||||
isSyncPersonUpdated: json["isSyncPersonUpdated"],
|
isSyncPersonUpdated: json["isSyncPersonUpdated"],
|
||||||
);
|
);
|
||||||
|
|
||||||
JsonObj toJson() => {
|
JsonObj toJson() => {
|
||||||
"syncFavoriteCount": syncFavoriteCount,
|
"syncFavoriteResult": syncFavoriteResult?.toJson(),
|
||||||
|
"syncTagResult": syncTagResult?.toJson(),
|
||||||
"isSyncPersonUpdated": isSyncPersonUpdated,
|
"isSyncPersonUpdated": isSyncPersonUpdated,
|
||||||
};
|
};
|
||||||
|
|
||||||
final int syncFavoriteCount;
|
@override
|
||||||
|
String toString() => _$toString();
|
||||||
|
|
||||||
|
final DbSyncIdResult? syncFavoriteResult;
|
||||||
|
final DbSyncIdResult? syncTagResult;
|
||||||
final bool isSyncPersonUpdated;
|
final bool isSyncPersonUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,14 @@ extension _$StartupSyncNpLog on StartupSync {
|
||||||
|
|
||||||
static final log = Logger("use_case.startup_sync.StartupSync");
|
static final log = Logger("use_case.startup_sync.StartupSync");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// ToStringGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
extension _$SyncResultToString on SyncResult {
|
||||||
|
String _$toString() {
|
||||||
|
// ignore: unnecessary_string_interpolations
|
||||||
|
return "SyncResult {syncFavoriteResult: $syncFavoriteResult, syncTagResult: $syncTagResult, isSyncPersonUpdated: $isSyncPersonUpdated}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||||
import 'package:nc_photos/entity/pref.dart';
|
import 'package:nc_photos/entity/pref.dart';
|
||||||
import 'package:nc_photos/use_case/cache_favorite.dart';
|
import 'package:nc_photos/use_case/cache_favorite.dart';
|
||||||
import 'package:np_codegen/np_codegen.dart';
|
import 'package:np_codegen/np_codegen.dart';
|
||||||
|
import 'package:np_db/np_db.dart';
|
||||||
|
|
||||||
part 'sync_favorite.g.dart';
|
part 'sync_favorite.g.dart';
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ class SyncFavorite {
|
||||||
/// Sync favorites in cache db with remote server
|
/// Sync favorites in cache db with remote server
|
||||||
///
|
///
|
||||||
/// Return number of files updated
|
/// Return number of files updated
|
||||||
Future<int> call(Account account) async {
|
Future<DbSyncIdResult> call(Account account) async {
|
||||||
_log.info("[call] Sync favorites with remote");
|
_log.info("[call] Sync favorites with remote");
|
||||||
final remote = await _getRemoteFavoriteFileIds(account);
|
final remote = await _getRemoteFavoriteFileIds(account);
|
||||||
return await CacheFavorite(_c)(account, remote);
|
return await CacheFavorite(_c)(account, remote);
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/db/entity_converter.dart';
|
import 'package:nc_photos/db/entity_converter.dart';
|
||||||
import 'package:nc_photos/di_container.dart';
|
import 'package:nc_photos/di_container.dart';
|
||||||
import 'package:np_codegen/np_codegen.dart';
|
import 'package:np_codegen/np_codegen.dart';
|
||||||
|
import 'package:np_db/np_db.dart';
|
||||||
|
|
||||||
part 'sync_tag.g.dart';
|
part 'sync_tag.g.dart';
|
||||||
|
|
||||||
|
@ -11,13 +12,16 @@ class SyncTag {
|
||||||
const SyncTag(this._c);
|
const SyncTag(this._c);
|
||||||
|
|
||||||
/// Sync tags in cache db with remote server
|
/// Sync tags in cache db with remote server
|
||||||
Future<void> call(Account account) async {
|
///
|
||||||
|
/// Return tagIds of the affected tags
|
||||||
|
Future<DbSyncIdResult> call(Account account) async {
|
||||||
_log.info("[call] Sync tags with remote");
|
_log.info("[call] Sync tags with remote");
|
||||||
final remote = await _c.tagRepoRemote.list(account);
|
final remote = await _c.tagRepoRemote.list(account);
|
||||||
await _c.npDb.syncTags(
|
final result = await _c.npDb.syncTags(
|
||||||
account: account.toDb(),
|
account: account.toDb(),
|
||||||
tags: remote.map(DbTagConverter.toDb).toList(),
|
tags: remote.map(DbTagConverter.toDb).toList(),
|
||||||
);
|
);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
final DiContainer _c;
|
final DiContainer _c;
|
||||||
|
|
|
@ -609,7 +609,11 @@ class _HomePhotosState extends State<HomePhotos>
|
||||||
if (isPostSuccess) {
|
if (isPostSuccess) {
|
||||||
_isScrollbarVisible = true;
|
_isScrollbarVisible = true;
|
||||||
context.read<AccountController>().syncController.requestSync(
|
context.read<AccountController>().syncController.requestSync(
|
||||||
widget.account, _accountPrefController.personProvider.value);
|
account: widget.account,
|
||||||
|
filesController: context.read(),
|
||||||
|
personsController: context.read(),
|
||||||
|
personProvider: _accountPrefController.personProvider.value,
|
||||||
|
);
|
||||||
_tryStartMetadataTask(context);
|
_tryStartMetadataTask(context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,8 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
required this.accountPrefController,
|
required this.accountPrefController,
|
||||||
required this.collectionsController,
|
required this.collectionsController,
|
||||||
required this.sessionController,
|
required this.sessionController,
|
||||||
|
required this.syncController,
|
||||||
|
required this.personsController,
|
||||||
}) : super(_State.init(
|
}) : super(_State.init(
|
||||||
zoom: prefController.homePhotosZoomLevel.value,
|
zoom: prefController.homePhotosZoomLevel.value,
|
||||||
isEnableMemoryCollection:
|
isEnableMemoryCollection:
|
||||||
|
@ -142,6 +144,12 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
memoryCollections: ev.memoryCollections,
|
memoryCollections: ev.memoryCollections,
|
||||||
isLoading: _itemTransformerQueue.isProcessing,
|
isLoading: _itemTransformerQueue.isProcessing,
|
||||||
));
|
));
|
||||||
|
syncController.requestSync(
|
||||||
|
account: account,
|
||||||
|
filesController: controller,
|
||||||
|
personsController: personsController,
|
||||||
|
personProvider: accountPrefController.personProvider.value,
|
||||||
|
);
|
||||||
_tryStartMetadataTask();
|
_tryStartMetadataTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,6 +411,8 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||||
final AccountPrefController accountPrefController;
|
final AccountPrefController accountPrefController;
|
||||||
final CollectionsController collectionsController;
|
final CollectionsController collectionsController;
|
||||||
final SessionController sessionController;
|
final SessionController sessionController;
|
||||||
|
final SyncController syncController;
|
||||||
|
final PersonsController personsController;
|
||||||
|
|
||||||
final _itemTransformerQueue =
|
final _itemTransformerQueue =
|
||||||
ComputeQueue<_ItemTransformerArgument, _ItemTransformerResult>();
|
ComputeQueue<_ItemTransformerArgument, _ItemTransformerResult>();
|
||||||
|
|
|
@ -18,8 +18,10 @@ import 'package:nc_photos/controller/account_controller.dart';
|
||||||
import 'package:nc_photos/controller/account_pref_controller.dart';
|
import 'package:nc_photos/controller/account_pref_controller.dart';
|
||||||
import 'package:nc_photos/controller/collections_controller.dart';
|
import 'package:nc_photos/controller/collections_controller.dart';
|
||||||
import 'package:nc_photos/controller/files_controller.dart';
|
import 'package:nc_photos/controller/files_controller.dart';
|
||||||
|
import 'package:nc_photos/controller/persons_controller.dart';
|
||||||
import 'package:nc_photos/controller/pref_controller.dart';
|
import 'package:nc_photos/controller/pref_controller.dart';
|
||||||
import 'package:nc_photos/controller/session_controller.dart';
|
import 'package:nc_photos/controller/session_controller.dart';
|
||||||
|
import 'package:nc_photos/controller/sync_controller.dart';
|
||||||
import 'package:nc_photos/db/entity_converter.dart';
|
import 'package:nc_photos/db/entity_converter.dart';
|
||||||
import 'package:nc_photos/di_container.dart';
|
import 'package:nc_photos/di_container.dart';
|
||||||
import 'package:nc_photos/download_handler.dart';
|
import 'package:nc_photos/download_handler.dart';
|
||||||
|
@ -87,6 +89,8 @@ class HomePhotos2 extends StatelessWidget {
|
||||||
accountPrefController: accountController.accountPrefController,
|
accountPrefController: accountController.accountPrefController,
|
||||||
collectionsController: accountController.collectionsController,
|
collectionsController: accountController.collectionsController,
|
||||||
sessionController: accountController.sessionController,
|
sessionController: accountController.sessionController,
|
||||||
|
syncController: accountController.syncController,
|
||||||
|
personsController: accountController.personsController,
|
||||||
),
|
),
|
||||||
child: const _WrappedHomePhotos(),
|
child: const _WrappedHomePhotos(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -109,8 +109,12 @@ class _WrappedAccountSettingsState extends State<_WrappedAccountSettings>
|
||||||
if (_bloc.state.shouldResync &&
|
if (_bloc.state.shouldResync &&
|
||||||
_bloc.state.personProvider != PersonProvider.none) {
|
_bloc.state.personProvider != PersonProvider.none) {
|
||||||
_log.fine("[dispose] Requesting to resync account");
|
_log.fine("[dispose] Requesting to resync account");
|
||||||
_accountController.syncController
|
_accountController.syncController.requestResync(
|
||||||
.requestResync(_bloc.state.account, _bloc.state.personProvider);
|
account: _bloc.state.account,
|
||||||
|
filesController: context.read(),
|
||||||
|
personsController: context.read(),
|
||||||
|
personProvider: _bloc.state.personProvider,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_animationController.dispose();
|
_animationController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
|
@ -49,6 +49,36 @@ class DbSyncResult {
|
||||||
final int update;
|
final int update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sync results with ids
|
||||||
|
///
|
||||||
|
/// The meaning of the ids returned depends on the specific call
|
||||||
|
class DbSyncIdResult {
|
||||||
|
const DbSyncIdResult({
|
||||||
|
required this.insert,
|
||||||
|
required this.delete,
|
||||||
|
required this.update,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory DbSyncIdResult.fromJson(JsonObj json) => DbSyncIdResult(
|
||||||
|
insert: (json["insert"] as List).cast<int>(),
|
||||||
|
delete: (json["delete"] as List).cast<int>(),
|
||||||
|
update: (json["update"] as List).cast<int>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
JsonObj toJson() => {
|
||||||
|
"insert": insert,
|
||||||
|
"delete": delete,
|
||||||
|
"update": update,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool get isEmpty => insert.isEmpty && delete.isEmpty && update.isEmpty;
|
||||||
|
bool get isNotEmpty => !isEmpty;
|
||||||
|
|
||||||
|
final List<int> insert;
|
||||||
|
final List<int> delete;
|
||||||
|
final List<int> update;
|
||||||
|
}
|
||||||
|
|
||||||
@toString
|
@toString
|
||||||
class DbLocationGroup with EquatableMixin {
|
class DbLocationGroup with EquatableMixin {
|
||||||
const DbLocationGroup({
|
const DbLocationGroup({
|
||||||
|
@ -235,7 +265,9 @@ abstract class NpDb {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Add or replace nc albums in db
|
/// Add or replace nc albums in db
|
||||||
Future<DbSyncResult> syncFavoriteFiles({
|
///
|
||||||
|
/// Return fileIds affected by this call
|
||||||
|
Future<DbSyncIdResult> syncFavoriteFiles({
|
||||||
required DbAccount account,
|
required DbAccount account,
|
||||||
required List<int> favoriteFileIds,
|
required List<int> favoriteFileIds,
|
||||||
});
|
});
|
||||||
|
@ -374,7 +406,7 @@ abstract class NpDb {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Replace all tags for [account]
|
/// Replace all tags for [account]
|
||||||
Future<DbSyncResult> syncTags({
|
Future<DbSyncIdResult> syncTags({
|
||||||
required DbAccount account,
|
required DbAccount account,
|
||||||
required List<DbTag> tags,
|
required List<DbTag> tags,
|
||||||
});
|
});
|
||||||
|
|
|
@ -337,7 +337,7 @@ class NpDbSqlite implements NpDb {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<DbSyncResult> syncFavoriteFiles({
|
Future<DbSyncIdResult> syncFavoriteFiles({
|
||||||
required DbAccount account,
|
required DbAccount account,
|
||||||
required List<int> favoriteFileIds,
|
required List<int> favoriteFileIds,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -370,10 +370,10 @@ class NpDbSqlite implements NpDb {
|
||||||
isFavorite: const OrNull(false),
|
isFavorite: const OrNull(false),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return DbSyncResult(
|
return DbSyncIdResult(
|
||||||
insert: inserts.length,
|
insert: inserts,
|
||||||
delete: deletes.length,
|
delete: deletes,
|
||||||
update: 0,
|
update: const [],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -834,7 +834,7 @@ class NpDbSqlite implements NpDb {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<DbSyncResult> syncTags({
|
Future<DbSyncIdResult> syncTags({
|
||||||
required DbAccount account,
|
required DbAccount account,
|
||||||
required List<DbTag> tags,
|
required List<DbTag> tags,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -863,10 +863,10 @@ class NpDbSqlite implements NpDb {
|
||||||
updates: updates,
|
updates: updates,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return DbSyncResult(
|
return DbSyncIdResult(
|
||||||
insert: inserts.length,
|
insert: inserts.map((e) => e.id).toList(),
|
||||||
delete: deletes.length,
|
delete: deletes.map((e) => e.id).toList(),
|
||||||
update: updates.length,
|
update: updates.map((e) => e.id).toList(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue