[mob][photos] Make filters useable (make them appear on appbar) in named people page

This commit is contained in:
ashilkn 2024-10-18 09:50:10 +05:30
parent fd9269ccdf
commit c8990d8f40
7 changed files with 210 additions and 116 deletions

View File

@ -951,6 +951,23 @@ class SearchService {
PeoplePage( PeoplePage(
tagPrefix: "${ResultType.faces.toString()}_${p.data.name}", tagPrefix: "${ResultType.faces.toString()}_${p.data.name}",
person: p, person: p,
searchResult: GenericSearchResult(
ResultType.faces,
p.data.name,
files,
params: {
kPersonParamID: personID,
kFileID: files.first.uploadedFileID,
},
hierarchicalSearchFilter: FaceFilter(
personId: p.remoteID,
clusterId: null,
faceName: p.data.name,
faceFile: files.first,
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(files),
),
),
), ),
); );
}, },

View File

@ -119,6 +119,7 @@ class _FaceWidgetState extends State<FaceWidget> {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => PeoplePage( builder: (context) => PeoplePage(
person: widget.person!, person: widget.person!,
searchResult: null,
), ),
), ),
); );

View File

@ -8,6 +8,7 @@ class InheritedSearchFilterData extends InheritedWidget {
required super.child, required super.child,
}); });
/// Pass null if gallery doesn't need hierarchical search
final SearchFilterDataProvider? searchFilterDataProvider; final SearchFilterDataProvider? searchFilterDataProvider;
bool get isHierarchicalSearchable => searchFilterDataProvider != null; bool get isHierarchicalSearchable => searchFilterDataProvider != null;

View File

@ -200,13 +200,22 @@ class _ClusterPageState extends State<ClusterPage> {
// ignore: unawaited_futures // ignore: unawaited_futures
routeToPage( routeToPage(
context, context,
PeoplePage(person: result.$1), PeoplePage(
person: result.$1,
searchResult: null,
),
); );
} else if (result != null && } else if (result != null &&
result is PersonEntity) { result is PersonEntity) {
Navigator.pop(context); Navigator.pop(context);
// ignore: unawaited_futures // ignore: unawaited_futures
routeToPage(context, PeoplePage(person: result)); routeToPage(
context,
PeoplePage(
person: result,
searchResult: null,
),
);
} }
} else { } else {
showShortToast(context, "No personID or clusterID"); showShortToast(context, "No personID or clusterID");

View File

@ -15,6 +15,8 @@ import 'package:photos/models/selected_files.dart';
import 'package:photos/services/collections_service.dart'; import 'package:photos/services/collections_service.dart';
import "package:photos/services/machine_learning/face_ml/person/person_service.dart"; import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
import 'package:photos/ui/actions/collection/collection_sharing_actions.dart'; import 'package:photos/ui/actions/collection/collection_sharing_actions.dart';
import "package:photos/ui/viewer/hierarchicial_search/applied_filters.dart";
import "package:photos/ui/viewer/hierarchicial_search/recommended_filters.dart";
import "package:photos/ui/viewer/people/add_person_action_sheet.dart"; import "package:photos/ui/viewer/people/add_person_action_sheet.dart";
import "package:photos/ui/viewer/people/people_page.dart"; import "package:photos/ui/viewer/people/people_page.dart";
import "package:photos/ui/viewer/people/person_cluster_suggestion.dart"; import "package:photos/ui/viewer/people/person_cluster_suggestion.dart";
@ -34,8 +36,8 @@ class PeopleAppBar extends StatefulWidget {
this.title, this.title,
this.selectedFiles, this.selectedFiles,
this.person, { this.person, {
Key? key, super.key,
}) : super(key: key); });
@override @override
State<PeopleAppBar> createState() => _AppBarWidgetState(); State<PeopleAppBar> createState() => _AppBarWidgetState();
@ -87,12 +89,39 @@ class _AppBarWidgetState extends State<PeopleAppBar> {
return AppBar( return AppBar(
elevation: 0, elevation: 0,
centerTitle: false, centerTitle: false,
title: Text( // title: Text(
_appBarTitle!, // _appBarTitle!,
style: // style:
Theme.of(context).textTheme.headlineSmall!.copyWith(fontSize: 16), // Theme.of(context).textTheme.headlineSmall!.copyWith(fontSize: 16),
maxLines: 2, // maxLines: 2,
overflow: TextOverflow.ellipsis, // overflow: TextOverflow.ellipsis,
// ),
title: Expanded(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Text(
_appBarTitle!,
style: Theme.of(context)
.textTheme
.headlineSmall!
.copyWith(fontSize: 16),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(
width: 200,
height: 50,
child: AppliedFilters(),
),
],
),
),
bottom: const PreferredSize(
preferredSize: Size.fromHeight(0),
child: Flexible(child: RecommendedFilters()),
), ),
actions: _getDefaultActions(context), actions: _getDefaultActions(context),
); );
@ -294,10 +323,22 @@ class _AppBarWidgetState extends State<PeopleAppBar> {
Navigator.pop(context); Navigator.pop(context);
if (result != null && result is (PersonEntity, EnteFile)) { if (result != null && result is (PersonEntity, EnteFile)) {
// ignore: unawaited_futures // ignore: unawaited_futures
routeToPage(context, PeoplePage(person: result.$1)); routeToPage(
context,
PeoplePage(
person: result.$1,
searchResult: null,
),
);
} else if (result != null && result is PersonEntity) { } else if (result != null && result is PersonEntity) {
// ignore: unawaited_futures // ignore: unawaited_futures
routeToPage(context, PeoplePage(person: result)); routeToPage(
context,
PeoplePage(
person: result,
searchResult: null,
),
);
} }
} }
} }

