Move city search to a separate isolate

This commit is contained in:
vishnukvmd 2024-01-08 21:29:21 +05:30
parent 63cb04d4c1
commit 0645ff89f5
4 changed files with 76 additions and 65 deletions

View file

@ -8,6 +8,7 @@ import "package:photos/core/constants.dart";
import "package:photos/core/event_bus.dart"; import "package:photos/core/event_bus.dart";
import "package:photos/events/location_tag_updated_event.dart"; import "package:photos/events/location_tag_updated_event.dart";
import "package:photos/models/api/entity/type.dart"; import "package:photos/models/api/entity/type.dart";
import "package:photos/models/file/file.dart";
import "package:photos/models/local_entity_data.dart"; import "package:photos/models/local_entity_data.dart";
import "package:photos/models/location/location.dart"; import "package:photos/models/location/location.dart";
import 'package:photos/models/location_tag/location_tag.dart'; import 'package:photos/models/location_tag/location_tag.dart';
@ -43,8 +44,19 @@ class LocationService {
); );
} }
List<City> getAllCities() { Future<Map<City, List<EnteFile>>> getFilesInCity(
return _cities; List<EnteFile> allFiles,
String query,
) async {
final result = await _computer.compute(
getCityResults,
param: {
"query": query,
"cities": _cities,
"files": allFiles,
},
);
return result;
} }
Future<Iterable<LocalEntity<LocationTag>>> getLocationTags() { Future<Iterable<LocalEntity<LocationTag>>> getLocationTags() {
@ -81,14 +93,6 @@ class LocationService {
} }
} }
///The area bounded by the location tag becomes more elliptical with increase
///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) {
return 1 / cos(lat * (pi / 180));
}
Future<List<LocalEntity<LocationTag>>> enclosingLocationTags( Future<List<LocalEntity<LocationTag>>> enclosingLocationTags(
Location fileCoordinates, Location fileCoordinates,
) async { ) async {
@ -114,22 +118,6 @@ class LocationService {
} }
} }
bool isFileInsideLocationTag(
Location centerPoint,
Location fileCoordinates,
double radius,
) {
final a =
(radius * _scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
final b = radius / kilometersPerDegree;
final x = centerPoint.latitude! - fileCoordinates.latitude!;
final y = centerPoint.longitude! - fileCoordinates.longitude!;
if ((x * x) / (a * a) + (y * y) / (b * b) <= 1) {
return true;
}
return false;
}
/// returns [lat, lng] /// returns [lat, lng]
List<String>? convertLocationToDMS(Location centerPoint) { List<String>? convertLocationToDMS(Location centerPoint) {
if (centerPoint.latitude == null || centerPoint.longitude == null) { if (centerPoint.latitude == null || centerPoint.longitude == null) {
@ -248,6 +236,61 @@ Future<List<City>> parseCities(Map args) async {
return cities; return cities;
} }
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 matchingCities = cities.where(
(city) => city.city.toLowerCase().contains(query),
);
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);
}
}
}
if (matchingFiles.isNotEmpty) {
results[city] = matchingFiles;
}
}
return results;
}
bool isFileInsideLocationTag(
Location centerPoint,
Location fileCoordinates,
double radius,
) {
final a =
(radius * _scaleFactor(centerPoint.latitude!)) / kilometersPerDegree;
final b = radius / kilometersPerDegree;
final x = centerPoint.latitude! - fileCoordinates.latitude!;
final y = centerPoint.longitude! - fileCoordinates.longitude!;
if ((x * x) / (a * a) + (y * y) / (b * b) <= 1) {
return true;
}
return false;
}
///The area bounded by the location tag becomes more elliptical with increase
///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) {
return 1 / cos(lat * (pi / 180));
}
class City { class City {
final String city; final String city;
final String country; final String country;

View file

@ -3,7 +3,6 @@ import "dart:math";
import "package:flutter/cupertino.dart"; import "package:flutter/cupertino.dart";
import "package:intl/intl.dart"; import "package:intl/intl.dart";
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import "package:photos/core/constants.dart";
import 'package:photos/core/event_bus.dart'; import 'package:photos/core/event_bus.dart';
import 'package:photos/data/holidays.dart'; import 'package:photos/data/holidays.dart';
import 'package:photos/data/months.dart'; import 'package:photos/data/months.dart';
@ -18,7 +17,6 @@ import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart'; import 'package:photos/models/file/file.dart';
import 'package:photos/models/file/file_type.dart'; import 'package:photos/models/file/file_type.dart';
import "package:photos/models/local_entity_data.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/location_tag/location_tag.dart";
import 'package:photos/models/search/album_search_result.dart'; import 'package:photos/models/search/album_search_result.dart';
import 'package:photos/models/search/generic_search_result.dart'; import 'package:photos/models/search/generic_search_result.dart';
@ -620,7 +618,7 @@ class SearchService {
for (EnteFile file in allFiles) { for (EnteFile file in allFiles) {
if (file.hasLocation) { if (file.hasLocation) {
for (LocalEntity<LocationTag> tag in result.keys) { for (LocalEntity<LocationTag> tag in result.keys) {
if (LocationService.instance.isFileInsideLocationTag( if (isFileInsideLocationTag(
tag.item.centerPoint, tag.item.centerPoint,
file.location!, file.location!,
tag.item.radius, tag.item.radius,
@ -639,7 +637,7 @@ class SearchService {
return false; return false;
} }
for (LocalEntity<LocationTag> tag in locationTagEntities) { for (LocalEntity<LocationTag> tag in locationTagEntities) {
if (LocationService.instance.isFileInsideLocationTag( if (isFileInsideLocationTag(
tag.item.centerPoint, tag.item.centerPoint,
file.location!, file.location!,
tag.item.radius, tag.item.radius,
@ -684,36 +682,9 @@ class SearchService {
} }
Future<List<GenericSearchResult>> getCityResults(String query) async { Future<List<GenericSearchResult>> getCityResults(String query) async {
final startTime = DateTime.now().microsecondsSinceEpoch;
final List<GenericSearchResult> searchResults = [];
final cities = LocationService.instance.getAllCities();
final matchingCities = <City>[];
final queryLower = query.toLowerCase();
for (City city in cities) {
if (city.city.toLowerCase().startsWith(queryLower)) {
matchingCities.add(city);
}
}
final files = await getAllFiles(); final files = await getAllFiles();
final Map<City, List<EnteFile>> results = {}; final results = await LocationService.instance.getFilesInCity(files, query);
for (final city in matchingCities) { final List<GenericSearchResult> searchResults = [];
final List<EnteFile> matchingFiles = [];
final cityLocation = Location(latitude: city.lat, longitude: city.lng);
for (final file in files) {
if (file.hasLocation) {
if (LocationService.instance.isFileInsideLocationTag(
cityLocation,
file.location!,
defaultCityRadius,
)) {
matchingFiles.add(file);
}
}
}
if (matchingFiles.isNotEmpty) {
results[city] = matchingFiles;
}
}
for (final entry in results.entries) { for (final entry in results.entries) {
searchResults.add( searchResults.add(
GenericSearchResult( GenericSearchResult(
@ -723,9 +694,6 @@ class SearchService {
), ),
); );
} }
final endTime = DateTime.now().microsecondsSinceEpoch;
_logger
.info("Time taken " + ((endTime - startTime) / 1000).toString() + "ms");
return searchResults; return searchResults;
} }
@ -745,7 +713,7 @@ class SearchService {
for (EnteFile file in allFiles) { for (EnteFile file in allFiles) {
if (file.hasLocation) { if (file.hasLocation) {
for (LocalEntity<LocationTag> tag in tagToItemsMap.keys) { for (LocalEntity<LocationTag> tag in tagToItemsMap.keys) {
if (LocationService.instance.isFileInsideLocationTag( if (isFileInsideLocationTag(
tag.item.centerPoint, tag.item.centerPoint,
file.location!, file.location!,
tag.item.radius, tag.item.radius,

View file

@ -62,7 +62,7 @@ class _DynamicLocationGalleryWidgetState
final stopWatch = Stopwatch()..start(); final stopWatch = Stopwatch()..start();
final copyOfFiles = List<EnteFile>.from(result.files); final copyOfFiles = List<EnteFile>.from(result.files);
copyOfFiles.removeWhere((f) { copyOfFiles.removeWhere((f) {
return !LocationService.instance.isFileInsideLocationTag( return !isFileInsideLocationTag(
InheritedLocationTagData.of(context).centerPoint, InheritedLocationTagData.of(context).centerPoint,
f.location!, f.location!,
selectedRadius, selectedRadius,

View file

@ -205,7 +205,7 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
final stopWatch = Stopwatch()..start(); final stopWatch = Stopwatch()..start();
final filesInLocation = allFilesWithLocation; final filesInLocation = allFilesWithLocation;
filesInLocation.removeWhere((f) { filesInLocation.removeWhere((f) {
return !LocationService.instance.isFileInsideLocationTag( return !isFileInsideLocationTag(
centerPoint, centerPoint,
f.location!, f.location!,
selectedRadius, selectedRadius,