Skip to content
This repository has been archived by the owner on Mar 14, 2024. It is now read-only.

Commit

Permalink
Perf improvement in city locatio search + suggestions for untagged lo…
Browse files Browse the repository at this point in the history
…cation clusters (#1720)
  • Loading branch information
ua741 authored Feb 15, 2024
2 parents f90b733 + dbbb110 commit 6ff97a8
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 35 deletions.
6 changes: 4 additions & 2 deletions lib/models/search/search_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "package:photos/events/location_tag_updated_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/models/collection/collection.dart";
import "package:photos/models/collection/collection_items.dart";
import "package:photos/models/search/generic_search_result.dart";
import "package:photos/models/search/search_result.dart";
import "package:photos/models/typedefs.dart";
import "package:photos/services/collections_service.dart";
Expand All @@ -24,6 +25,7 @@ enum ResultType {
collection,
file,
location,
locationSuggestion,
month,
year,
fileType,
Expand Down Expand Up @@ -243,10 +245,10 @@ extension SectionTypeExtensions on SectionType {
}) {
switch (this) {
case SectionType.face:
return SearchService.instance.getAllLocationTags(limit);
return Future.value(List<GenericSearchResult>.empty());

case SectionType.content:
return SearchService.instance.getAllLocationTags(limit);
return Future.value(List<GenericSearchResult>.empty());

case SectionType.moment:
return SearchService.instance.getRandomMomentsSearchResults(context);
Expand Down
38 changes: 18 additions & 20 deletions lib/services/location_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -242,31 +242,29 @@ Future<List<City>> parseCities(Map args) async {

Map<City, List<EnteFile>> getCityResults(Map args) {
final query = (args["query"] as String).toLowerCase();
final cities = args["cities"] as List<City>;
final files = args["files"] as List<EnteFile>;
final List<City> cities = args["cities"] as List<City>;
final List<EnteFile> files = args["files"] as List<EnteFile>;

final matchingCities = cities.where(
(city) => city.city.toLowerCase().contains(query),
);
final matchingCities = cities
.where(
(city) => city.city.toLowerCase().contains(query),
)
.toList();

final Map<City, List<EnteFile>> results = {};
for (final city in matchingCities) {
final List<EnteFile> matchingFiles = [];
final cityLocation = Location(latitude: city.lat, longitude: city.lng);
for (final file in files) {
if (file.hasLocation) {
if (isFileInsideLocationTag(
cityLocation,
file.location!,
defaultCityRadius,
)) {
matchingFiles.add(file);
}
for (final file in files) {
if (!file.hasLocation) continue; // Skip files without location
for (final city in matchingCities) {
final cityLocation = Location(latitude: city.lat, longitude: city.lng);
if (isFileInsideLocationTag(
cityLocation,
file.location!,
defaultCityRadius,
)) {
results.putIfAbsent(city, () => []).add(file);
break; // Stop searching once a file is matched with a city
}
}
if (matchingFiles.isNotEmpty) {
results[city] = matchingFiles;
}
}
return results;
}
Expand Down
35 changes: 35 additions & 0 deletions lib/services/search_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "dart:math";
import "package:flutter/cupertino.dart";
import "package:intl/intl.dart";
import 'package:logging/logging.dart';
import "package:photos/core/constants.dart";
import 'package:photos/core/event_bus.dart';
import 'package:photos/data/holidays.dart';
import 'package:photos/data/months.dart';
Expand All @@ -17,6 +18,7 @@ import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart';
import 'package:photos/models/file/file_type.dart';
import "package:photos/models/local_entity_data.dart";
import "package:photos/models/location/location.dart";
import "package:photos/models/location_tag/location_tag.dart";
import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/models/search/generic_search_result.dart';
Expand All @@ -25,6 +27,7 @@ import 'package:photos/services/collections_service.dart';
import "package:photos/services/location_service.dart";
import 'package:photos/services/semantic_search/semantic_search_service.dart';
import "package:photos/states/location_screen_state.dart";
import "package:photos/ui/viewer/location/add_location_sheet.dart";
import "package:photos/ui/viewer/location/location_screen.dart";
import 'package:photos/utils/date_time_util.dart';
import "package:photos/utils/navigation_util.dart";
Expand Down Expand Up @@ -708,6 +711,7 @@ class SearchService {
final locationTagEntities =
(await LocationService.instance.getLocationTags());
final allFiles = await getAllFiles();
final List<EnteFile> filesWithNoLocTag = [];

for (int i = 0; i < locationTagEntities.length; i++) {
if (limit != null && i >= limit) break;
Expand All @@ -716,15 +720,20 @@ class SearchService {

for (EnteFile file in allFiles) {
if (file.hasLocation) {
bool hasLocationTag = false;
for (LocalEntity<LocationTag> tag in tagToItemsMap.keys) {
if (isFileInsideLocationTag(
tag.item.centerPoint,
file.location!,
tag.item.radius,
)) {
hasLocationTag = true;
tagToItemsMap[tag]!.add(file);
}
}
if (!hasLocationTag) {
filesWithNoLocTag.add(file);
}
}
}

Expand Down Expand Up @@ -753,6 +762,32 @@ class SearchService {
);
}
}
if (limit == null || tagSearchResults.length < limit) {
final results = await LocationService.instance
.getFilesInCity(filesWithNoLocTag, '');
final List<City> sortedByResultCount = results.keys.toList()
..sort((a, b) => results[b]!.length.compareTo(results[a]!.length));
for (final city in sortedByResultCount) {
if (results[city]!.length <= 1) continue;
// If the location tag already exists for a city, don't add it again
tagSearchResults.add(
GenericSearchResult(
ResultType.locationSuggestion,
city.city,
results[city]!,
onResultTap: (ctx) {
Navigator.of(ctx).pop();
showAddLocationSheet(
ctx,
Location(latitude: city.lat, longitude: city.lng),
name: city.city,
radius: defaultCityRadius,
);
},
),
);
}
}
return tagSearchResults;
} catch (e) {
_logger.severe("Error in getAllLocationTags", e);
Expand Down
10 changes: 8 additions & 2 deletions lib/states/location_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ import "package:photos/utils/debouncer.dart";
class LocationTagStateProvider extends StatefulWidget {
final LocalEntity<LocationTag>? locationTagEntity;
final Location? centerPoint;
final double? radius;
final Widget child;
const LocationTagStateProvider(
this.child, {
this.centerPoint,
this.locationTagEntity,
// if the locationTagEntity is null, we use the centerPoint and radius
this.radius,
super.key,
});

Expand Down Expand Up @@ -47,9 +50,12 @@ class _LocationTagStateProviderState extends State<LocationTagStateProvider> {
///If the location tag has a custom radius value, we add the custom radius
///value to the list of default radius values only for this location tag and
///keep it in the state of this widget.
_radiusValues = _getRadiusValuesOfLocTag(_locationTagEntity?.item.radius);
_radiusValues = _getRadiusValuesOfLocTag(
_locationTagEntity?.item.radius ?? widget.radius,
);

_selectedRadius = _locationTagEntity?.item.radius ?? defaultRadiusValue;
_selectedRadius =
_locationTagEntity?.item.radius ?? widget.radius ?? defaultRadiusValue;

_locTagEntityListener =
Bus.instance.on<LocationTagUpdatedEvent>().listen((event) {
Expand Down
26 changes: 20 additions & 6 deletions lib/ui/viewer/location/add_location_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@ import "package:photos/ui/viewer/location/radius_picker_widget.dart";

showAddLocationSheet(
BuildContext context,
Location coordinates,
) {
Location coordinates, {
String name = '',
double radius = defaultRadiusValue,
}) {
showBarModalBottomSheet(
context: context,
builder: (context) {
return LocationTagStateProvider(
centerPoint: coordinates,
const AddLocationSheet(),
AddLocationSheet(
radius: radius,
name: name,
),
radius: radius,
);
},
shape: const RoundedRectangleBorder(
Expand All @@ -45,7 +51,13 @@ showAddLocationSheet(
}

class AddLocationSheet extends StatefulWidget {
const AddLocationSheet({super.key});
final double radius;
final String name;
const AddLocationSheet({
super.key,
this.radius = defaultRadiusValue,
this.name = '',
});

@override
State<AddLocationSheet> createState() => _AddLocationSheetState();
Expand All @@ -61,17 +73,19 @@ class _AddLocationSheetState extends State<AddLocationSheet> {
final ValueNotifier<bool> _submitNotifer = ValueNotifier(false);

final ValueNotifier<bool> _cancelNotifier = ValueNotifier(false);
final ValueNotifier<double> _selectedRadiusNotifier =
ValueNotifier(defaultRadiusValue);
late ValueNotifier<double> _selectedRadiusNotifier;
final _focusNode = FocusNode();
final _textEditingController = TextEditingController();
final _isEmptyNotifier = ValueNotifier(true);
Widget? _keyboardTopButtons;

@override
void initState() {
_textEditingController.text = widget.name;
_focusNode.addListener(_focusNodeListener);
_selectedRadiusNotifier = ValueNotifier(widget.radius);
_selectedRadiusNotifier.addListener(_selectedRadiusListener);

super.initState();
}

Expand Down
2 changes: 2 additions & 0 deletions lib/ui/viewer/search/result/search_result_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ class SearchResultWidget extends StatelessWidget {
return "Day";
case ResultType.location:
return "Location";
case ResultType.locationSuggestion:
return "Add Location";
case ResultType.fileType:
return "Type";
case ResultType.fileExtension:
Expand Down
13 changes: 10 additions & 3 deletions lib/ui/viewer/search/result/search_section_all_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "dart:async";
import "package:flutter/material.dart";
import "package:flutter_animate/flutter_animate.dart";
import "package:photos/events/event.dart";
import "package:photos/extensions/list.dart";
import "package:photos/models/search/album_search_result.dart";
import "package:photos/models/search/generic_search_result.dart";
import "package:photos/models/search/recent_searches.dart";
Expand Down Expand Up @@ -83,8 +84,6 @@ class _SearchSectionAllPageState extends State<SearchSectionAllPage> {
builder: (context, snapshot) {
if (snapshot.hasData) {
final sectionResults = snapshot.data!;
sectionResults
.sort((a, b) => a.name().compareTo(b.name()));
return Text(sectionResults.length.toString())
.animate()
.fadeIn(
Expand All @@ -109,7 +108,15 @@ class _SearchSectionAllPageState extends State<SearchSectionAllPage> {
future: sectionData,
builder: (context, snapshot) {
if (snapshot.hasData) {
final sectionResults = snapshot.data!;
List<SearchResult> sectionResults = snapshot.data!;
sectionResults.sort((a, b) => a.name().compareTo(b.name()));
if (widget.sectionType == SectionType.location) {
final result = sectionResults.splitMatch(
(e) => e.type() == ResultType.location,
);
sectionResults = result.matched;
sectionResults.addAll(result.unmatched);
}
return ListView.separated(
itemBuilder: (context, index) {
if (sectionResults.length == index) {
Expand Down
5 changes: 4 additions & 1 deletion lib/ui/viewer/search/result/searchable_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ class SearchableItemWidget extends StatelessWidget {
children: [
Text(
searchResult.name(),
style: textTheme.body,
style: searchResult.type() ==
ResultType.locationSuggestion
? textTheme.bodyFaint
: textTheme.body,
overflow: TextOverflow.ellipsis,
),
const SizedBox(
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description: ente photos application
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html

version: 0.8.58+578
version: 0.8.59+579

environment:
sdk: ">=3.0.0 <4.0.0"
Expand Down

0 comments on commit 6ff97a8

Please sign in to comment.