From 40270588091955340c04bcfd3c0ef5f35bec8763 Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Wed, 17 Nov 2021 04:02:24 +0800 Subject: [PATCH] Scan share_folder even if it's not under account roots --- lib/bloc/scan_account_dir.dart | 381 ++++++++++++++++++++++++++++++++ lib/bloc/scan_dir.dart | 335 ---------------------------- lib/widget/archive_browser.dart | 34 ++- lib/widget/home_photos.dart | 46 ++-- 4 files changed, 413 insertions(+), 383 deletions(-) create mode 100644 lib/bloc/scan_account_dir.dart delete mode 100644 lib/bloc/scan_dir.dart diff --git a/lib/bloc/scan_account_dir.dart b/lib/bloc/scan_account_dir.dart new file mode 100644 index 00000000..c20b0492 --- /dev/null +++ b/lib/bloc/scan_account_dir.dart @@ -0,0 +1,381 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:kiwi/kiwi.dart'; +import 'package:logging/logging.dart'; +import 'package:nc_photos/account.dart'; +import 'package:nc_photos/app_db.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/event/event.dart'; +import 'package:nc_photos/exception_event.dart'; +import 'package:nc_photos/pref.dart'; +import 'package:nc_photos/throttler.dart'; +import 'package:nc_photos/use_case/ls.dart'; +import 'package:nc_photos/use_case/scan_dir.dart'; + +abstract class ScanAccountDirBlocEvent { + const ScanAccountDirBlocEvent(); +} + +class ScanAccountDirBlocQueryBase extends ScanAccountDirBlocEvent { + const ScanAccountDirBlocQueryBase(); + + @override + toString() { + return "$runtimeType {" + "}"; + } +} + +class ScanAccountDirBlocQuery extends ScanAccountDirBlocQueryBase { + const ScanAccountDirBlocQuery(); +} + +class ScanAccountDirBlocRefresh extends ScanAccountDirBlocQueryBase { + const ScanAccountDirBlocRefresh(); +} + +/// An external event has happened and may affect the state of this bloc +class _ScanAccountDirBlocExternalEvent extends ScanAccountDirBlocEvent { + const _ScanAccountDirBlocExternalEvent(); + + @override + toString() { + return "$runtimeType {" + "}"; + } +} + +abstract class ScanAccountDirBlocState { + const ScanAccountDirBlocState(this.files); + + @override + toString() { + return "$runtimeType {" + "files: List {length: ${files.length}}, " + "}"; + } + + final List files; +} + +class ScanAccountDirBlocInit extends ScanAccountDirBlocState { + const ScanAccountDirBlocInit() : super(const []); +} + +class ScanAccountDirBlocLoading extends ScanAccountDirBlocState { + const ScanAccountDirBlocLoading(List files) : super(files); +} + +class ScanAccountDirBlocSuccess extends ScanAccountDirBlocState { + const ScanAccountDirBlocSuccess(List files) : super(files); +} + +class ScanAccountDirBlocFailure extends ScanAccountDirBlocState { + const ScanAccountDirBlocFailure(List files, this.exception) + : super(files); + + @override + toString() { + return "$runtimeType {" + "super: ${super.toString()}, " + "exception: $exception, " + "}"; + } + + final dynamic exception; +} + +/// The state of this bloc is inconsistent. This typically means that the data +/// may have been changed externally +class ScanAccountDirBlocInconsistent extends ScanAccountDirBlocState { + const ScanAccountDirBlocInconsistent(List files) : super(files); +} + +/// A bloc that return all files under a dir recursively +/// +/// See [ScanDir] +class ScanAccountDirBloc + extends Bloc { + ScanAccountDirBloc._(this.account) : super(const ScanAccountDirBlocInit()) { + _fileRemovedEventListener.begin(); + _filePropertyUpdatedEventListener.begin(); + _fileTrashbinRestoredEventListener.begin(); + _fileMovedEventListener.begin(); + _prefUpdatedEventListener.begin(); + } + + static ScanAccountDirBloc of(Account account) { + final id = + "${account.scheme}://${account.username}@${account.address}?${account.roots.join('&')}"; + try { + _log.fine("[of] Resolving bloc for '$id'"); + return KiwiContainer() + .resolve("ScanAccountDirBloc($id)"); + } catch (_) { + // no created instance for this account, make a new one + _log.info("[of] New bloc instance for account: $account"); + final bloc = ScanAccountDirBloc._(account); + KiwiContainer().registerInstance(bloc, + name: "ScanAccountDirBloc($id)"); + return bloc; + } + } + + @override + transformEvents(Stream events, transitionFn) { + return super.transformEvents(events.distinct((a, b) { + // only handle ScanAccountDirBlocQuery + final r = a is ScanAccountDirBlocQuery && + b is ScanAccountDirBlocQuery && + a == b; + if (r) { + _log.fine( + "[transformEvents] Skip identical ScanAccountDirBlocQuery event"); + } + return r; + }), transitionFn); + } + + @override + mapEventToState(ScanAccountDirBlocEvent event) async* { + _log.info("[mapEventToState] $event"); + if (event is ScanAccountDirBlocQueryBase) { + yield* _onEventQuery(event); + } else if (event is _ScanAccountDirBlocExternalEvent) { + yield* _onExternalEvent(event); + } + } + + @override + close() { + _fileRemovedEventListener.end(); + _filePropertyUpdatedEventListener.end(); + _fileTrashbinRestoredEventListener.end(); + _fileMovedEventListener.end(); + _prefUpdatedEventListener.end(); + + _refreshThrottler.clear(); + return super.close(); + } + + Stream _onEventQuery( + ScanAccountDirBlocQueryBase ev) async* { + yield ScanAccountDirBlocLoading(state.files); + bool hasContent = state.files.isNotEmpty; + + if (!hasContent) { + // show something instantly on first load + ScanAccountDirBlocState cacheState = const ScanAccountDirBlocInit(); + await for (final s in _queryOffline(ev, () => cacheState)) { + cacheState = s; + } + yield ScanAccountDirBlocLoading(cacheState.files); + hasContent = cacheState.files.isNotEmpty; + } + + ScanAccountDirBlocState newState = const ScanAccountDirBlocInit(); + if (!hasContent) { + await for (final s in _queryOnline(ev, () => newState)) { + newState = s; + yield s; + } + } else { + await for (final s in _queryOnline(ev, () => newState)) { + newState = s; + } + if (newState is ScanAccountDirBlocSuccess) { + yield newState; + } else if (newState is ScanAccountDirBlocFailure) { + yield ScanAccountDirBlocFailure(state.files, newState.exception); + } + } + } + + Stream _onExternalEvent( + _ScanAccountDirBlocExternalEvent ev) async* { + yield ScanAccountDirBlocInconsistent(state.files); + } + + void _onFileRemovedEvent(FileRemovedEvent ev) { + if (state is ScanAccountDirBlocInit) { + // no data in this bloc, ignore + return; + } + if (_isFileOfInterest(ev.file)) { + _refreshThrottler.trigger( + maxResponceTime: const Duration(seconds: 3), + maxPendingCount: 10, + ); + } + } + + void _onFilePropertyUpdatedEvent(FilePropertyUpdatedEvent ev) { + if (!ev.hasAnyProperties([ + FilePropertyUpdatedEvent.propMetadata, + FilePropertyUpdatedEvent.propIsArchived, + FilePropertyUpdatedEvent.propOverrideDateTime, + ])) { + // not interested + return; + } + if (state is ScanAccountDirBlocInit) { + // no data in this bloc, ignore + return; + } + if (!_isFileOfInterest(ev.file)) { + return; + } + + if (ev.hasAnyProperties([ + FilePropertyUpdatedEvent.propIsArchived, + FilePropertyUpdatedEvent.propOverrideDateTime, + ])) { + _refreshThrottler.trigger( + maxResponceTime: const Duration(seconds: 3), + maxPendingCount: 10, + ); + } else { + _refreshThrottler.trigger( + maxResponceTime: const Duration(seconds: 10), + maxPendingCount: 10, + ); + } + } + + void _onFileTrashbinRestoredEvent(FileTrashbinRestoredEvent ev) { + if (state is ScanAccountDirBlocInit) { + // no data in this bloc, ignore + return; + } + _refreshThrottler.trigger( + maxResponceTime: const Duration(seconds: 3), + maxPendingCount: 10, + ); + } + + void _onFileMovedEvent(FileMovedEvent ev) { + if (state is ScanAccountDirBlocInit) { + // no data in this bloc, ignore + return; + } + if (_isFileOfInterest(ev.file)) { + _refreshThrottler.trigger( + maxResponceTime: const Duration(seconds: 3), + maxPendingCount: 10, + ); + } + } + + void _onPrefUpdatedEvent(PrefUpdatedEvent ev) { + if (state is ScanAccountDirBlocInit) { + // no data in this bloc, ignore + return; + } + if (ev.key == PrefKey.accounts2) { + _refreshThrottler.trigger( + maxResponceTime: const Duration(seconds: 3), + maxPendingCount: 10, + ); + } + } + + Stream _queryOffline(ScanAccountDirBlocQueryBase ev, + ScanAccountDirBlocState Function() getState) => + _queryWithFileDataSource(ev, getState, FileAppDbDataSource(AppDb())); + + Stream _queryOnline(ScanAccountDirBlocQueryBase ev, + ScanAccountDirBlocState Function() getState) { + final stream = _queryWithFileDataSource(ev, getState, + FileCachedDataSource(AppDb(), shouldCheckCache: _shouldCheckCache)); + _shouldCheckCache = false; + return stream; + } + + Stream _queryWithFileDataSource( + ScanAccountDirBlocQueryBase ev, + ScanAccountDirBlocState Function() getState, + FileDataSource dataSrc) async* { + try { + final fileRepo = FileRepo(dataSrc); + // include files shared with this account + final settings = Pref().getAccountSettings(account); + final shareDir = + File(path: file_util.unstripPath(account, settings.shareFolder)); + bool isShareDirIncluded = false; + + for (final r in account.roots) { + final dir = File(path: file_util.unstripPath(account, r)); + final dataStream = ScanDir(fileRepo)(account, dir); + await for (final d in dataStream) { + if (d is ExceptionEvent) { + throw d.error; + } + yield ScanAccountDirBlocLoading(getState().files + d); + } + + isShareDirIncluded |= file_util.isOrUnderDir(shareDir, dir); + } + + if (!isShareDirIncluded) { + final files = await Ls(fileRepo)(account, + File(path: file_util.unstripPath(account, settings.shareFolder))); + final sharedFiles = + files.where((f) => !f.isOwned(account.username)).toList(); + yield ScanAccountDirBlocSuccess(getState().files + sharedFiles); + } else { + yield ScanAccountDirBlocSuccess(getState().files); + } + } catch (e) { + _log.severe("[_queryWithFileDataSource] Exception while request", e); + yield ScanAccountDirBlocFailure(getState().files, e); + } + } + + bool _isFileOfInterest(File file) { + if (!file_util.isSupportedFormat(file)) { + return false; + } + + for (final r in account.roots) { + final dir = File(path: file_util.unstripPath(account, r)); + if (file_util.isUnderDir(file, dir)) { + return true; + } + } + + final settings = Pref().getAccountSettings(account); + final shareDir = + File(path: file_util.unstripPath(account, settings.shareFolder)); + if (file_util.isUnderDir(file, shareDir)) { + return true; + } + return false; + } + + final Account account; + + late final _fileRemovedEventListener = + AppEventListener(_onFileRemovedEvent); + late final _filePropertyUpdatedEventListener = + AppEventListener(_onFilePropertyUpdatedEvent); + late final _fileTrashbinRestoredEventListener = + AppEventListener(_onFileTrashbinRestoredEvent); + late final _fileMovedEventListener = + AppEventListener(_onFileMovedEvent); + late final _prefUpdatedEventListener = + AppEventListener(_onPrefUpdatedEvent); + + late final _refreshThrottler = Throttler( + onTriggered: (_) { + add(const _ScanAccountDirBlocExternalEvent()); + }, + logTag: "ScanAccountDirBloc.refresh", + ); + + bool _shouldCheckCache = true; + + static final _log = Logger("bloc.scan_dir.ScanAccountDirBloc"); +} diff --git a/lib/bloc/scan_dir.dart b/lib/bloc/scan_dir.dart deleted file mode 100644 index 8f93ac7f..00000000 --- a/lib/bloc/scan_dir.dart +++ /dev/null @@ -1,335 +0,0 @@ -import 'dart:async'; - -import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; -import 'package:kiwi/kiwi.dart'; -import 'package:logging/logging.dart'; -import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.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/event/event.dart'; -import 'package:nc_photos/exception_event.dart'; -import 'package:nc_photos/iterable_extension.dart'; -import 'package:nc_photos/throttler.dart'; -import 'package:nc_photos/use_case/scan_dir.dart'; - -abstract class ScanDirBlocEvent { - const ScanDirBlocEvent(); -} - -class ScanDirBlocQueryBase extends ScanDirBlocEvent with EquatableMixin { - const ScanDirBlocQueryBase(this.account, this.roots); - - @override - toString() { - return "$runtimeType {" - "account: $account, " - "roots: ${roots.map((e) => e.path).toReadableString()}, " - "}"; - } - - @override - get props => [ - account, - roots, - ]; - - final Account account; - final List roots; -} - -class ScanDirBlocQuery extends ScanDirBlocQueryBase { - const ScanDirBlocQuery(Account account, List roots) - : super(account, roots); -} - -class ScanDirBlocRefresh extends ScanDirBlocQueryBase { - const ScanDirBlocRefresh(Account account, List roots) - : super(account, roots); -} - -/// An external event has happened and may affect the state of this bloc -class _ScanDirBlocExternalEvent extends ScanDirBlocEvent { - const _ScanDirBlocExternalEvent(); - - @override - toString() { - return "$runtimeType {" - "}"; - } -} - -abstract class ScanDirBlocState { - const ScanDirBlocState(this.account, this.files); - - @override - toString() { - return "$runtimeType {" - "account: $account, " - "files: List {length: ${files.length}}, " - "}"; - } - - final Account? account; - final List files; -} - -class ScanDirBlocInit extends ScanDirBlocState { - const ScanDirBlocInit() : super(null, const []); -} - -class ScanDirBlocLoading extends ScanDirBlocState { - const ScanDirBlocLoading(Account? account, List files) - : super(account, files); -} - -class ScanDirBlocSuccess extends ScanDirBlocState { - const ScanDirBlocSuccess(Account? account, List files) - : super(account, files); -} - -class ScanDirBlocFailure extends ScanDirBlocState { - const ScanDirBlocFailure(Account? account, List files, this.exception) - : super(account, files); - - @override - toString() { - return "$runtimeType {" - "super: ${super.toString()}, " - "exception: $exception, " - "}"; - } - - final dynamic exception; -} - -/// The state of this bloc is inconsistent. This typically means that the data -/// may have been changed externally -class ScanDirBlocInconsistent extends ScanDirBlocState { - const ScanDirBlocInconsistent(Account? account, List files) - : super(account, files); -} - -/// A bloc that return all files under a dir recursively -/// -/// See [ScanDir] -class ScanDirBloc extends Bloc { - ScanDirBloc() : super(const ScanDirBlocInit()) { - _fileRemovedEventListener = - AppEventListener(_onFileRemovedEvent); - _filePropertyUpdatedEventListener = - AppEventListener(_onFilePropertyUpdatedEvent); - _fileTrashbinRestoredEventListener = - AppEventListener( - _onFileTrashbinRestoredEvent); - _fileRemovedEventListener.begin(); - _filePropertyUpdatedEventListener.begin(); - _fileTrashbinRestoredEventListener.begin(); - _fileMovedEventListener.begin(); - - _refreshThrottler = Throttler( - onTriggered: (_) { - add(const _ScanDirBlocExternalEvent()); - }, - logTag: "ScanDirBloc.refresh", - ); - } - - static ScanDirBloc of(Account account) { - final id = - "${account.scheme}://${account.username}@${account.address}?${account.roots.join('&')}"; - try { - _log.fine("[of] Resolving bloc for '$id'"); - return KiwiContainer().resolve("ScanDirBloc($id)"); - } catch (_) { - // no created instance for this account, make a new one - _log.info("[of] New bloc instance for account: $account"); - final bloc = ScanDirBloc(); - KiwiContainer() - .registerInstance(bloc, name: "ScanDirBloc($id)"); - return bloc; - } - } - - @override - transformEvents(Stream events, transitionFn) { - return super.transformEvents(events.distinct((a, b) { - // only handle ScanDirBlocQuery - final r = a is ScanDirBlocQuery && b is ScanDirBlocQuery && a == b; - if (r) { - _log.fine("[transformEvents] Skip identical ScanDirBlocQuery event"); - } - return r; - }), transitionFn); - } - - @override - mapEventToState(ScanDirBlocEvent event) async* { - _log.info("[mapEventToState] $event"); - if (event is ScanDirBlocQueryBase) { - yield* _onEventQuery(event); - } else if (event is _ScanDirBlocExternalEvent) { - yield* _onExternalEvent(event); - } - } - - @override - close() { - _fileRemovedEventListener.end(); - _filePropertyUpdatedEventListener.end(); - _fileTrashbinRestoredEventListener.end(); - _refreshThrottler.clear(); - return super.close(); - } - - Stream _onEventQuery(ScanDirBlocQueryBase ev) async* { - yield ScanDirBlocLoading(ev.account, state.files); - bool hasContent = state.files.isNotEmpty; - - if (!hasContent) { - // show something instantly on first load - ScanDirBlocState cacheState = const ScanDirBlocInit(); - await for (final s in _queryOffline(ev, () => cacheState)) { - cacheState = s; - } - yield ScanDirBlocLoading(ev.account, cacheState.files); - hasContent = cacheState.files.isNotEmpty; - } - - ScanDirBlocState newState = const ScanDirBlocInit(); - if (!hasContent) { - await for (final s in _queryOnline(ev, () => newState)) { - newState = s; - yield s; - } - } else { - await for (final s in _queryOnline(ev, () => newState)) { - newState = s; - } - if (newState is ScanDirBlocSuccess) { - yield newState; - } else if (newState is ScanDirBlocFailure) { - yield ScanDirBlocFailure(ev.account, state.files, newState.exception); - } - } - } - - Stream _onExternalEvent( - _ScanDirBlocExternalEvent ev) async* { - yield ScanDirBlocInconsistent(state.account, state.files); - } - - void _onFileRemovedEvent(FileRemovedEvent ev) { - if (state is ScanDirBlocInit) { - // no data in this bloc, ignore - return; - } - if (!file_util.isTrash(ev.account, ev.file)) { - _refreshThrottler.trigger( - maxResponceTime: const Duration(seconds: 3), - maxPendingCount: 10, - ); - } - } - - void _onFilePropertyUpdatedEvent(FilePropertyUpdatedEvent ev) { - if (!ev.hasAnyProperties([ - FilePropertyUpdatedEvent.propMetadata, - FilePropertyUpdatedEvent.propIsArchived, - FilePropertyUpdatedEvent.propOverrideDateTime, - ])) { - // not interested - return; - } - if (state is ScanDirBlocInit) { - // no data in this bloc, ignore - return; - } - - if (ev.hasAnyProperties([ - FilePropertyUpdatedEvent.propIsArchived, - FilePropertyUpdatedEvent.propOverrideDateTime, - ])) { - _refreshThrottler.trigger( - maxResponceTime: const Duration(seconds: 3), - maxPendingCount: 10, - ); - } else { - _refreshThrottler.trigger( - maxResponceTime: const Duration(seconds: 10), - maxPendingCount: 10, - ); - } - } - - void _onFileTrashbinRestoredEvent(FileTrashbinRestoredEvent ev) { - if (state is ScanDirBlocInit) { - // no data in this bloc, ignore - return; - } - _refreshThrottler.trigger( - maxResponceTime: const Duration(seconds: 3), - maxPendingCount: 10, - ); - } - - void _onFileMovedEvent(FileMovedEvent ev) { - if (state is ScanDirBlocInit) { - // no data in this bloc, ignore - return; - } - if (file_util.isSupportedFormat(ev.file)) { - _refreshThrottler.trigger( - maxResponceTime: const Duration(seconds: 3), - maxPendingCount: 10, - ); - } - } - - Stream _queryOffline( - ScanDirBlocQueryBase ev, ScanDirBlocState Function() getState) => - _queryWithFileDataSource(ev, getState, FileAppDbDataSource(AppDb())); - - Stream _queryOnline( - ScanDirBlocQueryBase ev, ScanDirBlocState Function() getState) { - final stream = _queryWithFileDataSource(ev, getState, - FileCachedDataSource(AppDb(), shouldCheckCache: _shouldCheckCache)); - _shouldCheckCache = false; - return stream; - } - - Stream _queryWithFileDataSource(ScanDirBlocQueryBase ev, - ScanDirBlocState Function() getState, FileDataSource dataSrc) async* { - try { - for (final r in ev.roots) { - final dataStream = ScanDir(FileRepo(dataSrc))(ev.account, r); - await for (final d in dataStream) { - if (d is ExceptionEvent) { - throw d.error; - } - yield ScanDirBlocLoading(ev.account, getState().files + d); - } - } - yield ScanDirBlocSuccess(ev.account, getState().files); - } catch (e) { - _log.severe("[_queryWithFileDataSource] Exception while request", e); - yield ScanDirBlocFailure(ev.account, getState().files, e); - } - } - - late AppEventListener _fileRemovedEventListener; - late AppEventListener - _filePropertyUpdatedEventListener; - late final AppEventListener - _fileTrashbinRestoredEventListener; - late final _fileMovedEventListener = - AppEventListener(_onFileMovedEvent); - - late Throttler _refreshThrottler; - - bool _shouldCheckCache = true; - - static final _log = Logger("bloc.scan_dir.ScanDirBloc"); -} diff --git a/lib/widget/archive_browser.dart b/lib/widget/archive_browser.dart index 915c1233..61fac4f6 100644 --- a/lib/widget/archive_browser.dart +++ b/lib/widget/archive_browser.dart @@ -8,7 +8,7 @@ import 'package:nc_photos/account.dart'; 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/bloc/scan_dir.dart'; +import 'package:nc_photos/bloc/scan_account_dir.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file/data_source.dart'; @@ -70,10 +70,10 @@ class _ArchiveBrowserState extends State build(BuildContext context) { return AppTheme( child: Scaffold( - body: BlocListener( + body: BlocListener( bloc: _bloc, listener: (context, state) => _onStateChange(context, state), - child: BlocBuilder( + child: BlocBuilder( bloc: _bloc, builder: (context, state) => _buildContent(context, state), ), @@ -83,8 +83,7 @@ class _ArchiveBrowserState extends State } void _initBloc() { - _bloc = ScanDirBloc.of(widget.account); - if (_bloc.state is ScanDirBlocInit) { + if (_bloc.state is ScanAccountDirBlocInit) { _log.info("[_initBloc] Initialize bloc"); _reqQuery(); } else { @@ -97,8 +96,8 @@ class _ArchiveBrowserState extends State } } - Widget _buildContent(BuildContext context, ScanDirBlocState state) { - if (state is ScanDirBlocSuccess && itemStreamListItems.isEmpty) { + Widget _buildContent(BuildContext context, ScanAccountDirBlocState state) { + if (state is ScanAccountDirBlocSuccess && itemStreamListItems.isEmpty) { return Column( children: [ AppBar( @@ -137,7 +136,7 @@ class _ArchiveBrowserState extends State ), ), ), - if (state is ScanDirBlocLoading) + if (state is ScanAccountDirBlocLoading) const Align( alignment: Alignment.bottomCenter, child: LinearProgressIndicator(), @@ -195,18 +194,19 @@ class _ArchiveBrowserState extends State ); } - void _onStateChange(BuildContext context, ScanDirBlocState state) { - if (state is ScanDirBlocInit) { + void _onStateChange(BuildContext context, ScanAccountDirBlocState state) { + if (state is ScanAccountDirBlocInit) { itemStreamListItems = []; - } else if (state is ScanDirBlocSuccess || state is ScanDirBlocLoading) { + } else if (state is ScanAccountDirBlocSuccess || + state is ScanAccountDirBlocLoading) { _transformItems(state.files); - } else if (state is ScanDirBlocFailure) { + } else if (state is ScanAccountDirBlocFailure) { _transformItems(state.files); SnackBarManager().showSnackBar(SnackBar( content: Text(exception_util.toUserString(state.exception)), duration: k.snackBarDurationNormal, )); - } else if (state is ScanDirBlocInconsistent) { + } else if (state is ScanAccountDirBlocInconsistent) { _reqQuery(); } } @@ -294,11 +294,7 @@ class _ArchiveBrowserState extends State } void _reqQuery() { - _bloc.add(ScanDirBlocQuery( - widget.account, - widget.account.roots - .map((e) => File(path: file_util.unstripPath(widget.account, e))) - .toList())); + _bloc.add(const ScanAccountDirBlocQuery()); } int get _thumbSize { @@ -315,7 +311,7 @@ class _ArchiveBrowserState extends State } } - late ScanDirBloc _bloc; + late final _bloc = ScanAccountDirBloc.of(widget.account); var _backingFiles = []; diff --git a/lib/widget/home_photos.dart b/lib/widget/home_photos.dart index 80ce2eac..f8771985 100644 --- a/lib/widget/home_photos.dart +++ b/lib/widget/home_photos.dart @@ -12,7 +12,7 @@ import 'package:nc_photos/account.dart'; 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/bloc/scan_dir.dart'; +import 'package:nc_photos/bloc/scan_account_dir.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/download_handler.dart'; import 'package:nc_photos/entity/album.dart'; @@ -88,10 +88,10 @@ class _HomePhotosState extends State @override build(BuildContext context) { - return BlocListener( + return BlocListener( bloc: _bloc, listener: (context, state) => _onStateChange(context, state), - child: BlocBuilder( + child: BlocBuilder( bloc: _bloc, builder: (context, state) => _buildContent(context, state), ), @@ -99,8 +99,7 @@ class _HomePhotosState extends State } void _initBloc() { - _bloc = ScanDirBloc.of(widget.account); - if (_bloc.state is ScanDirBlocInit) { + if (_bloc.state is ScanAccountDirBlocInit) { _log.info("[_initBloc] Initialize bloc"); _reqQuery(); } else { @@ -113,7 +112,7 @@ class _HomePhotosState extends State } } - Widget _buildContent(BuildContext context, ScanDirBlocState state) { + Widget _buildContent(BuildContext context, ScanAccountDirBlocState state) { return LayoutBuilder(builder: (context, constraints) { final scrollExtent = _getScrollViewExtent(constraints); return Stack( @@ -161,7 +160,7 @@ class _HomePhotosState extends State ), ), ), - if (state is ScanDirBlocLoading) + if (state is ScanAccountDirBlocLoading) const Align( alignment: Alignment.bottomCenter, child: LinearProgressIndicator(), @@ -338,15 +337,16 @@ class _HomePhotosState extends State ); } - void _onStateChange(BuildContext context, ScanDirBlocState state) { - if (state is ScanDirBlocInit) { + void _onStateChange(BuildContext context, ScanAccountDirBlocState state) { + if (state is ScanAccountDirBlocInit) { itemStreamListItems = []; - } else if (state is ScanDirBlocSuccess || state is ScanDirBlocLoading) { + } else if (state is ScanAccountDirBlocSuccess || + state is ScanAccountDirBlocLoading) { _transformItems(state.files); - if (state is ScanDirBlocSuccess) { + if (state is ScanAccountDirBlocSuccess) { _tryStartMetadataTask(); } - } else if (state is ScanDirBlocFailure) { + } else if (state is ScanAccountDirBlocFailure) { _transformItems(state.files); if (isPageVisible()) { SnackBarManager().showSnackBar(SnackBar( @@ -354,7 +354,7 @@ class _HomePhotosState extends State duration: k.snackBarDurationNormal, )); } - } else if (state is ScanDirBlocInconsistent) { + } else if (state is ScanAccountDirBlocInconsistent) { _reqQuery(); } } @@ -546,7 +546,7 @@ class _HomePhotosState extends State void _tryStartMetadataTask({ bool ignoreFired = false, }) { - if (_bloc.state is ScanDirBlocSuccess && + if (_bloc.state is ScanAccountDirBlocSuccess && Pref().isEnableExifOr() && (!_hasFiredMetadataTask.value || ignoreFired)) { MetadataTaskManager().addTask(MetadataTask(widget.account)); @@ -603,23 +603,11 @@ class _HomePhotosState extends State } void _reqQuery() { - _bloc.add(ScanDirBlocQuery( - widget.account, - widget.account.roots - .map((e) => File( - path: - "${api_util.getWebdavRootUrlRelative(widget.account)}/$e")) - .toList())); + _bloc.add(const ScanAccountDirBlocQuery()); } void _reqRefresh() { - _bloc.add(ScanDirBlocRefresh( - widget.account, - widget.account.roots - .map((e) => File( - path: - "${api_util.getWebdavRootUrlRelative(widget.account)}/$e")) - .toList())); + _bloc.add(const ScanAccountDirBlocRefresh()); } void _setThumbZoomLevel(int level) { @@ -696,7 +684,7 @@ class _HomePhotosState extends State } } - late ScanDirBloc _bloc; + late final _bloc = ScanAccountDirBloc.of(widget.account); var _backingFiles = [];