View File

@ -11,6 +11,7 @@ import 'package:photos/models/file/file.dart';
import 'package:photos/models/file_load_result.dart'; import 'package:photos/models/file_load_result.dart';
import 'package:photos/models/gallery_type.dart'; import 'package:photos/models/gallery_type.dart';
import "package:photos/models/ml/face/person.dart"; import "package:photos/models/ml/face/person.dart";
import "package:photos/models/search/search_result.dart";
import 'package:photos/models/selected_files.dart'; import 'package:photos/models/selected_files.dart';
import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart"; import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart";
import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart"; import "package:photos/services/machine_learning/face_ml/feedback/cluster_feedback.dart";
@ -18,6 +19,8 @@ import "package:photos/services/search_service.dart";
import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart'; import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart'; import 'package:photos/ui/viewer/gallery/gallery.dart';
import "package:photos/ui/viewer/gallery/state/gallery_files_inherited_widget.dart"; import "package:photos/ui/viewer/gallery/state/gallery_files_inherited_widget.dart";
import "package:photos/ui/viewer/gallery/state/inherited_search_filter_data.dart";
import "package:photos/ui/viewer/gallery/state/search_filter_data_provider.dart";
import "package:photos/ui/viewer/gallery/state/selection_state.dart"; import "package:photos/ui/viewer/gallery/state/selection_state.dart";
import "package:photos/ui/viewer/people/people_app_bar.dart"; import "package:photos/ui/viewer/people/people_app_bar.dart";
import "package:photos/ui/viewer/people/people_banner.dart"; import "package:photos/ui/viewer/people/people_banner.dart";
@ -26,6 +29,7 @@ import "package:photos/ui/viewer/people/person_cluster_suggestion.dart";
class PeoplePage extends StatefulWidget { class PeoplePage extends StatefulWidget {
final String tagPrefix; final String tagPrefix;
final PersonEntity person; final PersonEntity person;
final SearchResult? searchResult;
static const GalleryType appBarType = GalleryType.peopleTag; static const GalleryType appBarType = GalleryType.peopleTag;
static const GalleryType overlayType = GalleryType.peopleTag; static const GalleryType overlayType = GalleryType.peopleTag;
@ -33,8 +37,9 @@ class PeoplePage extends StatefulWidget {
const PeoplePage({ const PeoplePage({
this.tagPrefix = "", this.tagPrefix = "",
required this.person, required this.person,
Key? key, required this.searchResult,
}) : super(key: key); super.key,
});
@override @override
State<PeoplePage> createState() => _PeoplePageState(); State<PeoplePage> createState() => _PeoplePageState();
@ -112,111 +117,119 @@ class _PeoplePageState extends State<PeoplePage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
_logger.info("Building for ${widget.person.data.name}"); _logger.info("Building for ${widget.person.data.name}");
return GalleryFilesState( return GalleryFilesState(
child: Scaffold( child: InheritedSearchFilterData(
appBar: PreferredSize( searchFilterDataProvider: widget.searchResult != null
preferredSize: const Size.fromHeight(50.0), ? SearchFilterDataProvider(
child: PeopleAppBar( initialGalleryFilter:
GalleryType.peopleTag, widget.searchResult!.getHierarchicalSearchFilter(),
widget.person.data.name, )
_selectedFiles, : null,
widget.person, child: Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(50.0),
child: PeopleAppBar(
GalleryType.peopleTag,
widget.person.data.name,
_selectedFiles,
widget.person,
),
), ),
), body: FutureBuilder<List<EnteFile>>(
body: FutureBuilder<List<EnteFile>>( future: filesFuture,
future: filesFuture, builder: (context, snapshot) {
builder: (context, snapshot) { if (snapshot.hasData) {
if (snapshot.hasData) { final personFiles = snapshot.data as List<EnteFile>;
final personFiles = snapshot.data as List<EnteFile>; return Column(
return Column( children: [
children: [ Expanded(
Expanded( child: SelectionState(
child: SelectionState( selectedFiles: _selectedFiles,
selectedFiles: _selectedFiles, child: Stack(
child: Stack( alignment: Alignment.bottomCenter,
alignment: Alignment.bottomCenter, children: [
children: [ Gallery(
Gallery( asyncLoader: (
asyncLoader: ( creationStartTime,
creationStartTime, creationEndTime, {
creationEndTime, { limit,
limit, asc,
asc, }) async {
}) async { final result = await loadPersonFiles();
final result = await loadPersonFiles(); return Future.value(
return Future.value( FileLoadResult(
FileLoadResult( result,
result, false,
false, ),
), );
); },
}, reloadEvent:
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
Bus.instance.on<LocalPhotosUpdatedEvent>(), forceReloadEvents: [
forceReloadEvents: [ Bus.instance.on<PeopleChangedEvent>(),
Bus.instance.on<PeopleChangedEvent>(), ],
], removalEventTypes: const {
removalEventTypes: const { EventType.deletedFromRemote,
EventType.deletedFromRemote, EventType.deletedFromEverywhere,
EventType.deletedFromEverywhere, EventType.hide,
EventType.hide, },
}, tagPrefix: widget.tagPrefix + widget.tagPrefix,
tagPrefix: widget.tagPrefix + widget.tagPrefix, selectedFiles: _selectedFiles,
selectedFiles: _selectedFiles, initialFiles: personFiles.isNotEmpty
initialFiles: personFiles.isNotEmpty ? [personFiles.first]
? [personFiles.first] : [],
: [], ),
), FileSelectionOverlayBar(
FileSelectionOverlayBar( PeoplePage.overlayType,
PeoplePage.overlayType, _selectedFiles,
_selectedFiles, person: widget.person,
person: widget.person, ),
), ],
], ),
), ),
), ),
), showSuggestionBanner
showSuggestionBanner ? Dismissible(
? Dismissible( key: const Key("suggestionBanner"),
key: const Key("suggestionBanner"), direction: DismissDirection.horizontal,
direction: DismissDirection.horizontal, onDismissed: (direction) {
onDismissed: (direction) { setState(() {
setState(() { userDismissedSuggestionBanner = true;
userDismissedSuggestionBanner = true; });
}); },
}, child: PeopleBanner(
child: PeopleBanner( type: PeopleBannerType.suggestion,
type: PeopleBannerType.suggestion, startIcon: Icons.face_retouching_natural,
startIcon: Icons.face_retouching_natural, actionIcon: Icons.search_outlined,
actionIcon: Icons.search_outlined, text: "Review suggestions",
text: "Review suggestions", subText: "Improve the results",
subText: "Improve the results", onTap: () async {
onTap: () async { unawaited(
unawaited( Navigator.of(context).push(
Navigator.of(context).push( MaterialPageRoute(
MaterialPageRoute( builder: (context) =>
builder: (context) => PersonReviewClusterSuggestion(
PersonReviewClusterSuggestion( widget.person,
widget.person, ),
), ),
), ),
), );
); },
}, ),
), )
) : const SizedBox.shrink(),
: const SizedBox.shrink(), ],
], );
); } else if (snapshot.hasError) {
} else if (snapshot.hasError) { log("Error: ${snapshot.error} ${snapshot.stackTrace}}");
log("Error: ${snapshot.error} ${snapshot.stackTrace}}"); //Need to show an error on the UI here
//Need to show an error on the UI here return const SizedBox.shrink();
return const SizedBox.shrink(); } else {
} else { return const Center(
return const Center( child: CircularProgressIndicator(),
child: CircularProgressIndicator(), );
); }
} },
}, ),
), ),
), ),
); );

View File

@ -265,10 +265,22 @@ class SearchExample extends StatelessWidget {
if (result != null && if (result != null &&
result is (PersonEntity, EnteFile)) { result is (PersonEntity, EnteFile)) {
// ignore: unawaited_futures // ignore: unawaited_futures
routeToPage(context, PeoplePage(person: result.$1)); routeToPage(
context,
PeoplePage(
person: result.$1,
searchResult: null,
),
);
} else if (result != null && result is PersonEntity) { } else if (result != null && result is PersonEntity) {
// ignore: unawaited_futures // ignore: unawaited_futures
routeToPage(context, PeoplePage(person: result)); routeToPage(
context,
PeoplePage(
person: result,
searchResult: null,
),
);
} }
}, },
child: Padding( child: Padding(