[mob][photos] Add option to sort by most recent and most relevant on magic results screen
This commit is contained in:
11
mobile/lib/events/magic_sort_change_event.dart
Normal file
11
mobile/lib/events/magic_sort_change_event.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import "package:photos/events/event.dart";
|
||||
|
||||
enum MagicSortType {
|
||||
mostRecent,
|
||||
mostRelevant,
|
||||
}
|
||||
|
||||
class MagicSortChangeEvent extends Event {
|
||||
final MagicSortType sortType;
|
||||
MagicSortChangeEvent(this.sortType);
|
||||
}
|
||||
@@ -20,6 +20,7 @@ enum GalleryType {
|
||||
quickLink,
|
||||
peopleTag,
|
||||
cluster,
|
||||
magic,
|
||||
}
|
||||
|
||||
extension GalleyTypeExtension on GalleryType {
|
||||
@@ -36,6 +37,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.uncategorized:
|
||||
case GalleryType.peopleTag:
|
||||
case GalleryType.sharedCollection:
|
||||
case GalleryType.magic:
|
||||
return true;
|
||||
|
||||
case GalleryType.hiddenSection:
|
||||
@@ -65,6 +67,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.sharedCollection:
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.cluster:
|
||||
case GalleryType.magic:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -83,6 +86,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.quickLink:
|
||||
case GalleryType.peopleTag:
|
||||
case GalleryType.cluster:
|
||||
case GalleryType.magic:
|
||||
return true;
|
||||
case GalleryType.trash:
|
||||
case GalleryType.archive:
|
||||
@@ -107,6 +111,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.quickLink:
|
||||
case GalleryType.peopleTag:
|
||||
case GalleryType.magic:
|
||||
return true;
|
||||
case GalleryType.trash:
|
||||
case GalleryType.cluster:
|
||||
@@ -126,6 +131,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.peopleTag:
|
||||
case GalleryType.cluster:
|
||||
case GalleryType.magic:
|
||||
return true;
|
||||
case GalleryType.hiddenSection:
|
||||
case GalleryType.hiddenOwnedCollection:
|
||||
@@ -155,6 +161,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.cluster:
|
||||
case GalleryType.trash:
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.magic:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -178,6 +185,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.sharedCollection:
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.cluster:
|
||||
case GalleryType.magic:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -195,6 +203,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.uncategorized:
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.quickLink:
|
||||
case GalleryType.magic:
|
||||
return true;
|
||||
|
||||
case GalleryType.hiddenSection:
|
||||
@@ -222,6 +231,7 @@ extension GalleyTypeExtension on GalleryType {
|
||||
case GalleryType.uncategorized:
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.peopleTag:
|
||||
case GalleryType.magic:
|
||||
return true;
|
||||
|
||||
case GalleryType.hiddenSection:
|
||||
@@ -353,6 +363,7 @@ extension GalleryAppBarExtn on GalleryType {
|
||||
case GalleryType.localFolder:
|
||||
case GalleryType.locationTag:
|
||||
case GalleryType.searchResults:
|
||||
case GalleryType.magic:
|
||||
return false;
|
||||
case GalleryType.cluster:
|
||||
case GalleryType.uncategorized:
|
||||
|
||||
@@ -11,6 +11,8 @@ import "package:photos/models/search/search_types.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart";
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/ui/viewer/search/result/magic_result_screen.dart";
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
import "package:shared_preferences/shared_preferences.dart";
|
||||
|
||||
class MagicCache {
|
||||
@@ -59,6 +61,15 @@ extension MagicCacheServiceExtension on MagicCache {
|
||||
ResultType.magic,
|
||||
title,
|
||||
enteFilesInMagicCache,
|
||||
onResultTap: (ctx) {
|
||||
routeToPage(
|
||||
ctx,
|
||||
MagicResultScreen(
|
||||
enteFilesInMagicCache,
|
||||
name: title,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import "package:photos/core/network/network.dart";
|
||||
import "package:photos/db/files_db.dart";
|
||||
import "package:photos/events/magic_sort_change_event.dart";
|
||||
import 'package:photos/events/subscription_purchased_event.dart';
|
||||
import "package:photos/gateways/cast_gw.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
@@ -58,11 +59,11 @@ class GalleryAppBarWidget extends StatefulWidget {
|
||||
this.type,
|
||||
this.title,
|
||||
this.selectedFiles, {
|
||||
Key? key,
|
||||
super.key,
|
||||
this.deviceCollection,
|
||||
this.collection,
|
||||
this.isFromCollectPhotos = false,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<GalleryAppBarWidget> createState() => _GalleryAppBarWidgetState();
|
||||
@@ -84,6 +85,8 @@ enum AlbumPopupAction {
|
||||
pinAlbum,
|
||||
removeLink,
|
||||
cleanUncategorized,
|
||||
sortByMostRecent,
|
||||
sortByMostRelevant
|
||||
}
|
||||
|
||||
class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
||||
@@ -293,6 +296,39 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
||||
!Configuration.instance.hasConfiguredAccount()) {
|
||||
return actions;
|
||||
}
|
||||
|
||||
if (galleryType == GalleryType.magic) {
|
||||
actions.add(
|
||||
Tooltip(
|
||||
message: "Sort",
|
||||
child: PopupMenuButton(
|
||||
icon: const Icon(Icons.sort_rounded),
|
||||
itemBuilder: (context) {
|
||||
return const [
|
||||
PopupMenuItem(
|
||||
value: AlbumPopupAction.sortByMostRecent,
|
||||
child: Text("Most recent"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: AlbumPopupAction.sortByMostRelevant,
|
||||
child: Text("Most relevant"),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (AlbumPopupAction value) {
|
||||
if (value == AlbumPopupAction.sortByMostRecent) {
|
||||
Bus.instance
|
||||
.fire(MagicSortChangeEvent(MagicSortType.mostRecent));
|
||||
} else if (value == AlbumPopupAction.sortByMostRelevant) {
|
||||
Bus.instance
|
||||
.fire(MagicSortChangeEvent(MagicSortType.mostRelevant));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final int userID = Configuration.instance.getUserID()!;
|
||||
isQuickLink = widget.collection?.isQuickLinkCollection() ?? false;
|
||||
if (galleryType.canAddFiles(widget.collection, userID)) {
|
||||
|
||||
141
mobile/lib/ui/viewer/search/result/magic_result_screen.dart
Normal file
141
mobile/lib/ui/viewer/search/result/magic_result_screen.dart
Normal file
@@ -0,0 +1,141 @@
|
||||
import "dart:async";
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import 'package:photos/events/files_updated_event.dart';
|
||||
import 'package:photos/events/local_photos_updated_event.dart';
|
||||
import "package:photos/events/magic_sort_change_event.dart";
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import 'package:photos/models/file_load_result.dart';
|
||||
import 'package:photos/models/gallery_type.dart';
|
||||
import 'package:photos/models/selected_files.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_app_bar_widget.dart';
|
||||
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
|
||||
|
||||
class MagicResultScreen extends StatefulWidget {
|
||||
final List<EnteFile> files;
|
||||
final String name;
|
||||
final bool enableGrouping;
|
||||
|
||||
static const GalleryType appBarType = GalleryType.magic;
|
||||
static const GalleryType overlayType = GalleryType.magic;
|
||||
|
||||
const MagicResultScreen(
|
||||
this.files, {
|
||||
required this.name,
|
||||
this.enableGrouping = true,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MagicResultScreen> createState() => _MagicResultScreenState();
|
||||
}
|
||||
|
||||
class _MagicResultScreenState extends State<MagicResultScreen> {
|
||||
final _selectedFiles = SelectedFiles();
|
||||
late final List<EnteFile> files;
|
||||
late final StreamSubscription<LocalPhotosUpdatedEvent> _filesUpdatedEvent;
|
||||
late final StreamSubscription<MagicSortChangeEvent> _magicSortChangeEvent;
|
||||
late bool _enableGrouping;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_enableGrouping = widget.enableGrouping;
|
||||
files = widget.files;
|
||||
_filesUpdatedEvent =
|
||||
Bus.instance.on<LocalPhotosUpdatedEvent>().listen((event) {
|
||||
if (event.type == EventType.deletedFromDevice ||
|
||||
event.type == EventType.deletedFromEverywhere ||
|
||||
event.type == EventType.deletedFromRemote ||
|
||||
event.type == EventType.hide) {
|
||||
for (var updatedFile in event.updatedFiles) {
|
||||
files.remove(updatedFile);
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
|
||||
_magicSortChangeEvent =
|
||||
Bus.instance.on<MagicSortChangeEvent>().listen((event) {
|
||||
if (event.sortType == MagicSortType.mostRelevant) {
|
||||
setState(() {
|
||||
_enableGrouping = false;
|
||||
});
|
||||
} else if (event.sortType == MagicSortType.mostRecent) {
|
||||
setState(() {
|
||||
_enableGrouping = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_filesUpdatedEvent.cancel();
|
||||
_magicSortChangeEvent.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final gallery = Gallery(
|
||||
key: ValueKey(_enableGrouping),
|
||||
asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
|
||||
final result = files
|
||||
.where(
|
||||
(file) =>
|
||||
file.creationTime! >= creationStartTime &&
|
||||
file.creationTime! <= creationEndTime,
|
||||
)
|
||||
.toList();
|
||||
return Future.value(
|
||||
FileLoadResult(
|
||||
result,
|
||||
result.length < files.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
|
||||
removalEventTypes: const {
|
||||
EventType.deletedFromRemote,
|
||||
EventType.deletedFromEverywhere,
|
||||
EventType.hide,
|
||||
},
|
||||
tagPrefix: "",
|
||||
selectedFiles: _selectedFiles,
|
||||
enableFileGrouping: _enableGrouping,
|
||||
initialFiles: [files.first],
|
||||
);
|
||||
return Scaffold(
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(50.0),
|
||||
child: GalleryAppBarWidget(
|
||||
MagicResultScreen.appBarType,
|
||||
widget.name,
|
||||
_selectedFiles,
|
||||
),
|
||||
),
|
||||
body: SelectionState(
|
||||
selectedFiles: _selectedFiles,
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: [
|
||||
AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 250),
|
||||
switchInCurve: Curves.easeInOutQuad,
|
||||
switchOutCurve: Curves.easeInOutQuad,
|
||||
child: gallery,
|
||||
),
|
||||
FileSelectionOverlayBar(
|
||||
MagicResultScreen.overlayType,
|
||||
_selectedFiles,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,6 @@ class SearchResultWidget extends StatelessWidget {
|
||||
context,
|
||||
SearchResultPage(
|
||||
searchResult,
|
||||
enableGrouping: searchResult.type() != ResultType.magic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,7 @@ import "package:photos/models/search/search_types.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/viewer/file/no_thumbnail_widget.dart";
|
||||
import "package:photos/ui/viewer/file/thumbnail_widget.dart";
|
||||
import "package:photos/ui/viewer/search/result/search_result_page.dart";
|
||||
import "package:photos/ui/viewer/search_tab/section_header.dart";
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
|
||||
class MagicSection extends StatefulWidget {
|
||||
final List<GenericSearchResult> magicSearchResults;
|
||||
@@ -149,17 +147,8 @@ class MagicRecommendation extends StatelessWidget {
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
RecentSearches().add(magicSearchResult.name());
|
||||
if (magicSearchResult.onResultTap != null) {
|
||||
magicSearchResult.onResultTap!(context);
|
||||
} else {
|
||||
routeToPage(
|
||||
context,
|
||||
SearchResultPage(
|
||||
magicSearchResult,
|
||||
enableGrouping: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
magicSearchResult.onResultTap!(context);
|
||||
},
|
||||
child: SizedBox(
|
||||
width: _width + _borderWidth * 2,
|
||||
|
||||
Reference in New Issue
Block a user