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?",
"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"
}

View file

@ -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"
}

View file

@ -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

View file

@ -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';
}

View file

@ -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';
}

View file

@ -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<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
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<bool?>(
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,
),
),
),
],
],
),
),
),
),