Overhaul how dependencies are injected to clients

This commit is contained in:
Ming Ming 2021-12-08 02:42:25 +08:00
parent 9cf061ad8e
commit 2d8738146e
29 changed files with 272 additions and 186 deletions

View file

@ -1,7 +1,8 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file/data_source.dart';
@ -10,6 +11,7 @@ import 'package:nc_photos/entity/share.dart';
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/exception.dart'; import 'package:nc_photos/exception.dart';
import 'package:nc_photos/exception_event.dart'; import 'package:nc_photos/exception_event.dart';
import 'package:nc_photos/or_null.dart';
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
import 'package:nc_photos/throttler.dart'; import 'package:nc_photos/throttler.dart';
import 'package:nc_photos/use_case/list_album.dart'; import 'package:nc_photos/use_case/list_album.dart';
@ -102,7 +104,19 @@ class ListAlbumBlocInconsistent extends ListAlbumBlocState {
} }
class ListAlbumBloc extends Bloc<ListAlbumBlocEvent, ListAlbumBlocState> { class ListAlbumBloc extends Bloc<ListAlbumBlocEvent, ListAlbumBlocState> {
ListAlbumBloc() : super(const ListAlbumBlocInit()) { /// Constructor
///
/// If [offlineC] is not null, this [DiContainer] will be used when requesting
/// offline contents, otherwise [_c] will be used
ListAlbumBloc(
this._c, [
DiContainer? offlineC,
]) : _offlineC = offlineC ?? _c,
assert(require(_c)),
assert(offlineC == null || require(offlineC)),
assert(ListAlbum.require(_c)),
assert(offlineC == null || ListAlbum.require(offlineC)),
super(const ListAlbumBlocInit()) {
_albumUpdatedListener = _albumUpdatedListener =
AppEventListener<AlbumUpdatedEvent>(_onAlbumUpdatedEvent); AppEventListener<AlbumUpdatedEvent>(_onAlbumUpdatedEvent);
_fileRemovedListener = _fileRemovedListener =
@ -124,6 +138,28 @@ class ListAlbumBloc extends Bloc<ListAlbumBlocEvent, ListAlbumBlocState> {
); );
} }
static bool require(DiContainer c) => true;
static ListAlbumBloc of(Account account) {
final id = "${account.scheme}://${account.username}@${account.address}";
try {
_log.fine("[of] Resolving bloc for '$id'");
return KiwiContainer().resolve<ListAlbumBloc>("ListAlbumBloc($id)");
} catch (_) {
// no created instance for this account, make a new one
_log.info("[of] New bloc instance for account: $account");
final c = KiwiContainer().resolve<DiContainer>();
final offlineC = c.copyWith(
fileRepo: OrNull(FileRepo(FileAppDbDataSource(c.appDb))),
albumRepo: OrNull(AlbumRepo(AlbumAppDbDataSource(c.appDb))),
);
final bloc = ListAlbumBloc(c, offlineC);
KiwiContainer()
.registerInstance<ListAlbumBloc>(bloc, name: "ListAlbumBloc($id)");
return bloc;
}
}
@override @override
mapEventToState(ListAlbumBlocEvent event) async* { mapEventToState(ListAlbumBlocEvent event) async* {
_log.info("[mapEventToState] $event"); _log.info("[mapEventToState] $event");
@ -249,20 +285,17 @@ class ListAlbumBloc extends Bloc<ListAlbumBlocEvent, ListAlbumBlocState> {
} }
Future<ListAlbumBlocState> _queryOffline(ListAlbumBlocQuery ev) => Future<ListAlbumBlocState> _queryOffline(ListAlbumBlocQuery ev) =>
_queryWithAlbumDataSource( _queryWithAlbumDataSource(_offlineC, ev);
ev, FileAppDbDataSource(AppDb()), AlbumAppDbDataSource(AppDb()));
Future<ListAlbumBlocState> _queryOnline(ListAlbumBlocQuery ev) => Future<ListAlbumBlocState> _queryOnline(ListAlbumBlocQuery ev) =>
_queryWithAlbumDataSource( _queryWithAlbumDataSource(_c, ev);
ev, FileCachedDataSource(AppDb()), AlbumCachedDataSource(AppDb()));
Future<ListAlbumBlocState> _queryWithAlbumDataSource(ListAlbumBlocQuery ev, Future<ListAlbumBlocState> _queryWithAlbumDataSource(
FileDataSource fileDataSource, AlbumDataSource albumDataSrc) async { DiContainer c, ListAlbumBlocQuery ev) async {
try { try {
final albums = <Album>[]; final albums = <Album>[];
final errors = <dynamic>[]; final errors = <dynamic>[];
await for (final result in ListAlbum( await for (final result in ListAlbum(c)(ev.account)) {
FileRepo(fileDataSource), AlbumRepo(albumDataSrc))(ev.account)) {
if (result is ExceptionEvent) { if (result is ExceptionEvent) {
if (result.error is CacheNotFoundException) { if (result.error is CacheNotFoundException) {
_log.info( _log.info(
@ -292,6 +325,9 @@ class ListAlbumBloc extends Bloc<ListAlbumBlocEvent, ListAlbumBlocState> {
bool _isAccountOfInterest(Account account) => bool _isAccountOfInterest(Account account) =>
state.account == null || state.account!.compareServerIdentity(account); state.account == null || state.account!.compareServerIdentity(account);
final DiContainer _c;
final DiContainer _offlineC;
late AppEventListener<AlbumUpdatedEvent> _albumUpdatedListener; late AppEventListener<AlbumUpdatedEvent> _albumUpdatedListener;
late AppEventListener<FileRemovedEvent> _fileRemovedListener; late AppEventListener<FileRemovedEvent> _fileRemovedListener;
late AppEventListener<AlbumCreatedEvent> _albumCreatedListener; late AppEventListener<AlbumCreatedEvent> _albumCreatedListener;

View file

@ -1,12 +1,11 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/debug_util.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/use_case/list_album.dart'; import 'package:nc_photos/use_case/list_album.dart';
@ -87,7 +86,12 @@ class ListImportableAlbumBlocFailure extends ListImportableAlbumBlocState {
/// Return all directories that potentially could be a new album /// Return all directories that potentially could be a new album
class ListImportableAlbumBloc class ListImportableAlbumBloc
extends Bloc<ListImportableAlbumBlocEvent, ListImportableAlbumBlocState> { extends Bloc<ListImportableAlbumBlocEvent, ListImportableAlbumBlocState> {
ListImportableAlbumBloc() : super(ListImportableAlbumBlocInit()); ListImportableAlbumBloc(this._c)
: assert(require(_c)),
assert(ListAlbum.require(_c)),
super(ListImportableAlbumBlocInit());
static bool require(DiContainer c) => DiContainer.has(c, DiType.fileRepo);
@override @override
mapEventToState(ListImportableAlbumBlocEvent event) async* { mapEventToState(ListImportableAlbumBlocEvent event) async* {
@ -101,9 +105,7 @@ class ListImportableAlbumBloc
ListImportableAlbumBlocQuery ev) async* { ListImportableAlbumBlocQuery ev) async* {
yield const ListImportableAlbumBlocLoading([]); yield const ListImportableAlbumBlocLoading([]);
try { try {
final fileRepo = FileRepo(FileCachedDataSource(AppDb())); final albums = (await ListAlbum(_c)(ev.account)
final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb()));
final albums = (await ListAlbum(fileRepo, albumRepo)(ev.account)
.where((event) => event is Album) .where((event) => event is Album)
.toList()) .toList())
.cast<Album>(); .cast<Album>();
@ -119,8 +121,7 @@ class ListImportableAlbumBloc
final products = <ListImportableAlbumBlocItem>[]; final products = <ListImportableAlbumBlocItem>[];
int count = 0; int count = 0;
for (final r in ev.roots) { for (final r in ev.roots) {
await for (final ev await for (final ev in _queryDir(ev.account, importedDirs, r)) {
in _queryDir(fileRepo, ev.account, importedDirs, r)) {
if (ev is Exception || ev is Error) { if (ev is Exception || ev is Error) {
throw ev; throw ev;
} else if (ev is ListImportableAlbumBlocItem) { } else if (ev is ListImportableAlbumBlocItem) {
@ -142,13 +143,13 @@ class ListImportableAlbumBloc
/// Query [dir] and emit all conforming dirs recursively (including [dir]) /// Query [dir] and emit all conforming dirs recursively (including [dir])
/// ///
/// Emit ListImportableAlbumBlocItem or Exception /// Emit ListImportableAlbumBlocItem or Exception
Stream<dynamic> _queryDir(FileRepo fileRepo, Account account, Stream<dynamic> _queryDir(
List<File> importedDirs, File dir) async* { Account account, List<File> importedDirs, File dir) async* {
try { try {
if (importedDirs.containsIf(dir, (a, b) => a.path == b.path)) { if (importedDirs.containsIf(dir, (a, b) => a.path == b.path)) {
return; return;
} }
final files = await Ls(fileRepo)(account, dir); final files = await Ls(_c.fileRepo)(account, dir);
// check number of supported files in this directory // check number of supported files in this directory
final count = files.where((f) => file_util.isSupportedFormat(f)).length; final count = files.where((f) => file_util.isSupportedFormat(f)).length;
// arbitrary number // arbitrary number
@ -156,7 +157,7 @@ class ListImportableAlbumBloc
yield ListImportableAlbumBlocItem(dir, count); yield ListImportableAlbumBlocItem(dir, count);
} }
for (final d in files.where((f) => f.isCollection == true)) { for (final d in files.where((f) => f.isCollection == true)) {
yield* _queryDir(fileRepo, account, importedDirs, d); yield* _queryDir(account, importedDirs, d);
} }
} catch (e, stacktrace) { } catch (e, stacktrace) {
_log.shout( _log.shout(
@ -167,6 +168,8 @@ class ListImportableAlbumBloc
} }
} }
final DiContainer _c;
static final _log = static final _log =
Logger("bloc.list_importable_album.ListImportableAlbumBloc"); Logger("bloc.list_importable_album.ListImportableAlbumBloc");
} }

View file

@ -2,13 +2,11 @@ import 'package:bloc/bloc.dart';
import 'package:kiwi/kiwi.dart'; import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/share.dart';
import 'package:nc_photos/entity/share/data_source.dart';
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
@ -152,7 +150,12 @@ class ListSharingBlocFailure extends ListSharingBlocState {
/// List shares to be shown in [SharingBrowser] /// List shares to be shown in [SharingBrowser]
class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> { class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
ListSharingBloc() : super(ListSharingBlocInit()) { ListSharingBloc(this._c)
: assert(require(_c)),
assert(FindFile.require(_c)),
assert(ListShareWithMe.require(_c)),
assert(LsSingleFile.require(_c)),
super(ListSharingBlocInit()) {
_shareRemovedListener.begin(); _shareRemovedListener.begin();
_fileMovedEventListener.begin(); _fileMovedEventListener.begin();
@ -164,6 +167,11 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
); );
} }
static bool require(DiContainer c) =>
DiContainer.has(c, DiType.albumRepo) &&
DiContainer.has(c, DiType.fileRepo) &&
DiContainer.has(c, DiType.shareRepo);
static ListSharingBloc of(Account account) { static ListSharingBloc of(Account account) {
final id = final id =
"${account.scheme}://${account.username}@${account.address}?${account.roots.join('&')}"; "${account.scheme}://${account.username}@${account.address}?${account.roots.join('&')}";
@ -173,7 +181,7 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
} catch (_) { } catch (_) {
// no created instance for this account, make a new one // no created instance for this account, make a new one
_log.info("[of] New bloc instance for account: $account"); _log.info("[of] New bloc instance for account: $account");
final bloc = ListSharingBloc(); final bloc = ListSharingBloc(KiwiContainer().resolve<DiContainer>());
KiwiContainer().registerInstance<ListSharingBloc>(bloc, KiwiContainer().registerInstance<ListSharingBloc>(bloc,
name: "ListSharingBloc($id)"); name: "ListSharingBloc($id)");
return bloc; return bloc;
@ -234,14 +242,10 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
final items = List.of(state.items); final items = List.of(state.items);
items.removeWhere( items.removeWhere(
(i) => i is ListSharingAlbum && i.share.path == ev.file.strippedPath); (i) => i is ListSharingAlbum && i.share.path == ev.file.strippedPath);
final fileRepo = FileRepo(FileCachedDataSource(AppDb())); final newShares =
final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); await ListShareWithMe(_c)(ev.account, File(path: ev.destination));
final shareRepo = ShareRepo(ShareRemoteDataSource()); final newAlbumFile = await LsSingleFile(_c)(ev.account, ev.destination);
final newShares = await ListShareWithMe(shareRepo)( final newAlbum = await _c.albumRepo.get(ev.account, newAlbumFile);
ev.account, File(path: ev.destination));
final newAlbumFile =
await LsSingleFile(fileRepo)(ev.account, ev.destination);
final newAlbum = await albumRepo.get(ev.account, newAlbumFile);
for (final s in newShares) { for (final s in newShares) {
items.add(ListSharingAlbum(s, newAlbum)); items.add(ListSharingAlbum(s, newAlbum));
} }
@ -282,8 +286,7 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
} }
Future<List<ListSharingItem>> _query(ListSharingBlocQuery ev) async { Future<List<ListSharingItem>> _query(ListSharingBlocQuery ev) async {
final fileRepo = FileRepo(FileCachedDataSource(AppDb())); final sharedAlbumFiles = await Ls(_c.fileRepo)(
final sharedAlbumFiles = await Ls(fileRepo)(
ev.account, ev.account,
File( File(
path: remote_storage_util.getRemoteAlbumsDir(ev.account), path: remote_storage_util.getRemoteAlbumsDir(ev.account),
@ -297,8 +300,7 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
Future<List<ListSharingItem>> _querySharesByMe( Future<List<ListSharingItem>> _querySharesByMe(
ListSharingBlocQuery ev, List<File> sharedAlbumFiles) async { ListSharingBlocQuery ev, List<File> sharedAlbumFiles) async {
final shareRepo = ShareRepo(ShareRemoteDataSource()); final shares = await _c.shareRepo.listAll(ev.account);
final shares = await shareRepo.listAll(ev.account);
final futures = shares.map((s) async { final futures = shares.map((s) async {
final webdavPath = file_util.unstripPath(ev.account, s.path); final webdavPath = file_util.unstripPath(ev.account, s.path);
// include link share dirs // include link share dirs
@ -344,7 +346,7 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
} }
try { try {
final file = await FindFile(AppDb())(ev.account, s.itemSource); final file = await FindFile(_c)(ev.account, s.itemSource);
return ListSharingFile(s, file); return ListSharingFile(s, file);
} catch (e, stackTrace) { } catch (e, stackTrace) {
_log.severe("[_querySharesByMe] File not found: ${s.itemSource}", e, _log.severe("[_querySharesByMe] File not found: ${s.itemSource}", e,
@ -357,15 +359,13 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
Future<List<ListSharingItem>> _querySharesWithMe( Future<List<ListSharingItem>> _querySharesWithMe(
ListSharingBlocQuery ev, List<File> sharedAlbumFiles) async { ListSharingBlocQuery ev, List<File> sharedAlbumFiles) async {
final fileRepo = FileRepo(FileCachedDataSource(AppDb())); final pendingSharedAlbumFiles = await Ls(_c.fileRepo)(
final pendingSharedAlbumFiles = await Ls(fileRepo)(
ev.account, ev.account,
File( File(
path: remote_storage_util.getRemotePendingSharedAlbumsDir(ev.account), path: remote_storage_util.getRemotePendingSharedAlbumsDir(ev.account),
)); ));
final shareRepo = ShareRepo(ShareRemoteDataSource()); final shares = await _c.shareRepo.reverseListAll(ev.account);
final shares = await shareRepo.reverseListAll(ev.account);
final futures = shares.map((s) async { final futures = shares.map((s) async {
final webdavPath = file_util.unstripPath(ev.account, s.path); final webdavPath = file_util.unstripPath(ev.account, s.path);
// include pending shared albums // include pending shared albums
@ -405,8 +405,7 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
Future<ListSharingItem?> _querySharedAlbum( Future<ListSharingItem?> _querySharedAlbum(
ListSharingBlocQuery ev, Share share, File albumFile) async { ListSharingBlocQuery ev, Share share, File albumFile) async {
try { try {
final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); final album = await _c.albumRepo.get(ev.account, albumFile);
final album = await albumRepo.get(ev.account, albumFile);
return ListSharingAlbum(share, album); return ListSharingAlbum(share, album);
} catch (e, stackTrace) { } catch (e, stackTrace) {
_log.shout( _log.shout(
@ -418,6 +417,8 @@ class ListSharingBloc extends Bloc<ListSharingBlocEvent, ListSharingBlocState> {
bool _isAccountOfInterest(Account account) => bool _isAccountOfInterest(Account account) =>
state.account == null || state.account!.compareServerIdentity(account); state.account == null || state.account!.compareServerIdentity(account);
final DiContainer _c;
late final _shareRemovedListener = late final _shareRemovedListener =
AppEventListener<ShareRemovedEvent>(_onShareRemovedEvent); AppEventListener<ShareRemovedEvent>(_onShareRemovedEvent);
late final _fileMovedEventListener = late final _fileMovedEventListener =

View file

@ -5,6 +5,7 @@ import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/person.dart'; import 'package:nc_photos/entity/person.dart';
import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/share.dart';
import 'package:nc_photos/entity/sharee.dart'; import 'package:nc_photos/entity/sharee.dart';
import 'package:nc_photos/or_null.dart';
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
enum DiType { enum DiType {
@ -58,6 +59,28 @@ class DiContainer {
} }
} }
DiContainer copyWith({
OrNull<AlbumRepo>? albumRepo,
OrNull<FaceRepo>? faceRepo,
OrNull<FileRepo>? fileRepo,
OrNull<PersonRepo>? personRepo,
OrNull<ShareRepo>? shareRepo,
OrNull<ShareeRepo>? shareeRepo,
OrNull<AppDb>? appDb,
OrNull<Pref>? pref,
}) {
return DiContainer(
albumRepo: albumRepo == null ? this.albumRepo : albumRepo.obj,
faceRepo: faceRepo == null ? this.faceRepo : faceRepo.obj,
fileRepo: fileRepo == null ? this.fileRepo : fileRepo.obj,
personRepo: personRepo == null ? this.personRepo : personRepo.obj,
shareRepo: shareRepo == null ? this.shareRepo : shareRepo.obj,
shareeRepo: shareeRepo == null ? this.shareeRepo : shareeRepo.obj,
appDb: appDb == null ? this.appDb : appDb.obj,
pref: pref == null ? this.pref : pref.obj,
);
}
AlbumRepo get albumRepo => _albumRepo!; AlbumRepo get albumRepo => _albumRepo!;
FaceRepo get faceRepo => _faceRepo!; FaceRepo get faceRepo => _faceRepo!;
FileRepo get fileRepo => _fileRepo!; FileRepo get fileRepo => _fileRepo!;

View file

@ -1,5 +1,6 @@
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/use_case/move.dart'; import 'package:nc_photos/use_case/move.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
@ -12,12 +13,16 @@ class CompatV25 {
/// Migrate an album file to the new naming scheme /// Migrate an album file to the new naming scheme
static Future<File> migrateAlbumFile( static Future<File> migrateAlbumFile(
FileRepo fileRepo, Account account, File albumFile) => DiContainer c, Account account, File albumFile) =>
_MigrateAlbumFile(fileRepo)(account, albumFile); _MigrateAlbumFile(c)(account, albumFile);
} }
class _MigrateAlbumFile { class _MigrateAlbumFile {
_MigrateAlbumFile(this.fileRepo); _MigrateAlbumFile(this._c)
: assert(require(_c)),
assert(Move.require(_c));
static bool require(DiContainer c) => true;
Future<File> call(Account account, File albumFile) async { Future<File> call(Account account, File albumFile) async {
assert(CompatV25.isAlbumFileNeedMigration(albumFile)); assert(CompatV25.isAlbumFileNeedMigration(albumFile));
@ -25,12 +30,13 @@ class _MigrateAlbumFile {
"/" + "/" +
path.basenameWithoutExtension(albumFile.path) + path.basenameWithoutExtension(albumFile.path) +
".nc_album.json"; ".nc_album.json";
_log.info("[call] Migrate album file from '${albumFile.path}' to '$newPath'"); _log.info(
await Move(fileRepo)(account, albumFile, newPath); "[call] Migrate album file from '${albumFile.path}' to '$newPath'");
await Move(_c)(account, albumFile, newPath);
return albumFile.copyWith(path: newPath); return albumFile.copyWith(path: newPath);
} }
final FileRepo fileRepo; final DiContainer _c;
static final _log = Logger("use_case.compat.v25._MigrateAlbumFile"); static final _log = Logger("use_case.compat.v25._MigrateAlbumFile");
} }

View file

@ -1,15 +1,18 @@
import 'package:idb_shim/idb_client.dart'; import 'package:idb_shim/idb_client.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
class FindFile { class FindFile {
const FindFile(this.appDb); FindFile(this._c) : assert(require(_c));
static bool require(DiContainer c) => DiContainer.has(c, DiType.appDb);
/// Find the [File] in the DB by [fileId] /// Find the [File] in the DB by [fileId]
Future<File> call(Account account, int fileId) async { Future<File> call(Account account, int fileId) async {
return await appDb.use((db) async { return await _c.appDb.use((db) async {
final transaction = final transaction =
db.transaction(AppDb.fileDbStoreName, idbModeReadOnly); db.transaction(AppDb.fileDbStoreName, idbModeReadOnly);
final store = transaction.objectStore(AppDb.fileDbStoreName); final store = transaction.objectStore(AppDb.fileDbStoreName);
@ -27,5 +30,5 @@ class FindFile {
}); });
} }
final AppDb appDb; final DiContainer _c;
} }

View file

@ -1,4 +1,5 @@
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
@ -7,22 +8,26 @@ import 'package:nc_photos/use_case/move.dart';
/// Import a shared album from the pending dir to the library /// Import a shared album from the pending dir to the library
class ImportPendingSharedAlbum { class ImportPendingSharedAlbum {
const ImportPendingSharedAlbum(this.fileRepo, this.albumRepo); ImportPendingSharedAlbum(this._c)
: assert(require(_c)),
assert(LsSingleFile.require(_c)),
assert(Move.require(_c));
static bool require(DiContainer c) => DiContainer.has(c, DiType.albumRepo);
Future<Album> call(Account account, Album album) async { Future<Album> call(Account account, Album album) async {
final destination = final destination =
"${remote_storage_util.getRemoteAlbumsDir(account)}/${album.albumFile!.filename}"; "${remote_storage_util.getRemoteAlbumsDir(account)}/${album.albumFile!.filename}";
await Move(fileRepo)( await Move(_c)(
account, account,
album.albumFile!, album.albumFile!,
destination, destination,
shouldCreateMissingDir: true, shouldCreateMissingDir: true,
); );
final newAlbumFile = await LsSingleFile(fileRepo)(account, destination); final newAlbumFile = await LsSingleFile(_c)(account, destination);
final newAlbum = await albumRepo.get(account, newAlbumFile); final newAlbum = await _c.albumRepo.get(account, newAlbumFile);
return newAlbum; return newAlbum;
} }
final FileRepo fileRepo; final DiContainer _c;
final AlbumRepo albumRepo;
} }

View file

@ -1,5 +1,6 @@
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
@ -9,20 +10,26 @@ import 'package:nc_photos/use_case/move.dart';
/// Import new shared albums to the pending dir /// Import new shared albums to the pending dir
class ImportPotentialSharedAlbum { class ImportPotentialSharedAlbum {
ImportPotentialSharedAlbum(this.fileRepo, this.albumRepo); ImportPotentialSharedAlbum(this._c)
: assert(require(_c)),
assert(Move.require(_c));
static bool require(DiContainer c) =>
DiContainer.has(c, DiType.albumRepo) &&
DiContainer.has(c, DiType.fileRepo);
Future<List<Album>> call(Account account, AccountPref accountPref) async { Future<List<Album>> call(Account account, AccountPref accountPref) async {
_log.info("[call] $account"); _log.info("[call] $account");
final products = <Album>[]; final products = <Album>[];
final files = final files =
await ListPotentialSharedAlbum(fileRepo)(account, accountPref); await ListPotentialSharedAlbum(_c.fileRepo)(account, accountPref);
for (final f in files) { for (final f in files) {
// check if the file is actually an album // check if the file is actually an album
try { try {
final album = await albumRepo.get(account, f); final album = await _c.albumRepo.get(account, f);
_log.info("[call] New shared album: ${album.name}, file: ${f.path}"); _log.info("[call] New shared album: ${album.name}, file: ${f.path}");
// move this file to the pending dir // move this file to the pending dir
await Move(fileRepo)( await Move(_c)(
account, account,
f, f,
"${remote_storage_util.getRemotePendingSharedAlbumsDir(account)}/${f.filename}", "${remote_storage_util.getRemotePendingSharedAlbumsDir(account)}/${f.filename}",
@ -36,8 +43,7 @@ class ImportPotentialSharedAlbum {
return products; return products;
} }
final FileRepo fileRepo; final DiContainer _c;
final AlbumRepo albumRepo;
static final _log = Logger( static final _log = Logger(
"user_case.import_potential_shared_album.ImportPotentialSharedAlbum"); "user_case.import_potential_shared_album.ImportPotentialSharedAlbum");

View file

@ -1,5 +1,6 @@
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/exception.dart'; import 'package:nc_photos/exception.dart';
@ -10,7 +11,11 @@ import 'package:nc_photos/use_case/compat/v25.dart';
import 'package:nc_photos/use_case/ls.dart'; import 'package:nc_photos/use_case/ls.dart';
class ListAlbum { class ListAlbum {
ListAlbum(this.fileRepo, this.albumRepo); ListAlbum(this._c) : assert(require(_c));
static bool require(DiContainer c) =>
DiContainer.has(c, DiType.albumRepo) &&
DiContainer.has(c, DiType.fileRepo);
/// List all albums associated with [account] /// List all albums associated with [account]
/// ///
@ -22,7 +27,7 @@ class ListAlbum {
yield result; yield result;
} }
if (!hasAlbum) { if (!hasAlbum) {
if (await CompatV15.migrateAlbumFiles(account, fileRepo)) { if (await CompatV15.migrateAlbumFiles(account, _c.fileRepo)) {
// migrated, try again // migrated, try again
yield* _call(account); yield* _call(account);
} }
@ -32,7 +37,7 @@ class ListAlbum {
Stream<dynamic> _call(Account account) async* { Stream<dynamic> _call(Account account) async* {
List<File> ls; List<File> ls;
try { try {
ls = await Ls(fileRepo)( ls = await Ls(_c.fileRepo)(
account, account,
File( File(
path: remote_storage_util.getRemoteAlbumsDir(account), path: remote_storage_util.getRemoteAlbumsDir(account),
@ -51,16 +56,16 @@ class ListAlbum {
var f = albumFiles[i]; var f = albumFiles[i];
try { try {
if (CompatV25.isAlbumFileNeedMigration(f)) { if (CompatV25.isAlbumFileNeedMigration(f)) {
f = await CompatV25.migrateAlbumFile(fileRepo, account, f); f = await CompatV25.migrateAlbumFile(_c, account, f);
} }
albumFiles[i] = f; albumFiles[i] = f;
yield await albumRepo.get(account, f); yield await _c.albumRepo.get(account, f);
} catch (e, stackTrace) { } catch (e, stackTrace) {
yield ExceptionEvent(e, stackTrace); yield ExceptionEvent(e, stackTrace);
} }
} }
try { try {
albumRepo.cleanUp( _c.albumRepo.cleanUp(
account, remote_storage_util.getRemoteAlbumsDir(account), albumFiles); account, remote_storage_util.getRemoteAlbumsDir(account), albumFiles);
} catch (e, stacktrace) { } catch (e, stacktrace) {
// not important, log and ignore // not important, log and ignore
@ -68,8 +73,7 @@ class ListAlbum {
} }
} }
final FileRepo fileRepo; final DiContainer _c;
final AlbumRepo albumRepo;
static final _log = Logger("use_case.list_album.ListAlbum"); static final _log = Logger("use_case.list_album.ListAlbum");
} }

View file

@ -9,10 +9,11 @@ import 'package:nc_photos/use_case/find_file.dart';
/// List all shares from a given file /// List all shares from a given file
class ListShare { class ListShare {
ListShare(this._c) : assert(require(_c)); ListShare(this._c)
: assert(require(_c)),
assert(FindFile.require(_c));
static bool require(DiContainer c) => static bool require(DiContainer c) => DiContainer.has(c, DiType.shareRepo);
DiContainer.has(c, DiType.shareRepo) && DiContainer.has(c, DiType.appDb);
Future<List<Share>> call( Future<List<Share>> call(
Account account, Account account,
@ -21,7 +22,7 @@ class ListShare {
}) async { }) async {
try { try {
if (file_util.getUserDirName(file) != account.username) { if (file_util.getUserDirName(file) != account.username) {
file = await FindFile(_c.appDb)(account, file.fileId!); file = await FindFile(_c)(account, file.fileId!);
} }
} catch (_) { } catch (_) {
// file not found // file not found

View file

@ -1,13 +1,16 @@
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/share.dart';
/// List all shares by other users from a given file /// List all shares by other users from a given file
class ListShareWithMe { class ListShareWithMe {
ListShareWithMe(this.shareRepo); ListShareWithMe(this._c) : assert(require(_c));
static bool require(DiContainer c) => DiContainer.has(c, DiType.shareRepo);
Future<List<Share>> call(Account account, File file) => Future<List<Share>> call(Account account, File file) =>
shareRepo.reverseList(account, file); _c.shareRepo.reverseList(account, file);
final ShareRepo shareRepo; final DiContainer _c;
} }

View file

@ -1,11 +1,14 @@
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
class LsSingleFile { class LsSingleFile {
LsSingleFile(this.fileRepo); LsSingleFile(this._c) : assert(require(_c));
static bool require(DiContainer c) => DiContainer.has(c, DiType.fileRepo);
Future<File> call(Account account, String path) => Future<File> call(Account account, String path) =>
fileRepo.listSingle(account, File(path: path)); _c.fileRepo.listSingle(account, File(path: path));
final FileRepo fileRepo; final DiContainer _c;
} }

View file

@ -2,6 +2,7 @@ import 'package:event_bus/event_bus.dart';
import 'package:kiwi/kiwi.dart'; import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
@ -10,7 +11,9 @@ import 'package:nc_photos/use_case/create_dir.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
class Move { class Move {
Move(this.fileRepo); Move(this._c) : assert(require(_c));
static bool require(DiContainer c) => DiContainer.has(c, DiType.fileRepo);
/// Move a file from its original location to [destination] /// Move a file from its original location to [destination]
Future<void> call( Future<void> call(
@ -44,15 +47,16 @@ class Move {
_log.info("[call] Retry with: '$to'"); _log.info("[call] Retry with: '$to'");
} }
try { try {
await fileRepo.move(account, file, to, shouldOverwrite: shouldOverwrite); await _c.fileRepo
.move(account, file, to, shouldOverwrite: shouldOverwrite);
} catch (e) { } catch (e) {
if (e is ApiException) { if (e is ApiException) {
if (e.response.statusCode == 409 && shouldCreateMissingDir) { if (e.response.statusCode == 409 && shouldCreateMissingDir) {
// no dir // no dir
_log.info("[call] Auto creating parent dirs"); _log.info("[call] Auto creating parent dirs");
await CreateDir(fileRepo)(account, path.dirname(to)); await CreateDir(_c.fileRepo)(account, path.dirname(to));
await fileRepo.move(account, file, to, await _c.fileRepo
shouldOverwrite: shouldOverwrite); .move(account, file, to, shouldOverwrite: shouldOverwrite);
} else if (e.response.statusCode == 412 && shouldRenameOnOverwrite) { } else if (e.response.statusCode == 412 && shouldRenameOnOverwrite) {
return _doWork( return _doWork(
account, account,
@ -84,7 +88,7 @@ class Move {
return "${path.dirname(destination)}/$newName"; return "${path.dirname(destination)}/$newName";
} }
final FileRepo fileRepo; final DiContainer _c;
static final _log = Logger("use_case.move.Move"); static final _log = Logger("use_case.move.Move");
} }

View file

@ -19,14 +19,13 @@ import 'package:nc_photos/use_case/remove_share.dart';
class Remove { class Remove {
Remove(this._c) Remove(this._c)
: assert(require(_c)), : assert(require(_c)),
assert(ListAlbum.require(_c)),
assert(ListShare.require(_c)), assert(ListShare.require(_c)),
assert(RemoveFromAlbum.require(_c)); assert(RemoveFromAlbum.require(_c));
static bool require(DiContainer c) => static bool require(DiContainer c) =>
DiContainer.has(c, DiType.albumRepo) &&
DiContainer.has(c, DiType.fileRepo) && DiContainer.has(c, DiType.fileRepo) &&
DiContainer.has(c, DiType.shareRepo) && DiContainer.has(c, DiType.shareRepo);
DiContainer.has(c, DiType.appDb);
/// Remove files /// Remove files
Future<void> call( Future<void> call(
@ -55,7 +54,7 @@ class Remove {
} }
Future<void> _cleanUpAlbums(Account account, List<File> removes) async { Future<void> _cleanUpAlbums(Account account, List<File> removes) async {
final albums = await ListAlbum(_c.fileRepo, _c.albumRepo)(account) final albums = await ListAlbum(_c)(account)
.where((event) => event is Album) .where((event) => event is Album)
.cast<Album>() .cast<Album>()
.toList(); .toList();

View file

@ -1,15 +1,20 @@
import 'package:event_bus/event_bus.dart'; import 'package:event_bus/event_bus.dart';
import 'package:kiwi/kiwi.dart'; import 'package:kiwi/kiwi.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/use_case/move.dart'; import 'package:nc_photos/use_case/move.dart';
class RestoreTrashbin { class RestoreTrashbin {
RestoreTrashbin(this.fileRepo); RestoreTrashbin(this._c)
: assert(require(_c)),
assert(Move.require(_c));
static bool require(DiContainer c) => true;
Future<void> call(Account account, File file) async { Future<void> call(Account account, File file) async {
await Move(fileRepo)( await Move(_c)(
account, account,
file, file,
"remote.php/dav/trashbin/${account.username}/restore/${file.filename}", "remote.php/dav/trashbin/${account.username}/restore/${file.filename}",
@ -20,5 +25,5 @@ class RestoreTrashbin {
.fire(FileTrashbinRestoredEvent(account, file)); .fire(FileTrashbinRestoredEvent(account, file));
} }
final FileRepo fileRepo; final DiContainer _c;
} }

View file

@ -1,4 +1,5 @@
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
@ -6,12 +7,16 @@ import 'package:nc_photos/use_case/move.dart';
/// Unimport a shared album from the library /// Unimport a shared album from the library
class UnimportSharedAlbum { class UnimportSharedAlbum {
const UnimportSharedAlbum(this.fileRepo); UnimportSharedAlbum(this._c)
: assert(require(_c)),
assert(Move.require(_c));
static bool require(DiContainer c) => true;
Future<void> call(Account account, Album album) async { Future<void> call(Account account, Album album) async {
final destination = final destination =
"${remote_storage_util.getRemotePendingSharedAlbumsDir(account)}/${album.albumFile!.filename}"; "${remote_storage_util.getRemotePendingSharedAlbumsDir(account)}/${album.albumFile!.filename}";
await Move(fileRepo)( await Move(_c)(
account, account,
album.albumFile!, album.albumFile!,
destination, destination,
@ -19,5 +24,5 @@ class UnimportSharedAlbum {
); );
} }
final FileRepo fileRepo; final DiContainer _c;
} }

View file

@ -15,12 +15,10 @@ import 'package:nc_photos/use_case/remove_share.dart';
class UnshareFileFromAlbum { class UnshareFileFromAlbum {
UnshareFileFromAlbum(this._c) UnshareFileFromAlbum(this._c)
: assert(require(_c)), : assert(require(_c)),
assert(ListAlbum.require(_c)),
assert(ListShare.require(_c)); assert(ListShare.require(_c));
static bool require(DiContainer c) => static bool require(DiContainer c) => DiContainer.has(c, DiType.shareRepo);
DiContainer.has(c, DiType.albumRepo) &&
DiContainer.has(c, DiType.fileRepo) &&
DiContainer.has(c, DiType.shareRepo);
/// Remove file shares created for an album /// Remove file shares created for an album
/// ///
@ -36,7 +34,7 @@ class UnshareFileFromAlbum {
_log.info( _log.info(
"[call] Unshare ${files.length} files from album '${album.name}' with ${unshareWith.length} users"); "[call] Unshare ${files.length} files from album '${album.name}' with ${unshareWith.length} users");
// list albums with shares identical to any element in [unshareWith] // list albums with shares identical to any element in [unshareWith]
final otherAlbums = await ListAlbum(_c.fileRepo, _c.albumRepo)(account) final otherAlbums = await ListAlbum(_c)(account)
.where((event) => event is Album) .where((event) => event is Album)
.cast<Album>() .cast<Album>()
.where((a) => .where((a) =>

View file

@ -15,7 +15,6 @@ import 'package:nc_photos/entity/album/item.dart';
import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/entity/album/sort_provider.dart'; import 'package:nc_photos/entity/album/sort_provider.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/exception_util.dart' as exception_util;
@ -185,9 +184,8 @@ class _AlbumBrowserState extends State<AlbumBrowser>
var album = await albumRepo.get(widget.account, widget.album.albumFile!); var album = await albumRepo.get(widget.account, widget.album.albumFile!);
if (widget.album.shares?.isNotEmpty == true) { if (widget.album.shares?.isNotEmpty == true) {
try { try {
final fileRepo = FileRepo(FileCachedDataSource(AppDb())); final file = await LsSingleFile(KiwiContainer().resolve<DiContainer>())(
final file = widget.account, album.albumFile!.path);
await LsSingleFile(fileRepo)(widget.account, album.albumFile!.path);
if (file.etag != album.albumFile!.etag) { if (file.etag != album.albumFile!.etag) {
_log.info("[_initAlbum] Album modified in remote, forcing download"); _log.info("[_initAlbum] Album modified in remote, forcing download");
album = await albumRepo.get(widget.account, File(path: file.path)); album = await albumRepo.get(widget.account, File(path: file.path));

View file

@ -1,16 +1,16 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/api/api_util.dart' as api_util; import 'package:nc_photos/api/api_util.dart' as api_util;
import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/debug_util.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/cover_provider.dart'; import 'package:nc_photos/entity/album/cover_provider.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/notified_action.dart'; import 'package:nc_photos/notified_action.dart';
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
@ -236,10 +236,8 @@ mixin AlbumBrowserMixin<T extends StatefulWidget>
try { try {
await NotifiedAction( await NotifiedAction(
() async { () async {
final fileRepo = FileRepo(FileCachedDataSource(AppDb())); newAlbum = await ImportPendingSharedAlbum(
final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); KiwiContainer().resolve<DiContainer>())(account, album);
newAlbum = await ImportPendingSharedAlbum(fileRepo, albumRepo)(
account, album);
}, },
L10n.global().addToCollectionProcessingNotification(album.name), L10n.global().addToCollectionProcessingNotification(album.name),
L10n.global().addToCollectionSuccessNotification(album.name), L10n.global().addToCollectionSuccessNotification(album.name),

View file

@ -1,11 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/bloc/list_importable_album.dart'; import 'package:nc_photos/bloc/list_importable_album.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/cover_provider.dart'; import 'package:nc_photos/entity/album/cover_provider.dart';
import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/provider.dart';
@ -79,7 +81,7 @@ class _AlbumImporterState extends State<AlbumImporter> {
void _initBloc() { void _initBloc() {
_log.info("[_initBloc] Initialize bloc"); _log.info("[_initBloc] Initialize bloc");
_bloc = ListImportableAlbumBloc(); _bloc = ListImportableAlbumBloc(KiwiContainer().resolve<DiContainer>());
_bloc.add(ListImportableAlbumBlocQuery( _bloc.add(ListImportableAlbumBlocQuery(
widget.account, widget.account,
widget.account.roots widget.account.roots

View file

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
@ -48,21 +47,6 @@ class _AlbumPickerDialogState extends State<AlbumPickerDialog> {
} }
void _initBloc() { void _initBloc() {
ListAlbumBloc bloc;
final blocId =
"${widget.account.scheme}://${widget.account.username}@${widget.account.address}";
try {
_log.fine("[_initBloc] Resolving bloc for '$blocId'");
bloc = KiwiContainer().resolve<ListAlbumBloc>("ListAlbumBloc($blocId)");
} catch (_) {
// no created instance for this account, make a new one
_log.info("[_initBloc] New bloc instance for account: ${widget.account}");
bloc = ListAlbumBloc();
KiwiContainer().registerInstance<ListAlbumBloc>(bloc,
name: "ListAlbumBloc($blocId)");
}
_bloc = bloc;
if (_bloc.state is ListAlbumBlocInit) { if (_bloc.state is ListAlbumBlocInit) {
_log.info("[_initBloc] Initialize bloc"); _log.info("[_initBloc] Initialize bloc");
_reqQuery(); _reqQuery();
@ -171,7 +155,7 @@ class _AlbumPickerDialogState extends State<AlbumPickerDialog> {
_bloc.add(ListAlbumBlocQuery(widget.account)); _bloc.add(ListAlbumBlocQuery(widget.account));
} }
late ListAlbumBloc _bloc; late final _bloc = ListAlbumBloc.of(widget.account);
final _items = <Album>[]; final _items = <Album>[];

View file

@ -1,15 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:kiwi/kiwi.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/bloc/album_search.dart'; import 'package:nc_photos/bloc/album_search.dart';
import 'package:nc_photos/bloc/search_suggestion.dart'; import 'package:nc_photos/bloc/search_suggestion.dart';
import 'package:nc_photos/ci_string.dart'; import 'package:nc_photos/ci_string.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/theme.dart'; import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/list_album.dart'; import 'package:nc_photos/use_case/list_album.dart';
import 'package:nc_photos/widget/builder/album_grid_item_builder.dart'; import 'package:nc_photos/widget/builder/album_grid_item_builder.dart';
@ -22,9 +21,9 @@ class AlbumSearchDelegate extends SearchDelegate {
: super( : super(
searchFieldLabel: L10n.global().albumSearchTextFieldHint, searchFieldLabel: L10n.global().albumSearchTextFieldHint,
) { ) {
final fileRepo = FileRepo(FileCachedDataSource(AppDb())); ListAlbum(KiwiContainer().resolve<DiContainer>())(account)
final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); .toList()
ListAlbum(fileRepo, albumRepo)(account).toList().then((value) { .then((value) {
final albums = value.whereType<Album>().toList(); final albums = value.whereType<Album>().toList();
_searchBloc.add(AlbumSearchBlocUpdateItemsEvent(albums)); _searchBloc.add(AlbumSearchBlocUpdateItemsEvent(albums));
_suggestionBloc.add(SearchSuggestionBlocUpdateItemsEvent<Album>(albums)); _suggestionBloc.add(SearchSuggestionBlocUpdateItemsEvent<Album>(albums));

View file

@ -1,12 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/or_null.dart';
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
import 'package:nc_photos/theme.dart'; import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/import_potential_shared_album.dart'; import 'package:nc_photos/use_case/import_potential_shared_album.dart';
@ -126,11 +129,13 @@ class _HomeState extends State<Home> {
} }
Future<List<Album>> _importPotentialSharedAlbum() async { Future<List<Album>> _importPotentialSharedAlbum() async {
const fileRepo = FileRepo(FileWebdavDataSource()); final c = KiwiContainer().resolve<DiContainer>().copyWith(
// don't want the potential albums to be cached at this moment // don't want the potential albums to be cached at this moment
final albumRepo = AlbumRepo(AlbumRemoteDataSource()); fileRepo: OrNull(const FileRepo(FileWebdavDataSource())),
albumRepo: OrNull(AlbumRepo(AlbumRemoteDataSource())),
);
try { try {
return await ImportPotentialSharedAlbum(fileRepo, albumRepo)( return await ImportPotentialSharedAlbum(c)(
widget.account, AccountPref.of(widget.account)); widget.account, AccountPref.of(widget.account));
} catch (e, stacktrace) { } catch (e, stacktrace) {
_log.shout( _log.shout(

View file

@ -6,14 +6,12 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:kiwi/kiwi.dart'; import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/bloc/list_album.dart'; import 'package:nc_photos/bloc/list_album.dart';
import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/provider.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/iterable_extension.dart';
@ -83,21 +81,6 @@ class _HomeAlbumsState extends State<HomeAlbums>
} }
void _initBloc() { void _initBloc() {
ListAlbumBloc bloc;
final blocId =
"${widget.account.scheme}://${widget.account.username}@${widget.account.address}";
try {
_log.fine("[_initBloc] Resolving bloc for '$blocId'");
bloc = KiwiContainer().resolve<ListAlbumBloc>("ListAlbumBloc($blocId)");
} catch (e) {
// no created instance for this account, make a new one
_log.info("[_initBloc] New bloc instance for account: ${widget.account}");
bloc = ListAlbumBloc();
KiwiContainer().registerInstance<ListAlbumBloc>(bloc,
name: "ListAlbumBloc($blocId)");
}
_bloc = bloc;
if (_bloc.state is ListAlbumBlocInit) { if (_bloc.state is ListAlbumBlocInit) {
_log.info("[_initBloc] Initialize bloc"); _log.info("[_initBloc] Initialize bloc");
_reqQuery(); _reqQuery();
@ -406,7 +389,6 @@ class _HomeAlbumsState extends State<HomeAlbums>
setState(() { setState(() {
clearSelectedItems(); clearSelectedItems();
}); });
final fileRepo = FileRepo(FileCachedDataSource(AppDb()));
final failures = <Album>[]; final failures = <Album>[];
for (final a in selected) { for (final a in selected) {
try { try {
@ -416,7 +398,8 @@ class _HomeAlbumsState extends State<HomeAlbums>
widget.account, a); widget.account, a);
} else { } else {
// remove shared albums from collection // remove shared albums from collection
await UnimportSharedAlbum(fileRepo)(widget.account, a); await UnimportSharedAlbum(KiwiContainer().resolve<DiContainer>())(
widget.account, a);
} }
} catch (e, stackTrace) { } catch (e, stackTrace) {
_log.shout( _log.shout(
@ -512,7 +495,7 @@ class _HomeAlbumsState extends State<HomeAlbums>
} }
} }
late ListAlbumBloc _bloc; late final _bloc = ListAlbumBloc.of(widget.account);
late final _accountPrefUpdatedEventListener = late final _accountPrefUpdatedEventListener =
AppEventListener<AccountPrefUpdatedEvent>(_onAccountPrefUpdatedEvent); AppEventListener<AccountPrefUpdatedEvent>(_onAccountPrefUpdatedEvent);

View file

@ -2,13 +2,13 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/api/api_util.dart' as api_util; import 'package:nc_photos/api/api_util.dart' as api_util;
import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
@ -58,12 +58,11 @@ class _RootPickerState extends State<RootPicker> {
void _initAccount() async { void _initAccount() async {
try { try {
final fileRepo = FileRepo(FileCachedDataSource(AppDb()));
final files = <File>[]; final files = <File>[];
for (final r in widget.account.roots) { for (final r in widget.account.roots) {
if (r.isNotEmpty) { if (r.isNotEmpty) {
_ensureInitDialog(); _ensureInitDialog();
files.add(await LsSingleFile(fileRepo)( files.add(await LsSingleFile(KiwiContainer().resolve<DiContainer>())(
widget.account, file_util.unstripPath(widget.account, r))); widget.account, file_util.unstripPath(widget.account, r)));
} }
} }

View file

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/api/api.dart'; import 'package:nc_photos/api/api.dart';
@ -10,6 +11,7 @@ import 'package:nc_photos/api/api_util.dart' as api_util;
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/bloc/list_sharing.dart'; import 'package:nc_photos/bloc/list_sharing.dart';
import 'package:nc_photos/cache_manager_util.dart'; import 'package:nc_photos/cache_manager_util.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file/data_source.dart';
@ -18,6 +20,7 @@ import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/object_extension.dart'; import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/or_null.dart';
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
import 'package:nc_photos/snack_bar_manager.dart'; import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart'; import 'package:nc_photos/theme.dart';
@ -325,11 +328,13 @@ class _SharingBrowserState extends State<SharingBrowser> {
} }
Future<List<Album>> _importPotentialSharedAlbum() async { Future<List<Album>> _importPotentialSharedAlbum() async {
const fileRepo = FileRepo(FileWebdavDataSource()); final c = KiwiContainer().resolve<DiContainer>().copyWith(
// don't want the potential albums to be cached at this moment // don't want the potential albums to be cached at this moment
final albumRepo = AlbumRepo(AlbumRemoteDataSource()); fileRepo: OrNull(const FileRepo(FileWebdavDataSource())),
albumRepo: OrNull(AlbumRepo(AlbumRemoteDataSource())),
);
try { try {
return await ImportPotentialSharedAlbum(fileRepo, albumRepo)( return await ImportPotentialSharedAlbum(c)(
widget.account, AccountPref.of(widget.account)); widget.account, AccountPref.of(widget.account));
} catch (e, stackTrace) { } catch (e, stackTrace) {
_log.shout( _log.shout(

View file

@ -3,14 +3,15 @@ import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/api/api_util.dart' as api_util; import 'package:nc_photos/api/api_util.dart' as api_util;
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/bloc/ls_trashbin.dart'; import 'package:nc_photos/bloc/ls_trashbin.dart';
import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/debug_util.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/iterable_extension.dart';
@ -291,11 +292,11 @@ class _TrashbinBrowserState extends State<TrashbinBrowser>
setState(() { setState(() {
clearSelectedItems(); clearSelectedItems();
}); });
const fileRepo = FileRepo(FileWebdavDataSource());
final failures = <File>[]; final failures = <File>[];
for (final f in selectedFiles) { for (final f in selectedFiles) {
try { try {
await RestoreTrashbin(fileRepo)(widget.account, f); await RestoreTrashbin(KiwiContainer().resolve<DiContainer>())(
widget.account, f);
} catch (e, stacktrace) { } catch (e, stacktrace) {
_log.shout( _log.shout(
"[_onSelectionAppBarRestorePressed] Failed while restoring file: ${logFilename(f.path)}", "[_onSelectionAppBarRestorePressed] Failed while restoring file: ${logFilename(f.path)}",

View file

@ -1,13 +1,13 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart'; import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_db.dart';
import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/debug_util.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file/data_source.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
@ -166,9 +166,9 @@ class _TrashbinViewerState extends State<TrashbinViewer> {
controller?.closed.whenComplete(() { controller?.closed.whenComplete(() {
controller = null; controller = null;
}); });
final fileRepo = FileRepo(FileCachedDataSource(AppDb()));
try { try {
await RestoreTrashbin(fileRepo)(widget.account, file); await RestoreTrashbin(KiwiContainer().resolve<DiContainer>())(
widget.account, file);
controller?.close(); controller?.close();
SnackBarManager().showSnackBar(SnackBar( SnackBarManager().showSnackBar(SnackBar(
content: Text(L10n.global().restoreSuccessNotification), content: Text(L10n.global().restoreSuccessNotification),

View file

@ -1,3 +1,5 @@
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/use_case/find_file.dart'; import 'package:nc_photos/use_case/find_file.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
@ -5,7 +7,6 @@ import '../mock_type.dart';
import '../test_util.dart' as util; import '../test_util.dart' as util;
void main() { void main() {
util.initLog();
group("FindFile", () { group("FindFile", () {
test("file", _findFile); test("file", _findFile);
test("missing file", _findMissingFile); test("missing file", _findMissingFile);
@ -21,10 +22,13 @@ Future<void> _findFile() async {
..addJpeg("admin/test1.jpg") ..addJpeg("admin/test1.jpg")
..addJpeg("admin/test2.jpg")) ..addJpeg("admin/test2.jpg"))
.build(); .build();
final appDb = MockAppDb(); final c = DiContainer(
await util.fillAppDb(appDb, account, files); appDb: await MockAppDb().applyFuture((obj) async {
await util.fillAppDb(obj, account, files);
}),
);
expect(await FindFile(appDb)(account, 1), files[1]); expect(await FindFile(c)(account, 1), files[1]);
} }
/// Find a file not existing in app db /// Find a file not existing in app db
@ -33,8 +37,11 @@ Future<void> _findFile() async {
Future<void> _findMissingFile() async { Future<void> _findMissingFile() async {
final account = util.buildAccount(); final account = util.buildAccount();
final files = (util.FilesBuilder()..addJpeg("admin/test1.jpg")).build(); final files = (util.FilesBuilder()..addJpeg("admin/test1.jpg")).build();
final appDb = MockAppDb(); final c = DiContainer(
await util.fillAppDb(appDb, account, files); appDb: await MockAppDb().applyFuture((obj) async {
await util.fillAppDb(obj, account, files);
}),
);
expect(() => FindFile(appDb)(account, 1), throwsStateError); expect(() => FindFile(c)(account, 1), throwsStateError);
} }