This commit is contained in:
otsmr 2025-11-13 22:14:01 +01:00
parent fc2513ddba
commit 58b286526d
6 changed files with 146 additions and 60 deletions

View file

@ -822,5 +822,8 @@
"dialogAskDeleteMediaFilePopTitle": "Bist du sicher, dass du dein Meisterwerk löschen möchtest?", "dialogAskDeleteMediaFilePopTitle": "Bist du sicher, dass du dein Meisterwerk löschen möchtest?",
"dialogAskDeleteMediaFilePopDelete": "Löschen", "dialogAskDeleteMediaFilePopDelete": "Löschen",
"allowErrorTracking": "Fehler und Crashes mit uns teilen", "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"
} }

View file

@ -600,5 +600,8 @@
"dialogAskDeleteMediaFilePopTitle": "Are you sure you want to delete your masterpiece?", "dialogAskDeleteMediaFilePopTitle": "Are you sure you want to delete your masterpiece?",
"dialogAskDeleteMediaFilePopDelete": "Delete", "dialogAskDeleteMediaFilePopDelete": "Delete",
"allowErrorTracking": "Share errors and crashes with us", "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"
} }

View file

@ -2707,6 +2707,24 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// 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.'** /// **'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; 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 class _AppLocalizationsDelegate

View file

@ -1495,4 +1495,13 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get allowErrorTrackingSubtitle => 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.'; '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';
} }

View file

@ -1485,4 +1485,13 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get allowErrorTrackingSubtitle => 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.'; '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';
} }

View file

@ -2,6 +2,7 @@ import 'dart:math';
import 'package:avatar_maker/avatar_maker.dart'; import 'package:avatar_maker/avatar_maker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.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/services/api/messages.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
@ -77,69 +78,112 @@ class _ModifyAvatarState extends State<ModifyAvatar> {
} }
} }
Future<bool?> _showBackDialog() {
return showDialog<bool>(
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<void> storeAvatarAndExit() async {
await _avatarMakerController.saveAvatarSVG();
final json = _avatarMakerController.getJsonOptionsSync();
final svg = _avatarMakerController.getAvatarSVGSync();
await updateUserAvatar(json, svg);
if (mounted) {
Navigator.pop(context, true);
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return PopScope<bool?>(
appBar: AppBar( canPop: false,
title: Text(context.lang.settingsProfileCustomizeAvatar), onPopInvokedWithResult: (bool didPop, bool? result) async {
), if (didPop) return;
body: Center( if (_avatarMakerController.getJsonOptionsSync() != gUser.avatarJson) {
child: SingleChildScrollView( // there where changes
child: Column( final shouldPop = await _showBackDialog() ?? false;
children: [ if (context.mounted && shouldPop) {
Padding( Navigator.pop(context);
padding: EdgeInsets.zero, }
child: AvatarMakerAvatar( } else {
radius: 130, Navigator.pop(context);
backgroundColor: Colors.transparent, }
controller: _avatarMakerController, },
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(
SizedBox( child: Row(
child: Row( mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: [
children: [ IconButton(
IconButton( icon: const FaIcon(FontAwesomeIcons.floppyDisk),
icon: const FaIcon(FontAwesomeIcons.floppyDisk), onPressed: storeAvatarAndExit,
onPressed: () async { ),
await _avatarMakerController.saveAvatarSVG(); IconButton(
final json = icon: const FaIcon(FontAwesomeIcons.shuffle),
_avatarMakerController.getJsonOptionsSync(); onPressed:
final svg = _avatarMakerController.getAvatarSVGSync(); _avatarMakerController.randomizedSelectedOptions,
await updateUserAvatar(json, svg); ),
if (context.mounted) { IconButton(
Navigator.pop(context); icon: const Icon(FontAwesomeIcons.rotateLeft),
} onLongPress: () async {
}, await PersistentAvatarMakerController
), .clearAvatarMaker();
IconButton( await _avatarMakerController.restoreState();
icon: const FaIcon(FontAwesomeIcons.shuffle), },
onPressed: onPressed: _avatarMakerController.restoreState,
_avatarMakerController.randomizedSelectedOptions, ),
), ],
IconButton( ),
icon: const Icon(FontAwesomeIcons.rotateLeft),
onLongPress: () async {
await PersistentAvatarMakerController
.clearAvatarMaker();
await _avatarMakerController.restoreState();
},
onPressed: _avatarMakerController.restoreState,
),
],
), ),
), Padding(
Padding( padding:
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 30),
const EdgeInsets.symmetric(horizontal: 8, vertical: 30), child: AvatarMakerCustomizer(
child: AvatarMakerCustomizer( scaffoldWidth:
scaffoldWidth: min(600, MediaQuery.of(context).size.width * 0.85),
min(600, MediaQuery.of(context).size.width * 0.85), theme: getAvatarMakerTheme(context),
theme: getAvatarMakerTheme(context), controller: _avatarMakerController,
controller: _avatarMakerController, ),
), ),
), ],
], ),
), ),
), ),
), ),