|
@@ -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() {
|
|
|
|
- return _cities;
|
|
|
|
|
|
+ Future<Map<City, List<EnteFile>>> getFilesInCity(
|
|
|
|
+ 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;
|