test fix, tuple record migration wip

This commit is contained in:
Thibault Deckers 2023-08-16 22:29:52 +02:00
parent 7afbdfaa84
commit 1117da068b
13 changed files with 61 additions and 63 deletions

View file

@ -13,7 +13,6 @@ import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
import 'package:tuple/tuple.dart';
final Covers covers = Covers._private();
@ -40,11 +39,11 @@ class Covers {
Set<CoverRow> get all => Set.unmodifiable(_rows);
Tuple3<int?, String?, Color?>? of(CollectionFilter filter) {
(int? entryId, String? packageName, Color? color)? of(CollectionFilter filter) {
if (filter is AlbumFilter && vaults.isLocked(filter.album)) return null;
final row = _rows.firstWhereOrNull((row) => row.filter == filter);
return row != null ? Tuple3(row.entryId, row.packageName, row.color) : null;
return row != null ? (row.entryId, row.packageName, row.color) : null;
}
Future<void> set({
@ -113,7 +112,7 @@ class Covers {
}
AlbumType effectiveAlbumType(String albumPath) {
final filterPackage = of(AlbumFilter(albumPath, null))?.item2;
final filterPackage = of(AlbumFilter(albumPath, null))?.$2;
if (filterPackage != null) {
return filterPackage.isEmpty ? AlbumType.regular : AlbumType.app;
} else {
@ -122,7 +121,7 @@ class Covers {
}
String? effectiveAlbumPackage(String albumPath) {
final filterPackage = of(AlbumFilter(albumPath, null))?.item2;
final filterPackage = of(AlbumFilter(albumPath, null))?.$2;
return filterPackage ?? appInventory.getAlbumAppPackageName(albumPath);
}

View file

@ -64,7 +64,7 @@ class AlbumFilter extends CoveredCollectionFilter {
@override
Future<Color> color(BuildContext context) {
// custom color has precedence over others, even custom app color
final customColor = covers.of(this)?.item3;
final customColor = covers.of(this)?.$3;
if (customColor != null) return SynchronousFuture(customColor);
final colors = context.read<AvesColorsData>();

View file

@ -157,7 +157,7 @@ abstract class CoveredCollectionFilter extends CollectionFilter {
@override
Future<Color> color(BuildContext context) {
final customColor = covers.of(this)?.item3;
final customColor = covers.of(this)?.$3;
if (customColor != null) {
return SynchronousFuture(customColor);
}

View file

@ -274,9 +274,9 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
final existingCover = covers.of(oldFilter);
await covers.set(
filter: newFilter,
entryId: existingCover?.item1,
packageName: existingCover?.item2,
color: existingCover?.item3,
entryId: existingCover?.$1,
packageName: existingCover?.$2,
color: existingCover?.$3,
);
renameNewAlbum(sourceAlbum, destinationAlbum);
@ -547,7 +547,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, CountryMixin, Place
}
AvesEntry? coverEntry(CollectionFilter filter) {
final id = covers.of(filter)?.item1;
final id = covers.of(filter)?.$1;
if (id != null) {
final entry = visibleEntries.firstWhereOrNull((entry) => entry.id == id);
if (entry != null) return entry;

View file

@ -14,7 +14,6 @@ import 'package:aves/services/common/services.dart';
import 'package:aves_model/aves_model.dart';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:tuple/tuple.dart';
mixin LocationMixin on CountryMixin, StateMixin {
static const commitCountThreshold = 200;
@ -96,16 +95,16 @@ mixin LocationMixin on CountryMixin, StateMixin {
// - 652 calls (22%) when approximating to 2 decimal places (~1km - town or village)
// cf https://en.wikipedia.org/wiki/Decimal_degrees#Precision
final latLngFactor = pow(10, 2);
Tuple2<int, int> approximateLatLng(AvesEntry entry) {
(int latitude, int longitude) approximateLatLng(AvesEntry entry) {
// entry has coordinates
final catalogMetadata = entry.catalogMetadata!;
final lat = catalogMetadata.latitude!;
final lng = catalogMetadata.longitude!;
return Tuple2<int, int>((lat * latLngFactor).round(), (lng * latLngFactor).round());
return ((lat * latLngFactor).round(), (lng * latLngFactor).round());
}
final located = visibleEntries.where((entry) => entry.hasGps).toSet().difference(todo);
final knownLocations = <Tuple2<int, int>, AddressDetails?>{};
final knownLocations = <(int, int), AddressDetails?>{};
located.forEach((entry) {
knownLocations.putIfAbsent(approximateLatLng(entry), () => entry.addressDetails);
});

View file

@ -3,13 +3,12 @@ import 'dart:collection';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:tuple/tuple.dart';
final ServicePolicy servicePolicy = ServicePolicy._private();
class ServicePolicy {
final StreamController<QueueState> _queueStreamController = StreamController.broadcast();
final Map<Object, Tuple2<int, _Task>> _paused = {};
final Map<Object, (int, _Task)> _paused = {};
final SplayTreeMap<int, LinkedHashMap<Object, _Task>> _queues = SplayTreeMap();
final LinkedHashMap<Object, _Task> _runningQueue = LinkedHashMap();
@ -30,8 +29,8 @@ class ServicePolicy {
key ??= platformCall.hashCode;
final toResume = _paused.remove(key);
if (toResume != null) {
priority = toResume.item1;
task = toResume.item2 as _Task<T>;
priority = toResume.$1;
task = toResume.$2 as _Task<T>;
completer = task.completer;
} else {
completer = Completer<T>();
@ -56,8 +55,8 @@ class ServicePolicy {
Future<T>? resume<T>(Object key) {
final toResume = _paused.remove(key);
if (toResume != null) {
final priority = toResume.item1;
final task = toResume.item2 as _Task<T>;
final priority = toResume.$1;
final task = toResume.$2 as _Task<T>;
_getQueue(priority)[key] = task;
_pickNext();
return task.completer.future;
@ -97,7 +96,7 @@ class ServicePolicy {
}
bool pause(Object key, Iterable<int> priorities) {
return _takeOut(key, priorities, (priority, task) => _paused.putIfAbsent(key, () => Tuple2(priority, task)));
return _takeOut(key, priorities, (priority, task) => _paused.putIfAbsent(key, () => (priority, task)));
}
bool isPaused(Object key) => _paused.containsKey(key);

View file

@ -1,8 +1,6 @@
import 'dart:math';
import 'dart:ui';
import 'package:tuple/tuple.dart';
int highestPowerOf2(num x) => x < 1 ? 0 : pow(2, (log(x) / ln2).floor()).toInt();
int smallestPowerOf2(num x) => x < 1 ? 1 : pow(2, (log(x) / ln2).ceil()).toInt();
@ -10,16 +8,16 @@ int smallestPowerOf2(num x) => x < 1 ? 1 : pow(2, (log(x) / ln2).ceil()).toInt()
double roundToPrecision(final double value, {required final int decimals}) => (value * pow(10, decimals)).round() / pow(10, decimals);
// cf https://en.wikipedia.org/wiki/Intersection_(geometry)#Two_line_segments
Offset? segmentIntersection(Tuple2<Offset, Offset> s1, Tuple2<Offset, Offset> s2) {
final x1 = s1.item1.dx;
final y1 = s1.item1.dy;
final x2 = s1.item2.dx;
final y2 = s1.item2.dy;
Offset? segmentIntersection((Offset, Offset) s1, (Offset, Offset) s2) {
final x1 = s1.$1.dx;
final y1 = s1.$1.dy;
final x2 = s1.$2.dx;
final y2 = s1.$2.dy;
final x3 = s2.item1.dx;
final y3 = s2.item1.dy;
final x4 = s2.item2.dx;
final y4 = s2.item2.dy;
final x3 = s2.$1.dx;
final y3 = s2.$1.dy;
final x4 = s2.$2.dx;
final y4 = s2.$2.dy;
final a1 = x2 - x1;
final b1 = -(x4 - x3);

View file

@ -4,7 +4,6 @@ import 'dart:math';
import 'package:aves/model/settings/settings.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:tuple/tuple.dart';
class TileExtentController {
final String settingsRouteKey;
@ -102,7 +101,7 @@ class TileExtentController {
double get effectiveExtentMax => _extentForColumnCount(_effectiveColumnCountMin());
Tuple2<int, int> get effectiveColumnRange => Tuple2(_effectiveColumnCountMin(), _effectiveColumnCountMax());
(int min, int max) get effectiveColumnRange => (_effectiveColumnCountMin(), _effectiveColumnCountMax());
int get columnCount => _effectiveColumnCountForExtent(extentNotifier.value);

View file

@ -40,7 +40,7 @@ class _AddShortcutDialogState extends State<AddShortcutDialog> {
if (_collection != null) {
final entries = _collection.sortedEntries;
if (entries.isNotEmpty) {
final coverEntries = _collection.filters.map((filter) => covers.of(filter)?.item1).whereNotNull().map((id) => entries.firstWhereOrNull((entry) => entry.id == id)).whereNotNull();
final coverEntries = _collection.filters.map((filter) => covers.of(filter)?.$1).whereNotNull().map((id) => entries.firstWhereOrNull((entry) => entry.id == id)).whereNotNull();
_coverEntry = coverEntries.firstOrNull ?? entries.first;
}
}

View file

@ -70,8 +70,8 @@ class _TileViewDialogState<S, G, L> extends State<TileViewDialog<S, G, L>> with
final extentController = tileExtentController;
final columnRange = extentController.effectiveColumnRange;
_columnMin = columnRange.item1;
_columnMax = columnRange.item2;
_columnMin = columnRange.$1;
_columnMax = columnRange.$2;
}
@override

View file

@ -326,15 +326,15 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
if (!await unlockFilter(context, filter)) return;
final existingCover = covers.of(filter);
final entryId = existingCover?.item1;
final entryId = existingCover?.$1;
final customEntry = entryId != null ? context.read<CollectionSource>().visibleEntries.firstWhereOrNull((entry) => entry.id == entryId) : null;
final selectedCover = await showDialog<Tuple3<AvesEntry?, String?, Color?>>(
context: context,
builder: (context) => CoverSelectionDialog(
filter: filter,
customEntry: customEntry,
customPackage: existingCover?.item2,
customColor: existingCover?.item3,
customPackage: existingCover?.$2,
customColor: existingCover?.$3,
),
routeSettings: const RouteSettings(name: CoverSelectionDialog.routeName),
);

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:aves/l10n/l10n.dart';
import 'package:aves/model/availability.dart';
import 'package:aves/model/covers.dart';
import 'package:aves/model/db/db_metadata.dart';
@ -201,7 +202,7 @@ void main() {
await covers.set(filter: albumFilter, entryId: image1.id, packageName: null, color: null);
expect(covers.count, 1);
expect(covers.of(albumFilter)?.item1, image1.id);
expect(covers.of(albumFilter)?.$1, image1.id);
await covers.set(filter: albumFilter, entryId: null, packageName: null, color: null);
expect(covers.count, 0);
@ -229,7 +230,7 @@ void main() {
expect(favourites.count, 1);
expect(image1.isFavourite, true);
expect(covers.count, 1);
expect(covers.of(albumFilter)?.item1, image1.id);
expect(covers.of(albumFilter)?.$1, image1.id);
});
test('favourites and covers are cleared when removing entries', () async {
@ -348,7 +349,7 @@ void main() {
expect(favourites.count, 1);
expect(image1.isFavourite, true);
expect(covers.count, 1);
expect(covers.of(albumFilter)?.item1, image1.id);
expect(covers.of(albumFilter)?.$1, image1.id);
});
testWidgets('unique album names', (tester) async {
@ -369,7 +370,10 @@ void main() {
final source = await _initSource();
await tester.pumpWidget(
Builder(
Localizations(
locale: AppLocalizations.supportedLocales.first,
delegates: AppLocalizations.localizationsDelegates,
child: Builder(
builder: (context) {
expect(source.getAlbumDisplayName(context, '${FakeStorageService.primaryPath}Pictures/Elea/Zeno'), 'Elea/Zeno');
expect(source.getAlbumDisplayName(context, '${FakeStorageService.primaryPath}Pictures/Citium/Zeno'), 'Citium/Zeno');
@ -386,6 +390,7 @@ void main() {
return const Placeholder();
},
),
),
);
});
}

View file

@ -2,7 +2,6 @@ import 'dart:ui';
import 'package:aves/utils/math_utils.dart';
import 'package:test/test.dart';
import 'package:tuple/tuple.dart';
void main() {
test('highest power of 2 that is smaller than or equal to the number', () {
@ -29,8 +28,8 @@ void main() {
});
test('segment intersection', () {
const s1 = Tuple2(Offset(1, 1), Offset(3, 2));
const s2 = Tuple2(Offset(1, 4), Offset(2, -1));
const s1 = (Offset(1, 1), Offset(3, 2));
const s2 = (Offset(1, 4), Offset(2, -1));
expect(segmentIntersection(s1, s2), const Offset(17 / 11, 14 / 11));
});
}