2021-11-16 21:02:24 +01:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
import 'package:bloc/bloc.dart';
|
|
|
|
import 'package:kiwi/kiwi.dart';
|
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
import 'package:nc_photos/account.dart';
|
2022-01-27 11:02:45 +01:00
|
|
|
import 'package:nc_photos/bloc/bloc_util.dart' as bloc_util;
|
2022-01-01 21:34:40 +01:00
|
|
|
import 'package:nc_photos/debug_util.dart';
|
|
|
|
import 'package:nc_photos/di_container.dart';
|
2021-11-16 21:02:24 +01:00
|
|
|
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';
|
2022-04-01 18:59:18 +02:00
|
|
|
import 'package:nc_photos/event/native_event.dart';
|
2021-11-16 21:02:24 +01:00
|
|
|
import 'package:nc_photos/exception_event.dart';
|
2022-04-01 18:59:18 +02:00
|
|
|
import 'package:nc_photos/platform/k.dart' as platform_k;
|
2021-11-16 21:02:24 +01:00
|
|
|
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';
|
2022-01-01 21:34:40 +01:00
|
|
|
import 'package:nc_photos/use_case/scan_dir_offline.dart';
|
2021-11-16 21:02:24 +01:00
|
|
|
|
|
|
|
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<File> files;
|
|
|
|
}
|
|
|
|
|
|
|
|
class ScanAccountDirBlocInit extends ScanAccountDirBlocState {
|
|
|
|
const ScanAccountDirBlocInit() : super(const []);
|
|
|
|
}
|
|
|
|
|
|
|
|
class ScanAccountDirBlocLoading extends ScanAccountDirBlocState {
|
|
|
|
const ScanAccountDirBlocLoading(List<File> files) : super(files);
|
|
|
|
}
|
|
|
|
|
|
|
|
class ScanAccountDirBlocSuccess extends ScanAccountDirBlocState {
|
|
|
|
const ScanAccountDirBlocSuccess(List<File> files) : super(files);
|
|
|
|
}
|
|
|
|
|
|
|
|
class ScanAccountDirBlocFailure extends ScanAccountDirBlocState {
|
|
|
|
const ScanAccountDirBlocFailure(List<File> 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<File> files) : super(files);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A bloc that return all files under a dir recursively
|
|
|
|
///
|
|
|
|
/// See [ScanDir]
|
|
|
|
class ScanAccountDirBloc
|
|
|
|
extends Bloc<ScanAccountDirBlocEvent, ScanAccountDirBlocState> {
|
|
|
|
ScanAccountDirBloc._(this.account) : super(const ScanAccountDirBlocInit()) {
|
2022-07-05 22:20:24 +02:00
|
|
|
final c = KiwiContainer().resolve<DiContainer>();
|
|
|
|
assert(require(c));
|
|
|
|
assert(ScanDirOffline.require(c));
|
|
|
|
_c = c;
|
|
|
|
|
2021-11-16 21:02:24 +01:00
|
|
|
_fileRemovedEventListener.begin();
|
|
|
|
_filePropertyUpdatedEventListener.begin();
|
|
|
|
_fileTrashbinRestoredEventListener.begin();
|
|
|
|
_fileMovedEventListener.begin();
|
2022-01-25 11:15:17 +01:00
|
|
|
_favoriteResyncedEventListener.begin();
|
2021-11-16 21:02:24 +01:00
|
|
|
_prefUpdatedEventListener.begin();
|
2021-12-05 19:49:16 +01:00
|
|
|
_accountPrefUpdatedEventListener.begin();
|
2022-04-01 18:59:18 +02:00
|
|
|
|
|
|
|
_nativeFileExifUpdatedListener?.begin();
|
2022-09-10 06:03:49 +02:00
|
|
|
_imageProcessorUploadSuccessListener?.begin();
|
2022-07-09 07:59:09 +02:00
|
|
|
|
|
|
|
on<ScanAccountDirBlocEvent>(_onEvent, transformer: ((events, mapper) {
|
2022-09-23 12:09:21 +02:00
|
|
|
return events.distinct((a, b) {
|
2022-07-09 07:59:09 +02:00
|
|
|
// only handle ScanAccountDirBlocQuery
|
2022-09-23 12:09:21 +02:00
|
|
|
final r = a is ScanAccountDirBlocQuery && b is ScanAccountDirBlocQuery;
|
2022-07-09 07:59:09 +02:00
|
|
|
if (r) {
|
|
|
|
_log.fine("[on] Skip identical ScanAccountDirBlocQuery event");
|
|
|
|
}
|
|
|
|
return r;
|
2022-09-23 12:09:21 +02:00
|
|
|
}).asyncExpand(mapper);
|
2022-07-09 07:59:09 +02:00
|
|
|
}));
|
2021-11-16 21:02:24 +01:00
|
|
|
}
|
|
|
|
|
2022-09-23 10:37:34 +02:00
|
|
|
static bool require(DiContainer c) =>
|
|
|
|
DiContainer.has(c, DiType.fileRepo) &&
|
|
|
|
DiContainer.has(c, DiType.touchManager);
|
2022-07-05 22:20:24 +02:00
|
|
|
|
2021-11-16 21:02:24 +01:00
|
|
|
static ScanAccountDirBloc of(Account account) {
|
2022-01-27 11:02:45 +01:00
|
|
|
final name =
|
|
|
|
bloc_util.getInstNameForRootAwareAccount("ScanAccountDirBloc", account);
|
2021-11-16 21:02:24 +01:00
|
|
|
try {
|
2022-01-27 11:02:45 +01:00
|
|
|
_log.fine("[of] Resolving bloc for '$name'");
|
|
|
|
return KiwiContainer().resolve<ScanAccountDirBloc>(name);
|
2021-11-16 21:02:24 +01:00
|
|
|
} catch (_) {
|
|
|
|
// no created instance for this account, make a new one
|
|
|
|
_log.info("[of] New bloc instance for account: $account");
|
|
|
|
final bloc = ScanAccountDirBloc._(account);
|
2022-01-27 11:02:45 +01:00
|
|
|
KiwiContainer().registerInstance<ScanAccountDirBloc>(bloc, name: name);
|
2021-11-16 21:02:24 +01:00
|
|
|
return bloc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
close() {
|
|
|
|
_fileRemovedEventListener.end();
|
|
|
|
_filePropertyUpdatedEventListener.end();
|
|
|
|
_fileTrashbinRestoredEventListener.end();
|
|
|
|
_fileMovedEventListener.end();
|
2022-01-25 11:15:17 +01:00
|
|
|
_favoriteResyncedEventListener.end();
|
2021-11-16 21:02:24 +01:00
|
|
|
_prefUpdatedEventListener.end();
|
2021-12-05 19:49:16 +01:00
|
|
|
_accountPrefUpdatedEventListener.end();
|
2021-11-16 21:02:24 +01:00
|
|
|
|
2022-04-01 18:59:18 +02:00
|
|
|
_nativeFileExifUpdatedListener?.end();
|
2022-09-10 06:03:49 +02:00
|
|
|
_imageProcessorUploadSuccessListener?.end();
|
2022-04-01 18:59:18 +02:00
|
|
|
|
2021-11-16 21:02:24 +01:00
|
|
|
_refreshThrottler.clear();
|
|
|
|
return super.close();
|
|
|
|
}
|
|
|
|
|
2022-07-09 07:59:09 +02:00
|
|
|
Future<void> _onEvent(ScanAccountDirBlocEvent event,
|
|
|
|
Emitter<ScanAccountDirBlocState> emit) async {
|
|
|
|
_log.info("[_onEvent] $event");
|
|
|
|
if (event is ScanAccountDirBlocQueryBase) {
|
|
|
|
await _onEventQuery(event, emit);
|
|
|
|
} else if (event is _ScanAccountDirBlocExternalEvent) {
|
|
|
|
await _onExternalEvent(event, emit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _onEventQuery(ScanAccountDirBlocQueryBase ev,
|
|
|
|
Emitter<ScanAccountDirBlocState> emit) async {
|
|
|
|
_log.info("[_onEventQuery] $ev");
|
|
|
|
emit(ScanAccountDirBlocLoading(state.files));
|
2022-05-28 08:33:04 +02:00
|
|
|
final hasContent = state.files.isNotEmpty;
|
2021-11-16 21:02:24 +01:00
|
|
|
|
2022-05-28 08:33:04 +02:00
|
|
|
final stopwatch = Stopwatch()..start();
|
2022-07-13 22:23:41 +02:00
|
|
|
if (!hasContent) {
|
|
|
|
try {
|
|
|
|
emit(ScanAccountDirBlocLoading(await _queryOfflineMini(ev)));
|
|
|
|
} catch (e, stackTrace) {
|
|
|
|
_log.shout(
|
|
|
|
"[_onEventQuery] Failed while _queryOfflineMini", e, stackTrace);
|
|
|
|
}
|
|
|
|
_log.info(
|
|
|
|
"[_onEventQuery] Elapsed time (_queryOfflineMini): ${stopwatch.elapsedMilliseconds}ms");
|
|
|
|
stopwatch.reset();
|
|
|
|
}
|
2022-05-28 08:33:04 +02:00
|
|
|
final cacheFiles = await _queryOffline(ev);
|
|
|
|
_log.info(
|
|
|
|
"[_onEventQuery] Elapsed time (_queryOffline): ${stopwatch.elapsedMilliseconds}ms");
|
2021-11-16 21:02:24 +01:00
|
|
|
if (!hasContent) {
|
|
|
|
// show something instantly on first load
|
2022-07-09 07:59:09 +02:00
|
|
|
emit(ScanAccountDirBlocLoading(
|
|
|
|
cacheFiles.where((f) => file_util.isSupportedFormat(f)).toList()));
|
2021-11-16 21:02:24 +01:00
|
|
|
}
|
|
|
|
|
2022-07-09 07:59:09 +02:00
|
|
|
await _queryOnline(ev, emit, cacheFiles);
|
2021-11-16 21:02:24 +01:00
|
|
|
}
|
|
|
|
|
2022-07-09 07:59:09 +02:00
|
|
|
Future<void> _onExternalEvent(_ScanAccountDirBlocExternalEvent ev,
|
|
|
|
Emitter<ScanAccountDirBlocState> emit) async {
|
|
|
|
emit(ScanAccountDirBlocInconsistent(state.files));
|
2021-11-16 21:02:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2022-01-25 11:15:17 +01:00
|
|
|
FilePropertyUpdatedEvent.propFavorite,
|
2021-11-16 21:02:24 +01:00
|
|
|
])) {
|
|
|
|
// 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,
|
2022-01-25 11:15:17 +01:00
|
|
|
FilePropertyUpdatedEvent.propFavorite,
|
2021-11-16 21:02:24 +01:00
|
|
|
])) {
|
|
|
|
_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,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-25 11:15:17 +01:00
|
|
|
void _onFavoriteResyncedEvent(FavoriteResyncedEvent ev) {
|
|
|
|
if (state is ScanAccountDirBlocInit) {
|
|
|
|
// no data in this bloc, ignore
|
|
|
|
return;
|
|
|
|
}
|
2022-07-27 21:00:42 +02:00
|
|
|
if (ev.account.compareServerIdentity(account)) {
|
2022-01-25 11:15:17 +01:00
|
|
|
_refreshThrottler.trigger(
|
|
|
|
maxResponceTime: const Duration(seconds: 3),
|
|
|
|
maxPendingCount: 10,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 21:02:24 +01:00
|
|
|
void _onPrefUpdatedEvent(PrefUpdatedEvent ev) {
|
|
|
|
if (state is ScanAccountDirBlocInit) {
|
|
|
|
// no data in this bloc, ignore
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 13:02:22 +01:00
|
|
|
if (ev.key == PrefKey.accounts3) {
|
2021-11-16 21:02:24 +01:00
|
|
|
_refreshThrottler.trigger(
|
|
|
|
maxResponceTime: const Duration(seconds: 3),
|
|
|
|
maxPendingCount: 10,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 19:49:16 +01:00
|
|
|
void _onAccountPrefUpdatedEvent(AccountPrefUpdatedEvent ev) {
|
|
|
|
if (state is ScanAccountDirBlocInit) {
|
|
|
|
// no data in this bloc, ignore
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ev.key == PrefKey.shareFolder &&
|
|
|
|
identical(ev.pref, AccountPref.of(account))) {
|
|
|
|
_refreshThrottler.trigger(
|
|
|
|
maxResponceTime: const Duration(seconds: 3),
|
|
|
|
maxPendingCount: 10,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-01 18:59:18 +02:00
|
|
|
void _onNativeFileExifUpdated(FileExifUpdatedEvent ev) {
|
|
|
|
_refreshThrottler.trigger(
|
|
|
|
maxResponceTime: const Duration(seconds: 3),
|
|
|
|
maxPendingCount: 10,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-09-10 06:03:49 +02:00
|
|
|
void _onImageProcessorUploadSuccessEvent(
|
|
|
|
ImageProcessorUploadSuccessEvent ev) {
|
|
|
|
_refreshThrottler.trigger(
|
|
|
|
maxResponceTime: const Duration(seconds: 3),
|
|
|
|
maxPendingCount: 10,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-13 22:23:41 +02:00
|
|
|
/// Query a small amount of files to give an illusion of quick startup
|
|
|
|
Future<List<File>> _queryOfflineMini(ScanAccountDirBlocQueryBase ev) async {
|
|
|
|
return await ScanDirOfflineMini(_c)(
|
|
|
|
account,
|
|
|
|
account.roots.map((r) => File(path: file_util.unstripPath(account, r))),
|
|
|
|
100,
|
|
|
|
isOnlySupportedFormat: true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-01 21:34:40 +01:00
|
|
|
Future<List<File>> _queryOffline(ScanAccountDirBlocQueryBase ev) async {
|
|
|
|
final files = <File>[];
|
|
|
|
for (final r in account.roots) {
|
|
|
|
try {
|
|
|
|
final dir = File(path: file_util.unstripPath(account, r));
|
2022-07-05 22:20:24 +02:00
|
|
|
files.addAll(await ScanDirOffline(_c)(account, dir,
|
2022-05-28 08:33:04 +02:00
|
|
|
isOnlySupportedFormat: false));
|
2022-01-01 21:34:40 +01:00
|
|
|
} catch (e, stackTrace) {
|
|
|
|
_log.shout(
|
|
|
|
"[_queryOffline] Failed while ScanDirOffline: ${logFilename(r)}",
|
|
|
|
e,
|
|
|
|
stackTrace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return files;
|
|
|
|
}
|
2021-11-16 21:02:24 +01:00
|
|
|
|
2022-07-09 07:59:09 +02:00
|
|
|
Future<void> _queryOnline(ScanAccountDirBlocQueryBase ev,
|
|
|
|
Emitter<ScanAccountDirBlocState> emit, List<File> cache) async {
|
2022-01-05 06:20:37 +01:00
|
|
|
// 1st pass: scan for new files
|
2022-01-20 06:23:49 +01:00
|
|
|
var files = <File>[];
|
2022-05-28 08:33:04 +02:00
|
|
|
final cacheMap = FileForwardCacheManager.prepareFileMap(cache);
|
2022-09-23 10:37:34 +02:00
|
|
|
final stopwatch = Stopwatch()..start();
|
|
|
|
_c.touchManager.clearTouchCache();
|
2022-07-05 22:20:24 +02:00
|
|
|
final fileRepo = FileRepo(FileCachedDataSource(
|
|
|
|
_c,
|
2022-09-23 10:37:34 +02:00
|
|
|
forwardCacheManager: FileForwardCacheManager(_c, cacheMap),
|
2022-07-05 22:20:24 +02:00
|
|
|
shouldCheckCache: true,
|
|
|
|
));
|
2022-09-23 10:37:34 +02:00
|
|
|
await for (final event
|
|
|
|
in _queryWithFileRepo(fileRepo, ev, fileRepoForShareDir: _c.fileRepo)) {
|
2022-01-20 06:23:49 +01:00
|
|
|
if (event is ExceptionEvent) {
|
2022-09-23 10:37:34 +02:00
|
|
|
_log.shout("[_queryOnline] Exception while request", event.error,
|
|
|
|
event.stackTrace);
|
|
|
|
emit(ScanAccountDirBlocFailure(
|
|
|
|
cache.isEmpty
|
|
|
|
? files
|
|
|
|
: cache.where((f) => file_util.isSupportedFormat(f)).toList(),
|
|
|
|
event.error));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
files.addAll(event);
|
|
|
|
if (cache.isEmpty) {
|
|
|
|
// only emit partial results if there's no cache
|
|
|
|
emit(ScanAccountDirBlocLoading(files.toList()));
|
2022-01-20 06:23:49 +01:00
|
|
|
}
|
2022-01-05 06:20:37 +01:00
|
|
|
}
|
2022-01-20 06:23:49 +01:00
|
|
|
_log.info(
|
2022-09-23 10:37:34 +02:00
|
|
|
"[_queryOnline] Elapsed time (_queryOnline): ${stopwatch.elapsedMilliseconds}ms, ${files.length} files");
|
|
|
|
|
|
|
|
emit(ScanAccountDirBlocSuccess(files));
|
2022-01-05 06:20:37 +01:00
|
|
|
}
|
2021-11-16 21:02:24 +01:00
|
|
|
|
2022-01-05 06:20:37 +01:00
|
|
|
/// Emit all files under this account
|
|
|
|
///
|
|
|
|
/// Emit List<File> or ExceptionEvent
|
|
|
|
Stream<dynamic> _queryWithFileRepo(
|
|
|
|
FileRepo fileRepo,
|
|
|
|
ScanAccountDirBlocQueryBase ev, {
|
|
|
|
FileRepo? fileRepoForShareDir,
|
|
|
|
}) async* {
|
|
|
|
final settings = AccountPref.of(account);
|
|
|
|
final shareDir =
|
|
|
|
File(path: file_util.unstripPath(account, settings.getShareFolderOr()));
|
|
|
|
bool isShareDirIncluded = false;
|
|
|
|
|
|
|
|
for (final r in account.roots) {
|
|
|
|
final dir = File(path: file_util.unstripPath(account, r));
|
|
|
|
yield* ScanDir(fileRepo)(account, dir);
|
|
|
|
isShareDirIncluded |= file_util.isOrUnderDir(shareDir, dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isShareDirIncluded) {
|
|
|
|
_log.info("[_queryWithFileRepo] Explicitly scanning share folder");
|
|
|
|
try {
|
|
|
|
final files = await Ls(fileRepoForShareDir ?? fileRepo)(
|
2021-12-05 13:02:22 +01:00
|
|
|
account,
|
|
|
|
File(
|
|
|
|
path: file_util.unstripPath(account, settings.getShareFolderOr()),
|
|
|
|
),
|
|
|
|
);
|
2022-01-05 06:20:37 +01:00
|
|
|
yield files
|
2021-12-19 19:09:38 +01:00
|
|
|
.where((f) =>
|
2022-07-11 20:14:42 +02:00
|
|
|
file_util.isSupportedFormat(f) && !f.isOwned(account.userId))
|
2021-12-19 19:09:38 +01:00
|
|
|
.toList();
|
2022-01-05 06:20:37 +01:00
|
|
|
} catch (e, stackTrace) {
|
|
|
|
yield ExceptionEvent(e, stackTrace);
|
2021-11-16 21:02:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 13:02:22 +01:00
|
|
|
final settings = AccountPref.of(account);
|
2021-11-16 21:02:24 +01:00
|
|
|
final shareDir =
|
2021-12-05 13:02:22 +01:00
|
|
|
File(path: file_util.unstripPath(account, settings.getShareFolderOr()));
|
2021-11-16 21:02:24 +01:00
|
|
|
if (file_util.isUnderDir(file, shareDir)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-07-05 22:20:24 +02:00
|
|
|
late final DiContainer _c;
|
|
|
|
|
2021-11-16 21:02:24 +01:00
|
|
|
final Account account;
|
|
|
|
|
|
|
|
late final _fileRemovedEventListener =
|
|
|
|
AppEventListener<FileRemovedEvent>(_onFileRemovedEvent);
|
|
|
|
late final _filePropertyUpdatedEventListener =
|
|
|
|
AppEventListener<FilePropertyUpdatedEvent>(_onFilePropertyUpdatedEvent);
|
|
|
|
late final _fileTrashbinRestoredEventListener =
|
|
|
|
AppEventListener<FileTrashbinRestoredEvent>(_onFileTrashbinRestoredEvent);
|
|
|
|
late final _fileMovedEventListener =
|
|
|
|
AppEventListener<FileMovedEvent>(_onFileMovedEvent);
|
2022-01-25 11:15:17 +01:00
|
|
|
late final _favoriteResyncedEventListener =
|
|
|
|
AppEventListener<FavoriteResyncedEvent>(_onFavoriteResyncedEvent);
|
2021-11-16 21:02:24 +01:00
|
|
|
late final _prefUpdatedEventListener =
|
|
|
|
AppEventListener<PrefUpdatedEvent>(_onPrefUpdatedEvent);
|
2021-12-05 19:49:16 +01:00
|
|
|
late final _accountPrefUpdatedEventListener =
|
|
|
|
AppEventListener<AccountPrefUpdatedEvent>(_onAccountPrefUpdatedEvent);
|
2021-11-16 21:02:24 +01:00
|
|
|
|
2022-04-01 18:59:18 +02:00
|
|
|
late final _nativeFileExifUpdatedListener = platform_k.isWeb
|
|
|
|
? null
|
|
|
|
: NativeEventListener<FileExifUpdatedEvent>(_onNativeFileExifUpdated);
|
2022-09-10 06:03:49 +02:00
|
|
|
late final _imageProcessorUploadSuccessListener = platform_k.isWeb
|
|
|
|
? null
|
|
|
|
: NativeEventListener<ImageProcessorUploadSuccessEvent>(
|
|
|
|
_onImageProcessorUploadSuccessEvent);
|
2022-04-01 18:59:18 +02:00
|
|
|
|
2021-11-16 21:02:24 +01:00
|
|
|
late final _refreshThrottler = Throttler(
|
|
|
|
onTriggered: (_) {
|
|
|
|
add(const _ScanAccountDirBlocExternalEvent());
|
|
|
|
},
|
|
|
|
logTag: "ScanAccountDirBloc.refresh",
|
|
|
|
);
|
|
|
|
|
|
|
|
static final _log = Logger("bloc.scan_dir.ScanAccountDirBloc");
|
|
|
|
}
|