Added Delete all games button to Settings

This commit is contained in:
2025-07-11 11:10:06 +02:00
parent 86cd0db997
commit 55a61be44b
7 changed files with 222 additions and 147 deletions

View File

@@ -95,6 +95,9 @@
"game_data": "Spieldaten", "game_data": "Spieldaten",
"import_data": "Spieldaten importieren", "import_data": "Spieldaten importieren",
"export_data": "Spieldaten exportieren", "export_data": "Spieldaten exportieren",
"delete_data": "Alle Spieldaten löschen",
"delete_data_title": "Spieldaten löschen?",
"delete_data_message": "Bist du sicher, dass du alle Spieldaten löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
"app": "App", "app": "App",
"import_success_title": "Import erfolgreich", "import_success_title": "Import erfolgreich",

View File

@@ -95,6 +95,9 @@
"game_data": "Game Data", "game_data": "Game Data",
"import_data": "Import Data", "import_data": "Import Data",
"export_data": "Export Data", "export_data": "Export Data",
"delete_data": "Delete all Game Data",
"delete_data_title": "Delete game data?",
"delete_data_message": "Bist du sicher, dass du alle Spieldaten löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
"app": "App", "app": "App",
"import_success_title": "Import successful", "import_success_title": "Import successful",

View File

