From 58b286526d94347e0b2d6f0273bf350442b0eca4 Mon Sep 17 00:00:00 2001 From: otsmr Date: Thu, 13 Nov 2025 22:14:01 +0100 Subject: [PATCH] fix #308 --- lib/src/localization/app_de.arb | 5 +- lib/src/localization/app_en.arb | 5 +- .../generated/app_localizations.dart | 18 ++ .../generated/app_localizations_de.dart | 9 + .../generated/app_localizations_en.dart | 9 + .../settings/profile/modify_avatar.view.dart | 160 +++++++++++------- 6 files changed, 146 insertions(+), 60 deletions(-) diff --git a/lib/src/localization/app_de.arb b/lib/src/localization/app_de.arb index 5b1a748..a6f3abf 100644 --- a/lib/src/localization/app_de.arb +++ b/lib/src/localization/app_de.arb @@ -822,5 +822,8 @@ "dialogAskDeleteMediaFilePopTitle": "Bist du sicher, dass du dein Meisterwerk löschen möchtest?", "dialogAskDeleteMediaFilePopDelete": "Löschen", "allowErrorTracking": "Fehler und Crashes mit uns teilen", - "allowErrorTrackingSubtitle": "Wenn twonly abstürzt oder Fehler auftreten, werden diese automatisch an unsere selbst gehostete Glitchtip-Instanz gemeldet. Persönliche Daten wie Nachrichten oder Bilder werden niemals hochgeladen." + "allowErrorTrackingSubtitle": "Wenn twonly abstürzt oder Fehler auftreten, werden diese automatisch an unsere selbst gehostete Glitchtip-Instanz gemeldet. Persönliche Daten wie Nachrichten oder Bilder werden niemals hochgeladen.", + "avatarSaveChanges": "Möchtest du die Änderungen speichern?", + "avatarSaveChangesStore": "Speichern", + "avatarSaveChangesDiscard": "Verwerfen" } \ No newline at end of file diff --git a/lib/src/localization/app_en.arb b/lib/src/localization/app_en.arb index bc772d9..8b6dec4 100644 --- a/lib/src/localization/app_en.arb +++ b/lib/src/localization/app_en.arb @@ -600,5 +600,8 @@ "dialogAskDeleteMediaFilePopTitle": "Are you sure you want to delete your masterpiece?", "dialogAskDeleteMediaFilePopDelete": "Delete", "allowErrorTracking": "Share errors and crashes with us", - "allowErrorTrackingSubtitle": "If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded." + "allowErrorTrackingSubtitle": "If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.", + "avatarSaveChanges": "Would you like to save the changes?", + "avatarSaveChangesStore": "Save", + "avatarSaveChangesDiscard": "Discard" } \ 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 1e8274f..a196691 100644 --- a/lib/src/localization/generated/app_localizations.dart +++ b/lib/src/localization/generated/app_localizations.dart @@ -2707,6 +2707,24 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.'** String get allowErrorTrackingSubtitle; + + /// No description provided for @avatarSaveChanges. + /// + /// In en, this message translates to: + /// **'Would you like to save the changes?'** + String get avatarSaveChanges; + + /// No description provided for @avatarSaveChangesStore. + /// + /// In en, this message translates to: + /// **'Save'** + String get avatarSaveChangesStore; + + /// No description provided for @avatarSaveChangesDiscard. + /// + /// In en, this message translates to: + /// **'Discard'** + String get avatarSaveChangesDiscard; } class _AppLocalizationsDelegate diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart index b5fc863..7e07674 100644 --- a/lib/src/localization/generated/app_localizations_de.dart +++ b/lib/src/localization/generated/app_localizations_de.dart @@ -1495,4 +1495,13 @@ class AppLocalizationsDe extends AppLocalizations { @override String get allowErrorTrackingSubtitle => 'Wenn twonly abstürzt oder Fehler auftreten, werden diese automatisch an unsere selbst gehostete Glitchtip-Instanz gemeldet. Persönliche Daten wie Nachrichten oder Bilder werden niemals hochgeladen.'; + + @override + String get avatarSaveChanges => 'Möchtest du die Änderungen speichern?'; + + @override + String get avatarSaveChangesStore => 'Speichern'; + + @override + String get avatarSaveChangesDiscard => 'Verwerfen'; } diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart index 0fb3086..427d317 100644 --- a/lib/src/localization/generated/app_localizations_en.dart +++ b/lib/src/localization/generated/app_localizations_en.dart @@ -1485,4 +1485,13 @@ class AppLocalizationsEn extends AppLocalizations { @override String get allowErrorTrackingSubtitle => 'If twonly crashes or errors occur, these are automatically reported to our self-hosted Glitchtip instance. Personal data such as messages or images are never uploaded.'; + + @override + String get avatarSaveChanges => 'Would you like to save the changes?'; + + @override + String get avatarSaveChangesStore => 'Save'; + + @override + String get avatarSaveChangesDiscard => 'Discard'; } diff --git a/lib/src/views/settings/profile/modify_avatar.view.dart b/lib/src/views/settings/profile/modify_avatar.view.dart index 0a489da..e496e14 100644 --- a/lib/src/views/settings/profile/modify_avatar.view.dart +++ b/lib/src/views/settings/profile/modify_avatar.view.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:avatar_maker/avatar_maker.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:twonly/globals.dart'; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; @@ -77,69 +78,112 @@ class _ModifyAvatarState extends State { } } + Future _showBackDialog() { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text( + context.lang.avatarSaveChanges, + ), + actions: [ + FilledButton( + child: Text(context.lang.avatarSaveChangesStore), + onPressed: () async { + await storeAvatarAndExit(); + }, + ), + TextButton( + child: Text(context.lang.avatarSaveChangesDiscard), + onPressed: () { + Navigator.pop(context, true); + }, + ), + ], + ); + }, + ); + } + + Future storeAvatarAndExit() async { + await _avatarMakerController.saveAvatarSVG(); + final json = _avatarMakerController.getJsonOptionsSync(); + final svg = _avatarMakerController.getAvatarSVGSync(); + await updateUserAvatar(json, svg); + if (mounted) { + Navigator.pop(context, true); + } + } + @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(context.lang.settingsProfileCustomizeAvatar), - ), - body: Center( - child: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: EdgeInsets.zero, - child: AvatarMakerAvatar( - radius: 130, - backgroundColor: Colors.transparent, - controller: _avatarMakerController, + return PopScope( + canPop: false, + onPopInvokedWithResult: (bool didPop, bool? result) async { + if (didPop) return; + if (_avatarMakerController.getJsonOptionsSync() != gUser.avatarJson) { + // there where changes + final shouldPop = await _showBackDialog() ?? false; + if (context.mounted && shouldPop) { + Navigator.pop(context); + } + } else { + Navigator.pop(context); + } + }, + child: Scaffold( + appBar: AppBar( + title: Text(context.lang.settingsProfileCustomizeAvatar), + ), + body: Center( + child: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: EdgeInsets.zero, + child: AvatarMakerAvatar( + radius: 130, + backgroundColor: Colors.transparent, + controller: _avatarMakerController, + ), ), - ), - SizedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - icon: const FaIcon(FontAwesomeIcons.floppyDisk), - onPressed: () async { - await _avatarMakerController.saveAvatarSVG(); - final json = - _avatarMakerController.getJsonOptionsSync(); - final svg = _avatarMakerController.getAvatarSVGSync(); - await updateUserAvatar(json, svg); - if (context.mounted) { - Navigator.pop(context); - } - }, - ), - IconButton( - icon: const FaIcon(FontAwesomeIcons.shuffle), - onPressed: - _avatarMakerController.randomizedSelectedOptions, - ), - IconButton( - icon: const Icon(FontAwesomeIcons.rotateLeft), - onLongPress: () async { - await PersistentAvatarMakerController - .clearAvatarMaker(); - await _avatarMakerController.restoreState(); - }, - onPressed: _avatarMakerController.restoreState, - ), - ], + SizedBox( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + icon: const FaIcon(FontAwesomeIcons.floppyDisk), + onPressed: storeAvatarAndExit, + ), + IconButton( + icon: const FaIcon(FontAwesomeIcons.shuffle), + onPressed: + _avatarMakerController.randomizedSelectedOptions, + ), + IconButton( + icon: const Icon(FontAwesomeIcons.rotateLeft), + onLongPress: () async { + await PersistentAvatarMakerController + .clearAvatarMaker(); + await _avatarMakerController.restoreState(); + }, + onPressed: _avatarMakerController.restoreState, + ), + ], + ), ), - ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8, vertical: 30), - child: AvatarMakerCustomizer( - scaffoldWidth: - min(600, MediaQuery.of(context).size.width * 0.85), - theme: getAvatarMakerTheme(context), - controller: _avatarMakerController, + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8, vertical: 30), + child: AvatarMakerCustomizer( + scaffoldWidth: + min(600, MediaQuery.of(context).size.width * 0.85), + theme: getAvatarMakerTheme(context), + controller: _avatarMakerController, + ), ), - ), - ], + ], + ), ), ), ),