mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 18:38:48 +01:00
Migrate PersonBrowser to use PhotoListItemBuilder
This commit is contained in:
parent
80bb6b7f80
commit
2f4c6ba68e
3 changed files with 207 additions and 237 deletions
|
@ -1,102 +0,0 @@
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:nc_photos/account.dart';
|
|
||||||
import 'package:nc_photos/entity/face.dart';
|
|
||||||
import 'package:nc_photos/entity/face/data_source.dart';
|
|
||||||
import 'package:nc_photos/entity/person.dart';
|
|
||||||
|
|
||||||
abstract class ListFaceBlocEvent {
|
|
||||||
const ListFaceBlocEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ListFaceBlocQuery extends ListFaceBlocEvent {
|
|
||||||
const ListFaceBlocQuery(this.account, this.person);
|
|
||||||
|
|
||||||
@override
|
|
||||||
toString() {
|
|
||||||
return "$runtimeType {"
|
|
||||||
"account: $account, "
|
|
||||||
"person: $person, "
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
final Account account;
|
|
||||||
final Person person;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class ListFaceBlocState {
|
|
||||||
const ListFaceBlocState(this.account, this.items);
|
|
||||||
|
|
||||||
@override
|
|
||||||
toString() {
|
|
||||||
return "$runtimeType {"
|
|
||||||
"account: $account, "
|
|
||||||
"items: List {length: ${items.length}}, "
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
final Account? account;
|
|
||||||
final List<Face> items;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ListFaceBlocInit extends ListFaceBlocState {
|
|
||||||
ListFaceBlocInit() : super(null, const []);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ListFaceBlocLoading extends ListFaceBlocState {
|
|
||||||
const ListFaceBlocLoading(Account? account, List<Face> items)
|
|
||||||
: super(account, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ListFaceBlocSuccess extends ListFaceBlocState {
|
|
||||||
const ListFaceBlocSuccess(Account? account, List<Face> items)
|
|
||||||
: super(account, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ListFaceBlocFailure extends ListFaceBlocState {
|
|
||||||
const ListFaceBlocFailure(Account? account, List<Face> items, this.exception)
|
|
||||||
: super(account, items);
|
|
||||||
|
|
||||||
@override
|
|
||||||
toString() {
|
|
||||||
return "$runtimeType {"
|
|
||||||
"super: ${super.toString()}, "
|
|
||||||
"exception: $exception, "
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
final dynamic exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List all people recognized in an account
|
|
||||||
class ListFaceBloc extends Bloc<ListFaceBlocEvent, ListFaceBlocState> {
|
|
||||||
ListFaceBloc() : super(ListFaceBlocInit()) {
|
|
||||||
on<ListFaceBlocEvent>(_onEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onEvent(
|
|
||||||
ListFaceBlocEvent event, Emitter<ListFaceBlocState> emit) async {
|
|
||||||
_log.info("[_onEvent] $event");
|
|
||||||
if (event is ListFaceBlocQuery) {
|
|
||||||
await _onEventQuery(event, emit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onEventQuery(
|
|
||||||
ListFaceBlocQuery ev, Emitter<ListFaceBlocState> emit) async {
|
|
||||||
try {
|
|
||||||
emit(ListFaceBlocLoading(ev.account, state.items));
|
|
||||||
emit(ListFaceBlocSuccess(ev.account, await _query(ev)));
|
|
||||||
} catch (e, stackTrace) {
|
|
||||||
_log.severe("[_onEventQuery] Exception while request", e, stackTrace);
|
|
||||||
emit(ListFaceBlocFailure(ev.account, state.items, e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<Face>> _query(ListFaceBlocQuery ev) {
|
|
||||||
const personRepo = FaceRepo(FaceRemoteDataSource());
|
|
||||||
return personRepo.list(ev.account, ev.person);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final _log = Logger("bloc.list_personListFaceBloc");
|
|
||||||
}
|
|
115
app/lib/bloc/list_face_file.dart
Normal file
115
app/lib/bloc/list_face_file.dart
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:logging/logging.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_util.dart' as file_util;
|
||||||
|
import 'package:nc_photos/entity/person.dart';
|
||||||
|
import 'package:nc_photos/use_case/populate_person.dart';
|
||||||
|
|
||||||
|
abstract class ListFaceFileBlocEvent {
|
||||||
|
const ListFaceFileBlocEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListFaceFileBlocQuery extends ListFaceFileBlocEvent {
|
||||||
|
const ListFaceFileBlocQuery(this.account, this.person);
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString() => "$runtimeType {"
|
||||||
|
"account: $account, "
|
||||||
|
"person: $person, "
|
||||||
|
"}";
|
||||||
|
|
||||||
|
final Account account;
|
||||||
|
final Person person;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ListFaceFileBlocState {
|
||||||
|
const ListFaceFileBlocState(this.account, this.items);
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString() => "$runtimeType {"
|
||||||
|
"account: $account, "
|
||||||
|
"items: List {length: ${items.length}}, "
|
||||||
|
"}";
|
||||||
|
|
||||||
|
final Account? account;
|
||||||
|
final List<File> items;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListFaceFileBlocInit extends ListFaceFileBlocState {
|
||||||
|
ListFaceFileBlocInit() : super(null, const []);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListFaceFileBlocLoading extends ListFaceFileBlocState {
|
||||||
|
const ListFaceFileBlocLoading(Account? account, List<File> items)
|
||||||
|
: super(account, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListFaceFileBlocSuccess extends ListFaceFileBlocState {
|
||||||
|
const ListFaceFileBlocSuccess(Account? account, List<File> items)
|
||||||
|
: super(account, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListFaceFileBlocFailure extends ListFaceFileBlocState {
|
||||||
|
const ListFaceFileBlocFailure(
|
||||||
|
Account? account, List<File> items, this.exception)
|
||||||
|
: super(account, items);
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString() => "$runtimeType {"
|
||||||
|
"super: ${super.toString()}, "
|
||||||
|
"exception: $exception, "
|
||||||
|
"}";
|
||||||
|
|
||||||
|
final Object exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List all people recognized in an account
|
||||||
|
class ListFaceFileBloc
|
||||||
|
extends Bloc<ListFaceFileBlocEvent, ListFaceFileBlocState> {
|
||||||
|
ListFaceFileBloc(this._c)
|
||||||
|
: assert(require(_c)),
|
||||||
|
assert(PopulatePerson.require(_c)),
|
||||||
|
super(ListFaceFileBlocInit()) {
|
||||||
|
on<ListFaceFileBlocEvent>(_onEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool require(DiContainer c) => DiContainer.has(c, DiType.faceRepo);
|
||||||
|
|
||||||
|
Future<void> _onEvent(
|
||||||
|
ListFaceFileBlocEvent event, Emitter<ListFaceFileBlocState> emit) async {
|
||||||
|
_log.info("[_onEvent] $event");
|
||||||
|
if (event is ListFaceFileBlocQuery) {
|
||||||
|
await _onEventQuery(event, emit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onEventQuery(
|
||||||
|
ListFaceFileBlocQuery ev, Emitter<ListFaceFileBlocState> emit) async {
|
||||||
|
try {
|
||||||
|
emit(ListFaceFileBlocLoading(ev.account, state.items));
|
||||||
|
emit(ListFaceFileBlocSuccess(ev.account, await _query(ev)));
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
_log.severe("[_onEventQuery] Exception while request", e, stackTrace);
|
||||||
|
emit(ListFaceFileBlocFailure(ev.account, state.items, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
final rootDirs = ev.account.roots
|
||||||
|
.map((e) => File(path: file_util.unstripPath(ev.account, e)))
|
||||||
|
.toList();
|
||||||
|
return files
|
||||||
|
.where((f) =>
|
||||||
|
file_util.isSupportedFormat(f) &&
|
||||||
|
rootDirs.any((dir) => file_util.isUnderDir(f, dir)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
final DiContainer _c;
|
||||||
|
|
||||||
|
static final _log = Logger("bloc.list_face_file.ListFaceFileBloc");
|
||||||
|
}
|
|
@ -1,34 +1,34 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
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: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/api/api.dart';
|
import 'package:nc_photos/api/api.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/list_face.dart';
|
import 'package:nc_photos/bloc/list_face_file.dart';
|
||||||
import 'package:nc_photos/cache_manager_util.dart';
|
import 'package:nc_photos/cache_manager_util.dart';
|
||||||
|
import 'package:nc_photos/compute_queue.dart';
|
||||||
import 'package:nc_photos/di_container.dart';
|
import 'package:nc_photos/di_container.dart';
|
||||||
import 'package:nc_photos/download_handler.dart';
|
import 'package:nc_photos/download_handler.dart';
|
||||||
import 'package:nc_photos/entity/face.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/person.dart';
|
import 'package:nc_photos/entity/person.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';
|
||||||
import 'package:nc_photos/k.dart' as k;
|
import 'package:nc_photos/k.dart' as k;
|
||||||
|
import 'package:nc_photos/language_util.dart' as language_util;
|
||||||
import 'package:nc_photos/object_extension.dart';
|
import 'package:nc_photos/object_extension.dart';
|
||||||
import 'package:nc_photos/pref.dart';
|
import 'package:nc_photos/pref.dart';
|
||||||
import 'package:nc_photos/share_handler.dart';
|
import 'package:nc_photos/share_handler.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';
|
||||||
import 'package:nc_photos/throttler.dart';
|
import 'package:nc_photos/throttler.dart';
|
||||||
import 'package:nc_photos/use_case/populate_person.dart';
|
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
|
||||||
import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart';
|
import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart';
|
||||||
import 'package:nc_photos/widget/handler/archive_selection_handler.dart';
|
import 'package:nc_photos/widget/handler/archive_selection_handler.dart';
|
||||||
import 'package:nc_photos/widget/handler/remove_selection_handler.dart';
|
import 'package:nc_photos/widget/handler/remove_selection_handler.dart';
|
||||||
|
@ -79,10 +79,11 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
_PersonBrowserState() {
|
_PersonBrowserState() {
|
||||||
final c = KiwiContainer().resolve<DiContainer>();
|
final c = KiwiContainer().resolve<DiContainer>();
|
||||||
assert(require(c));
|
assert(require(c));
|
||||||
|
assert(ListFaceFileBloc.require(c));
|
||||||
_c = c;
|
_c = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb);
|
static bool require(DiContainer c) => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
initState() {
|
initState() {
|
||||||
|
@ -103,12 +104,12 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
build(BuildContext context) {
|
build(BuildContext context) {
|
||||||
return AppTheme(
|
return AppTheme(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: BlocListener<ListFaceBloc, ListFaceBlocState>(
|
body: BlocListener<ListFaceFileBloc, ListFaceFileBlocState>(
|
||||||
bloc: _bloc,
|
bloc: _bloc,
|
||||||
listener: (context, state) => _onStateChange(context, state),
|
listener: (context, state) => _onStateChange(context, state),
|
||||||
child: BlocBuilder<ListFaceBloc, ListFaceBlocState>(
|
child: BlocBuilder<ListFaceFileBloc, ListFaceFileBlocState>(
|
||||||
bloc: _bloc,
|
bloc: _bloc,
|
||||||
builder: (context, state) => _buildContent(context),
|
builder: (context, state) => _buildContent(context, state),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -117,7 +118,10 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
onItemTap(SelectableItem item, int index) {
|
onItemTap(SelectableItem item, int index) {
|
||||||
item.as<_ListItem>()?.onTap?.call();
|
item.as<PhotoListFileItem>()?.run((fileItem) {
|
||||||
|
Navigator.pushNamed(context, Viewer.routeName,
|
||||||
|
arguments: ViewerArguments(widget.account, _backingFiles, index));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initBloc() {
|
void _initBloc() {
|
||||||
|
@ -125,36 +129,33 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
_reqQuery();
|
_reqQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildContent(BuildContext context) {
|
Widget _buildContent(BuildContext context, ListFaceFileBlocState state) {
|
||||||
if (_backingFiles == null) {
|
return buildItemStreamListOuter(
|
||||||
return CustomScrollView(
|
context,
|
||||||
slivers: [
|
child: Theme(
|
||||||
_buildNormalAppBar(context),
|
data: Theme.of(context).copyWith(
|
||||||
const SliverToBoxAdapter(
|
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||||
child: LinearProgressIndicator(),
|
secondary: AppTheme.getOverscrollIndicatorColor(context),
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return buildItemStreamListOuter(
|
|
||||||
context,
|
|
||||||
child: Theme(
|
|
||||||
data: Theme.of(context).copyWith(
|
|
||||||
colorScheme: Theme.of(context).colorScheme.copyWith(
|
|
||||||
secondary: AppTheme.getOverscrollIndicatorColor(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: CustomScrollView(
|
|
||||||
slivers: [
|
|
||||||
_buildAppBar(context),
|
|
||||||
buildItemStreamList(
|
|
||||||
maxCrossAxisExtent: _thumbSize.toDouble(),
|
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
child: CustomScrollView(
|
||||||
}
|
slivers: [
|
||||||
|
_buildAppBar(context),
|
||||||
|
if (state is ListFaceFileBlocLoading ||
|
||||||
|
_buildItemQueue.isProcessing)
|
||||||
|
const SliverToBoxAdapter(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: LinearProgressIndicator(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
buildItemStreamList(
|
||||||
|
maxCrossAxisExtent: _thumbSize.toDouble(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAppBar(BuildContext context) {
|
Widget _buildAppBar(BuildContext context) {
|
||||||
|
@ -310,12 +311,13 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStateChange(BuildContext context, ListFaceBlocState state) {
|
void _onStateChange(BuildContext context, ListFaceFileBlocState state) {
|
||||||
if (state is ListFaceBlocInit) {
|
if (state is ListFaceFileBlocInit) {
|
||||||
_backingFiles = null;
|
itemStreamListItems = [];
|
||||||
} else if (state is ListFaceBlocSuccess || state is ListFaceBlocLoading) {
|
} else if (state is ListFaceFileBlocSuccess ||
|
||||||
|
state is ListFaceFileBlocLoading) {
|
||||||
_transformItems(state.items);
|
_transformItems(state.items);
|
||||||
} else if (state is ListFaceBlocFailure) {
|
} else if (state is ListFaceFileBlocFailure) {
|
||||||
_transformItems(state.items);
|
_transformItems(state.items);
|
||||||
SnackBarManager().showSnackBar(SnackBar(
|
SnackBarManager().showSnackBar(SnackBar(
|
||||||
content: Text(exception_util.toUserString(state.exception)),
|
content: Text(exception_util.toUserString(state.exception)),
|
||||||
|
@ -324,11 +326,6 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onItemTap(int index) {
|
|
||||||
Navigator.pushNamed(context, Viewer.routeName,
|
|
||||||
arguments: ViewerArguments(widget.account, _backingFiles!, index));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onSelectionMenuSelected(
|
void _onSelectionMenuSelected(
|
||||||
BuildContext context, _SelectionMenuOption option) {
|
BuildContext context, _SelectionMenuOption option) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
|
@ -348,8 +345,10 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectionSharePressed(BuildContext context) {
|
void _onSelectionSharePressed(BuildContext context) {
|
||||||
final selected =
|
final selected = selectedListItems
|
||||||
selectedListItems.whereType<_ListItem>().map((e) => e.file).toList();
|
.whereType<PhotoListFileItem>()
|
||||||
|
.map((e) => e.file)
|
||||||
|
.toList();
|
||||||
ShareHandler(
|
ShareHandler(
|
||||||
context: context,
|
context: context,
|
||||||
clearSelection: () {
|
clearSelection: () {
|
||||||
|
@ -364,8 +363,10 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
return AddSelectionToAlbumHandler()(
|
return AddSelectionToAlbumHandler()(
|
||||||
context: context,
|
context: context,
|
||||||
account: widget.account,
|
account: widget.account,
|
||||||
selectedFiles:
|
selectedFiles: selectedListItems
|
||||||
selectedListItems.whereType<_ListItem>().map((e) => e.file).toList(),
|
.whereType<PhotoListFileItem>()
|
||||||
|
.map((e) => e.file)
|
||||||
|
.toList(),
|
||||||
clearSelection: () {
|
clearSelection: () {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -377,8 +378,10 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectionDownloadPressed() {
|
void _onSelectionDownloadPressed() {
|
||||||
final selected =
|
final selected = selectedListItems
|
||||||
selectedListItems.whereType<_ListItem>().map((e) => e.file).toList();
|
.whereType<PhotoListFileItem>()
|
||||||
|
.map((e) => e.file)
|
||||||
|
.toList();
|
||||||
DownloadHandler().downloadFiles(widget.account, selected);
|
DownloadHandler().downloadFiles(widget.account, selected);
|
||||||
setState(() {
|
setState(() {
|
||||||
clearSelectedItems();
|
clearSelectedItems();
|
||||||
|
@ -386,8 +389,10 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onSelectionArchivePressed(BuildContext context) async {
|
Future<void> _onSelectionArchivePressed(BuildContext context) async {
|
||||||
final selectedFiles =
|
final selectedFiles = selectedListItems
|
||||||
selectedListItems.whereType<_ListItem>().map((e) => e.file).toList();
|
.whereType<PhotoListFileItem>()
|
||||||
|
.map((e) => e.file)
|
||||||
|
.toList();
|
||||||
setState(() {
|
setState(() {
|
||||||
clearSelectedItems();
|
clearSelectedItems();
|
||||||
});
|
});
|
||||||
|
@ -398,8 +403,10 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onSelectionDeletePressed(BuildContext context) async {
|
Future<void> _onSelectionDeletePressed(BuildContext context) async {
|
||||||
final selectedFiles =
|
final selectedFiles = selectedListItems
|
||||||
selectedListItems.whereType<_ListItem>().map((e) => e.file).toList();
|
.whereType<PhotoListFileItem>()
|
||||||
|
.map((e) => e.file)
|
||||||
|
.toList();
|
||||||
setState(() {
|
setState(() {
|
||||||
clearSelectedItems();
|
clearSelectedItems();
|
||||||
});
|
});
|
||||||
|
@ -411,7 +418,7 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onFilePropertyUpdated(FilePropertyUpdatedEvent ev) {
|
void _onFilePropertyUpdated(FilePropertyUpdatedEvent ev) {
|
||||||
if (_backingFiles?.containsIf(ev.file, (a, b) => a.fileId == b.fileId) !=
|
if (_backingFiles.containsIf(ev.file, (a, b) => a.fileId == b.fileId) !=
|
||||||
true) {
|
true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -421,39 +428,38 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _transformItems(List<Face> items) async {
|
Future<void> _transformItems(List<File> files) async {
|
||||||
final files = await PopulatePerson(_c)(widget.account, items);
|
_buildItemQueue.addJob(
|
||||||
_backingFiles = files
|
PhotoListItemBuilderArguments(
|
||||||
.sorted(compareFileDateTimeDescending)
|
widget.account,
|
||||||
.where((element) =>
|
files,
|
||||||
file_util.isSupportedFormat(element) && element.isArchived != true)
|
sorter: photoListFileDateTimeSorter,
|
||||||
.toList();
|
locale: language_util.getSelectedLocale() ??
|
||||||
setState(() {
|
PlatformDispatcher.instance.locale,
|
||||||
itemStreamListItems = _backingFiles!
|
),
|
||||||
.mapIndexed((i, f) => _ListItem(
|
buildPhotoListItem,
|
||||||
index: i,
|
(result) {
|
||||||
file: f,
|
if (mounted) {
|
||||||
account: widget.account,
|
setState(() {
|
||||||
previewUrl: api_util.getFilePreviewUrl(
|
_backingFiles = result.backingFiles;
|
||||||
widget.account,
|
itemStreamListItems = result.listItems;
|
||||||
f,
|
});
|
||||||
width: k.photoThumbSize,
|
}
|
||||||
height: k.photoThumbSize,
|
},
|
||||||
),
|
);
|
||||||
onTap: () => _onItemTap(i),
|
|
||||||
))
|
|
||||||
.toList();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _reqQuery() {
|
void _reqQuery() {
|
||||||
_bloc.add(ListFaceBlocQuery(widget.account, widget.person));
|
_bloc.add(ListFaceFileBlocQuery(widget.account, widget.person));
|
||||||
}
|
}
|
||||||
|
|
||||||
late final DiContainer _c;
|
late final DiContainer _c;
|
||||||
|
|
||||||
final ListFaceBloc _bloc = ListFaceBloc();
|
late final ListFaceFileBloc _bloc = ListFaceFileBloc(_c);
|
||||||
List<File>? _backingFiles;
|
var _backingFiles = <File>[];
|
||||||
|
|
||||||
|
final _buildItemQueue =
|
||||||
|
ComputeQueue<PhotoListItemBuilderArguments, PhotoListItemBuilderResult>();
|
||||||
|
|
||||||
var _thumbZoomLevel = 0;
|
var _thumbZoomLevel = 0;
|
||||||
int get _thumbSize => photo_list_util.getThumbSize(_thumbZoomLevel);
|
int get _thumbSize => photo_list_util.getThumbSize(_thumbZoomLevel);
|
||||||
|
@ -473,55 +479,6 @@ class _PersonBrowserState extends State<PersonBrowser>
|
||||||
static final _log = Logger("widget.person_browser._PersonBrowserState");
|
static final _log = Logger("widget.person_browser._PersonBrowserState");
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ListItem implements SelectableItem {
|
|
||||||
_ListItem({
|
|
||||||
required this.index,
|
|
||||||
required this.file,
|
|
||||||
required this.account,
|
|
||||||
required this.previewUrl,
|
|
||||||
this.onTap,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
get isTappable => onTap != null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
get isSelectable => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
get staggeredTile => const StaggeredTile.count(1, 1);
|
|
||||||
|
|
||||||
@override
|
|
||||||
operator ==(Object other) {
|
|
||||||
return other is _ListItem && file.path == other.file.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
get hashCode => file.path.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
toString() {
|
|
||||||
return "$runtimeType {"
|
|
||||||
"index: $index, "
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
buildWidget(BuildContext context) {
|
|
||||||
return PhotoListImage(
|
|
||||||
account: account,
|
|
||||||
previewUrl: previewUrl,
|
|
||||||
isGif: file.contentType == "image/gif",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final int index;
|
|
||||||
final File file;
|
|
||||||
final Account account;
|
|
||||||
final String previewUrl;
|
|
||||||
final VoidCallback? onTap;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum _SelectionMenuOption {
|
enum _SelectionMenuOption {
|
||||||
archive,
|
archive,
|
||||||
delete,
|
delete,
|
||||||
|
|
Loading…
Reference in a new issue