@@ -530,6 +530,24 @@ abstract class AppLocalizations {
/// **'Spieldaten exportieren'** /// **'Spieldaten exportieren'**
String get export_data; String get export_data;
/// No description provided for @delete_data.
///
/// In de, this message translates to:
/// **'Alle Spieldaten löschen'**
String get delete_data;
/// No description provided for @delete_data_title.
///
/// In de, this message translates to:
/// **'Spieldaten löschen?'**
String get delete_data_title;
/// No description provided for @delete_data_message.
///
/// In de, this message translates to:
/// **'Bist du sicher, dass du alle Spieldaten löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'**
String get delete_data_message;
/// No description provided for @app. /// No description provided for @app.
/// ///
/// In de, this message translates to: /// In de, this message translates to:

View File

@@ -237,6 +237,16 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get export_data => 'Spieldaten exportieren'; String get export_data => 'Spieldaten exportieren';
@override
String get delete_data => 'Alle Spieldaten löschen';
@override
String get delete_data_title => 'Spieldaten löschen?';
@override
String get delete_data_message =>
'Bist du sicher, dass du alle Spieldaten löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.';
@override @override
String get app => 'App'; String get app => 'App';

View File

@@ -92,7 +92,7 @@ class AppLocalizationsEn extends AppLocalizations {
'If you are not satisfied with the app, please let me know before leaving a bad rating. I will try to fix the issue as soon as possible.'; 'If you are not satisfied with the app, please let me know before leaving a bad rating. I will try to fix the issue as soon as possible.';
@override @override
String get contact_email => 'Contac via E-Mail'; String get contact_email => 'Contact via E-Mail';
@override @override
String get email_subject => 'Feedback: Cabo Counter App'; String get email_subject => 'Feedback: Cabo Counter App';
@@ -234,6 +234,16 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get export_data => 'Export Data'; String get export_data => 'Export Data';
@override
String get delete_data => 'Delete all Game Data';
@override
String get delete_data_title => 'Delete game data?';
@override
String get delete_data_message =>
'Bist du sicher, dass du alle Spieldaten löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.';
@override @override
String get app => 'App'; String get app => 'App';

View File

@@ -32,162 +32,193 @@ class _SettingsViewState extends State<SettingsView> {
middle: Text(AppLocalizations.of(context).settings), middle: Text(AppLocalizations.of(context).settings),
), ),
child: SafeArea( child: SafeArea(
child: Stack( child: SingleChildScrollView(
children: [ child: Column(
Column( mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Padding(
Padding( padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), child: Text(
child: Text( AppLocalizations.of(context).points,
AppLocalizations.of(context).points, style: CustomTheme.rowTitle,
style: CustomTheme.rowTitle,
),
), ),
Padding( ),
padding: const EdgeInsets.fromLTRB(10, 15, 10, 10), Padding(
child: CupertinoFormSection.insetGrouped( padding: const EdgeInsets.fromLTRB(10, 15, 10, 10),
backgroundColor: CustomTheme.backgroundColor, child: CupertinoFormSection.insetGrouped(
margin: EdgeInsets.zero, backgroundColor: CustomTheme.backgroundColor,
children: [ margin: EdgeInsets.zero,
CustomFormRow( children: [
prefixText: 'Cabo-Strafe', CustomFormRow(
prefixIcon: CupertinoIcons.bolt_fill, prefixText: AppLocalizations.of(context).cabo_penalty,
suffixWidget: CustomStepper( prefixIcon: CupertinoIcons.bolt_fill,
key: _stepperKey1, suffixWidget: CustomStepper(
initialValue: ConfigService.caboPenalty, key: _stepperKey1,
minValue: 0, initialValue: ConfigService.caboPenalty,
maxValue: 50, minValue: 0,
step: 1, maxValue: 50,
onChanged: (newCaboPenalty) { step: 1,
setState(() { onChanged: (newCaboPenalty) {
ConfigService.setCaboPenalty(newCaboPenalty);
ConfigService.caboPenalty = newCaboPenalty;
});
},
),
),
CustomFormRow(
prefixText: 'Punkte-Limit',
prefixIcon: FontAwesomeIcons.bullseye,
suffixWidget: CustomStepper(
key: _stepperKey2,
initialValue: ConfigService.pointLimit,
minValue: 30,
maxValue: 1000,
step: 10,
onChanged: (newPointLimit) {
setState(() {
ConfigService.setPointLimit(newPointLimit);
ConfigService.pointLimit = newPointLimit;
});
},
),
),
CustomFormRow(
prefixText:
AppLocalizations.of(context).reset_to_default,
prefixIcon: CupertinoIcons.arrow_counterclockwise,
onPressed: () {
ConfigService.resetConfig();
setState(() { setState(() {
_stepperKey1 = UniqueKey(); ConfigService.setCaboPenalty(newCaboPenalty);
_stepperKey2 = UniqueKey(); ConfigService.caboPenalty = newCaboPenalty;
}); });
}, },
) ),
])), ),
Padding( CustomFormRow(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), prefixText: AppLocalizations.of(context).point_limit,
child: Text( prefixIcon: FontAwesomeIcons.bullseye,
AppLocalizations.of(context).game_data, suffixWidget: CustomStepper(
style: CustomTheme.rowTitle, key: _stepperKey2,
), initialValue: ConfigService.pointLimit,
), minValue: 30,
Padding( maxValue: 1000,
padding: const EdgeInsets.fromLTRB(10, 15, 10, 10), step: 10,
child: CupertinoFormSection.insetGrouped( onChanged: (newPointLimit) {
backgroundColor: CustomTheme.backgroundColor, setState(() {
margin: EdgeInsets.zero, ConfigService.setPointLimit(newPointLimit);
children: [ ConfigService.pointLimit = newPointLimit;
CustomFormRow( });
prefixText: AppLocalizations.of(context).import_data,
prefixIcon: CupertinoIcons.square_arrow_down,
onPressed: () async {
final status =
await LocalStorageService.importJsonFile();
showFeedbackDialog(status);
}, },
suffixWidget: const CupertinoListTileChevron(),
), ),
CustomFormRow( ),
prefixText: AppLocalizations.of(context).export_data, CustomFormRow(
prefixIcon: CupertinoIcons.square_arrow_up, prefixText:
onPressed: () => LocalStorageService.exportGameData(), AppLocalizations.of(context).reset_to_default,
suffixWidget: const CupertinoListTileChevron(), prefixIcon: CupertinoIcons.arrow_counterclockwise,
), onPressed: () {
])), ConfigService.resetConfig();
Padding( setState(() {
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), _stepperKey1 = UniqueKey();
child: Text( _stepperKey2 = UniqueKey();
AppLocalizations.of(context).app, });
style: CustomTheme.rowTitle, },
), )
])),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
child: Text(
AppLocalizations.of(context).game_data,
style: CustomTheme.rowTitle,
), ),
Padding( ),
padding: const EdgeInsets.fromLTRB(10, 15, 10, 0), Padding(
child: CupertinoFormSection.insetGrouped( padding: const EdgeInsets.fromLTRB(10, 15, 10, 10),
backgroundColor: CustomTheme.backgroundColor, child: CupertinoFormSection.insetGrouped(
margin: EdgeInsets.zero, backgroundColor: CustomTheme.backgroundColor,
children: [ margin: EdgeInsets.zero,
CustomFormRow( children: [
prefixText: AppLocalizations.of(context).wiki, CustomFormRow(
prefixIcon: CupertinoIcons.book, prefixText: AppLocalizations.of(context).import_data,
onPressed: () => prefixIcon: CupertinoIcons.square_arrow_down,
launchUrl(Uri.parse(Constants.GITHUB_WIKI_LINK)), onPressed: () async {
suffixWidget: const CupertinoListTileChevron(), final status =
), await LocalStorageService.importJsonFile();
CustomFormRow( showFeedbackDialog(status);
prefixText: },
AppLocalizations.of(context).privacy_policy, suffixWidget: const CupertinoListTileChevron(),
prefixIcon: CupertinoIcons.doc_append, ),
onPressed: () => launchUrl( CustomFormRow(
Uri.parse(Constants.PRIVACY_POLICY_LINK)), prefixText: AppLocalizations.of(context).export_data,
suffixWidget: const CupertinoListTileChevron(), prefixIcon: CupertinoIcons.square_arrow_up,
), onPressed: () => LocalStorageService.exportGameData(),
CustomFormRow( suffixWidget: const CupertinoListTileChevron(),
prefixText: AppLocalizations.of(context).error_found, ),
prefixIcon: FontAwesomeIcons.github, CustomFormRow(
onPressed: () => launchUrl( prefixText: AppLocalizations.of(context).delete_data,
Uri.parse(Constants.GITHUB_ISSUES_LINK)), prefixIcon: CupertinoIcons.trash,
suffixWidget: const CupertinoListTileChevron(), onPressed: () => _deleteAllGames(),
), ),
CustomFormRow( ])),
prefixText: Padding(
AppLocalizations.of(context).app_version, padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
prefixIcon: CupertinoIcons.tag, child: Text(
onPressed: null, AppLocalizations.of(context).app,
suffixWidget: Text(VersionService.getVersion(), style: CustomTheme.rowTitle,
style: TextStyle( ),
color: CustomTheme.primaryColor, ),
))), Padding(
CustomFormRow( padding: const EdgeInsets.fromLTRB(10, 15, 10, 0),
prefixText: AppLocalizations.of(context).build, child: CupertinoFormSection.insetGrouped(
prefixIcon: CupertinoIcons.number, backgroundColor: CustomTheme.backgroundColor,
onPressed: null, margin: EdgeInsets.zero,
suffixWidget: Text(VersionService.getBuildNumber(), children: [
style: TextStyle( CustomFormRow(
color: CustomTheme.primaryColor, prefixText: AppLocalizations.of(context).wiki,
))), prefixIcon: CupertinoIcons.book,
])), onPressed: () =>
], launchUrl(Uri.parse(Constants.GITHUB_WIKI_LINK)),
), suffixWidget: const CupertinoListTileChevron(),
], ),
CustomFormRow(
prefixText: AppLocalizations.of(context).privacy_policy,
prefixIcon: CupertinoIcons.doc_append,
onPressed: () =>
launchUrl(Uri.parse(Constants.PRIVACY_POLICY_LINK)),
suffixWidget: const CupertinoListTileChevron(),
),
CustomFormRow(
prefixText: AppLocalizations.of(context).error_found,
prefixIcon: FontAwesomeIcons.github,
onPressed: () =>
launchUrl(Uri.parse(Constants.GITHUB_ISSUES_LINK)),
suffixWidget: const CupertinoListTileChevron(),
),
CustomFormRow(
prefixText: AppLocalizations.of(context).app_version,
prefixIcon: CupertinoIcons.tag,
onPressed: null,
suffixWidget: Text(VersionService.getVersion(),
style: TextStyle(
color: CustomTheme.primaryColor,
))),
CustomFormRow(
prefixText: AppLocalizations.of(context).build,
prefixIcon: CupertinoIcons.number,
onPressed: null,
suffixWidget: Text(VersionService.getBuildNumber(),
style: TextStyle(
color: CustomTheme.primaryColor,
))),
])),
const SizedBox(height: 50)
],
),
)), )),
); );
} }
/// Shows a dialog to confirm the deletion of all game data.
/// When confirmed, it deletes all game data from local storage.
void _deleteAllGames() {
showCupertinoDialog(
context: context,
builder: (context) {
return CupertinoAlertDialog(
title: Text(AppLocalizations.of(context).delete_data_title),
content: Text(AppLocalizations.of(context).delete_data_message),
actions: [
CupertinoDialogAction(
child: Text(AppLocalizations.of(context).cancel),
onPressed: () => Navigator.pop(context),
),
CupertinoDialogAction(
isDestructiveAction: true,
isDefaultAction: true,
child: Text(AppLocalizations.of(context).delete),
onPressed: () {
LocalStorageService.deleteAllGames();
Navigator.pop(context);
},
),
],
);
},
);
}
void showFeedbackDialog(ImportStatus status) { void showFeedbackDialog(ImportStatus status) {
if (status == ImportStatus.canceled) return; if (status == ImportStatus.canceled) return;
final (title, message) = _getDialogContent(status); final (title, message) = _getDialogContent(status);

View File

@@ -2,7 +2,7 @@ name: cabo_counter
description: "Mobile app for the card game Cabo" description: "Mobile app for the card game Cabo"
publish_to: 'none' publish_to: 'none'
version: 0.4.0+467 version: 0.4.2+470
environment: environment:
sdk: ^3.5.4 sdk: ^3.5.4