Move city search to a separate isolate
This commit is contained in:
parent
63cb04d4c1
commit
0645ff89f5
4 changed files with 76 additions and 65 deletions
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue