From 1870830b39445dc09480ceb134c72ef25ae2e440 Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Mon, 1 Jul 2024 03:00:11 +0800 Subject: [PATCH] Replace tuple with records --- app/lib/bloc/home_search_suggestion.dart | 13 ++++----- app/lib/bloc/search_suggestion.dart | 13 ++++----- app/lib/download_handler.dart | 9 +++--- app/lib/entity/album/upgrader.dart | 11 ++++--- app/lib/entity/collection/adapter/album.dart | 16 +++++----- app/lib/entity/collection/util.dart | 13 ++++----- app/lib/entity/collection_item/sorter.dart | 29 +++++++++---------- app/lib/internal_download_handler.dart | 6 ++-- app/lib/suggester.dart | 13 ++++----- app/lib/use_case/remove.dart | 4 +-- app/lib/use_case/sync_dir.dart | 11 ++++--- app/lib/widget/file_sharer_dialog.dart | 1 - app/lib/widget/file_sharer_dialog/bloc.dart | 18 +++++------- app/lib/widget/home_photos/bloc.dart | 7 +++-- app/lib/widget/home_photos2.dart | 1 - .../widget/settings/enhancement_settings.dart | 29 +++++++++---------- app/lib/widget/viewer_detail_pane.dart | 7 ++--- app/pubspec.lock | 8 ----- app/pubspec.yaml | 1 - app/test/test_util.dart | 28 +++++++++--------- .../sync_face_recognition_person_test.dart | 11 +++---- app/test/use_case/sync_tag_test.dart | 5 ++-- np_async/lib/src/future_util.dart | 8 ++--- np_collection/lib/src/iterable_extension.dart | 3 +- np_collection/pubspec.yaml | 1 - .../test/iterable_extension_test.dart | 11 ++++--- .../lib/src/database/compat_extension.dart | 13 +++++---- np_db_sqlite/lib/src/database_extension.dart | 1 - np_db_sqlite/pubspec.yaml | 1 - np_gps_map/lib/src/gps_map.dart | 3 +- np_gps_map/lib/src/native/google_gps_map.dart | 5 ++-- np_gps_map/lib/src/osm_gps_map.dart | 7 ++--- np_gps_map/lib/src/web/google_gps_map.dart | 7 ++--- np_gps_map/pubspec.yaml | 1 - 34 files changed, 142 insertions(+), 173 deletions(-) diff --git a/app/lib/bloc/home_search_suggestion.dart b/app/lib/bloc/home_search_suggestion.dart index 33b4fb18..98dc322d 100644 --- a/app/lib/bloc/home_search_suggestion.dart +++ b/app/lib/bloc/home_search_suggestion.dart @@ -19,7 +19,6 @@ import 'package:np_codegen/np_codegen.dart'; import 'package:np_collection/np_collection.dart'; import 'package:np_string/np_string.dart'; import 'package:to_string/to_string.dart'; -import 'package:tuple/tuple.dart'; import 'package:woozy_search/woozy_search.dart'; part 'home_search_suggestion.g.dart'; @@ -172,17 +171,17 @@ class HomeSearchSuggestionBloc .map((e) { if (e.value!.toKeywords().any((k) => k.startsWith(ev.phrase))) { // prefer names that start exactly with the search phrase - return Tuple2(e.score + 1, e.value); + return (score: e.score + 1, item: e.value); } else { - return Tuple2(e.score, e.value); + return (score: e.score, item: e.value); } }) - .sorted((a, b) => b.item1.compareTo(a.item1)) + .sorted((a, b) => b.score.compareTo(a.score)) .distinctIf( - (a, b) => identical(a.item2, b.item2), - (a) => a.item2.hashCode, + (a, b) => identical(a.item, b.item), + (a) => a.item.hashCode, ) - .map((e) => e.item2!.toResult()) + .map((e) => e.item!.toResult()) .toList(); emit(HomeSearchSuggestionBlocSuccess(matches)); } diff --git a/app/lib/bloc/search_suggestion.dart b/app/lib/bloc/search_suggestion.dart index d98e170b..57422938 100644 --- a/app/lib/bloc/search_suggestion.dart +++ b/app/lib/bloc/search_suggestion.dart @@ -6,7 +6,6 @@ import 'package:np_codegen/np_codegen.dart'; import 'package:np_collection/np_collection.dart'; import 'package:np_string/np_string.dart'; import 'package:to_string/to_string.dart'; -import 'package:tuple/tuple.dart'; import 'package:woozy_search/woozy_search.dart'; part 'search_suggestion.g.dart'; @@ -92,18 +91,18 @@ class SearchSuggestionBloc if (itemToKeywords(e.value as T) .any((k) => k.startsWith(ev.phrase))) { // prefer names that start exactly with the search phrase - return Tuple2(e.score + 1, e.value as T); + return (score: e.score + 1, item: e.value as T); } else { - return Tuple2(e.score, e.value as T); + return (score: e.score, item: e.value as T); } }) - .sorted((a, b) => a.item1.compareTo(b.item1)) + .sorted((a, b) => a.score.compareTo(b.score)) .reversed .distinctIf( - (a, b) => identical(a.item2, b.item2), - (a) => a.item2.hashCode, + (a, b) => identical(a.item, b.item), + (a) => a.item.hashCode, ) - .map((e) => e.item2) + .map((e) => e.item) .toList(); emit(SearchSuggestionBlocSuccess(matches)); _lastSearch = ev; diff --git a/app/lib/download_handler.dart b/app/lib/download_handler.dart index 084737ba..a1998c5b 100644 --- a/app/lib/download_handler.dart +++ b/app/lib/download_handler.dart @@ -21,7 +21,6 @@ import 'package:nc_photos/use_case/inflate_file_descriptor.dart'; import 'package:nc_photos_plugin/nc_photos_plugin.dart'; import 'package:np_codegen/np_codegen.dart'; import 'package:np_platform_util/np_platform_util.dart'; -import 'package:tuple/tuple.dart'; part 'download_handler.g.dart'; @@ -79,7 +78,7 @@ class _DownlaodHandlerAndroid extends _DownloadHandlerBase { ); final id = await nm.notify(notif); - final successes = >[]; + final successes = <({File file, dynamic result})>[]; StreamSubscription? subscription; try { bool isCancel = false; @@ -117,7 +116,7 @@ class _DownlaodHandlerAndroid extends _DownloadHandlerBase { } }); final result = await download(); - successes.add(Tuple2(f, result)); + successes.add((file: f, result: result)); } on PermissionException catch (_) { _log.warning("[downloadFiles] Permission not granted"); SnackBarManager().showSnackBar(SnackBar( @@ -143,8 +142,8 @@ class _DownlaodHandlerAndroid extends _DownloadHandlerBase { } finally { unawaited(subscription?.cancel()); if (successes.isNotEmpty) { - await _onDownloadSuccessful(successes.map((e) => e.item1).toList(), - successes.map((e) => e.item2).toList(), id); + await _onDownloadSuccessful(successes.map((e) => e.file).toList(), + successes.map((e) => e.result).toList(), id); } else { await nm.dismiss(id); } diff --git a/app/lib/entity/album/upgrader.dart b/app/lib/entity/album/upgrader.dart index e62174e1..562a8c7f 100644 --- a/app/lib/entity/album/upgrader.dart +++ b/app/lib/entity/album/upgrader.dart @@ -9,7 +9,6 @@ import 'package:np_codegen/np_codegen.dart'; import 'package:np_common/type.dart'; import 'package:np_db/np_db.dart'; import 'package:np_string/np_string.dart'; -import 'package:tuple/tuple.dart'; part 'upgrader.g.dart'; @@ -143,22 +142,22 @@ class AlbumUpgraderV4 implements AlbumUpgrader { // remove metadata e.remove("metadata"); if (latestItemTime != null) { - return Tuple2(latestItemTime, e); + return (latestItemTime: latestItemTime, item: e); } else { return null; } }) - .whereType>() - .sorted((a, b) => a.item1.compareTo(b.item1)) + .whereType<({DateTime latestItemTime, JsonObj item})>() + .sorted((a, b) => a.latestItemTime.compareTo(b.latestItemTime)) .lastOrNull; if (latestItem != null) { // save the latest item time result["provider"]["content"]["latestItemTime"] = - latestItem.item1.toIso8601String(); + latestItem.latestItemTime.toIso8601String(); if (result["coverProvider"]["type"] == "auto") { // save the cover result["coverProvider"]["content"]["coverFile"] = - Map.of(latestItem.item2); + Map.of(latestItem.item); } } } catch (e, stackTrace) { diff --git a/app/lib/entity/collection/adapter/album.dart b/app/lib/entity/collection/adapter/album.dart index 5023a497..a57608bd 100644 --- a/app/lib/entity/collection/adapter/album.dart +++ b/app/lib/entity/collection/adapter/album.dart @@ -35,7 +35,6 @@ import 'package:np_collection/np_collection.dart'; import 'package:np_common/or_null.dart'; import 'package:np_common/type.dart'; import 'package:np_string/np_string.dart'; -import 'package:tuple/tuple.dart'; part 'album.g.dart'; @@ -135,20 +134,20 @@ class CollectionAlbumAdapter implements CollectionAdapter { try { final group = items .withIndex() - .groupListsBy((e) => e.item2 is AlbumAdaptedCollectionItem); + .groupListsBy((e) => e.e is AlbumAdaptedCollectionItem); var failed = 0; if (group[true]?.isNotEmpty ?? false) { final newAlbum = await RemoveFromAlbum(_c)( account, _provider.album, group[true]! - .map((e) => e.item2) + .map((e) => e.e) .cast() .map((e) => e.albumItem) .toList(), onError: (i, item, e, stackTrace) { ++failed; - final actualIndex = group[true]![i].item1; + final actualIndex = group[true]![i].i; try { onError?.call(actualIndex, items[actualIndex], e, stackTrace); } catch (e, stackTrace) { @@ -162,8 +161,9 @@ class CollectionAlbumAdapter implements CollectionAdapter { ), )); } - for (final pair in (group[false] ?? const >[])) { - final actualIndex = pair.item1; + for (final (:i, e: _) + in (group[false] ?? const <({int i, CollectionItem e})>[])) { + final actualIndex = i; onError?.call( actualIndex, items[actualIndex], @@ -174,8 +174,8 @@ class CollectionAlbumAdapter implements CollectionAdapter { } return (group[true] ?? []).length - failed; } catch (e, stackTrace) { - for (final pair in items.withIndex()) { - onError?.call(pair.item1, pair.item2, e, stackTrace); + for (final (:i, e: item) in items.withIndex()) { + onError?.call(i, item, e, stackTrace); } return 0; } diff --git a/app/lib/entity/collection/util.dart b/app/lib/entity/collection/util.dart index b955ed42..e1bd36b4 100644 --- a/app/lib/entity/collection/util.dart +++ b/app/lib/entity/collection/util.dart @@ -3,7 +3,6 @@ import 'package:equatable/equatable.dart'; import 'package:nc_photos/entity/collection.dart'; import 'package:np_string/np_string.dart'; import 'package:to_string/to_string.dart'; -import 'package:tuple/tuple.dart'; part 'util.g.dart'; @@ -43,28 +42,28 @@ enum CollectionShareResult { extension CollectionListExtension on Iterable { List sortedBy(CollectionSort by) { - return map>((e) { + return map<({Comparable comparable, Collection collection})>((e) { switch (by) { case CollectionSort.nameAscending: case CollectionSort.nameDescending: - return Tuple2(e.name.toLowerCase(), e); + return (comparable: e.name.toLowerCase(), collection: e); case CollectionSort.dateAscending: case CollectionSort.dateDescending: - return Tuple2(e.contentProvider.lastModified, e); + return (comparable: e.contentProvider.lastModified, collection: e); } }) .sorted((a, b) { final x = by.isAscending() ? a : b; final y = by.isAscending() ? b : a; - final tmp = x.item1.compareTo(y.item1); + final tmp = x.comparable.compareTo(y.comparable); if (tmp != 0) { return tmp; } else { - return x.item2.name.compareTo(y.item2.name); + return x.collection.name.compareTo(y.collection.name); } }) - .map((e) => e.item2) + .map((e) => e.collection) .toList(); } } diff --git a/app/lib/entity/collection_item/sorter.dart b/app/lib/entity/collection_item/sorter.dart index 56d3bf3a..f736b3a9 100644 --- a/app/lib/entity/collection_item/sorter.dart +++ b/app/lib/entity/collection_item/sorter.dart @@ -6,7 +6,6 @@ import 'package:nc_photos/entity/collection_item/util.dart'; import 'package:nc_photos/entity/file_descriptor.dart'; import 'package:np_codegen/np_codegen.dart'; import 'package:np_collection/np_collection.dart'; -import 'package:tuple/tuple.dart'; part 'sorter.g.dart'; @@ -58,24 +57,24 @@ class CollectionTimeSorter implements CollectionSorter { prevFileTime = e.file.fdDateTime; } // for non file items, use the sibling file's time - return Tuple2(prevFileTime, e); + return (dateTime: prevFileTime, item: e); }) .stableSorted((x, y) { - if (x.item1 == null && y.item1 == null) { + if (x.dateTime == null && y.dateTime == null) { return 0; - } else if (x.item1 == null) { + } else if (x.dateTime == null) { return -1; - } else if (y.item1 == null) { + } else if (y.dateTime == null) { return 1; } else { if (isAscending) { - return x.item1!.compareTo(y.item1!); + return x.dateTime!.compareTo(y.dateTime!); } else { - return y.item1!.compareTo(x.item1!); + return y.dateTime!.compareTo(x.dateTime!); } } }) - .map((e) => e.item2) + .map((e) => e.item) .toList(); } @@ -98,24 +97,24 @@ class CollectionFilenameSorter implements CollectionSorter { prevFilename = e.file.filename; } // for non file items, use the sibling file's name - return Tuple2(prevFilename, e); + return (dateTime: prevFilename, item: e); }) .stableSorted((x, y) { - if (x.item1 == null && y.item1 == null) { + if (x.dateTime == null && y.dateTime == null) { return 0; - } else if (x.item1 == null) { + } else if (x.dateTime == null) { return -1; - } else if (y.item1 == null) { + } else if (y.dateTime == null) { return 1; } else { if (isAscending) { - return compareNatural(x.item1!, y.item1!); + return compareNatural(x.dateTime!, y.dateTime!); } else { - return compareNatural(y.item1!, x.item1!); + return compareNatural(y.dateTime!, x.dateTime!); } } }) - .map((e) => e.item2) + .map((e) => e.item) .toList(); } diff --git a/app/lib/internal_download_handler.dart b/app/lib/internal_download_handler.dart index 282daf05..903d7c4f 100644 --- a/app/lib/internal_download_handler.dart +++ b/app/lib/internal_download_handler.dart @@ -56,8 +56,7 @@ class InternalDownloadHandler { ); try { final results = >[]; - for (final pair in files.withIndex()) { - final i = pair.item1, f = pair.item2; + for (final (:i, e: f) in files.withIndex()) { controller.add(_DownloadProgress(current: i)); try { final dynamic result; @@ -122,8 +121,7 @@ class InternalDownloadHandler { ); try { final results = >[]; - for (final pair in files.withIndex()) { - final i = pair.item1, f = pair.item2; + for (final (:i, e: f) in files.withIndex()) { controller.add(_DownloadProgress(current: i)); try { download = DownloadFile().build( diff --git a/app/lib/suggester.dart b/app/lib/suggester.dart index b82a3a44..547bf2aa 100644 --- a/app/lib/suggester.dart +++ b/app/lib/suggester.dart @@ -4,7 +4,6 @@ import 'package:logging/logging.dart'; import 'package:np_codegen/np_codegen.dart'; import 'package:np_collection/np_collection.dart'; import 'package:np_string/np_string.dart'; -import 'package:tuple/tuple.dart'; import 'package:woozy_search/woozy_search.dart'; part 'suggester.g.dart'; @@ -34,18 +33,18 @@ class Suggester { .map((e) { if (itemToKeywords(e.value as T).any((k) => k.startsWith(phrase))) { // prefer names that start exactly with the search phrase - return Tuple2(e.score + 1, e.value as T); + return (score: e.score + 1, item: e.value as T); } else { - return Tuple2(e.score, e.value as T); + return (score: e.score, item: e.value as T); } }) - .sorted((a, b) => a.item1.compareTo(b.item1)) + .sorted((a, b) => a.score.compareTo(b.score)) .reversed .distinctIf( - (a, b) => identical(a.item2, b.item2), - (a) => a.item2.hashCode, + (a, b) => identical(a.item, b.item), + (a) => a.item.hashCode, ) - .map((e) => e.item2) + .map((e) => e.item) .toList(); return matches; } diff --git a/app/lib/use_case/remove.dart b/app/lib/use_case/remove.dart index e6ef30c2..dc7f1a87 100644 --- a/app/lib/use_case/remove.dart +++ b/app/lib/use_case/remove.dart @@ -39,9 +39,7 @@ class Remove { await _cleanUpAlbums(account, files); } var count = 0; - for (final pair in files.withIndex()) { - final i = pair.item1; - final f = pair.item2; + for (final (:i, e: f) in files.withIndex()) { try { await _c.fileRepo2.remove(account, f); ++count; diff --git a/app/lib/use_case/sync_dir.dart b/app/lib/use_case/sync_dir.dart index 015ffd4a..36dcf4f4 100644 --- a/app/lib/use_case/sync_dir.dart +++ b/app/lib/use_case/sync_dir.dart @@ -11,7 +11,6 @@ import 'package:nc_photos/progress_util.dart'; import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/use_case/ls_single_file.dart'; import 'package:np_codegen/np_codegen.dart'; -import 'package:tuple/tuple.dart'; part 'sync_dir.g.dart'; @@ -52,7 +51,7 @@ class SyncDir { ValueChanged? onProgressUpdate, }) async { final status = await _checkContentUpdated(account, remoteDir, dirCache); - if (!status.item1) { + if (!status.isUpdated) { _log.finer("[_syncDir] Dir unchanged: ${remoteDir.path}"); return false; } @@ -60,7 +59,7 @@ class SyncDir { final dataSrc = FileCachedDataSource(_c, shouldCheckCache: true); final syncState = await dataSrc.beginSync(account, remoteDir, - remoteTouchEtag: status.item2); + remoteTouchEtag: status.touchResult); final children = syncState.files; if (!isRecursive) { await dataSrc.concludeSync(syncState); @@ -97,19 +96,19 @@ class SyncDir { return true; } - Future> _checkContentUpdated( + Future<({bool isUpdated, String? touchResult})> _checkContentUpdated( Account account, File remoteDir, Map dirCache) async { String? touchResult; try { touchResult = await _c.touchManager.checkTouchEtag(account, remoteDir); if (touchResult == null && dirCache[remoteDir.fileId!] == remoteDir.etag!) { - return const Tuple2(false, null); + return const (isUpdated: false, touchResult: null); } } catch (e, stackTrace) { _log.severe("[_isContentUpdated] Uncaught exception", e, stackTrace); } - return Tuple2(true, touchResult); + return (isUpdated: true, touchResult: touchResult); } Future> _queryAllDirEtags( diff --git a/app/lib/widget/file_sharer_dialog.dart b/app/lib/widget/file_sharer_dialog.dart index 0f2090c1..2c70b272 100644 --- a/app/lib/widget/file_sharer_dialog.dart +++ b/app/lib/widget/file_sharer_dialog.dart @@ -38,7 +38,6 @@ import 'package:np_codegen/np_codegen.dart'; import 'package:np_collection/np_collection.dart'; import 'package:np_platform_util/np_platform_util.dart'; import 'package:to_string/to_string.dart'; -import 'package:tuple/tuple.dart'; part 'file_sharer_dialog.g.dart'; part 'file_sharer_dialog/bloc.dart'; diff --git a/app/lib/widget/file_sharer_dialog/bloc.dart b/app/lib/widget/file_sharer_dialog/bloc.dart index 0cea7976..677c0385 100644 --- a/app/lib/widget/file_sharer_dialog/bloc.dart +++ b/app/lib/widget/file_sharer_dialog/bloc.dart @@ -97,9 +97,8 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger { emit(state.copyWith( fileState: _FileState.init(count: files.length), )); - final results = >[]; - for (final pair in files.withIndex()) { - final i = pair.item1, f = pair.item2; + final results = <({FileDescriptor file, dynamic result})>[]; + for (final (:i, e: f) in files.withIndex()) { emit(state.copyWith( fileState: state.fileState?.copyWith( index: i, @@ -124,7 +123,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger { if (state.fileState?.shouldRun == false) { throw const JobCanceledException(); } - results.add(Tuple2(f, result)); + results.add((file: f, result: result)); } on PermissionException catch (e, stackTrace) { _log.warning("[_doShareFile] Permission not granted"); emit(state.copyWith(error: ExceptionEvent(e, stackTrace))); @@ -141,7 +140,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger { } if (results.isNotEmpty) { final share = AndroidFileShare(results - .map((e) => AndroidFileShareFile(e.item2 as String, e.item1.fdMime)) + .map((e) => AndroidFileShareFile(e.result as String, e.file.fdMime)) .toList()); unawaited(share.share()); } @@ -153,9 +152,8 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger { emit(state.copyWith( previewState: _PreviewState(index: 0, count: files.length), )); - final results = >[]; - for (final pair in files.withIndex()) { - final i = pair.item1, f = pair.item2; + final results = <({FileDescriptor file, dynamic result})>[]; + for (final (:i, e: f) in files.withIndex()) { emit(state.copyWith( previewState: state.previewState?.copyWith(index: i), )); @@ -166,7 +164,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger { } else { uri = await DownloadFile()(account, f, shouldNotify: false); } - results.add(Tuple2(f, uri)); + results.add((file: f, result: uri)); } catch (e, stackTrace) { _log.shout( "[_doSharePreview] Failed while DownloadPreview", e, stackTrace); @@ -175,7 +173,7 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger { } if (results.isNotEmpty) { final share = AndroidFileShare(results - .map((e) => AndroidFileShareFile(e.item2 as String, e.item1.fdMime)) + .map((e) => AndroidFileShareFile(e.result as String, e.file.fdMime)) .toList()); unawaited(share.share()); } diff --git a/app/lib/widget/home_photos/bloc.dart b/app/lib/widget/home_photos/bloc.dart index ea3242cc..a9182f77 100644 --- a/app/lib/widget/home_photos/bloc.dart +++ b/app/lib/widget/home_photos/bloc.dart @@ -477,11 +477,12 @@ class _Bloc extends Bloc<_Event, _State> month: localToday.month, day: localToday.day, cover: e.value - .map((e) => Tuple2(e.bestDateTime.difference(center), e)) - .sorted((a, b) => a.item1.compareTo(b.item1)) + .map((e) => + (comparable: e.bestDateTime.difference(center), item: e)) + .sorted((a, b) => a.comparable.compareTo(b.comparable)) .firstOrNull ?.let((e) => DbFileDescriptorConverter.fromDb( - account.userId.toString(), e.item2)), + account.userId.toString(), e.item)), ), ); }).toList(), diff --git a/app/lib/widget/home_photos2.dart b/app/lib/widget/home_photos2.dart index 5741c85f..930ad148 100644 --- a/app/lib/widget/home_photos2.dart +++ b/app/lib/widget/home_photos2.dart @@ -67,7 +67,6 @@ import 'package:np_db/np_db.dart'; import 'package:np_platform_util/np_platform_util.dart'; import 'package:np_ui/np_ui.dart'; import 'package:to_string/to_string.dart'; -import 'package:tuple/tuple.dart'; import 'package:visibility_detector/visibility_detector.dart'; part 'home_photos/app_bar.dart'; diff --git a/app/lib/widget/settings/enhancement_settings.dart b/app/lib/widget/settings/enhancement_settings.dart index fbcc63f8..e389a58b 100644 --- a/app/lib/widget/settings/enhancement_settings.dart +++ b/app/lib/widget/settings/enhancement_settings.dart @@ -12,7 +12,6 @@ import 'package:nc_photos/widget/page_visibility_mixin.dart'; import 'package:np_codegen/np_codegen.dart'; import 'package:np_ui/np_ui.dart'; import 'package:to_string/to_string.dart'; -import 'package:tuple/tuple.dart'; part 'enhancement/bloc.dart'; part 'enhancement/state_event.dart'; @@ -135,9 +134,9 @@ class _WrappedEnhancementSettingsState _SizeSlider( initialWidth: initialSize.width, initialHeight: initialSize.height, - onChanged: (value) { - width = value.item1; - height = value.item2; + onChanged: (size) { + width = size.w; + height = size.h; }, ) ], @@ -175,7 +174,7 @@ class _SizeSlider extends StatefulWidget { final int initialWidth; final int initialHeight; - final ValueChanged>? onChanged; + final ValueChanged<({int w, int h})>? onChanged; } class _SizeSliderState extends State<_SizeSlider> { @@ -202,8 +201,8 @@ class _SizeSliderState extends State<_SizeSlider> { onChangeEnd: (value) async { final resolution = sliderValueToResolution(value.toInt()); setState(() { - _width = resolution.item1; - _height = resolution.item2; + _width = resolution.w; + _height = resolution.h; }); widget.onChanged?.call(resolution); }, @@ -212,22 +211,22 @@ class _SizeSliderState extends State<_SizeSlider> { ); } - static Tuple2 sliderValueToResolution(int value) { + static ({int w, int h}) sliderValueToResolution(int value) { switch (value) { case -3: - return const Tuple2(1024, 768); + return const (w: 1024, h: 768); case -2: - return const Tuple2(1280, 960); + return const (w: 1280, h: 960); case -1: - return const Tuple2(1600, 1200); + return const (w: 1600, h: 1200); case 1: - return const Tuple2(2560, 1920); + return const (w: 2560, h: 1920); case 2: - return const Tuple2(3200, 2400); + return const (w: 3200, h: 2400); case 3: - return const Tuple2(4096, 3072); + return const (w: 4096, h: 3072); default: - return const Tuple2(2048, 1536); + return const (w: 2048, h: 1536); } } diff --git a/app/lib/widget/viewer_detail_pane.dart b/app/lib/widget/viewer_detail_pane.dart index 9b523d24..eeea20c9 100644 --- a/app/lib/widget/viewer_detail_pane.dart +++ b/app/lib/widget/viewer_detail_pane.dart @@ -40,7 +40,6 @@ import 'package:np_platform_util/np_platform_util.dart'; import 'package:np_string/np_string.dart'; import 'package:np_ui/np_ui.dart'; import 'package:path/path.dart' as path_lib; -import 'package:tuple/tuple.dart'; part 'viewer_detail_pane.g.dart'; @@ -405,7 +404,7 @@ class _ViewerDetailPaneState extends State { final lng = exif.gpsLongitudeDeg; if (lat != null && lng != null) { _log.fine("GPS: ($lat, $lng)"); - _gps = Tuple2(lat, lng); + _gps = (lat: lat, lng: lng); _location = _file!.location; } } @@ -503,7 +502,7 @@ class _ViewerDetailPaneState extends State { if (getRawPlatform() == NpPlatform.android) { final intent = AndroidIntent( action: "action_view", - data: Uri.encodeFull("geo:${_gps!.item1},${_gps!.item2}?z=16"), + data: Uri.encodeFull("geo:${_gps!.lat},${_gps!.lng}?z=16"), ); intent.launch(); } @@ -597,7 +596,7 @@ class _ViewerDetailPaneState extends State { String? _exposureTime; double? _focalLength; int? _isoSpeedRatings; - Tuple2? _gps; + ({double lat, double lng})? _gps; ImageLocation? _location; final _tags = []; diff --git a/app/pubspec.lock b/app/pubspec.lock index 91e49447..2a3a3ed7 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1660,14 +1660,6 @@ packages: url: "https://gitlab.com/nkming2/dart-to-string" source: git version: "1.0.0" - tuple: - dependency: "direct main" - description: - name: tuple - sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 - url: "https://pub.dev" - source: hosted - version: "2.0.2" typed_data: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index c0371fb7..0f4dfe5d 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -150,7 +150,6 @@ dependencies: url: https://gitlab.com/nkming2/dart-to-string ref: to_string-1.0.0 path: to_string - tuple: ^2.0.2 url_launcher: ^6.2.6 uuid: ^3.0.7 video_player: diff --git a/app/test/test_util.dart b/app/test/test_util.dart index 0d160d14..9f9ab81c 100644 --- a/app/test/test_util.dart +++ b/app/test/test_util.dart @@ -28,7 +28,6 @@ import 'package:np_db_sqlite/np_db_sqlite.dart'; import 'package:np_db_sqlite/np_db_sqlite_compat.dart' as compat; import 'package:np_geocoder/np_geocoder.dart'; import 'package:np_string/np_string.dart'; -import 'package:tuple/tuple.dart'; part 'test_compat_util.dart'; @@ -589,10 +588,11 @@ Future>> listSqliteDbDirs(compat.SqliteDb db) async { }).get()); final dirQuery = db.select(db.dirFiles); - final dirs = await dirQuery.map((r) => Tuple2(r.dir, r.child)).get(); + final dirs = + await dirQuery.map((r) => (dirRowId: r.dir, childRowId: r.child)).get(); final result = >{}; - for (final d in dirs) { - (result[fileMap[d.item1]!] ??= {}).add(fileMap[d.item2]!); + for (final (:dirRowId, :childRowId) in dirs) { + (result[fileMap[dirRowId]!] ??= {}).add(fileMap[childRowId]!); } return result; } @@ -616,26 +616,28 @@ Future> listSqliteDbAlbums(compat.SqliteDb db) async { null, ), ); - return Tuple2( - r.read(db.albums.rowId)!, - _SqliteAlbumConverter.fromSql(r.readTable(db.albums), albumFile, []), + return ( + rowId: r.read(db.albums.rowId)!, + album: + _SqliteAlbumConverter.fromSql(r.readTable(db.albums), albumFile, []), ); }).get(); final results = {}; - for (final a in albums) { + for (final (:rowId, :album) in albums) { final shareQuery = db.select(db.albumShares) - ..where((t) => t.album.equals(a.item1)); + ..where((t) => t.album.equals(rowId)); final dbShares = await shareQuery.get(); - results.add(a.item2.copyWith( + results.add(album.copyWith( lastUpdated: const OrNull(null), shares: dbShares.isEmpty ? null : OrNull(dbShares .map((s) => AlbumShare( - userId: s.userId.toCi(), - displayName: s.displayName, - sharedAt: s.sharedAt)) + userId: s.userId.toCi(), + displayName: s.displayName, + sharedAt: s.sharedAt, + )) .toList()), )); } diff --git a/app/test/use_case/face_recognition_person/sync_face_recognition_person_test.dart b/app/test/use_case/face_recognition_person/sync_face_recognition_person_test.dart index d01de770..03ba7326 100644 --- a/app/test/use_case/face_recognition_person/sync_face_recognition_person_test.dart +++ b/app/test/use_case/face_recognition_person/sync_face_recognition_person_test.dart @@ -8,7 +8,6 @@ import 'package:nc_photos/use_case/face_recognition_person/sync_face_recognition import 'package:np_db/np_db.dart'; import 'package:np_db_sqlite/np_db_sqlite_compat.dart' as compat; import 'package:test/test.dart'; -import 'package:tuple/tuple.dart'; import '../../mock_type.dart'; import '../../test_util.dart' as util; @@ -157,13 +156,15 @@ Future>> _listSqliteDbPersons( db.accounts.rowId.equalsExp(db.faceRecognitionPersons.account)), ]); final result = await query - .map((r) => Tuple2( - r.readTable(db.accounts), r.readTable(db.faceRecognitionPersons))) + .map((r) => ( + account: r.readTable(db.accounts), + faceRecognitionPerson: r.readTable(db.faceRecognitionPersons), + )) .get(); final product = >{}; for (final r in result) { - (product[r.item1.userId] ??= {}) - .add(compat.FaceRecognitionPersonConverter.fromSql(r.item2)); + (product[r.account.userId] ??= {}).add( + compat.FaceRecognitionPersonConverter.fromSql(r.faceRecognitionPerson)); } return product; } diff --git a/app/test/use_case/sync_tag_test.dart b/app/test/use_case/sync_tag_test.dart index 4c504a1f..a4f6d546 100644 --- a/app/test/use_case/sync_tag_test.dart +++ b/app/test/use_case/sync_tag_test.dart @@ -8,7 +8,6 @@ import 'package:nc_photos/use_case/sync_tag.dart'; import 'package:np_db/np_db.dart'; import 'package:np_db_sqlite/np_db_sqlite_compat.dart' as compat; import 'package:test/test.dart'; -import 'package:tuple/tuple.dart'; import '../mock_type.dart'; import '../test_util.dart' as util; @@ -175,11 +174,11 @@ Future>> _listSqliteDbTags(compat.SqliteDb db) async { sql.innerJoin(db.servers, db.servers.rowId.equalsExp(db.tags.server)), ]); final result = await query - .map((r) => Tuple2(r.readTable(db.servers), r.readTable(db.tags))) + .map((r) => (server: r.readTable(db.servers), tag: r.readTable(db.tags))) .get(); final product = >{}; for (final r in result) { - (product[r.item1.address] ??= {}).add(compat.TagConverter.fromSql(r.item2)); + (product[r.server.address] ??= {}).add(compat.TagConverter.fromSql(r.tag)); } return product; } diff --git a/np_async/lib/src/future_util.dart b/np_async/lib/src/future_util.dart index f08ec474..011e074c 100644 --- a/np_async/lib/src/future_util.dart +++ b/np_async/lib/src/future_util.dart @@ -28,13 +28,13 @@ Future> waitOr( } } - for (final p in futures.withIndex()) { + for (final (:i, :e) in futures.withIndex()) { unawaited( - p.item2.then((value) { - results[p.item1] = value; + e.then((value) { + results[i] = value; onResult(); }).onError((error, stackTrace) { - results[p.item1] = onError(error!, stackTrace); + results[i] = onError(error!, stackTrace); onResult(); }), ); diff --git a/np_collection/lib/src/iterable_extension.dart b/np_collection/lib/src/iterable_extension.dart index af30fd78..ae82a816 100644 --- a/np_collection/lib/src/iterable_extension.dart +++ b/np_collection/lib/src/iterable_extension.dart @@ -4,7 +4,6 @@ import 'dart:collection'; import 'package:collection/collection.dart'; import 'package:np_collection/src/list_extension.dart'; import 'package:quiver/iterables.dart'; -import 'package:tuple/tuple.dart'; extension IterableExtension on Iterable { /// Return a new stable sorted list @@ -15,7 +14,7 @@ extension IterableExtension on Iterable { /// toString for each items String toReadableString() => "[${join(', ')}]"; - Iterable> withIndex() => mapIndexed((i, e) => Tuple2(i, e)); + Iterable<({int i, T e})> withIndex() => mapIndexed((i, e) => (i: i, e: e)); /// Whether the collection contains an element equal to [element] using the /// equality function [equalFn] diff --git a/np_collection/pubspec.yaml b/np_collection/pubspec.yaml index f03fefa5..8753b516 100644 --- a/np_collection/pubspec.yaml +++ b/np_collection/pubspec.yaml @@ -12,7 +12,6 @@ dependencies: np_math: path: ../np_math quiver: ^3.2.1 - tuple: ^2.0.2 dev_dependencies: np_lints: diff --git a/np_collection/test/iterable_extension_test.dart b/np_collection/test/iterable_extension_test.dart index 4cfea48c..32097a8c 100644 --- a/np_collection/test/iterable_extension_test.dart +++ b/np_collection/test/iterable_extension_test.dart @@ -2,18 +2,17 @@ import 'package:np_collection/src/iterable_extension.dart'; import 'package:np_math/np_math.dart'; import 'package:quiver/core.dart'; import 'package:test/test.dart'; -import 'package:tuple/tuple.dart'; void main() { group("IterableExtension", () { test("withIndex", () { final src = [1, 4, 5, 2, 3]; final result = src.withIndex().toList(); - expect(result[0], const Tuple2(0, 1)); - expect(result[1], const Tuple2(1, 4)); - expect(result[2], const Tuple2(2, 5)); - expect(result[3], const Tuple2(3, 2)); - expect(result[4], const Tuple2(4, 3)); + expect(result[0], const (i: 0, e: 1)); + expect(result[1], const (i: 1, e: 4)); + expect(result[2], const (i: 2, e: 5)); + expect(result[3], const (i: 3, e: 2)); + expect(result[4], const (i: 4, e: 3)); }); test("containsIf", () { diff --git a/np_db_sqlite/lib/src/database/compat_extension.dart b/np_db_sqlite/lib/src/database/compat_extension.dart index 197f2b83..09f60cdc 100644 --- a/np_db_sqlite/lib/src/database/compat_extension.dart +++ b/np_db_sqlite/lib/src/database/compat_extension.dart @@ -8,7 +8,7 @@ extension SqliteDbCompatExtension on SqliteDb { final count = await countQ.map((r) => r.read(countExp)!).getSingle(); onProgress?.call(0, count); - final dateTimeUpdates = >[]; + final dateTimeUpdates = <({int rowId, DateTime dateTime})>[]; final imageRemoves = []; for (var i = 0; i < count; i += 1000) { final q = select(files).join([ @@ -40,7 +40,10 @@ extension SqliteDbCompatExtension on SqliteDb { ); if (f.accountFile.bestDateTime != bestDateTime) { // need update - dateTimeUpdates.add(Tuple2(f.accountFile.rowId, bestDateTime)); + dateTimeUpdates.add(( + rowId: f.accountFile.rowId, + dateTime: bestDateTime, + )); } if (f.file.contentType == "image/heic" && @@ -56,7 +59,7 @@ extension SqliteDbCompatExtension on SqliteDb { "[migrateV55] ${dateTimeUpdates.length} rows require updating, ${imageRemoves.length} rows require removing"); if (kDebugMode) { _log.fine( - "[migrateV55] dateTimeUpdates: ${dateTimeUpdates.map((e) => e.item1).toReadableString()}"); + "[migrateV55] dateTimeUpdates: ${dateTimeUpdates.map((e) => e.rowId).toReadableString()}"); _log.fine( "[migrateV55] imageRemoves: ${imageRemoves.map((e) => e).toReadableString()}"); } @@ -65,9 +68,9 @@ extension SqliteDbCompatExtension on SqliteDb { batch.update( accountFiles, AccountFilesCompanion( - bestDateTime: Value(pair.item2), + bestDateTime: Value(pair.dateTime), ), - where: ($AccountFilesTable table) => table.rowId.equals(pair.item1), + where: ($AccountFilesTable table) => table.rowId.equals(pair.rowId), ); } for (final r in imageRemoves) { diff --git a/np_db_sqlite/lib/src/database_extension.dart b/np_db_sqlite/lib/src/database_extension.dart index d9b4b116..f90a147b 100644 --- a/np_db_sqlite/lib/src/database_extension.dart +++ b/np_db_sqlite/lib/src/database_extension.dart @@ -22,7 +22,6 @@ import 'package:np_db_sqlite/src/util.dart'; import 'package:np_geocoder/np_geocoder.dart'; import 'package:np_platform_lock/np_platform_lock.dart'; import 'package:np_platform_util/np_platform_util.dart'; -import 'package:tuple/tuple.dart'; part 'database/account_extension.dart'; part 'database/album_extension.dart'; diff --git a/np_db_sqlite/pubspec.yaml b/np_db_sqlite/pubspec.yaml index 4f31e801..ca21c7ca 100644 --- a/np_db_sqlite/pubspec.yaml +++ b/np_db_sqlite/pubspec.yaml @@ -50,7 +50,6 @@ dependencies: url: https://gitlab.com/nkming2/dart-to-string ref: to_string-1.0.0 path: to_string - tuple: ^2.0.2 dev_dependencies: build_runner: ^2.4.9 diff --git a/np_gps_map/lib/src/gps_map.dart b/np_gps_map/lib/src/gps_map.dart index d42a5070..89612d9e 100644 --- a/np_gps_map/lib/src/gps_map.dart +++ b/np_gps_map/lib/src/gps_map.dart @@ -4,7 +4,6 @@ import 'package:np_gps_map/src/native/google_gps_map.dart' if (dart.library.html) 'package:np_gps_map/src/web/google_gps_map.dart'; import 'package:np_gps_map/src/osm_gps_map.dart'; import 'package:np_platform_util/np_platform_util.dart'; -import 'package:tuple/tuple.dart'; enum GpsMapProvider { google, @@ -50,7 +49,7 @@ class GpsMap extends StatelessWidget { final GpsMapProvider providerHint; /// A pair of latitude and longitude coordinates, stored as degrees - final Tuple2 center; + final ({double lat, double lng}) center; final double zoom; final void Function()? onTap; diff --git a/np_gps_map/lib/src/native/google_gps_map.dart b/np_gps_map/lib/src/native/google_gps_map.dart index 9f231760..72ce0fd4 100644 --- a/np_gps_map/lib/src/native/google_gps_map.dart +++ b/np_gps_map/lib/src/native/google_gps_map.dart @@ -1,6 +1,5 @@ import 'package:flutter/widgets.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:tuple/tuple.dart'; class GoogleGpsMap extends StatelessWidget { const GoogleGpsMap({ @@ -12,7 +11,7 @@ class GoogleGpsMap extends StatelessWidget { @override Widget build(BuildContext context) { - final centerLl = LatLng(center.item1, center.item2); + final centerLl = LatLng(center.lat, center.lng); return GoogleMap( compassEnabled: false, mapToolbarEnabled: false, @@ -41,7 +40,7 @@ class GoogleGpsMap extends StatelessWidget { ); } - final Tuple2 center; + final ({double lat, double lng}) center; final double zoom; final VoidCallback? onTap; } diff --git a/np_gps_map/lib/src/osm_gps_map.dart b/np_gps_map/lib/src/osm_gps_map.dart index e6fffde7..00ee6832 100644 --- a/np_gps_map/lib/src/osm_gps_map.dart +++ b/np_gps_map/lib/src/osm_gps_map.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; -import 'package:tuple/tuple.dart'; import 'package:url_launcher/url_launcher_string.dart'; class OsmGpsMap extends StatelessWidget { @@ -15,11 +14,11 @@ class OsmGpsMap extends StatelessWidget { @override Widget build(BuildContext context) { const double pinSize = 48; - final centerLl = LatLng(center.item1, center.item2); + final centerLl = LatLng(center.lat, center.lng); return GestureDetector( onTap: () { launchUrlString( - "https://www.openstreetmap.org/?mlat=${center.item1}&mlon=${center.item2}#map=${zoom.toInt()}/${center.item1}/${center.item2}", + "https://www.openstreetmap.org/?mlat=${center.lat}&mlon=${center.lng}#map=${zoom.toInt()}/${center.lat}/${center.lng}", mode: LaunchMode.externalApplication, ); }, @@ -62,7 +61,7 @@ class OsmGpsMap extends StatelessWidget { ); } - final Tuple2 center; + final ({double lat, double lng}) center; final double zoom; final void Function()? onTap; } diff --git a/np_gps_map/lib/src/web/google_gps_map.dart b/np_gps_map/lib/src/web/google_gps_map.dart index a08e671b..1f9e759e 100644 --- a/np_gps_map/lib/src/web/google_gps_map.dart +++ b/np_gps_map/lib/src/web/google_gps_map.dart @@ -4,7 +4,6 @@ import 'dart:html'; import 'package:flutter/widgets.dart'; import 'package:np_gps_map/src/ui_hack.dart' if (dart.library.html) 'dart:ui' as ui; -import 'package:tuple/tuple.dart'; class GoogleGpsMap extends StatefulWidget { const GoogleGpsMap({ @@ -17,7 +16,7 @@ class GoogleGpsMap extends StatefulWidget { @override State createState() => _GoogleGpsMapState(); - final Tuple2 center; + final ({double lat, double lng}) center; final double zoom; final void Function()? onTap; } @@ -28,7 +27,7 @@ class _GoogleGpsMapState extends State { super.initState(); final iframe = IFrameElement() ..src = "https://www.google.com/maps/embed/v1/place?key=$_apiKey" - "&q=${widget.center.item1},${widget.center.item2}" + "&q=${widget.center.lat},${widget.center.lng}" "&zoom=${widget.zoom}" ..style.border = "none"; ui.platformViewRegistry.registerViewFactory(viewType, (_) => iframe); @@ -44,5 +43,5 @@ class _GoogleGpsMapState extends State { static const _apiKey = ""; String get viewType => - "googleMapIframe(${widget.center.item1},${widget.center.item2})"; + "googleMapIframe(${widget.center.lat},${widget.center.lng})"; } diff --git a/np_gps_map/pubspec.yaml b/np_gps_map/pubspec.yaml index 19b2b7c6..a6d24b89 100644 --- a/np_gps_map/pubspec.yaml +++ b/np_gps_map/pubspec.yaml @@ -18,7 +18,6 @@ dependencies: path: ../np_async np_platform_util: path: ../np_platform_util - tuple: ^2.0.2 url_launcher: ^6.1.11 dev_dependencies: