From ddcd3c6099c90257dd79f44a9e88b147b72a5ea6 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sun, 10 Dec 2023 18:22:02 +0530 Subject: [PATCH 01/25] create UI of row in file info to add location data manually when location data is absent --- lib/ui/viewer/file/file_details_widget.dart | 24 +++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index 4ed1fe844..0022ad226 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -11,6 +11,7 @@ import "package:photos/services/update_service.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import "package:photos/ui/components/divider_widget.dart"; +import "package:photos/ui/components/info_item_widget.dart"; import 'package:photos/ui/components/title_bar_widget.dart'; import 'package:photos/ui/viewer/file/file_caption_widget.dart'; import "package:photos/ui/viewer/file_details/added_by_widget.dart"; @@ -157,7 +158,25 @@ class _FileDetailsWidgetState extends State { const FileDetailsDivider(), ], ) - : const SizedBox.shrink(); + : Column( + children: [ + InfoItemWidget( + leadingIcon: Icons.pin_drop_outlined, + title: "No location data", + subtitleSection: Future.value( + [ + Text( + "Add location data", + style: getEnteTextTheme(context).miniBoldMuted, + ), + ], + ), + hasChipButtons: false, + onTap: () {}, + ), + const FileDetailsDivider(), + ], + ); }, ), ]); @@ -280,7 +299,8 @@ class _FileDetailsWidgetState extends State { if (imageWidth != null && imageLength != null) { _exifData["resolution"] = '$imageWidth x $imageLength'; final double megaPixels = - (imageWidth.values.firstAsInt() * imageLength.values.firstAsInt()) / 1000000; + (imageWidth.values.firstAsInt() * imageLength.values.firstAsInt()) / + 1000000; final double roundedMegaPixels = (megaPixels * 10).round() / 10.0; _exifData['megaPixels'] = roundedMegaPixels..toStringAsFixed(1); } else { From 635f7e724fd91a26f512ef785a506a6bfd19c178 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sun, 10 Dec 2023 22:06:45 +0530 Subject: [PATCH 02/25] use const + wrap unawited future with unawaited --- lib/ui/map/map_screen.dart | 2 +- lib/ui/map/map_view.dart | 4 ++-- lib/ui/viewer/search/result/go_to_map_widget.dart | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/ui/map/map_screen.dart b/lib/ui/map/map_screen.dart index 1a5c54c9b..df692a2fe 100644 --- a/lib/ui/map/map_screen.dart +++ b/lib/ui/map/map_screen.dart @@ -45,7 +45,7 @@ class _MapScreenState extends State { double maxZoom = 18.0; double minZoom = 2.8; int debounceDuration = 500; - LatLng center = LatLng(46.7286, 4.8614); + LatLng center = const LatLng(46.7286, 4.8614); final Logger _logger = Logger("_MapScreenState"); StreamSubscription? _mapMoveSubscription; Isolate? isolate; diff --git a/lib/ui/map/map_view.dart b/lib/ui/map/map_view.dart index 471ca7098..f316a7719 100644 --- a/lib/ui/map/map_view.dart +++ b/lib/ui/map/map_view.dart @@ -77,8 +77,8 @@ class _MapViewState extends State { enableMultiFingerGestureRace: true, zoom: widget.initialZoom, maxBounds: LatLngBounds( - LatLng(-90, -180), - LatLng(90, 180), + const LatLng(-90, -180), + const LatLng(90, 180), ), onPositionChanged: (position, hasGesture) { if (position.bounds != null) { diff --git a/lib/ui/viewer/search/result/go_to_map_widget.dart b/lib/ui/viewer/search/result/go_to_map_widget.dart index e9921d363..d3e91009b 100644 --- a/lib/ui/viewer/search/result/go_to_map_widget.dart +++ b/lib/ui/viewer/search/result/go_to_map_widget.dart @@ -1,3 +1,5 @@ +import "dart:async"; + import "package:flutter/material.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/services/search_service.dart"; @@ -22,10 +24,12 @@ class GoToMapWidget extends StatelessWidget { onTap: () async { final bool result = await requestForMapEnable(context); if (result) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => MapScreen( - filesFutureFn: SearchService.instance.getAllFiles, + unawaited( + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => MapScreen( + filesFutureFn: SearchService.instance.getAllFiles, + ), ), ), ); From 841debe1812eec251fbd65cfe9019803b14b8e8a Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sun, 10 Dec 2023 22:07:32 +0530 Subject: [PATCH 03/25] Show map inside bottom sheet on clicking 'add location data' --- lib/ui/viewer/file/file_details_widget.dart | 21 ++++- .../location/add_location_data_widget.dart | 78 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 lib/ui/viewer/location/add_location_data_widget.dart diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index 0022ad226..da7485ae2 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -1,6 +1,7 @@ import "package:exif/exif.dart"; import "package:flutter/material.dart"; import "package:logging/logging.dart"; +import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; import "package:photos/core/configuration.dart"; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; @@ -8,6 +9,7 @@ import 'package:photos/models/file/file_type.dart'; import "package:photos/models/metadata/file_magic.dart"; import "package:photos/services/file_magic_service.dart"; import "package:photos/services/update_service.dart"; +import "package:photos/theme/colors.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import "package:photos/ui/components/divider_widget.dart"; @@ -22,6 +24,7 @@ import 'package:photos/ui/viewer/file_details/exif_item_widgets.dart'; import "package:photos/ui/viewer/file_details/file_properties_item_widget.dart"; import "package:photos/ui/viewer/file_details/location_tags_widget.dart"; import "package:photos/ui/viewer/file_details/objects_item_widget.dart"; +import 'package:photos/ui/viewer/location/add_location_data_widget.dart'; import "package:photos/utils/exif_util.dart"; class FileDetailsWidget extends StatefulWidget { @@ -87,6 +90,7 @@ class _FileDetailsWidgetState extends State { getExif(widget.file).then((exif) { _exifNotifier.value = exif; }); + super.initState(); } @@ -172,7 +176,22 @@ class _FileDetailsWidgetState extends State { ], ), hasChipButtons: false, - onTap: () {}, + onTap: () { + showBarModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(5), + ), + ), + backgroundColor: + getEnteColorScheme(context).backgroundElevated, + barrierColor: backdropFaintDark, + context: context, + builder: (context) { + return const AddLocationDataWidget(); + }, + ); + }, ), const FileDetailsDivider(), ], diff --git a/lib/ui/viewer/location/add_location_data_widget.dart b/lib/ui/viewer/location/add_location_data_widget.dart new file mode 100644 index 000000000..f7e089584 --- /dev/null +++ b/lib/ui/viewer/location/add_location_data_widget.dart @@ -0,0 +1,78 @@ +import "package:flutter/material.dart"; +import "package:flutter_map/flutter_map.dart"; +import "package:photos/ui/map/map_button.dart"; +import "package:photos/ui/map/tile/layers.dart"; + +class AddLocationDataWidget extends StatefulWidget { + const AddLocationDataWidget({super.key}); + + @override + State createState() => _AddLocationDataWidgetState(); +} + +class _AddLocationDataWidgetState extends State { + final MapController _mapController = MapController(); + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + _mapController.dispose(); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + FlutterMap( + mapController: _mapController, + options: MapOptions( + zoom: 3, + maxZoom: 18.0, + minZoom: 2.8, + onTap: (tapPosition, latlng) { + print(latlng); + }, + ), + children: const [ + OSMFranceTileLayer(), + ], + ), + Positioned( + // bottom: widget.bottomSheetDraggableAreaHeight + 10, + bottom: 30, + + right: 10, + child: Column( + children: [ + MapButton( + icon: Icons.add, + onPressed: () { + _mapController.move( + _mapController.center, + _mapController.zoom + 1, + ); + }, + heroTag: 'zoom-in', + ), + MapButton( + icon: Icons.remove, + onPressed: () { + _mapController.move( + _mapController.center, + _mapController.zoom - 1, + ); + }, + heroTag: 'zoom-out', + ), + ], + ), + ), + ], + ); + } +} From 8ea0254a82c3275757c705dce65f34ea027248f5 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sun, 10 Dec 2023 23:06:07 +0530 Subject: [PATCH 04/25] built basic UI for choosing location --- .../location/add_location_data_widget.dart | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/ui/viewer/location/add_location_data_widget.dart b/lib/ui/viewer/location/add_location_data_widget.dart index f7e089584..ebc1e0e0a 100644 --- a/lib/ui/viewer/location/add_location_data_widget.dart +++ b/lib/ui/viewer/location/add_location_data_widget.dart @@ -1,5 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_map/flutter_map.dart"; +import "package:latlong2/latlong.dart"; import "package:photos/ui/map/map_button.dart"; import "package:photos/ui/map/tile/layers.dart"; @@ -12,6 +13,7 @@ class AddLocationDataWidget extends StatefulWidget { class _AddLocationDataWidgetState extends State { final MapController _mapController = MapController(); + ValueNotifier selectedLocation = ValueNotifier(null); @override void initState() { @@ -21,6 +23,8 @@ class _AddLocationDataWidgetState extends State { @override void dispose() { super.dispose(); + selectedLocation.dispose(); + _mapController.dispose(); } @@ -35,7 +39,17 @@ class _AddLocationDataWidgetState extends State { maxZoom: 18.0, minZoom: 2.8, onTap: (tapPosition, latlng) { - print(latlng); + final zoom = selectedLocation.value == null + ? _mapController.zoom + 2.0 + : _mapController.zoom; + _mapController.move(latlng, zoom); + + selectedLocation.value = latlng; + }, + onPositionChanged: (position, hasGesture) { + if (selectedLocation.value != null) { + selectedLocation.value = position.center; + } }, ), children: const [ @@ -72,6 +86,45 @@ class _AddLocationDataWidgetState extends State { ], ), ), + ValueListenableBuilder( + valueListenable: selectedLocation, + builder: (context, value, _) { + return value != null + ? const Positioned( + bottom: 20, + top: 0, + left: 0, + right: 0, + child: Icon( + Icons.location_pin, + color: Color.fromARGB(255, 250, 34, 19), + size: 40, + ), + ) + : const SizedBox.shrink(); + }, + ), + ValueListenableBuilder( + valueListenable: selectedLocation, + builder: (context, value, _) { + return value != null + ? Positioned( + left: 0, + right: 0, + child: Row( + children: [ + Text( + selectedLocation.value.toString(), + style: const TextStyle( + color: Colors.black, + ), + ), + ], + ), + ) + : const SizedBox.shrink(); + }, + ), ], ); } From dd0463f020594b317498ec80bd323045c40ab29c Mon Sep 17 00:00:00 2001 From: ashilkn Date: Mon, 11 Dec 2023 13:41:57 +0530 Subject: [PATCH 05/25] Changes to UI/UX of map --- .../location/add_location_data_widget.dart | 50 +++++++------------ 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/lib/ui/viewer/location/add_location_data_widget.dart b/lib/ui/viewer/location/add_location_data_widget.dart index ebc1e0e0a..ffdf51d38 100644 --- a/lib/ui/viewer/location/add_location_data_widget.dart +++ b/lib/ui/viewer/location/add_location_data_widget.dart @@ -13,7 +13,8 @@ class AddLocationDataWidget extends StatefulWidget { class _AddLocationDataWidgetState extends State { final MapController _mapController = MapController(); - ValueNotifier selectedLocation = ValueNotifier(null); + LatLng? selectedLocation; + ValueNotifier hasSelectedLocation = ValueNotifier(false); @override void initState() { @@ -23,7 +24,6 @@ class _AddLocationDataWidgetState extends State { @override void dispose() { super.dispose(); - selectedLocation.dispose(); _mapController.dispose(); } @@ -39,16 +39,17 @@ class _AddLocationDataWidgetState extends State { maxZoom: 18.0, minZoom: 2.8, onTap: (tapPosition, latlng) { - final zoom = selectedLocation.value == null + final zoom = selectedLocation == null ? _mapController.zoom + 2.0 : _mapController.zoom; _mapController.move(latlng, zoom); - selectedLocation.value = latlng; + selectedLocation = latlng; + hasSelectedLocation.value = true; }, onPositionChanged: (position, hasGesture) { - if (selectedLocation.value != null) { - selectedLocation.value = position.center; + if (selectedLocation != null) { + selectedLocation = position.center; } }, ), @@ -63,6 +64,14 @@ class _AddLocationDataWidgetState extends State { right: 10, child: Column( children: [ + MapButton( + // icon: Icons.add_location_alt_outlined, + icon: Icons.check, + + onPressed: () {}, + heroTag: 'zoom-in', + ), + const SizedBox(height: 16), MapButton( icon: Icons.add, onPressed: () { @@ -87,39 +96,18 @@ class _AddLocationDataWidgetState extends State { ), ), ValueListenableBuilder( - valueListenable: selectedLocation, + valueListenable: hasSelectedLocation, builder: (context, value, _) { - return value != null + return value ? const Positioned( - bottom: 20, + bottom: 16, top: 0, left: 0, right: 0, child: Icon( Icons.location_pin, color: Color.fromARGB(255, 250, 34, 19), - size: 40, - ), - ) - : const SizedBox.shrink(); - }, - ), - ValueListenableBuilder( - valueListenable: selectedLocation, - builder: (context, value, _) { - return value != null - ? Positioned( - left: 0, - right: 0, - child: Row( - children: [ - Text( - selectedLocation.value.toString(), - style: const TextStyle( - color: Colors.black, - ), - ), - ], + size: 32, ), ) : const SizedBox.shrink(); From a1d4873e88cc7268d44eb40ae12a6606991ff58c Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 12 Dec 2023 15:33:57 +0530 Subject: [PATCH 06/25] change name of file and widget used to update location data --- lib/ui/viewer/file/file_details_widget.dart | 4 ++-- ...dget.dart => update_location_data_widget.dart} | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) rename lib/ui/viewer/location/{add_location_data_widget.dart => update_location_data_widget.dart} (87%) diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index da7485ae2..92e080cf7 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -24,7 +24,7 @@ import 'package:photos/ui/viewer/file_details/exif_item_widgets.dart'; import "package:photos/ui/viewer/file_details/file_properties_item_widget.dart"; import "package:photos/ui/viewer/file_details/location_tags_widget.dart"; import "package:photos/ui/viewer/file_details/objects_item_widget.dart"; -import 'package:photos/ui/viewer/location/add_location_data_widget.dart'; +import 'package:photos/ui/viewer/location/update_location_data_widget.dart'; import "package:photos/utils/exif_util.dart"; class FileDetailsWidget extends StatefulWidget { @@ -188,7 +188,7 @@ class _FileDetailsWidgetState extends State { barrierColor: backdropFaintDark, context: context, builder: (context) { - return const AddLocationDataWidget(); + return UpdateLocationDataWidget([file]); }, ); }, diff --git a/lib/ui/viewer/location/add_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart similarity index 87% rename from lib/ui/viewer/location/add_location_data_widget.dart rename to lib/ui/viewer/location/update_location_data_widget.dart index ffdf51d38..fe2377625 100644 --- a/lib/ui/viewer/location/add_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -1,17 +1,20 @@ import "package:flutter/material.dart"; import "package:flutter_map/flutter_map.dart"; import "package:latlong2/latlong.dart"; +import "package:photos/models/file/file.dart"; import "package:photos/ui/map/map_button.dart"; import "package:photos/ui/map/tile/layers.dart"; -class AddLocationDataWidget extends StatefulWidget { - const AddLocationDataWidget({super.key}); +class UpdateLocationDataWidget extends StatefulWidget { + final List files; + const UpdateLocationDataWidget(this.files, {super.key}); @override - State createState() => _AddLocationDataWidgetState(); + State createState() => + _UpdateLocationDataWidgetState(); } -class _AddLocationDataWidgetState extends State { +class _UpdateLocationDataWidgetState extends State { final MapController _mapController = MapController(); LatLng? selectedLocation; ValueNotifier hasSelectedLocation = ValueNotifier(false); @@ -24,7 +27,7 @@ class _AddLocationDataWidgetState extends State { @override void dispose() { super.dispose(); - + hasSelectedLocation.dispose(); _mapController.dispose(); } @@ -69,7 +72,7 @@ class _AddLocationDataWidgetState extends State { icon: Icons.check, onPressed: () {}, - heroTag: 'zoom-in', + heroTag: 'add-location', ), const SizedBox(height: 16), MapButton( From e2f9ce717a009a94e9c8fc1264117e951c897786 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 12 Dec 2023 15:46:34 +0530 Subject: [PATCH 07/25] wrote service method to update location data --- lib/services/files_service.dart | 33 +++++++++++++++++++ .../location/update_location_data_widget.dart | 6 +++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index d97b8a25e..8f3869d92 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import "package:latlong2/latlong.dart"; import 'package:logging/logging.dart'; import 'package:path/path.dart'; import 'package:photos/core/configuration.dart'; @@ -85,6 +86,38 @@ class FilesService { } } + Future bulkEditLocationData( + List files, + LatLng location, + ) async { + final List uploadedFiles = + files.where((element) => element.uploadedFileID != null).toList(); + + final List remoteFilesToUpdate = []; + final Map> fileIDToUpdateMetadata = {}; + for (EnteFile remoteFile in uploadedFiles) { + // discard files not owned by user and also dedupe already processed + // files + if (remoteFile.ownerID != _config.getUserID()! || + fileIDToUpdateMetadata.containsKey(remoteFile.uploadedFileID!)) { + continue; + } + + remoteFilesToUpdate.add(remoteFile); + fileIDToUpdateMetadata[remoteFile.uploadedFileID!] = { + latKey: location.latitude, + longKey: location.longitude, + }; + } + if (remoteFilesToUpdate.isNotEmpty) { + await FileMagicService.instance.updatePublicMagicMetadata( + remoteFilesToUpdate, + null, + metadataUpdateMap: fileIDToUpdateMetadata, + ); + } + } + // Note: this method is not used anywhere, but it is kept for future // reference when we add bulk EditTime feature Future bulkEditTime( diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index fe2377625..1a33ceab1 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "package:flutter_map/flutter_map.dart"; import "package:latlong2/latlong.dart"; import "package:photos/models/file/file.dart"; +import "package:photos/services/files_service.dart"; import "package:photos/ui/map/map_button.dart"; import "package:photos/ui/map/tile/layers.dart"; @@ -71,7 +72,10 @@ class _UpdateLocationDataWidgetState extends State { // icon: Icons.add_location_alt_outlined, icon: Icons.check, - onPressed: () {}, + onPressed: () async { + await FilesService.instance + .bulkEditLocationData(widget.files, selectedLocation!); + }, heroTag: 'add-location', ), const SizedBox(height: 16), From 1339101d9410f7cb4dbfd12eed2a10013487a80d Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 12 Dec 2023 16:05:54 +0530 Subject: [PATCH 08/25] show option to edit location data for photos that already have location data --- lib/ui/viewer/file/file_details_widget.dart | 2 +- .../file_details/location_tags_widget.dart | 30 +++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index 92e080cf7..00ee29f37 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -157,7 +157,7 @@ class _FileDetailsWidgetState extends State { ? Column( children: [ LocationTagsWidget( - widget.file.location!, + widget.file, ), const FileDetailsDivider(), ], diff --git a/lib/ui/viewer/file_details/location_tags_widget.dart b/lib/ui/viewer/file_details/location_tags_widget.dart index b8b5ab78e..1f22121f1 100644 --- a/lib/ui/viewer/file_details/location_tags_widget.dart +++ b/lib/ui/viewer/file_details/location_tags_widget.dart @@ -1,22 +1,25 @@ import "dart:async"; import "package:flutter/material.dart"; +import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/location_tag_updated_event.dart"; import "package:photos/generated/l10n.dart"; -import "package:photos/models/location/location.dart"; +import "package:photos/models/file/file.dart"; import "package:photos/services/location_service.dart"; import "package:photos/states/location_screen_state.dart"; +import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/components/buttons/chip_button_widget.dart"; import "package:photos/ui/components/info_item_widget.dart"; import 'package:photos/ui/viewer/location/add_location_sheet.dart'; import "package:photos/ui/viewer/location/location_screen.dart"; +import "package:photos/ui/viewer/location/update_location_data_widget.dart"; import "package:photos/utils/navigation_util.dart"; class LocationTagsWidget extends StatefulWidget { - final Location centerPoint; - const LocationTagsWidget(this.centerPoint, {super.key}); + final EnteFile file; + const LocationTagsWidget(this.file, {super.key}); @override State createState() => _LocationTagsWidgetState(); @@ -58,13 +61,28 @@ class _LocationTagsWidgetState extends State { subtitleSection: locationTagChips, hasChipButtons: hasChipButtons ?? true, onTap: onTap, + editOnTap: () { + showBarModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(5), + ), + ), + backgroundColor: getEnteColorScheme(context).backgroundElevated, + barrierColor: backdropFaintDark, + context: context, + builder: (context) { + return UpdateLocationDataWidget([widget.file]); + }, + ); + }, ), ); } Future> _getLocationTags() async { final locationTags = await LocationService.instance - .enclosingLocationTags(widget.centerPoint); + .enclosingLocationTags(widget.file.location!); if (locationTags.isEmpty) { if (mounted) { setState(() { @@ -73,7 +91,7 @@ class _LocationTagsWidgetState extends State { hasChipButtons = false; onTap = () => showAddLocationSheet( context, - widget.centerPoint, + widget.file.location!, ); }); } @@ -112,7 +130,7 @@ class _LocationTagsWidgetState extends State { ChipButtonWidget( null, leadingIcon: Icons.add_outlined, - onTap: () => showAddLocationSheet(context, widget.centerPoint), + onTap: () => showAddLocationSheet(context, widget.file.location!), ), ); return result; From 0a6a4c6835c75360ed4e9c500d169af4b536d362 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 12 Dec 2023 16:54:04 +0530 Subject: [PATCH 09/25] add option to update location for all file types except for videos --- lib/ui/viewer/file/file_details_widget.dart | 66 +++++++++++---------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index 00ee29f37..cc27fe300 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -162,40 +162,42 @@ class _FileDetailsWidgetState extends State { const FileDetailsDivider(), ], ) - : Column( - children: [ - InfoItemWidget( - leadingIcon: Icons.pin_drop_outlined, - title: "No location data", - subtitleSection: Future.value( - [ - Text( - "Add location data", - style: getEnteTextTheme(context).miniBoldMuted, - ), - ], - ), - hasChipButtons: false, - onTap: () { - showBarModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(5), - ), + : file.fileType != FileType.video + ? Column( + children: [ + InfoItemWidget( + leadingIcon: Icons.pin_drop_outlined, + title: "No location data", + subtitleSection: Future.value( + [ + Text( + "Add location data", + style: getEnteTextTheme(context).miniBoldMuted, + ), + ], ), - backgroundColor: - getEnteColorScheme(context).backgroundElevated, - barrierColor: backdropFaintDark, - context: context, - builder: (context) { - return UpdateLocationDataWidget([file]); + hasChipButtons: false, + onTap: () async { + await showBarModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(5), + ), + ), + backgroundColor: getEnteColorScheme(context) + .backgroundElevated, + barrierColor: backdropFaintDark, + context: context, + builder: (context) { + return UpdateLocationDataWidget([file]); + }, + ); }, - ); - }, - ), - const FileDetailsDivider(), - ], - ); + ), + const FileDetailsDivider(), + ], + ) + : const SizedBox.shrink(); }, ), ]); From 131a83afe6bebb06a3c6e8acd0dd925367fda68e Mon Sep 17 00:00:00 2001 From: ashilkn Date: Tue, 12 Dec 2023 19:28:23 +0530 Subject: [PATCH 10/25] add support for editing location data of more than one file by selecting from gallery --- lib/models/gallery_type.dart | 4 +++ .../file_selection_actions_widget.dart | 34 +++++++++++++++++++ .../location/update_location_data_widget.dart | 2 ++ 3 files changed, 40 insertions(+) diff --git a/lib/models/gallery_type.dart b/lib/models/gallery_type.dart index a90ba8f95..351b10ce0 100644 --- a/lib/models/gallery_type.dart +++ b/lib/models/gallery_type.dart @@ -242,6 +242,10 @@ extension GalleyTypeExtension on GalleryType { bool showRemoveFromHiddenAlbum() { return this == GalleryType.hiddenOwnedCollection; } + + bool showEditLocation() { + return this != GalleryType.sharedCollection; + } } extension GalleryAppBarExtn on GalleryType { diff --git a/lib/ui/viewer/actions/file_selection_actions_widget.dart b/lib/ui/viewer/actions/file_selection_actions_widget.dart index dbbf5c4df..18039ab0d 100644 --- a/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -1,6 +1,7 @@ import 'package:fast_base58/fast_base58.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; import 'package:photos/core/configuration.dart'; import "package:photos/generated/l10n.dart"; import 'package:photos/models/collection/collection.dart'; @@ -13,6 +14,8 @@ import "package:photos/models/metadata/common_keys.dart"; import 'package:photos/models/selected_files.dart'; import 'package:photos/services/collections_service.dart'; import 'package:photos/services/hidden_service.dart'; +import "package:photos/theme/colors.dart"; +import "package:photos/theme/ente_theme.dart"; import 'package:photos/ui/actions/collection/collection_file_actions.dart'; import 'package:photos/ui/actions/collection/collection_sharing_actions.dart'; import 'package:photos/ui/collections/collection_action_sheet.dart'; @@ -22,6 +25,7 @@ import 'package:photos/ui/components/buttons/button_widget.dart'; import 'package:photos/ui/components/models/button_type.dart'; import 'package:photos/ui/sharing/manage_links_widget.dart'; import "package:photos/ui/tools/collage/collage_creator_page.dart"; +import "package:photos/ui/viewer/location/update_location_data_widget.dart"; import 'package:photos/utils/delete_file_util.dart'; import 'package:photos/utils/magic_util.dart'; import 'package:photos/utils/navigation_util.dart'; @@ -309,6 +313,36 @@ class _FileSelectionActionsWidgetState ); } + if (widget.type.showEditLocation()) { + items.add( + SelectionActionButton( + shouldShow: widget.selectedFiles.files.any( + (element) => (element.fileType != FileType.video && + element.ownerID == currentUserID), + ), + labelText: "Edit location", + icon: Icons.edit_location_alt_outlined, + onTap: () async { + await showBarModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(5), + ), + ), + backgroundColor: getEnteColorScheme(context).backgroundElevated, + barrierColor: backdropFaintDark, + context: context, + builder: (context) { + return UpdateLocationDataWidget( + widget.selectedFiles.files.toList(), + ); + }, + ); + }, + ), + ); + } + items.add( SelectionActionButton( icon: Icons.grid_view_outlined, diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index 1a33ceab1..7d5367485 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -75,7 +75,9 @@ class _UpdateLocationDataWidgetState extends State { onPressed: () async { await FilesService.instance .bulkEditLocationData(widget.files, selectedLocation!); + Navigator.of(context).pop(); }, + heroTag: 'add-location', ), const SizedBox(height: 16), From 3c00672aefaf0d37e5fcb17b9514b15989572f76 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Thu, 14 Dec 2023 06:15:48 +0530 Subject: [PATCH 11/25] Add support for resetting location data to original location data from exif or removing location data for files without location data in exif --- lib/models/file/file.dart | 2 + lib/services/files_service.dart | 132 ++++++++++++++++-- .../location/update_location_data_widget.dart | 16 ++- lib/utils/exif_util.dart | 4 +- 4 files changed, 137 insertions(+), 17 deletions(-) diff --git a/lib/models/file/file.dart b/lib/models/file/file.dart index a0481cd39..208cfa790 100644 --- a/lib/models/file/file.dart +++ b/lib/models/file/file.dart @@ -14,6 +14,7 @@ import 'package:photos/utils/date_time_util.dart'; import 'package:photos/utils/exif_util.dart'; import 'package:photos/utils/file_uploader_util.dart'; +//Todo: files with no location data have lat and long set to 0.0. This should ideally be null. class EnteFile { int? generatedID; int? uploadedFileID; @@ -271,6 +272,7 @@ class EnteFile { int get width { return pubMagicMetadata?.w ?? 0; } + bool get hasDimensions { return height != 0 && width != 0; } diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index 8f3869d92..426334832 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import "package:flutter/material.dart"; import "package:latlong2/latlong.dart"; import 'package:logging/logging.dart'; import 'package:path/path.dart'; @@ -6,12 +7,17 @@ import 'package:photos/core/configuration.dart'; import 'package:photos/core/network/network.dart'; import 'package:photos/db/files_db.dart'; import 'package:photos/extensions/list.dart'; +import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; import "package:photos/models/file_load_result.dart"; import "package:photos/models/metadata/file_magic.dart"; import 'package:photos/services/file_magic_service.dart'; import "package:photos/services/ignored_files_service.dart"; +import "package:photos/ui/components/action_sheet_widget.dart"; +import "package:photos/ui/components/buttons/button_widget.dart"; +import "package:photos/ui/components/models/button_type.dart"; import 'package:photos/utils/date_time_util.dart'; +import "package:photos/utils/exif_util.dart"; class FilesService { late Dio _enteDio; @@ -88,27 +94,39 @@ class FilesService { Future bulkEditLocationData( List files, - LatLng location, + LatLng? location, + BuildContext context, ) async { final List uploadedFiles = files.where((element) => element.uploadedFileID != null).toList(); final List remoteFilesToUpdate = []; final Map> fileIDToUpdateMetadata = {}; - for (EnteFile remoteFile in uploadedFiles) { - // discard files not owned by user and also dedupe already processed - // files - if (remoteFile.ownerID != _config.getUserID()! || - fileIDToUpdateMetadata.containsKey(remoteFile.uploadedFileID!)) { - continue; - } - remoteFilesToUpdate.add(remoteFile); - fileIDToUpdateMetadata[remoteFile.uploadedFileID!] = { - latKey: location.latitude, - longKey: location.longitude, - }; + if (location == null) { + await _processFilesForBulkRemoveLocation( + remoteFilesToUpdate, + uploadedFiles, + fileIDToUpdateMetadata, + context, + ); + } else { + for (EnteFile remoteFile in uploadedFiles) { + // discard files not owned by user and also dedupe already processed + // files + if (remoteFile.ownerID != _config.getUserID()! || + fileIDToUpdateMetadata.containsKey(remoteFile.uploadedFileID!)) { + continue; + } + + remoteFilesToUpdate.add(remoteFile); + fileIDToUpdateMetadata[remoteFile.uploadedFileID!] = { + latKey: location.latitude, + longKey: location.longitude, + }; + } } + if (remoteFilesToUpdate.isNotEmpty) { await FileMagicService.instance.updatePublicMagicMetadata( remoteFilesToUpdate, @@ -118,6 +136,94 @@ class FilesService { } } + Future _processFilesForBulkRemoveLocation( + List remoteFilesToUpdate, + List uploadedFiles, + Map> fileIDToUpdateMetadata, + BuildContext context, + ) async { + final filesWithOgLocation = []; + final filesWithoutOgLocation = []; + for (EnteFile remoteFile in uploadedFiles) { + // discard files not owned by user and also dedupe files + if (remoteFile.ownerID != _config.getUserID()! || + filesWithoutOgLocation.any( + (file) => file.uploadedFileID == remoteFile.uploadedFileID, + ) || + filesWithOgLocation.any( + (file) => file.uploadedFileID == remoteFile.uploadedFileID, + )) { + continue; + } + final exif = await getExif(remoteFile); + final locationFromExif = gpsDataFromExif(exif).toLocationObj(); + locationFromExif == null + ? filesWithoutOgLocation.add(remoteFile) + : filesWithOgLocation.add(remoteFile); + } + if (filesWithOgLocation.isEmpty && filesWithoutOgLocation.isEmpty) { + _logger.info( + "Skipping bulkRemoveLocation, no owned files to remove location data from", + ); + return; + } + if (filesWithoutOgLocation.isEmpty) { + remoteFilesToUpdate.addAll(filesWithOgLocation); + } else { + final buttons = [ + ButtonWidget( + labelText: "All items", + buttonType: ButtonType.neutral, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.first, + shouldSurfaceExecutionStates: true, + isInAlert: true, + onTap: () async { + remoteFilesToUpdate.addAll( + [...filesWithOgLocation, ...filesWithoutOgLocation], + ); + }, + ), + ButtonWidget( + labelText: "Items with location data", + buttonType: ButtonType.neutral, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.first, + shouldSurfaceExecutionStates: true, + isInAlert: true, + onTap: () async { + remoteFilesToUpdate.addAll(filesWithOgLocation); + }, + ), + ButtonWidget( + labelText: S.of(context).cancel, + buttonType: ButtonType.secondary, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.fourth, + isInAlert: true, + ), + ]; + + await showActionSheet( + context: context, + buttons: buttons, + title: "Choose items to reset", + body: + "Some items selected never had location data in the first place.\n\nResetting location data for such items will delete its custom location data", + ); + } + + for (var element in remoteFilesToUpdate) { + fileIDToUpdateMetadata[element.uploadedFileID!] = { + latKey: null, + longKey: null, + }; + } + } + // Note: this method is not used anywhere, but it is kept for future // reference when we add bulk EditTime feature Future bulkEditTime( diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index 7d5367485..c67585667 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -68,13 +68,25 @@ class _UpdateLocationDataWidgetState extends State { right: 10, child: Column( children: [ + MapButton( + icon: Icons.undo, + onPressed: () async { + await FilesService.instance + .bulkEditLocationData(widget.files, null, context); + Navigator.of(context).pop(); + }, + heroTag: "revert-to-og-location", + ), MapButton( // icon: Icons.add_location_alt_outlined, icon: Icons.check, onPressed: () async { - await FilesService.instance - .bulkEditLocationData(widget.files, selectedLocation!); + await FilesService.instance.bulkEditLocationData( + widget.files, + selectedLocation!, + context, + ); Navigator.of(context).pop(); }, diff --git a/lib/utils/exif_util.dart b/lib/utils/exif_util.dart index 7e8a99fbd..aa7ed4887 100644 --- a/lib/utils/exif_util.dart +++ b/lib/utils/exif_util.dart @@ -66,7 +66,7 @@ Future getCreationTimeFromEXIF( Location? locationFromExif(Map exif) { try { - return _gpsDataFromExif(exif).toLocationObj(); + return gpsDataFromExif(exif).toLocationObj(); } catch (e, s) { _logger.severe("failed to get location from exif", e, s); return null; @@ -85,7 +85,7 @@ Future> readExifAsync(File file) async { ); } -GPSData _gpsDataFromExif(Map exif) { +GPSData gpsDataFromExif(Map exif) { final Map exifLocationData = { "lat": null, "long": null, From 8bf92fb5f5374673c88715f50cf75c453db6d1a8 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Thu, 14 Dec 2023 11:43:20 +0530 Subject: [PATCH 12/25] minor change --- lib/services/files_service.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index 426334832..aa2bd4e66 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -167,6 +167,7 @@ class FilesService { ); return; } + if (filesWithoutOgLocation.isEmpty) { remoteFilesToUpdate.addAll(filesWithOgLocation); } else { @@ -211,8 +212,9 @@ class FilesService { context: context, buttons: buttons, title: "Choose items to reset", - body: - "Some items selected never had location data in the first place.\n\nResetting location data for such items will delete its custom location data", + body: "Some items selected never had location data in the first place", + bodyHighlight: + "Resetting location data for such items will delete its custom location data", ); } From 6f33a52f7372b1879cc627d465954a279351a23b Mon Sep 17 00:00:00 2001 From: ashilkn Date: Thu, 14 Dec 2023 12:14:43 +0530 Subject: [PATCH 13/25] restrict changing location data of videos --- lib/services/files_service.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index aa2bd4e66..c21d5e0f7 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -9,6 +9,7 @@ import 'package:photos/db/files_db.dart'; import 'package:photos/extensions/list.dart'; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; +import "package:photos/models/file/file_type.dart"; import "package:photos/models/file_load_result.dart"; import "package:photos/models/metadata/file_magic.dart"; import 'package:photos/services/file_magic_service.dart'; @@ -97,12 +98,16 @@ class FilesService { LatLng? location, BuildContext context, ) async { - final List uploadedFiles = - files.where((element) => element.uploadedFileID != null).toList(); + final List uploadedFiles = files + .where( + (element) => + element.uploadedFileID != null && + element.fileType != FileType.video, + ) + .toList(); final List remoteFilesToUpdate = []; final Map> fileIDToUpdateMetadata = {}; - if (location == null) { await _processFilesForBulkRemoveLocation( remoteFilesToUpdate, @@ -162,9 +167,6 @@ class FilesService { : filesWithOgLocation.add(remoteFile); } if (filesWithOgLocation.isEmpty && filesWithoutOgLocation.isEmpty) { - _logger.info( - "Skipping bulkRemoveLocation, no owned files to remove location data from", - ); return; } From 5019ca808ebac52a772250ca390d8d3d9577f7a3 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 15 Dec 2023 12:10:25 +0530 Subject: [PATCH 14/25] Stop seperating files with og location and ones with not and let user choose which ones to edit/revert on. Updated dialogs shown when user edits/reverts location data --- lib/services/files_service.dart | 187 ++++++++---------- lib/ui/viewer/file/file_details_widget.dart | 3 +- .../file_details/location_tags_widget.dart | 34 ++-- 3 files changed, 107 insertions(+), 117 deletions(-) diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index c21d5e0f7..eb4eda36d 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -18,7 +18,6 @@ import "package:photos/ui/components/action_sheet_widget.dart"; import "package:photos/ui/components/buttons/button_widget.dart"; import "package:photos/ui/components/models/button_type.dart"; import 'package:photos/utils/date_time_util.dart'; -import "package:photos/utils/exif_util.dart"; class FilesService { late Dio _enteDio; @@ -109,122 +108,108 @@ class FilesService { final List remoteFilesToUpdate = []; final Map> fileIDToUpdateMetadata = {}; if (location == null) { - await _processFilesForBulkRemoveLocation( - remoteFilesToUpdate, - uploadedFiles, - fileIDToUpdateMetadata, - context, - ); - } else { - for (EnteFile remoteFile in uploadedFiles) { - // discard files not owned by user and also dedupe already processed - // files - if (remoteFile.ownerID != _config.getUserID()! || - fileIDToUpdateMetadata.containsKey(remoteFile.uploadedFileID!)) { - continue; - } + final buttonResult = (await showActionSheet( + context: context, + body: "Revert to original location for all items?", + buttons: [ + ButtonWidget( + labelText: "Yes", + buttonType: ButtonType.neutral, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.first, + shouldSurfaceExecutionStates: true, + isInAlert: true, + onTap: () async { + await _editLocationData( + uploadedFiles, + fileIDToUpdateMetadata, + remoteFilesToUpdate, + location, + ); + }, + ), + ButtonWidget( + labelText: S.of(context).cancel, + buttonType: ButtonType.secondary, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.cancel, + isInAlert: true, + ), + ], + ))!; - remoteFilesToUpdate.add(remoteFile); - fileIDToUpdateMetadata[remoteFile.uploadedFileID!] = { - latKey: location.latitude, - longKey: location.longitude, - }; + if (buttonResult.action == ButtonAction.cancel) { + return; } - } + } else { + final buttonResult = (await showActionSheet( + context: context, + body: "Change location of selected items?", + bodyHighlight: "You can revert back to the original location anytime", + buttons: [ + ButtonWidget( + labelText: "Yes", + buttonType: ButtonType.neutral, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.first, + shouldSurfaceExecutionStates: true, + isInAlert: true, + onTap: () async { + await _editLocationData( + uploadedFiles, + fileIDToUpdateMetadata, + remoteFilesToUpdate, + location, + ); + }, + ), + ButtonWidget( + labelText: S.of(context).cancel, + buttonType: ButtonType.secondary, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.cancel, + isInAlert: true, + ), + ], + ))!; - if (remoteFilesToUpdate.isNotEmpty) { - await FileMagicService.instance.updatePublicMagicMetadata( - remoteFilesToUpdate, - null, - metadataUpdateMap: fileIDToUpdateMetadata, - ); + if (buttonResult.action == ButtonAction.cancel) { + return; + } } } - Future _processFilesForBulkRemoveLocation( - List remoteFilesToUpdate, + Future _editLocationData( List uploadedFiles, Map> fileIDToUpdateMetadata, - BuildContext context, + List remoteFilesToUpdate, + LatLng? location, ) async { - final filesWithOgLocation = []; - final filesWithoutOgLocation = []; for (EnteFile remoteFile in uploadedFiles) { - // discard files not owned by user and also dedupe files + // discard files not owned by user and also dedupe already processed + // files if (remoteFile.ownerID != _config.getUserID()! || - filesWithoutOgLocation.any( - (file) => file.uploadedFileID == remoteFile.uploadedFileID, - ) || - filesWithOgLocation.any( - (file) => file.uploadedFileID == remoteFile.uploadedFileID, - )) { + fileIDToUpdateMetadata.containsKey(remoteFile.uploadedFileID!)) { continue; } - final exif = await getExif(remoteFile); - final locationFromExif = gpsDataFromExif(exif).toLocationObj(); - locationFromExif == null - ? filesWithoutOgLocation.add(remoteFile) - : filesWithOgLocation.add(remoteFile); - } - if (filesWithOgLocation.isEmpty && filesWithoutOgLocation.isEmpty) { - return; - } - if (filesWithoutOgLocation.isEmpty) { - remoteFilesToUpdate.addAll(filesWithOgLocation); - } else { - final buttons = [ - ButtonWidget( - labelText: "All items", - buttonType: ButtonType.neutral, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.first, - shouldSurfaceExecutionStates: true, - isInAlert: true, - onTap: () async { - remoteFilesToUpdate.addAll( - [...filesWithOgLocation, ...filesWithoutOgLocation], - ); - }, - ), - ButtonWidget( - labelText: "Items with location data", - buttonType: ButtonType.neutral, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.first, - shouldSurfaceExecutionStates: true, - isInAlert: true, - onTap: () async { - remoteFilesToUpdate.addAll(filesWithOgLocation); - }, - ), - ButtonWidget( - labelText: S.of(context).cancel, - buttonType: ButtonType.secondary, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.fourth, - isInAlert: true, - ), - ]; - - await showActionSheet( - context: context, - buttons: buttons, - title: "Choose items to reset", - body: "Some items selected never had location data in the first place", - bodyHighlight: - "Resetting location data for such items will delete its custom location data", - ); + remoteFilesToUpdate.add(remoteFile); + fileIDToUpdateMetadata[remoteFile.uploadedFileID!] = { + latKey: location?.latitude, + longKey: location?.longitude, + }; } - for (var element in remoteFilesToUpdate) { - fileIDToUpdateMetadata[element.uploadedFileID!] = { - latKey: null, - longKey: null, - }; + if (remoteFilesToUpdate.isNotEmpty) { + await FileMagicService.instance.updatePublicMagicMetadata( + remoteFilesToUpdate, + null, + metadataUpdateMap: fileIDToUpdateMetadata, + ); } } diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index cc27fe300..b1a43cdbc 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -162,7 +162,8 @@ class _FileDetailsWidgetState extends State { const FileDetailsDivider(), ], ) - : file.fileType != FileType.video + : file.fileType != FileType.video && + file.ownerID == _currentUserID ? Column( children: [ InfoItemWidget( diff --git a/lib/ui/viewer/file_details/location_tags_widget.dart b/lib/ui/viewer/file_details/location_tags_widget.dart index 1f22121f1..bfcb812fb 100644 --- a/lib/ui/viewer/file_details/location_tags_widget.dart +++ b/lib/ui/viewer/file_details/location_tags_widget.dart @@ -2,6 +2,7 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; +import "package:photos/core/configuration.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/location_tag_updated_event.dart"; import "package:photos/generated/l10n.dart"; @@ -61,21 +62,24 @@ class _LocationTagsWidgetState extends State { subtitleSection: locationTagChips, hasChipButtons: hasChipButtons ?? true, onTap: onTap, - editOnTap: () { - showBarModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(5), - ), - ), - backgroundColor: getEnteColorScheme(context).backgroundElevated, - barrierColor: backdropFaintDark, - context: context, - builder: (context) { - return UpdateLocationDataWidget([widget.file]); - }, - ); - }, + editOnTap: widget.file.ownerID == Configuration.instance.getUserID()! + ? () { + showBarModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(5), + ), + ), + backgroundColor: + getEnteColorScheme(context).backgroundElevated, + barrierColor: backdropFaintDark, + context: context, + builder: (context) { + return UpdateLocationDataWidget([widget.file]); + }, + ); + } + : null, ), ); } From 6925e46b5c9099fb0e8720372662396c6f8958a7 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 15 Dec 2023 16:44:54 +0530 Subject: [PATCH 15/25] Remove option to edit location from file info due to state issues --- lib/ui/viewer/file/file_details_widget.dart | 82 +++++++++---------- .../file_details/location_tags_widget.dart | 42 +++++----- 2 files changed, 61 insertions(+), 63 deletions(-) diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index b1a43cdbc..8c39cc927 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -1,7 +1,6 @@ import "package:exif/exif.dart"; import "package:flutter/material.dart"; import "package:logging/logging.dart"; -import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; import "package:photos/core/configuration.dart"; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; @@ -9,11 +8,9 @@ import 'package:photos/models/file/file_type.dart'; import "package:photos/models/metadata/file_magic.dart"; import "package:photos/services/file_magic_service.dart"; import "package:photos/services/update_service.dart"; -import "package:photos/theme/colors.dart"; import 'package:photos/theme/ente_theme.dart'; import 'package:photos/ui/components/buttons/icon_button_widget.dart'; import "package:photos/ui/components/divider_widget.dart"; -import "package:photos/ui/components/info_item_widget.dart"; import 'package:photos/ui/components/title_bar_widget.dart'; import 'package:photos/ui/viewer/file/file_caption_widget.dart'; import "package:photos/ui/viewer/file_details/added_by_widget.dart"; @@ -24,7 +21,6 @@ import 'package:photos/ui/viewer/file_details/exif_item_widgets.dart'; import "package:photos/ui/viewer/file_details/file_properties_item_widget.dart"; import "package:photos/ui/viewer/file_details/location_tags_widget.dart"; import "package:photos/ui/viewer/file_details/objects_item_widget.dart"; -import 'package:photos/ui/viewer/location/update_location_data_widget.dart'; import "package:photos/utils/exif_util.dart"; class FileDetailsWidget extends StatefulWidget { @@ -162,43 +158,47 @@ class _FileDetailsWidgetState extends State { const FileDetailsDivider(), ], ) - : file.fileType != FileType.video && - file.ownerID == _currentUserID - ? Column( - children: [ - InfoItemWidget( - leadingIcon: Icons.pin_drop_outlined, - title: "No location data", - subtitleSection: Future.value( - [ - Text( - "Add location data", - style: getEnteTextTheme(context).miniBoldMuted, - ), - ], - ), - hasChipButtons: false, - onTap: () async { - await showBarModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(5), - ), - ), - backgroundColor: getEnteColorScheme(context) - .backgroundElevated, - barrierColor: backdropFaintDark, - context: context, - builder: (context) { - return UpdateLocationDataWidget([file]); - }, - ); - }, - ), - const FileDetailsDivider(), - ], - ) - : const SizedBox.shrink(); + : const SizedBox.shrink(); + + ///To be used when state issues are fixed when location is updated. + // + // file.fileType != FileType.video && + // file.ownerID == _currentUserID + // ? Column( + // children: [ + // InfoItemWidget( + // leadingIcon: Icons.pin_drop_outlined, + // title: "No location data", + // subtitleSection: Future.value( + // [ + // Text( + // "Add location data", + // style: getEnteTextTheme(context).miniBoldMuted, + // ), + // ], + // ), + // hasChipButtons: false, + // onTap: () async { + // await showBarModalBottomSheet( + // shape: const RoundedRectangleBorder( + // borderRadius: BorderRadius.vertical( + // top: Radius.circular(5), + // ), + // ), + // backgroundColor: getEnteColorScheme(context) + // .backgroundElevated, + // barrierColor: backdropFaintDark, + // context: context, + // builder: (context) { + // return UpdateLocationDataWidget([file]); + // }, + // ); + // }, + // ), + // const FileDetailsDivider(), + // ], + // ) + // : const SizedBox.shrink(); }, ), ]); diff --git a/lib/ui/viewer/file_details/location_tags_widget.dart b/lib/ui/viewer/file_details/location_tags_widget.dart index bfcb812fb..713e39ecc 100644 --- a/lib/ui/viewer/file_details/location_tags_widget.dart +++ b/lib/ui/viewer/file_details/location_tags_widget.dart @@ -1,21 +1,17 @@ import "dart:async"; import "package:flutter/material.dart"; -import "package:modal_bottom_sheet/modal_bottom_sheet.dart"; -import "package:photos/core/configuration.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/location_tag_updated_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/file/file.dart"; import "package:photos/services/location_service.dart"; import "package:photos/states/location_screen_state.dart"; -import "package:photos/theme/colors.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/components/buttons/chip_button_widget.dart"; import "package:photos/ui/components/info_item_widget.dart"; import 'package:photos/ui/viewer/location/add_location_sheet.dart'; import "package:photos/ui/viewer/location/location_screen.dart"; -import "package:photos/ui/viewer/location/update_location_data_widget.dart"; import "package:photos/utils/navigation_util.dart"; class LocationTagsWidget extends StatefulWidget { @@ -62,24 +58,26 @@ class _LocationTagsWidgetState extends State { subtitleSection: locationTagChips, hasChipButtons: hasChipButtons ?? true, onTap: onTap, - editOnTap: widget.file.ownerID == Configuration.instance.getUserID()! - ? () { - showBarModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(5), - ), - ), - backgroundColor: - getEnteColorScheme(context).backgroundElevated, - barrierColor: backdropFaintDark, - context: context, - builder: (context) { - return UpdateLocationDataWidget([widget.file]); - }, - ); - } - : null, + + /// to be used when state issues are fixed when location is updated + // editOnTap: widget.file.ownerID == Configuration.instance.getUserID()! + // ? () { + // showBarModalBottomSheet( + // shape: const RoundedRectangleBorder( + // borderRadius: BorderRadius.vertical( + // top: Radius.circular(5), + // ), + // ), + // backgroundColor: + // getEnteColorScheme(context).backgroundElevated, + // barrierColor: backdropFaintDark, + // context: context, + // builder: (context) { + // return UpdateLocationDataWidget([widget.file]); + // }, + // ); + // } + // : null, ), ); } From 51422f81dbff18e70474873c75eaed9f88dbbe43 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 15 Dec 2023 16:53:44 +0530 Subject: [PATCH 16/25] remove option to revert location edits --- lib/services/files_service.dart | 105 ++++++------------ .../location/update_location_data_widget.dart | 12 -- 2 files changed, 31 insertions(+), 86 deletions(-) diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index eb4eda36d..1d7772c11 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -107,80 +107,37 @@ class FilesService { final List remoteFilesToUpdate = []; final Map> fileIDToUpdateMetadata = {}; - if (location == null) { - final buttonResult = (await showActionSheet( - context: context, - body: "Revert to original location for all items?", - buttons: [ - ButtonWidget( - labelText: "Yes", - buttonType: ButtonType.neutral, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.first, - shouldSurfaceExecutionStates: true, - isInAlert: true, - onTap: () async { - await _editLocationData( - uploadedFiles, - fileIDToUpdateMetadata, - remoteFilesToUpdate, - location, - ); - }, - ), - ButtonWidget( - labelText: S.of(context).cancel, - buttonType: ButtonType.secondary, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.cancel, - isInAlert: true, - ), - ], - ))!; - - if (buttonResult.action == ButtonAction.cancel) { - return; - } - } else { - final buttonResult = (await showActionSheet( - context: context, - body: "Change location of selected items?", - bodyHighlight: "You can revert back to the original location anytime", - buttons: [ - ButtonWidget( - labelText: "Yes", - buttonType: ButtonType.neutral, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.first, - shouldSurfaceExecutionStates: true, - isInAlert: true, - onTap: () async { - await _editLocationData( - uploadedFiles, - fileIDToUpdateMetadata, - remoteFilesToUpdate, - location, - ); - }, - ), - ButtonWidget( - labelText: S.of(context).cancel, - buttonType: ButtonType.secondary, - buttonSize: ButtonSize.large, - shouldStickToDarkTheme: true, - buttonAction: ButtonAction.cancel, - isInAlert: true, - ), - ], - ))!; - - if (buttonResult.action == ButtonAction.cancel) { - return; - } - } + await showActionSheet( + context: context, + body: "Change location of selected items?", + buttons: [ + ButtonWidget( + labelText: "Yes", + buttonType: ButtonType.neutral, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.first, + shouldSurfaceExecutionStates: true, + isInAlert: true, + onTap: () async { + await _editLocationData( + uploadedFiles, + fileIDToUpdateMetadata, + remoteFilesToUpdate, + location, + ); + }, + ), + ButtonWidget( + labelText: S.of(context).cancel, + buttonType: ButtonType.secondary, + buttonSize: ButtonSize.large, + shouldStickToDarkTheme: true, + buttonAction: ButtonAction.cancel, + isInAlert: true, + ), + ], + ); } Future _editLocationData( diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index c67585667..99dca3bfc 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -69,18 +69,7 @@ class _UpdateLocationDataWidgetState extends State { child: Column( children: [ MapButton( - icon: Icons.undo, - onPressed: () async { - await FilesService.instance - .bulkEditLocationData(widget.files, null, context); - Navigator.of(context).pop(); - }, - heroTag: "revert-to-og-location", - ), - MapButton( - // icon: Icons.add_location_alt_outlined, icon: Icons.check, - onPressed: () async { await FilesService.instance.bulkEditLocationData( widget.files, @@ -89,7 +78,6 @@ class _UpdateLocationDataWidgetState extends State { ); Navigator.of(context).pop(); }, - heroTag: 'add-location', ), const SizedBox(height: 16), From aa53bc015b864d249c26b4ef42193750db99a7a6 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 15 Dec 2023 21:50:13 +0530 Subject: [PATCH 17/25] show location coordinates in DMS when selecting location on editing --- lib/services/location_service.dart | 18 ++- .../edit_center_point_tile_widget.dart | 7 +- .../location/update_location_data_widget.dart | 109 ++++++++++++++---- 3 files changed, 106 insertions(+), 28 deletions(-) diff --git a/lib/services/location_service.dart b/lib/services/location_service.dart index 2bef2ef41..10e3bfd72 100644 --- a/lib/services/location_service.dart +++ b/lib/services/location_service.dart @@ -114,17 +114,25 @@ class LocationService { return false; } - String convertLocationToDMS(Location centerPoint) { + /// returns [lat, lng] + List? convertLocationToDMS(Location centerPoint) { + if (centerPoint.latitude == null || centerPoint.longitude == null) { + return null; + } final lat = centerPoint.latitude!; final long = centerPoint.longitude!; final latRef = lat >= 0 ? "N" : "S"; final longRef = long >= 0 ? "E" : "W"; - final latDMS = convertCoordinateToDMS(lat.abs()); - final longDMS = convertCoordinateToDMS(long.abs()); - return "${latDMS[0]}°${latDMS[1]}'${latDMS[2]}\"$latRef, ${longDMS[0]}°${longDMS[1]}'${longDMS[2]}\"$longRef"; + final latDMS = _convertCoordinateToDMS(lat.abs()); + final longDMS = _convertCoordinateToDMS(long.abs()); + + return [ + "${latDMS[0]}°${latDMS[1]}'${latDMS[2]}\" $latRef", + "${longDMS[0]}°${longDMS[1]}'${longDMS[2]}\" $longRef", + ]; } - List convertCoordinateToDMS(double coordinate) { + List _convertCoordinateToDMS(double coordinate) { final degrees = coordinate.floor(); final minutes = ((coordinate - degrees) * 60).floor(); final seconds = ((coordinate - degrees - minutes / 60) * 3600).floor(); diff --git a/lib/ui/viewer/location/edit_center_point_tile_widget.dart b/lib/ui/viewer/location/edit_center_point_tile_widget.dart index 9891bd02e..f78009b87 100644 --- a/lib/ui/viewer/location/edit_center_point_tile_widget.dart +++ b/lib/ui/viewer/location/edit_center_point_tile_widget.dart @@ -14,6 +14,9 @@ class EditCenterPointTileWidget extends StatelessWidget { Widget build(BuildContext context) { final textTheme = getEnteTextTheme(context); final colorScheme = getEnteColorScheme(context); + final centerPointInDMS = LocationService.instance.convertLocationToDMS( + InheritedLocationTagData.of(context).centerPoint, + ); return Row( children: [ Container( @@ -39,9 +42,7 @@ class EditCenterPointTileWidget extends StatelessWidget { ), const SizedBox(height: 4), Text( - LocationService.instance.convertLocationToDMS( - InheritedLocationTagData.of(context).centerPoint, - ), + "${centerPointInDMS![0]}, ${centerPointInDMS[1]}", style: textTheme.miniMuted, ), ], diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index 99dca3bfc..6ff1ca844 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -1,10 +1,17 @@ +import "dart:async"; + import "package:flutter/material.dart"; import "package:flutter_map/flutter_map.dart"; import "package:latlong2/latlong.dart"; import "package:photos/models/file/file.dart"; +import "package:photos/models/location/location.dart"; import "package:photos/services/files_service.dart"; +import "package:photos/services/location_service.dart"; +import "package:photos/theme/effects.dart"; +import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/map/map_button.dart"; import "package:photos/ui/map/tile/layers.dart"; +import "package:photos/utils/toast_util.dart"; class UpdateLocationDataWidget extends StatefulWidget { final List files; @@ -17,8 +24,8 @@ class UpdateLocationDataWidget extends StatefulWidget { class _UpdateLocationDataWidgetState extends State { final MapController _mapController = MapController(); - LatLng? selectedLocation; ValueNotifier hasSelectedLocation = ValueNotifier(false); + final selectedLocation = ValueNotifier(null); @override void initState() { @@ -29,12 +36,15 @@ class _UpdateLocationDataWidgetState extends State { void dispose() { super.dispose(); hasSelectedLocation.dispose(); + selectedLocation.dispose(); _mapController.dispose(); } @override Widget build(BuildContext context) { + final textTheme = getEnteTextTheme(context); return Stack( + alignment: Alignment.topCenter, children: [ FlutterMap( mapController: _mapController, @@ -43,17 +53,17 @@ class _UpdateLocationDataWidgetState extends State { maxZoom: 18.0, minZoom: 2.8, onTap: (tapPosition, latlng) { - final zoom = selectedLocation == null + final zoom = selectedLocation.value == null ? _mapController.zoom + 2.0 : _mapController.zoom; _mapController.move(latlng, zoom); - selectedLocation = latlng; + selectedLocation.value = latlng; hasSelectedLocation.value = true; }, onPositionChanged: (position, hasGesture) { - if (selectedLocation != null) { - selectedLocation = position.center; + if (selectedLocation.value != null) { + selectedLocation.value = position.center; } }, ), @@ -61,26 +71,62 @@ class _UpdateLocationDataWidgetState extends State { OSMFranceTileLayer(), ], ), + Positioned( + top: 24, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 10, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: getEnteColorScheme(context).backgroundElevated, + boxShadow: shadowFloatFaintLight, + ), + child: ValueListenableBuilder( + builder: (context, value, _) { + final locationInDMS = + LocationService.instance.convertLocationToDMS( + Location( + latitude: value?.latitude, + longitude: value?.longitude, + ), + ); + return locationInDMS != null + ? SizedBox( + width: 80 * MediaQuery.textScaleFactorOf(context), + child: Column( + children: [ + Text( + locationInDMS[0], + style: textTheme.mini, + ), + const SizedBox(height: 8), + Text( + locationInDMS[1], + style: textTheme.mini, + ), + ], + ), + ) + : Text( + "Select a location", + style: textTheme.mini, + ); + }, + valueListenable: selectedLocation, + ), + ), + ), Positioned( // bottom: widget.bottomSheetDraggableAreaHeight + 10, - bottom: 30, + bottom: 48, - right: 10, + right: 24, + left: 24, child: Column( + crossAxisAlignment: CrossAxisAlignment.end, children: [ - MapButton( - icon: Icons.check, - onPressed: () async { - await FilesService.instance.bulkEditLocationData( - widget.files, - selectedLocation!, - context, - ); - Navigator.of(context).pop(); - }, - heroTag: 'add-location', - ), - const SizedBox(height: 16), MapButton( icon: Icons.add, onPressed: () { @@ -91,6 +137,7 @@ class _UpdateLocationDataWidgetState extends State { }, heroTag: 'zoom-in', ), + const SizedBox(height: 8), MapButton( icon: Icons.remove, onPressed: () { @@ -101,6 +148,28 @@ class _UpdateLocationDataWidgetState extends State { }, heroTag: 'zoom-out', ), + const SizedBox(height: 8), + MapButton( + icon: Icons.check, + onPressed: () async { + if (selectedLocation.value == null) { + unawaited( + showShortToast( + context, + "Select a location first", + ), + ); + return; + } + await FilesService.instance.bulkEditLocationData( + widget.files, + selectedLocation.value, + context, + ); + Navigator.of(context).pop(); + }, + heroTag: 'add-location', + ), ], ), ), From ba407a1f517b48581722d148ca64a28295345b02 Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 15 Dec 2023 22:35:13 +0530 Subject: [PATCH 18/25] add animation and shadow to location pin when map is dragged --- .../location/update_location_data_widget.dart | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index 6ff1ca844..cab993e3a 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -26,6 +26,7 @@ class _UpdateLocationDataWidgetState extends State { final MapController _mapController = MapController(); ValueNotifier hasSelectedLocation = ValueNotifier(false); final selectedLocation = ValueNotifier(null); + final isDragging = ValueNotifier(false); @override void initState() { @@ -38,6 +39,7 @@ class _UpdateLocationDataWidgetState extends State { hasSelectedLocation.dispose(); selectedLocation.dispose(); _mapController.dispose(); + isDragging.dispose(); } @override @@ -49,9 +51,17 @@ class _UpdateLocationDataWidgetState extends State { FlutterMap( mapController: _mapController, options: MapOptions( + enableMultiFingerGestureRace: true, zoom: 3, maxZoom: 18.0, minZoom: 2.8, + onMapEvent: (p0) { + if (p0.source == MapEventSource.onDrag) { + isDragging.value = true; + } else if (p0.source == MapEventSource.dragEnd) { + isDragging.value = false; + } + }, onTap: (tapPosition, latlng) { final zoom = selectedLocation.value == null ? _mapController.zoom + 2.0 @@ -84,6 +94,7 @@ class _UpdateLocationDataWidgetState extends State { boxShadow: shadowFloatFaintLight, ), child: ValueListenableBuilder( + valueListenable: selectedLocation, builder: (context, value, _) { final locationInDMS = LocationService.instance.convertLocationToDMS( @@ -114,7 +125,6 @@ class _UpdateLocationDataWidgetState extends State { style: textTheme.mini, ); }, - valueListenable: selectedLocation, ), ), ), @@ -177,15 +187,43 @@ class _UpdateLocationDataWidgetState extends State { valueListenable: hasSelectedLocation, builder: (context, value, _) { return value - ? const Positioned( - bottom: 16, + ? Positioned( + bottom: 32, top: 0, left: 0, right: 0, - child: Icon( - Icons.location_pin, - color: Color.fromARGB(255, 250, 34, 19), - size: 32, + child: Stack( + alignment: Alignment.center, + children: [ + ValueListenableBuilder( + valueListenable: isDragging, + builder: (context, value, child) { + return AnimatedContainer( + duration: const Duration(milliseconds: 200), + height: value ? 32 : 16, + // color: Colors.yellow, + child: child, + ); + }, + child: const Icon( + Icons.location_on, + color: Color.fromARGB(255, 250, 34, 19), + size: 32, + ), + ), + Transform( + transform: Matrix4.translationValues(0, 21, 0), + child: Container( + height: 2, + width: 12, + decoration: BoxDecoration( + boxShadow: shadowMenuDark, + // borderRadius: BorderRadius.circular(2), + // color: Colors.yellow, + ), + ), + ), + ], ), ) : const SizedBox.shrink(); From c2a6aabfaaffe9e91a0dae8f39d0a6773a1e540c Mon Sep 17 00:00:00 2001 From: ashilkn Date: Fri, 15 Dec 2023 22:42:06 +0530 Subject: [PATCH 19/25] enable editing location of video files --- lib/services/files_service.dart | 10 ++-------- .../viewer/actions/file_selection_actions_widget.dart | 3 +-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index 1d7772c11..61b63c12f 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -9,7 +9,6 @@ import 'package:photos/db/files_db.dart'; import 'package:photos/extensions/list.dart'; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; -import "package:photos/models/file/file_type.dart"; import "package:photos/models/file_load_result.dart"; import "package:photos/models/metadata/file_magic.dart"; import 'package:photos/services/file_magic_service.dart'; @@ -97,13 +96,8 @@ class FilesService { LatLng? location, BuildContext context, ) async { - final List uploadedFiles = files - .where( - (element) => - element.uploadedFileID != null && - element.fileType != FileType.video, - ) - .toList(); + final List uploadedFiles = + files.where((element) => element.uploadedFileID != null).toList(); final List remoteFilesToUpdate = []; final Map> fileIDToUpdateMetadata = {}; diff --git a/lib/ui/viewer/actions/file_selection_actions_widget.dart b/lib/ui/viewer/actions/file_selection_actions_widget.dart index c46280a3e..e15f4576a 100644 --- a/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -316,8 +316,7 @@ class _FileSelectionActionsWidgetState items.add( SelectionActionButton( shouldShow: widget.selectedFiles.files.any( - (element) => (element.fileType != FileType.video && - element.ownerID == currentUserID), + (element) => (element.ownerID == currentUserID), ), labelText: "Edit location", icon: Icons.edit_location_alt_outlined, From a11a3af31707d3e6727629a27aacc8a7c368919a Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sat, 16 Dec 2023 06:02:50 +0530 Subject: [PATCH 20/25] made location non nullable in service method used for bulk editing location --- lib/services/files_service.dart | 8 ++++---- lib/ui/viewer/location/update_location_data_widget.dart | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index 61b63c12f..efef5c33c 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -93,7 +93,7 @@ class FilesService { Future bulkEditLocationData( List files, - LatLng? location, + LatLng location, BuildContext context, ) async { final List uploadedFiles = @@ -138,7 +138,7 @@ class FilesService { List uploadedFiles, Map> fileIDToUpdateMetadata, List remoteFilesToUpdate, - LatLng? location, + LatLng location, ) async { for (EnteFile remoteFile in uploadedFiles) { // discard files not owned by user and also dedupe already processed @@ -150,8 +150,8 @@ class FilesService { remoteFilesToUpdate.add(remoteFile); fileIDToUpdateMetadata[remoteFile.uploadedFileID!] = { - latKey: location?.latitude, - longKey: location?.longitude, + latKey: location.latitude, + longKey: location.longitude, }; } diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index cab993e3a..b7b5c0b99 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -173,7 +173,7 @@ class _UpdateLocationDataWidgetState extends State { } await FilesService.instance.bulkEditLocationData( widget.files, - selectedLocation.value, + selectedLocation.value!, context, ); Navigator.of(context).pop(); From 52b8e3a74cc1ee7f5bed9fcf2f19166dcda381ab Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sat, 16 Dec 2023 06:12:36 +0530 Subject: [PATCH 21/25] clean up code --- .../viewer/location/update_location_data_widget.dart | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index b7b5c0b99..982d0afe0 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -28,11 +28,6 @@ class _UpdateLocationDataWidgetState extends State { final selectedLocation = ValueNotifier(null); final isDragging = ValueNotifier(false); - @override - void initState() { - super.initState(); - } - @override void dispose() { super.dispose(); @@ -129,9 +124,7 @@ class _UpdateLocationDataWidgetState extends State { ), ), Positioned( - // bottom: widget.bottomSheetDraggableAreaHeight + 10, bottom: 48, - right: 24, left: 24, child: Column( @@ -201,7 +194,6 @@ class _UpdateLocationDataWidgetState extends State { return AnimatedContainer( duration: const Duration(milliseconds: 200), height: value ? 32 : 16, - // color: Colors.yellow, child: child, ); }, @@ -218,8 +210,6 @@ class _UpdateLocationDataWidgetState extends State { width: 12, decoration: BoxDecoration( boxShadow: shadowMenuDark, - // borderRadius: BorderRadius.circular(2), - // color: Colors.yellow, ), ), ), From aaf15892d821952c8e173635c8e9a5963eaf5e7f Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sat, 16 Dec 2023 06:53:10 +0530 Subject: [PATCH 22/25] extract strings for translation --- lib/generated/l10n.dart | 40 +++++++++++++++++++ lib/l10n/intl_cs.arb | 6 ++- lib/l10n/intl_de.arb | 6 ++- lib/l10n/intl_en.arb | 11 +++-- lib/l10n/intl_es.arb | 6 ++- lib/l10n/intl_fr.arb | 6 ++- lib/l10n/intl_it.arb | 6 ++- lib/l10n/intl_ko.arb | 6 ++- lib/l10n/intl_nl.arb | 6 ++- lib/l10n/intl_no.arb | 6 ++- lib/l10n/intl_pl.arb | 6 ++- lib/l10n/intl_pt.arb | 6 ++- lib/l10n/intl_zh.arb | 6 ++- lib/services/files_service.dart | 4 +- .../file_selection_actions_widget.dart | 2 +- .../location/update_location_data_widget.dart | 6 ++- 16 files changed, 109 insertions(+), 20 deletions(-) diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 6291e10c0..ff1cbcc22 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -8157,6 +8157,46 @@ class S { args: [], ); } + + /// `Edit location` + String get editLocation { + return Intl.message( + 'Edit location', + name: 'editLocation', + desc: '', + args: [], + ); + } + + /// `Select a location` + String get selectALocation { + return Intl.message( + 'Select a location', + name: 'selectALocation', + desc: '', + args: [], + ); + } + + /// `Select a location first` + String get selectALocationFirst { + return Intl.message( + 'Select a location first', + name: 'selectALocationFirst', + desc: '', + args: [], + ); + } + + /// `Change location of selected items?` + String get changeLocationOfSelectedItems { + return Intl.message( + 'Change location of selected items?', + name: 'changeLocationOfSelectedItems', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/intl_cs.arb b/lib/l10n/intl_cs.arb index 515bfae5a..038d7b617 100644 --- a/lib/l10n/intl_cs.arb +++ b/lib/l10n/intl_cs.arb @@ -5,5 +5,9 @@ "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", "yourMap": "Your map", "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 086da1998..1afcd1b5a 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1158,5 +1158,9 @@ "signOutFromOtherDevices": "Von anderen Geräten abmelden", "signOutOtherBody": "Falls du denkst, dass jemand dein Passwort kennen könnte, kannst du alle anderen Geräte von deinem Account abmelden.", "signOutOtherDevices": "Andere Geräte abmelden", - "doNotSignOut": "Melde dich nicht ab" + "doNotSignOut": "Melde dich nicht ab", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 37f514814..e39b977d6 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -929,8 +929,8 @@ "itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.", "error": "Error", "tempErrorContactSupportIfPersists": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.", - "networkHostLookUpErr" : "Unable to connect to Ente, please check your network settings and contact support if the error persists.", - "networkConnectionRefusedErr" : "Unable to connect to Ente, please retry after sometime. If the error persists, please contact support.", + "networkHostLookUpErr": "Unable to connect to Ente, please check your network settings and contact support if the error persists.", + "networkConnectionRefusedErr": "Unable to connect to Ente, please retry after sometime. If the error persists, please contact support.", "cachedData": "Cached data", "clearCaches": "Clear caches", "remoteImages": "Remote images", @@ -1155,9 +1155,12 @@ "contacts": "Contacts", "noInternetConnection": "No internet connection", "pleaseCheckYourInternetConnectionAndTryAgain": "Please check your internet connection and try again.", - "signOutFromOtherDevices": "Sign out from other devices", "signOutOtherBody": "If you think someone might know your password, you can force all other devices using your account to sign out.", "signOutOtherDevices": "Sign out other devices", - "doNotSignOut": "Do not sign out" + "doNotSignOut": "Do not sign out", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index d7a9aabd8..8a7bdf418 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -968,5 +968,9 @@ "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", "yourMap": "Your map", "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index deab1cabe..047f9ccb9 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1149,5 +1149,9 @@ "@addNew": { "description": "Text to add a new item (location tag, album, caption etc)" }, - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index d82d8e682..ceddbbe58 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1111,5 +1111,9 @@ "addOnPageSubtitle": "Dettagli dei componenti aggiuntivi", "yourMap": "Your map", "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_ko.arb b/lib/l10n/intl_ko.arb index 515bfae5a..038d7b617 100644 --- a/lib/l10n/intl_ko.arb +++ b/lib/l10n/intl_ko.arb @@ -5,5 +5,9 @@ "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", "yourMap": "Your map", "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index b4d60d451..07f45b66f 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -1158,5 +1158,9 @@ "signOutFromOtherDevices": "Log uit op andere apparaten", "signOutOtherBody": "Als je denkt dat iemand je wachtwoord zou kunnen kennen, kun je alle andere apparaten die je account gebruiken dwingen om uit te loggen.", "signOutOtherDevices": "Log uit op andere apparaten", - "doNotSignOut": "Niet uitloggen" + "doNotSignOut": "Niet uitloggen", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_no.arb b/lib/l10n/intl_no.arb index 8106b8ca7..88ffdc7ce 100644 --- a/lib/l10n/intl_no.arb +++ b/lib/l10n/intl_no.arb @@ -19,5 +19,9 @@ "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", "yourMap": "Your map", "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 306b0a31c..8a512258e 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -106,5 +106,9 @@ "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", "yourMap": "Your map", "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index cd674a347..029322d42 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -272,5 +272,9 @@ "deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.", "yourMap": "Your map", "modifyYourQueryOrTrySearchingFor": "Modify your query, or try searching for", - "contacts": "Contacts" + "contacts": "Contacts", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index a445e3e8e..dff07f8bf 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -1158,5 +1158,9 @@ "signOutFromOtherDevices": "从其他设备退出登录", "signOutOtherBody": "如果你认为有人可能知道你的密码,你可以强制所有使用你账户的其他设备退出登录。", "signOutOtherDevices": "登出其他设备", - "doNotSignOut": "不要退登" + "doNotSignOut": "不要退登", + "editLocation": "Edit location", + "selectALocation": "Select a location", + "selectALocationFirst": "Select a location first", + "changeLocationOfSelectedItems": "Change location of selected items?" } \ No newline at end of file diff --git a/lib/services/files_service.dart b/lib/services/files_service.dart index efef5c33c..a72db91a9 100644 --- a/lib/services/files_service.dart +++ b/lib/services/files_service.dart @@ -103,10 +103,10 @@ class FilesService { final Map> fileIDToUpdateMetadata = {}; await showActionSheet( context: context, - body: "Change location of selected items?", + body: S.of(context).changeLocationOfSelectedItems, buttons: [ ButtonWidget( - labelText: "Yes", + labelText: S.of(context).yes, buttonType: ButtonType.neutral, buttonSize: ButtonSize.large, shouldStickToDarkTheme: true, diff --git a/lib/ui/viewer/actions/file_selection_actions_widget.dart b/lib/ui/viewer/actions/file_selection_actions_widget.dart index e15f4576a..c427741ad 100644 --- a/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -318,7 +318,7 @@ class _FileSelectionActionsWidgetState shouldShow: widget.selectedFiles.files.any( (element) => (element.ownerID == currentUserID), ), - labelText: "Edit location", + labelText: S.of(context).editLocation, icon: Icons.edit_location_alt_outlined, onTap: () async { await showBarModalBottomSheet( diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index 982d0afe0..cdda98790 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -3,6 +3,7 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:flutter_map/flutter_map.dart"; import "package:latlong2/latlong.dart"; +import "package:photos/generated/l10n.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/location/location.dart"; import "package:photos/services/files_service.dart"; @@ -116,7 +117,7 @@ class _UpdateLocationDataWidgetState extends State { ), ) : Text( - "Select a location", + S.of(context).selectALocation, style: textTheme.mini, ); }, @@ -159,7 +160,7 @@ class _UpdateLocationDataWidgetState extends State { unawaited( showShortToast( context, - "Select a location first", + S.of(context).selectALocationFirst, ), ); return; @@ -192,6 +193,7 @@ class _UpdateLocationDataWidgetState extends State { valueListenable: isDragging, builder: (context, value, child) { return AnimatedContainer( + curve: Curves.easeInOut, duration: const Duration(milliseconds: 200), height: value ? 32 : 16, child: child, From 111c8885ce71c80fd6dae7ac0ddb882cf79e473c Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sat, 16 Dec 2023 07:21:48 +0530 Subject: [PATCH 23/25] increase tap area of bottom sheet on it's top for making it easier to slide it down --- .../file_selection_actions_widget.dart | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/ui/viewer/actions/file_selection_actions_widget.dart b/lib/ui/viewer/actions/file_selection_actions_widget.dart index c427741ad..589bc325a 100644 --- a/lib/ui/viewer/actions/file_selection_actions_widget.dart +++ b/lib/ui/viewer/actions/file_selection_actions_widget.dart @@ -329,6 +329,27 @@ class _FileSelectionActionsWidgetState ), backgroundColor: getEnteColorScheme(context).backgroundElevated, barrierColor: backdropFaintDark, + topControl: Stack( + alignment: Alignment.bottomCenter, + children: [ + // This container is for increasing the tap area + Container( + width: double.infinity, + height: 36, + color: Colors.transparent, + ), + Container( + height: 5, + width: 40, + decoration: const BoxDecoration( + color: backgroundElevated2Light, + borderRadius: BorderRadius.all( + Radius.circular(5), + ), + ), + ), + ], + ), context: context, builder: (context) { return UpdateLocationDataWidget( From eab3ef28629bd9174453970290cfda36a143c19b Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sat, 16 Dec 2023 07:33:12 +0530 Subject: [PATCH 24/25] added logging --- lib/ui/viewer/location/update_location_data_widget.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index cdda98790..428fe84dd 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -3,6 +3,7 @@ import "dart:async"; import "package:flutter/material.dart"; import "package:flutter_map/flutter_map.dart"; import "package:latlong2/latlong.dart"; +import "package:logging/logging.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/models/file/file.dart"; import "package:photos/models/location/location.dart"; @@ -40,6 +41,7 @@ class _UpdateLocationDataWidgetState extends State { @override Widget build(BuildContext context) { + Logger("UpdateLocationDataWiget").info("building"); final textTheme = getEnteTextTheme(context); return Stack( alignment: Alignment.topCenter, @@ -78,7 +80,7 @@ class _UpdateLocationDataWidgetState extends State { ], ), Positioned( - top: 24, + top: 20, child: Container( padding: const EdgeInsets.symmetric( horizontal: 16, From 2f528e33ac0df6467d6d5e72abd4b16af5367a2f Mon Sep 17 00:00:00 2001 From: ashilkn Date: Sat, 16 Dec 2023 12:39:07 +0530 Subject: [PATCH 25/25] show info to users that edits to location will only be seen within Ente --- lib/generated/l10n.dart | 10 +++ lib/l10n/intl_cs.arb | 3 +- lib/l10n/intl_de.arb | 3 +- lib/l10n/intl_en.arb | 3 +- lib/l10n/intl_es.arb | 3 +- lib/l10n/intl_fr.arb | 3 +- lib/l10n/intl_it.arb | 3 +- lib/l10n/intl_ko.arb | 3 +- lib/l10n/intl_nl.arb | 3 +- lib/l10n/intl_no.arb | 3 +- lib/l10n/intl_pl.arb | 3 +- lib/l10n/intl_pt.arb | 3 +- lib/l10n/intl_zh.arb | 3 +- .../location/update_location_data_widget.dart | 73 +++++++++++++++++-- 14 files changed, 101 insertions(+), 18 deletions(-) diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index ff1cbcc22..13be3c9af 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -8197,6 +8197,16 @@ class S { args: [], ); } + + /// `Edits to location will only be seen within Ente` + String get editsToLocationWillOnlyBeSeenWithinEnte { + return Intl.message( + 'Edits to location will only be seen within Ente', + name: 'editsToLocationWillOnlyBeSeenWithinEnte', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/intl_cs.arb b/lib/l10n/intl_cs.arb index 038d7b617..6a71af50f 100644 --- a/lib/l10n/intl_cs.arb +++ b/lib/l10n/intl_cs.arb @@ -9,5 +9,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 1afcd1b5a..5549ff9ef 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1162,5 +1162,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index e39b977d6..9640abb45 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1162,5 +1162,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 8a7bdf418..0720f8d3e 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -972,5 +972,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 047f9ccb9..fe9c4c64c 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1153,5 +1153,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index ceddbbe58..7df3892f5 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1115,5 +1115,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_ko.arb b/lib/l10n/intl_ko.arb index 038d7b617..6a71af50f 100644 --- a/lib/l10n/intl_ko.arb +++ b/lib/l10n/intl_ko.arb @@ -9,5 +9,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index 07f45b66f..bb8404dc4 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -1162,5 +1162,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_no.arb b/lib/l10n/intl_no.arb index 88ffdc7ce..d55787f17 100644 --- a/lib/l10n/intl_no.arb +++ b/lib/l10n/intl_no.arb @@ -23,5 +23,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 8a512258e..7dfb7abc1 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -110,5 +110,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 029322d42..e0232c58e 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -276,5 +276,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index dff07f8bf..4bb5448d0 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -1162,5 +1162,6 @@ "editLocation": "Edit location", "selectALocation": "Select a location", "selectALocationFirst": "Select a location first", - "changeLocationOfSelectedItems": "Change location of selected items?" + "changeLocationOfSelectedItems": "Change location of selected items?", + "editsToLocationWillOnlyBeSeenWithinEnte": "Edits to location will only be seen within Ente" } \ No newline at end of file diff --git a/lib/ui/viewer/location/update_location_data_widget.dart b/lib/ui/viewer/location/update_location_data_widget.dart index 428fe84dd..93b608a52 100644 --- a/lib/ui/viewer/location/update_location_data_widget.dart +++ b/lib/ui/viewer/location/update_location_data_widget.dart @@ -75,6 +75,9 @@ class _UpdateLocationDataWidgetState extends State { } }, ), + nonRotatedChildren: const [ + OSMFranceTileAttributes(), + ], children: const [ OSMFranceTileLayer(), ], @@ -102,8 +105,10 @@ class _UpdateLocationDataWidgetState extends State { ), ); return locationInDMS != null - ? SizedBox( - width: 80 * MediaQuery.textScaleFactorOf(context), + ? ConstrainedBox( + constraints: BoxConstraints( + minWidth: 80 * MediaQuery.textScaleFactorOf(context), + ), child: Column( children: [ Text( @@ -118,10 +123,7 @@ class _UpdateLocationDataWidgetState extends State { ], ), ) - : Text( - S.of(context).selectALocation, - style: textTheme.mini, - ); + : const UpdateLocationInfo(); }, ), ), @@ -227,3 +229,62 @@ class _UpdateLocationDataWidgetState extends State { ); } } + +class UpdateLocationInfo extends StatefulWidget { + const UpdateLocationInfo({super.key}); + + @override + State createState() => _UpdateLocationInfoState(); +} + +class _UpdateLocationInfoState extends State { + bool showSelectLocationText = false; + + @override + initState() { + super.initState(); + Future.delayed(const Duration(seconds: 3), () { + setState(() { + showSelectLocationText = true; + }); + }); + } + + @override + Widget build(BuildContext context) { + return AnimatedCrossFade( + duration: const Duration(milliseconds: 200), + firstCurve: Curves.easeInOutExpo, + secondCurve: Curves.easeInOutExpo, + sizeCurve: Curves.easeInOutExpo, + crossFadeState: showSelectLocationText + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: Text( + S.of(context).selectALocation, + style: getEnteTextTheme(context).mini, + ), + secondChild: Text( + S.of(context).editsToLocationWillOnlyBeSeenWithinEnte, + style: getEnteTextTheme(context).mini, + ), + layoutBuilder: (topChild, topChildKey, bottomChild, bottomChildKey) { + return Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 0, + key: bottomChildKey, + child: bottomChild, + // top: 0, + ), + Positioned( + key: topChildKey, + child: topChild, + ), + ], + ); + }, + ); + } +}