Make PersonBrowser looks more like the photos tab

This commit is contained in:
Ming Ming 2022-08-07 19:55:00 +08:00
parent abe215aee0
commit 8b1ed216b0
2 changed files with 130 additions and 3 deletions

View file

@ -5,6 +5,8 @@ import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/entity/person.dart';
import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/throttler.dart';
import 'package:nc_photos/use_case/populate_person.dart';
abstract class ListFaceFileBlocEvent {
@ -24,6 +26,15 @@ class ListFaceFileBlocQuery extends ListFaceFileBlocEvent {
final Person person;
}
/// An external event has happened and may affect the state of this bloc
class _ListFaceFileBlocExternalEvent extends ListFaceFileBlocEvent {
const _ListFaceFileBlocExternalEvent();
@override
toString() => "$runtimeType {"
"}";
}
abstract class ListFaceFileBlocState {
const ListFaceFileBlocState(this.account, this.items);
@ -65,6 +76,13 @@ class ListFaceFileBlocFailure extends ListFaceFileBlocState {
final Object exception;
}
/// The state of this bloc is inconsistent. This typically means that the data
/// may have been changed externally
class ListFaceFileBlocInconsistent extends ListFaceFileBlocState {
const ListFaceFileBlocInconsistent(Account? account, List<File> items)
: super(account, items);
}
/// List all people recognized in an account
class ListFaceFileBloc
extends Bloc<ListFaceFileBlocEvent, ListFaceFileBlocState> {
@ -72,16 +90,28 @@ class ListFaceFileBloc
: assert(require(_c)),
assert(PopulatePerson.require(_c)),
super(ListFaceFileBlocInit()) {
_fileRemovedEventListener.begin();
_filePropertyUpdatedEventListener.begin();
on<ListFaceFileBlocEvent>(_onEvent);
}
static bool require(DiContainer c) => DiContainer.has(c, DiType.faceRepo);
@override
close() {
_fileRemovedEventListener.end();
_filePropertyUpdatedEventListener.end();
return super.close();
}
Future<void> _onEvent(
ListFaceFileBlocEvent event, Emitter<ListFaceFileBlocState> emit) async {
_log.info("[_onEvent] $event");
if (event is ListFaceFileBlocQuery) {
await _onEventQuery(event, emit);
} else if (event is _ListFaceFileBlocExternalEvent) {
await _onExternalEvent(event, emit);
}
}
@ -96,6 +126,59 @@ class ListFaceFileBloc
}
}
Future<void> _onExternalEvent(_ListFaceFileBlocExternalEvent ev,
Emitter<ListFaceFileBlocState> emit) async {
emit(ListFaceFileBlocInconsistent(state.account, state.items));
}
void _onFileRemovedEvent(FileRemovedEvent ev) {
if (state is ListFaceFileBlocInit) {
// 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,
FilePropertyUpdatedEvent.propFavorite,
])) {
// not interested
return;
}
if (state is ListFaceFileBlocInit) {
// no data in this bloc, ignore
return;
}
if (!_isFileOfInterest(ev.file)) {
return;
}
if (ev.hasAnyProperties([
FilePropertyUpdatedEvent.propIsArchived,
FilePropertyUpdatedEvent.propOverrideDateTime,
FilePropertyUpdatedEvent.propFavorite,
])) {
_refreshThrottler.trigger(
maxResponceTime: const Duration(seconds: 3),
maxPendingCount: 10,
);
} else {
_refreshThrottler.trigger(
maxResponceTime: const Duration(seconds: 10),
maxPendingCount: 10,
);
}
}
Future<List<File>> _query(ListFaceFileBlocQuery ev) async {
final faces = await _c.faceRepo.list(ev.account, ev.person);
final files = await PopulatePerson(_c)(ev.account, faces);
@ -109,7 +192,33 @@ class ListFaceFileBloc
.toList();
}
bool _isFileOfInterest(File file) {
if (!file_util.isSupportedFormat(file)) {
return false;
}
for (final r in state.account?.roots ?? []) {
final dir = File(path: file_util.unstripPath(state.account!, r));
if (file_util.isUnderDir(file, dir)) {
return true;
}
}
return false;
}
final DiContainer _c;
late final _fileRemovedEventListener =
AppEventListener<FileRemovedEvent>(_onFileRemovedEvent);
late final _filePropertyUpdatedEventListener =
AppEventListener<FilePropertyUpdatedEvent>(_onFilePropertyUpdatedEvent);
late final _refreshThrottler = Throttler(
onTriggered: (_) {
add(const _ListFaceFileBlocExternalEvent());
},
logTag: "ListFaceFileBloc.refresh",
);
static final _log = Logger("bloc.list_face_file.ListFaceFileBloc");
}

View file

@ -119,8 +119,12 @@ class _PersonBrowserState extends State<PersonBrowser>
@override
onItemTap(SelectableItem item, int index) {
item.as<PhotoListFileItem>()?.run((fileItem) {
Navigator.pushNamed(context, Viewer.routeName,
arguments: ViewerArguments(widget.account, _backingFiles, index));
Navigator.pushNamed(
context,
Viewer.routeName,
arguments:
ViewerArguments(widget.account, _backingFiles, fileItem.fileIndex),
);
});
}
@ -324,6 +328,8 @@ class _PersonBrowserState extends State<PersonBrowser>
content: Text(exception_util.toUserString(state.exception)),
duration: k.snackBarDurationNormal,
));
} else if (state is ListFaceFileBlocInconsistent) {
_reqQuery();
}
}
@ -430,11 +436,23 @@ class _PersonBrowserState extends State<PersonBrowser>
}
Future<void> _transformItems(List<File> files) async {
final PhotoListItemSorter? sorter;
final PhotoListItemGrouper? grouper;
if (Pref().isPhotosTabSortByNameOr()) {
sorter = photoListFilenameSorter;
grouper = null;
} else {
sorter = photoListFileDateTimeSorter;
grouper = PhotoListFileDateGrouper(isMonthOnly: _thumbZoomLevel < 0);
}
_buildItemQueue.addJob(
PhotoListItemBuilderArguments(
widget.account,
files,
sorter: photoListFileDateTimeSorter,
sorter: sorter,
grouper: grouper,
shouldShowFavoriteBadge: true,
locale: language_util.getSelectedLocale() ??
PlatformDispatcher.instance.locale,
),