[mob][photos] Attach a SearchResults's corresponding HierarchicalSearchFilter to it when ever a instance is created

This commit is contained in:
ashilkn 2024-10-11 20:57:45 +05:30
parent 4450018491
commit 171e96976a
12 changed files with 282 additions and 17 deletions

View File

@ -39,4 +39,13 @@ class AlbumSearchResult extends SearchResult {
occurrence: kMostRelevantFilter,
);
}
@override
HierarchicalSearchFilter getHierarchicalSearchResult() {
return AlbumFilter(
collectionID: collectionWithThumbnail.collection.id,
albumName: collectionWithThumbnail.collection.displayName,
occurrence: kMostRelevantFilter,
);
}
}

View File

@ -33,4 +33,9 @@ class FileSearchResult extends SearchResult {
HierarchicalSearchFilter toHierarchicalSearchFilter() {
throw UnimplementedError();
}
@override
HierarchicalSearchFilter getHierarchicalSearchResult() {
throw UnimplementedError();
}
}

View File

@ -10,11 +10,13 @@ class GenericSearchResult extends SearchResult {
final ResultType _type;
final Function(BuildContext context)? onResultTap;
final Map<String, dynamic> params;
final HierarchicalSearchFilter hierarchicalSearchFilter;
GenericSearchResult(
this._type,
this._name,
this._files, {
required this.hierarchicalSearchFilter,
this.onResultTap,
this.params = const {},
});
@ -43,4 +45,9 @@ class GenericSearchResult extends SearchResult {
HierarchicalSearchFilter toHierarchicalSearchFilter() {
return _type.toHierarchicalSearchFilter(this);
}
@override
getHierarchicalSearchResult() {
return hierarchicalSearchFilter;
}
}

View File

@ -11,6 +11,7 @@ class ContactsFilter extends HierarchicalSearchFilter {
ContactsFilter({
required this.user,
required this.occurrence,
super.matchedUploadedIDs,
});
@override

View File

@ -19,6 +19,7 @@ class FaceFilter extends HierarchicalSearchFilter {
required this.faceName,
required this.faceFile,
required this.occurrence,
super.matchedUploadedIDs,
}) : assert(
personId != null || clusterId != null,
"personId or clusterId must be provided",

View File

@ -18,6 +18,10 @@ abstract class HierarchicalSearchFilter {
String name();
IconData? icon();
/// Will be [kmostRelevantFilter] if the filter is a Top-levl filter. For
/// example, when searching for an album 'A' and opening it, when
/// hierarchical search starts, the album 'A' will be the top level filter.
int relevance();
bool isMatch(EnteFile file);
Set<int> getMatchedUploadedIDs();

View File

@ -12,6 +12,7 @@ class LocationFilter extends HierarchicalSearchFilter {
LocationFilter({
required this.locationTag,
required this.occurrence,
super.matchedUploadedIDs,
});
@override

View File

@ -0,0 +1,48 @@
import "package:flutter/widgets.dart";
import "package:photos/models/file/file.dart";
import "package:photos/models/search/hierarchical/hierarchical_search_filter.dart";
import "package:photos/models/search/search_types.dart";
class MagicFilter extends HierarchicalSearchFilter {
@override
Set<int> getMatchedUploadedIDs() {
// TODO: implement getMatchedUploadedIDs
throw UnimplementedError();
}
@override
IconData? icon() {
// TODO: implement icon
throw UnimplementedError();
}
@override
bool isMatch(EnteFile file) {
// TODO: implement isMatch
throw UnimplementedError();
}
@override
bool isSameFilter(HierarchicalSearchFilter other) {
// TODO: implement isSameFilter
throw UnimplementedError();
}
@override
String name() {
// TODO: implement name
throw UnimplementedError();
}
@override
int relevance() {
// TODO: implement relevance
throw UnimplementedError();
}
@override
ResultType resultType() {
// TODO: implement resultType
throw UnimplementedError();
}
}

View File

@ -15,5 +15,7 @@ abstract class SearchResult {
List<EnteFile> resultFiles();
HierarchicalSearchFilter getHierarchicalSearchResult();
HierarchicalSearchFilter toHierarchicalSearchFilter();
}

View File

@ -94,7 +94,7 @@ class LocationService {
try {
final a =
(radius * _scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
(radius * scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
final b = radius / kilometersPerDegree;
final locationTag = LocationTag(
name: location,
@ -181,7 +181,7 @@ class LocationService {
return;
}
final a =
(radius * _scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
(radius * scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
final b = radius / kilometersPerDegree;
final updatedLoationTag = locationTagEntity.item.copyWith(
centerPoint: centerPoint,
@ -321,8 +321,7 @@ bool isFileInsideLocationTag(
Location fileCoordinates,
double radius,
) {
final a =
(radius * _scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
final a = (radius * scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
final b = radius / kilometersPerDegree;
final x = centerPoint.latitude! - fileCoordinates.latitude!;
final y = centerPoint.longitude! - fileCoordinates.longitude!;
@ -336,7 +335,7 @@ bool isFileInsideLocationTag(
///in the magnitude of the latitude on the caritesian plane. When latitude is
///0 degrees, the ellipse is a circle with a = b = r. When latitude incrases,
///the major axis (a) has to be scaled by the secant of the latitude.
double _scaleFactor(double lat) {
double scaleFactor(double lat) {
return 1 / cos(lat * (pi / 180));
}

View File

@ -16,6 +16,7 @@ import "package:photos/models/file/extensions/file_props.dart";
import "package:photos/models/file/file.dart";
import "package:photos/models/ml/discover/prompt.dart";
import "package:photos/models/search/generic_search_result.dart";
import "package:photos/models/search/hierarchical/magic_filter.dart";
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";
@ -140,10 +141,12 @@ GenericSearchResult? toGenericSearchResult(
ResultType.magic,
title,
enteFilesInMagicCache,
hierarchicalSearchFilter: MagicFilter(),
).heroTag(),
),
);
},
hierarchicalSearchFilter: MagicFilter(),
);
}

View File

@ -24,6 +24,12 @@ import "package:photos/models/location_tag/location_tag.dart";
import "package:photos/models/ml/face/person.dart";
import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/models/search/generic_search_result.dart';
import "package:photos/models/search/hierarchical/contacts_filter.dart";
import "package:photos/models/search/hierarchical/face_filter.dart";
import "package:photos/models/search/hierarchical/hierarchical_search_filter.dart";
import "package:photos/models/search/hierarchical/location_filter.dart";
import "package:photos/models/search/hierarchical/magic_filter.dart";
import "package:photos/models/search/hierarchical/top_level_generic_filter.dart";
import "package:photos/models/search/search_constants.dart";
import "package:photos/models/search/search_types.dart";
import "package:photos/service_locator.dart";
@ -40,6 +46,7 @@ import "package:photos/ui/viewer/people/cluster_page.dart";
import "package:photos/ui/viewer/people/people_page.dart";
import "package:photos/ui/viewer/search/result/magic_result_screen.dart";
import 'package:photos/utils/date_time_util.dart';
import "package:photos/utils/file_util.dart";
import "package:photos/utils/navigation_util.dart";
import 'package:tuple/tuple.dart';
@ -169,6 +176,12 @@ class SearchService {
ResultType.year,
yearData.year,
filesInYear,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: yearData.year,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.year,
matchedUploadedIDs: filesToUploadedFileIDs(filesInYear),
),
),
);
}
@ -223,6 +236,12 @@ class SearchService {
ResultType.year,
yearData.year,
filesInYear,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: yearData.year,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.year,
matchedUploadedIDs: filesToUploadedFileIDs(filesInYear),
),
);
}
}
@ -248,6 +267,12 @@ class SearchService {
ResultType.month,
month.name,
matchedFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: month.name,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.month,
matchedUploadedIDs: filesToUploadedFileIDs(matchedFiles),
),
),
);
}
@ -271,6 +296,12 @@ class SearchService {
ResultType.month,
month.name,
matchedFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: month.name,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.month,
matchedUploadedIDs: filesToUploadedFileIDs(matchedFiles),
),
);
}
}
@ -297,7 +328,17 @@ class SearchService {
);
if (matchedFiles.isNotEmpty) {
searchResults.add(
GenericSearchResult(ResultType.event, holiday.name, matchedFiles),
GenericSearchResult(
ResultType.event,
holiday.name,
matchedFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: holiday.name,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.event,
matchedUploadedIDs: filesToUploadedFileIDs(matchedFiles),
),
),
);
}
}
@ -321,6 +362,12 @@ class SearchService {
ResultType.event,
holiday.name,
matchedFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: holiday.name,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.event,
matchedUploadedIDs: filesToUploadedFileIDs(matchedFiles),
),
);
}
}
@ -344,6 +391,12 @@ class SearchService {
ResultType.fileType,
fileTypeString,
matchedFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: fileTypeString,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.fileType,
matchedUploadedIDs: filesToUploadedFileIDs(matchedFiles),
),
),
);
}
@ -383,11 +436,18 @@ class SearchService {
}
fileTypesAndMatchingFiles.forEach((key, value) {
final name = getHumanReadableString(context, key);
searchResults.add(
GenericSearchResult(
ResultType.fileType,
getHumanReadableString(context, key),
name,
value,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: name,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.fileType,
matchedUploadedIDs: filesToUploadedFileIDs(value),
),
),
);
});
@ -398,6 +458,12 @@ class SearchService {
ResultType.fileExtension,
key + "s",
value,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: key + "s",
occurrence: kMostRelevantFilter,
filterResultType: ResultType.fileExtension,
matchedUploadedIDs: filesToUploadedFileIDs(value),
),
),
);
});
@ -545,8 +611,19 @@ class SearchService {
}
relevantDescAndFiles.forEach((key, value) {
final listOfFiles = value.toList();
searchResults.add(
GenericSearchResult(ResultType.fileCaption, key, value.toList()),
GenericSearchResult(
ResultType.fileCaption,
key,
listOfFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: key,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.fileCaption,
matchedUploadedIDs: filesToUploadedFileIDs(listOfFiles),
),
),
);
});
if (limit != null) {
@ -585,6 +662,12 @@ class SearchService {
ResultType.fileCaption,
query,
captionMatch,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: query,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.fileCaption,
matchedUploadedIDs: filesToUploadedFileIDs(captionMatch),
),
),
);
}
@ -594,6 +677,12 @@ class SearchService {
ResultType.file,
query,
displayNameMatch,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: query,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.file,
matchedUploadedIDs: filesToUploadedFileIDs(displayNameMatch),
),
),
);
}
@ -627,6 +716,12 @@ class SearchService {
ResultType.fileExtension,
entry.key.toUpperCase(),
entry.value,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: entry.key.toUpperCase(),
occurrence: kMostRelevantFilter,
filterResultType: ResultType.fileExtension,
matchedUploadedIDs: filesToUploadedFileIDs(entry.value),
),
),
);
}
@ -686,6 +781,12 @@ class SearchService {
ResultType.fileType,
"No Location Tag",
noLocationTagFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: "No Location Tag",
occurrence: kMostRelevantFilter,
filterResultType: ResultType.fileType,
matchedUploadedIDs: filesToUploadedFileIDs(noLocationTagFiles),
),
),
);
}
@ -710,6 +811,11 @@ class SearchService {
),
);
},
hierarchicalSearchFilter: LocationFilter(
locationTag: entry.key.item,
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(entry.value),
),
),
);
}
@ -727,11 +833,25 @@ class SearchService {
for (final city in sortedByResultCount) {
// If the location tag already exists for a city, don't add it again
if (!locationTagNames.contains(city.city)) {
final a =
(defaultCityRadius * scaleFactor(city.lat)) / kilometersPerDegree;
const b = defaultCityRadius / kilometersPerDegree;
searchResults.add(
GenericSearchResult(
ResultType.location,
city.city,
results[city]!,
hierarchicalSearchFilter: LocationFilter(
locationTag: LocationTag(
name: city.city,
radius: defaultCityRadius,
centerPoint: Location(latitude: city.lat, longitude: city.lng),
aSquare: a * a,
bSquare: b * b,
),
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(results[city]!),
),
),
);
}
@ -834,6 +954,14 @@ class SearchService {
),
);
},
hierarchicalSearchFilter: FaceFilter(
personId: p.remoteID,
clusterId: null,
faceName: p.data.name,
faceFile: files.first,
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(files),
),
),
);
}
@ -880,6 +1008,14 @@ class SearchService {
),
);
},
hierarchicalSearchFilter: FaceFilter(
personId: null,
clusterId: clusterId,
faceName: clusterName,
faceFile: files.first,
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(files),
),
),
);
}
@ -950,6 +1086,11 @@ class SearchService {
),
);
},
hierarchicalSearchFilter: LocationFilter(
locationTag: entry.key.item,
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(entry.value),
),
),
);
}
@ -961,6 +1102,9 @@ class SearchService {
..sort((a, b) => results[b]!.length.compareTo(results[a]!.length));
for (final city in sortedByResultCount) {
if (results[city]!.length <= 1) continue;
final a =
(defaultCityRadius * scaleFactor(city.lat)) / kilometersPerDegree;
const b = defaultCityRadius / kilometersPerDegree;
tagSearchResults.add(
GenericSearchResult(
ResultType.locationSuggestion,
@ -974,6 +1118,18 @@ class SearchService {
radius: defaultCityRadius,
);
},
hierarchicalSearchFilter: LocationFilter(
locationTag: LocationTag(
name: city.city,
radius: defaultCityRadius,
centerPoint:
Location(latitude: city.lat, longitude: city.lng),
aSquare: a * a,
bSquare: b * b,
),
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(results[city]!),
),
),
);
}
@ -1003,11 +1159,18 @@ class SearchService {
order: 'DESC',
);
if (matchedFiles.isNotEmpty) {
final name = '$day ${potentialDate.item2.name} ${year ?? ''}';
searchResults.add(
GenericSearchResult(
ResultType.event,
'$day ${potentialDate.item2.name} ${year ?? ''}',
name,
matchedFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: name,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.event,
matchedUploadedIDs: filesToUploadedFileIDs(matchedFiles),
),
),
);
}
@ -1042,11 +1205,16 @@ class SearchService {
files,
name: query,
enableGrouping: false,
heroTag: GenericSearchResult(ResultType.magic, query, files)
.heroTag(),
heroTag: GenericSearchResult(
ResultType.magic,
query,
files,
hierarchicalSearchFilter: MagicFilter(),
).heroTag(),
),
);
},
hierarchicalSearchFilter: MagicFilter(),
),
);
}
@ -1087,12 +1255,18 @@ class SearchService {
order: 'DESC',
);
final name = DateFormat.yMMMd(Localizations.localeOf(context).languageCode)
.format(originalDateTime.toLocal());
return GenericSearchResult(
ResultType.event,
DateFormat.yMMMd(Localizations.localeOf(context).languageCode).format(
DateTime.fromMicrosecondsSinceEpoch(creationTime).toLocal(),
),
name,
matchedFiles,
hierarchicalSearchFilter: TopLevelGenericFilter(
filterName: name,
occurrence: kMostRelevantFilter,
filterResultType: ResultType.event,
matchedUploadedIDs: filesToUploadedFileIDs(matchedFiles),
),
);
}
@ -1125,6 +1299,11 @@ class SearchService {
ResultType.shared,
key.name != null && key.name!.isNotEmpty ? key.name! : key.email,
value,
hierarchicalSearchFilter: ContactsFilter(
user: key,
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(value),
),
),
);
});
@ -1155,13 +1334,19 @@ class SearchService {
}
peopleToSharedFiles.forEach((key, value) {
final name = key.name != null && key.name!.isNotEmpty
? key.name!
: key.email.split("@")[0];
searchResults.add(
GenericSearchResult(
ResultType.shared,
key.name != null && key.name!.isNotEmpty
? key.name!
: key.email.split("@")[0],
name,
value,
hierarchicalSearchFilter: ContactsFilter(
user: key,
occurrence: kMostRelevantFilter,
matchedUploadedIDs: filesToUploadedFileIDs(value),
),
),
);
});