(possible) optimization when locating entries
This commit is contained in:
parent
80a591ca82
commit
de3528baab
1 changed files with 21 additions and 2 deletions
|
@ -4,6 +4,7 @@ import 'package:aves/model/metadata_db.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
mixin LocationMixin on SourceBase {
|
mixin LocationMixin on SourceBase {
|
||||||
static const _commitCountThreshold = 50;
|
static const _commitCountThreshold = 50;
|
||||||
|
@ -24,16 +25,34 @@ mixin LocationMixin on SourceBase {
|
||||||
|
|
||||||
Future<void> locateEntries() async {
|
Future<void> locateEntries() async {
|
||||||
// final stopwatch = Stopwatch()..start();
|
// final stopwatch = Stopwatch()..start();
|
||||||
final todo = rawEntries.where((entry) => entry.hasGps && !entry.isLocated).toList();
|
final byLocated = groupBy<ImageEntry, bool>(rawEntries.where((entry) => entry.hasGps), (entry) => entry.isLocated);
|
||||||
|
final todo = byLocated[false] ?? [];
|
||||||
if (todo.isEmpty) return;
|
if (todo.isEmpty) return;
|
||||||
|
|
||||||
|
// cache known locations to avoid querying the geocoder unless necessary
|
||||||
|
// measuring the time it takes to process ~3000 coordinates (with ~10% of duplicates)
|
||||||
|
// does not clearly show whether it is an actual optimization,
|
||||||
|
// as results vary wildly (durations in "min:sec"):
|
||||||
|
// - with no cache: 06:17, 08:36, 08:34
|
||||||
|
// - with cache: 08:28, 05:42, 08:03, 05:58
|
||||||
|
// anyway, in theory it should help!
|
||||||
|
final knownLocations = <Tuple2<double, double>, AddressDetails>{};
|
||||||
|
byLocated[true]?.forEach((entry) => knownLocations.putIfAbsent(entry.latLng, () => entry.addressDetails));
|
||||||
|
|
||||||
var progressDone = 0;
|
var progressDone = 0;
|
||||||
final progressTotal = todo.length;
|
final progressTotal = todo.length;
|
||||||
setProgress(done: progressDone, total: progressTotal);
|
setProgress(done: progressDone, total: progressTotal);
|
||||||
|
|
||||||
final newAddresses = <AddressDetails>[];
|
final newAddresses = <AddressDetails>[];
|
||||||
await Future.forEach<ImageEntry>(todo, (entry) async {
|
await Future.forEach<ImageEntry>(todo, (entry) async {
|
||||||
await entry.locate(background: true);
|
if (knownLocations.containsKey(entry.latLng)) {
|
||||||
|
entry.addressDetails = knownLocations[entry.latLng]?.copyWith(contentId: entry.contentId);
|
||||||
|
} else {
|
||||||
|
await entry.locate(background: true);
|
||||||
|
// it is intended to insert `null` if the geocoder failed,
|
||||||
|
// so that we skip geocoding of following entries with the same coordinates
|
||||||
|
knownLocations[entry.latLng] = entry.addressDetails;
|
||||||
|
}
|
||||||
if (entry.isLocated) {
|
if (entry.isLocated) {
|
||||||
newAddresses.add(entry.addressDetails);
|
newAddresses.add(entry.addressDetails);
|
||||||
if (newAddresses.length >= _commitCountThreshold) {
|
if (newAddresses.length >= _commitCountThreshold) {
|
||||||
|
|
Loading…
Reference in a new issue