From 6d86af155c90f555f19c7147931c6ea2273cd7f3 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 9 Nov 2025 23:32:46 +0100 Subject: [PATCH] ask before deleting image --- lib/src/localization/app_de.arb | 4 +- lib/src/localization/app_en.arb | 4 +- .../generated/app_localizations.dart | 12 + .../generated/app_localizations_de.dart | 7 + .../generated/app_localizations_en.dart | 7 + .../image_editor/layers/filter_layer.dart | 2 +- .../views/camera/share_image_editor_view.dart | 318 ++++++++++-------- 7 files changed, 216 insertions(+), 138 deletions(-) diff --git a/lib/src/localization/app_de.arb b/lib/src/localization/app_de.arb index 5e7bba5..deaf7b0 100644 --- a/lib/src/localization/app_de.arb +++ b/lib/src/localization/app_de.arb @@ -818,5 +818,7 @@ "deleteChatAfterAMonth": "einem Monat.", "deleteChatAfterAYear": "einem Jahr.", "yourTwonlyScore": "Dein twonly-Score", - "registrationClosed": "Aufgrund des aktuell sehr hohen Aufkommens haben wir die Registrierung vorübergehend deaktiviert, damit der Dienst zuverlässig bleibt. Bitte versuche es in ein paar Tagen noch einmal." + "registrationClosed": "Aufgrund des aktuell sehr hohen Aufkommens haben wir die Registrierung vorübergehend deaktiviert, damit der Dienst zuverlässig bleibt. Bitte versuche es in ein paar Tagen noch einmal.", + "dialogAskDeleteMediaFilePopTitle": "Bist du sicher, dass du dein Meisterwerk löschen möchtest?", + "dialogAskDeleteMediaFilePopDelete": "Löschen" } \ No newline at end of file diff --git a/lib/src/localization/app_en.arb b/lib/src/localization/app_en.arb index cb78dfd..c122b12 100644 --- a/lib/src/localization/app_en.arb +++ b/lib/src/localization/app_en.arb @@ -596,5 +596,7 @@ "deleteChatAfterAMonth": "one month.", "deleteChatAfterAYear": "one year.", "yourTwonlyScore": "Your twonly-Score", - "registrationClosed": "Due to the current high volume of registrations, we have temporarily disabled registration to ensure that the service remains reliable. Please try again in a few days." + "registrationClosed": "Due to the current high volume of registrations, we have temporarily disabled registration to ensure that the service remains reliable. Please try again in a few days.", + "dialogAskDeleteMediaFilePopTitle": "Are you sure you want to delete your masterpiece?", + "dialogAskDeleteMediaFilePopDelete": "Delete" } \ No newline at end of file diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart index feedd96..549cd0d 100644 --- a/lib/src/localization/generated/app_localizations.dart +++ b/lib/src/localization/generated/app_localizations.dart @@ -2683,6 +2683,18 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Due to the current high volume of registrations, we have temporarily disabled registration to ensure that the service remains reliable. Please try again in a few days.'** String get registrationClosed; + + /// No description provided for @dialogAskDeleteMediaFilePopTitle. + /// + /// In en, this message translates to: + /// **'Are you sure you want to delete your masterpiece?'** + String get dialogAskDeleteMediaFilePopTitle; + + /// No description provided for @dialogAskDeleteMediaFilePopDelete. + /// + /// In en, this message translates to: + /// **'Delete'** + String get dialogAskDeleteMediaFilePopDelete; } class _AppLocalizationsDelegate diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart index fe61244..ce54fd6 100644 --- a/lib/src/localization/generated/app_localizations_de.dart +++ b/lib/src/localization/generated/app_localizations_de.dart @@ -1481,4 +1481,11 @@ class AppLocalizationsDe extends AppLocalizations { @override String get registrationClosed => 'Aufgrund des aktuell sehr hohen Aufkommens haben wir die Registrierung vorübergehend deaktiviert, damit der Dienst zuverlässig bleibt. Bitte versuche es in ein paar Tagen noch einmal.'; + + @override + String get dialogAskDeleteMediaFilePopTitle => + 'Bist du sicher, dass du dein Meisterwerk löschen möchtest?'; + + @override + String get dialogAskDeleteMediaFilePopDelete => 'Löschen'; } diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart index 790bd19..180e7fc 100644 --- a/lib/src/localization/generated/app_localizations_en.dart +++ b/lib/src/localization/generated/app_localizations_en.dart @@ -1471,4 +1471,11 @@ class AppLocalizationsEn extends AppLocalizations { @override String get registrationClosed => 'Due to the current high volume of registrations, we have temporarily disabled registration to ensure that the service remains reliable. Please try again in a few days.'; + + @override + String get dialogAskDeleteMediaFilePopTitle => + 'Are you sure you want to delete your masterpiece?'; + + @override + String get dialogAskDeleteMediaFilePopDelete => 'Delete'; } diff --git a/lib/src/views/camera/image_editor/layers/filter_layer.dart b/lib/src/views/camera/image_editor/layers/filter_layer.dart index 13e76a2..813ea66 100644 --- a/lib/src/views/camera/image_editor/layers/filter_layer.dart +++ b/lib/src/views/camera/image_editor/layers/filter_layer.dart @@ -75,7 +75,7 @@ class _FilterLayerState extends State { List pages = [ const FilterSkeleton(), const DateTimeFilter(), - const LocationFilter(), + // const LocationFilter(), const FilterSkeleton(), ]; diff --git a/lib/src/views/camera/share_image_editor_view.dart b/lib/src/views/camera/share_image_editor_view.dart index daa2ca8..515e8ce 100644 --- a/lib/src/views/camera/share_image_editor_view.dart +++ b/lib/src/views/camera/share_image_editor_view.dart @@ -264,6 +264,40 @@ class _ShareImageEditorView extends State { ]; } + Future _showBackDialog() { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text( + context.lang.dialogAskDeleteMediaFilePopTitle, + ), + actions: [ + FilledButton( + child: Text(context.lang.dialogAskDeleteMediaFilePopDelete), + onPressed: () { + Navigator.pop(context, true); + }, + ), + TextButton( + child: Text(context.lang.cancel), + onPressed: () { + Navigator.pop(context, false); + }, + ), + ], + ); + }, + ); + } + + Future askToCloseThenClose() async { + final shouldPop = await _showBackDialog() ?? false; + if (mounted && shouldPop) { + Navigator.pop(context); + } + } + List get actionsAtTheTop { if (layers.isNotEmpty && layers.last.isEditing && @@ -275,7 +309,14 @@ class _ShareImageEditorView extends State { FontAwesomeIcons.xmark, tooltipText: context.lang.close, onPressed: () async { - Navigator.pop(context, false); + final nonImageFilterLayer = layers.where( + (x) => x is! BackgroundLayerData && x is! FilterLayerData, + ); + if (nonImageFilterLayer.isEmpty) { + Navigator.pop(context, false); + } else { + await askToCloseThenClose(); + } }, ), Expanded(child: Container()), @@ -446,154 +487,161 @@ class _ShareImageEditorView extends State { Widget build(BuildContext context) { pixelRatio = MediaQuery.of(context).devicePixelRatio; - return Scaffold( - backgroundColor: - widget.sharedFromGallery ? null : Colors.white.withAlpha(0), - resizeToAvoidBottomInset: false, - body: Stack( - fit: StackFit.expand, - children: [ - GestureDetector( - onTapDown: (details) { - if (details.globalPosition.dy > 60) { - tabDownPosition = details.globalPosition.dy - 60; - } else { - tabDownPosition = details.globalPosition.dy; - } - }, - onTap: () { - if (layers.any((x) => x.isEditing)) { - return; - } - layers = layers.where((x) => !x.isDeleted).toList(); - undoLayers.clear(); - removedLayers.clear(); - layers.add( - TextLayerData( - offset: Offset(0, tabDownPosition), - textLayersBefore: layers.whereType().length, - ), - ); - setState(() {}); - }, - child: MediaViewSizing( - requiredHeight: 90, - bottomNavigation: ColoredBox( - color: Theme.of(context).colorScheme.surface, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SaveToGalleryButton( - storeImageAsOriginal: storeImageAsOriginal, - mediaService: mediaService, - displayButtonLabel: widget.sendToGroup == null, - isLoading: loadingImage, - ), - if (widget.sendToGroup != null) const SizedBox(width: 10), - if (widget.sendToGroup != null) - OutlinedButton( - style: OutlinedButton.styleFrom( - iconColor: Theme.of(context).colorScheme.primary, - foregroundColor: - Theme.of(context).colorScheme.primary, - ), - onPressed: pushShareImageView, - child: const FaIcon(FontAwesomeIcons.userPlus), + return PopScope( + canPop: false, + onPopInvokedWithResult: (bool didPop, bool? result) async { + if (didPop) return; + await askToCloseThenClose(); + }, + child: Scaffold( + backgroundColor: + widget.sharedFromGallery ? null : Colors.white.withAlpha(0), + resizeToAvoidBottomInset: false, + body: Stack( + fit: StackFit.expand, + children: [ + GestureDetector( + onTapDown: (details) { + if (details.globalPosition.dy > 60) { + tabDownPosition = details.globalPosition.dy - 60; + } else { + tabDownPosition = details.globalPosition.dy; + } + }, + onTap: () { + if (layers.any((x) => x.isEditing)) { + return; + } + layers = layers.where((x) => !x.isDeleted).toList(); + undoLayers.clear(); + removedLayers.clear(); + layers.add( + TextLayerData( + offset: Offset(0, tabDownPosition), + textLayersBefore: layers.whereType().length, + ), + ); + setState(() {}); + }, + child: MediaViewSizing( + requiredHeight: 90, + bottomNavigation: ColoredBox( + color: Theme.of(context).colorScheme.surface, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SaveToGalleryButton( + storeImageAsOriginal: storeImageAsOriginal, + mediaService: mediaService, + displayButtonLabel: widget.sendToGroup == null, + isLoading: loadingImage, ), - SizedBox(width: widget.sendToGroup == null ? 20 : 10), - FilledButton.icon( - icon: sendingOrLoadingImage - ? SizedBox( - height: 12, - width: 12, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Theme.of(context) - .colorScheme - .inversePrimary, - ), - ) - : const FaIcon(FontAwesomeIcons.solidPaperPlane), - onPressed: () async { - if (sendingOrLoadingImage) return; - if (widget.sendToGroup == null) { - return pushShareImageView(); - } - await sendImageToSinglePerson(); - }, - style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric( - vertical: 10, - horizontal: 30, + if (widget.sendToGroup != null) const SizedBox(width: 10), + if (widget.sendToGroup != null) + OutlinedButton( + style: OutlinedButton.styleFrom( + iconColor: Theme.of(context).colorScheme.primary, + foregroundColor: + Theme.of(context).colorScheme.primary, + ), + onPressed: pushShareImageView, + child: const FaIcon(FontAwesomeIcons.userPlus), + ), + SizedBox(width: widget.sendToGroup == null ? 20 : 10), + FilledButton.icon( + icon: sendingOrLoadingImage + ? SizedBox( + height: 12, + width: 12, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Theme.of(context) + .colorScheme + .inversePrimary, + ), + ) + : const FaIcon(FontAwesomeIcons.solidPaperPlane), + onPressed: () async { + if (sendingOrLoadingImage) return; + if (widget.sendToGroup == null) { + return pushShareImageView(); + } + await sendImageToSinglePerson(); + }, + style: ButtonStyle( + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric( + vertical: 10, + horizontal: 30, + ), ), ), + label: Text( + (widget.sendToGroup == null) + ? context.lang.shareImagedEditorShareWith + : substringBy(widget.sendToGroup!.groupName, 15), + style: const TextStyle(fontSize: 17), + ), ), - label: Text( - (widget.sendToGroup == null) - ? context.lang.shareImagedEditorShareWith - : substringBy(widget.sendToGroup!.groupName, 15), - style: const TextStyle(fontSize: 17), - ), - ), - ], + ], + ), ), - ), - child: SizedBox( - height: currentImage.height / pixelRatio, - width: currentImage.width / pixelRatio, - child: Stack( - children: [ - if (videoController != null) - Positioned.fill( - child: VideoPlayer(videoController!), - ), - Screenshot( - controller: screenshotController, - child: LayersViewer( - layers: layers.where((x) => !x.isDeleted).toList(), - onUpdate: () { - for (final layer in layers) { - layer.isEditing = false; - if (layer.isDeleted) { - removedLayers.add(layer); + child: SizedBox( + height: currentImage.height / pixelRatio, + width: currentImage.width / pixelRatio, + child: Stack( + children: [ + if (videoController != null) + Positioned.fill( + child: VideoPlayer(videoController!), + ), + Screenshot( + controller: screenshotController, + child: LayersViewer( + layers: layers.where((x) => !x.isDeleted).toList(), + onUpdate: () { + for (final layer in layers) { + layer.isEditing = false; + if (layer.isDeleted) { + removedLayers.add(layer); + } } - } - layers = layers.where((x) => !x.isDeleted).toList(); - setState(() {}); - }, + layers = layers.where((x) => !x.isDeleted).toList(); + setState(() {}); + }, + ), ), - ), - ], + ], + ), ), ), ), - ), - Positioned( - top: 10, - left: 5, - right: 0, - child: SafeArea( - child: Row( - children: actionsAtTheTop, - ), - ), - ), - Positioned( - right: 6, - top: 100, - child: Container( - alignment: Alignment.bottomCenter, - padding: const EdgeInsets.symmetric(vertical: 16), + Positioned( + top: 10, + left: 5, + right: 0, child: SafeArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: actionsAtTheRight, + child: Row( + children: actionsAtTheTop, ), ), ), - ), - ], + Positioned( + right: 6, + top: 100, + child: Container( + alignment: Alignment.bottomCenter, + padding: const EdgeInsets.symmetric(vertical: 16), + child: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: actionsAtTheRight, + ), + ), + ), + ), + ], + ), ), ); }