* Updated createGameView ListBuilder * Added ReorderableListView * Increment build no * Fixed bug with wrong medal icon * change not equal to greater than * Updated bool var * Fixed deletion error * Small translation improvements * Implemented first version of point overview * Visual improvements on table * Added details and sum row * Updated strings * Implemented new strings * Refactoring * Updated graph displayment * Moved new views to statistics section * Added seperator in main menu * Renaming * Updated sign * Updated colors & class name * Removed empty line * Updated round index * Updated types * Added new kamikaze button and bundles navigation functionality * Updated lock icon * Updated button position and design * Removed title row and changed segmendetControl Padding * Refactored logic and added comments * Updated comment * Chaned icon * Added comment * Removed print * Updated colors * Changed var name * Removed unused strings * Added gameMode * Changed creation variable * Updated mode selection * Updated strings * Changed mode order * Implemented default mode selection * Updated initState * Removed print * Removed print * Removed comments * Updated config service * Changed create game view * Changed icon * Updated strings * Updated config * Updated mode selection logic * Deleted getter * Removed not used code * Implemented reset logic for default game mode * Updated to 0.5.0 * Hotfix: Pixel Overflow * Changed the overall return type for gamemodes * Updated documentation * Fixed merge issues * Added Custom button * Updated strings * Updated buttons, implemented animatedOpacity * Keyboard still doesnt works * Fixed keyboard behaviour * Changed keyboard height * Added method getGameSessionById() * Updated gameSession class * id gets added to gameSession class at creation * Cleaned up file * Added docs and dependency * Removed toString * Implemented null safety * Added named parameter * Replaced button with custom button * Updated key * Updated addGameSessionMethod * Update README.md * Added Strings for popup * Implemented popup & confetti * Extracted code to method _playFinishAnimation() * Replaced tenary operator with Visibility Widget * Replaced tenary operator with Visibility Widget * Used variable again * Added delays in constants.dart * Removed confetti button * Updated strings * Removed print * Added dispose for confettiController * Implemented missing constant in code * Updated gameSession logic so more than one player can be winner * Updated strings * Updated winner popup * game names now can have up to 20 chars * Updated strings * Added sized box for visual enhancement * Centered the add player button and made it wider * New created player textfields get automatically focused * Added focus nodes for autofocus and navigation between textfields * Updated version number * Updated game title textfield with focus node and textaction * Added focusnodes to dispose * Update README.md * Fixed bug with no popup shown * Fixed bug with out of range error * Updated listener notification
305 lines
13 KiB
Dart
305 lines
13 KiB
Dart
import 'package:cabo_counter/core/constants.dart';
|
|
import 'package:cabo_counter/core/custom_theme.dart';
|
|
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
|
import 'package:cabo_counter/presentation/views/mode_selection_view.dart';
|
|
import 'package:cabo_counter/presentation/widgets/custom_form_row.dart';
|
|
import 'package:cabo_counter/presentation/widgets/custom_stepper.dart';
|
|
import 'package:cabo_counter/services/config_service.dart';
|
|
import 'package:cabo_counter/services/local_storage_service.dart';
|
|
import 'package:cabo_counter/services/version_service.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
class SettingsView extends StatefulWidget {
|
|
const SettingsView({super.key});
|
|
|
|
@override
|
|
State<SettingsView> createState() => _SettingsViewState();
|
|
}
|
|
|
|
class _SettingsViewState extends State<SettingsView> {
|
|
UniqueKey _stepperKey1 = UniqueKey();
|
|
UniqueKey _stepperKey2 = UniqueKey();
|
|
GameMode defaultMode = ConfigService.getGameMode();
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return CupertinoPageScaffold(
|
|
navigationBar: CupertinoNavigationBar(
|
|
middle: Text(AppLocalizations.of(context).settings),
|
|
),
|
|
child: SafeArea(
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
|
|
child: Text(
|
|
AppLocalizations.of(context).points,
|
|
style: CustomTheme.rowTitle,
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(10, 15, 10, 10),
|
|
child: CupertinoFormSection.insetGrouped(
|
|
backgroundColor: CustomTheme.backgroundColor,
|
|
margin: EdgeInsets.zero,
|
|
children: [
|
|
CustomFormRow(
|
|
prefixText: AppLocalizations.of(context).cabo_penalty,
|
|
prefixIcon: CupertinoIcons.bolt_fill,
|
|
suffixWidget: CustomStepper(
|
|
key: _stepperKey1,
|
|
initialValue: ConfigService.getCaboPenalty(),
|
|
minValue: 0,
|
|
maxValue: 50,
|
|
step: 1,
|
|
onChanged: (newCaboPenalty) {
|
|
setState(() {
|
|
ConfigService.setCaboPenalty(newCaboPenalty);
|
|
});
|
|
},
|
|
),
|
|
),
|
|
CustomFormRow(
|
|
prefixText: AppLocalizations.of(context).point_limit,
|
|
prefixIcon: FontAwesomeIcons.bullseye,
|
|
suffixWidget: CustomStepper(
|
|
key: _stepperKey2,
|
|
initialValue: ConfigService.getPointLimit(),
|
|
minValue: 30,
|
|
maxValue: 1000,
|
|
step: 10,
|
|
onChanged: (newPointLimit) {
|
|
setState(() {
|
|
ConfigService.setPointLimit(newPointLimit);
|
|
});
|
|
},
|
|
),
|
|
),
|
|
CustomFormRow(
|
|
prefixText: AppLocalizations.of(context).standard_mode,
|
|
prefixIcon: CupertinoIcons.square_stack,
|
|
suffixWidget: Row(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
children: [
|
|
Text(
|
|
defaultMode == GameMode.none
|
|
? AppLocalizations.of(context).no_default_mode
|
|
: (defaultMode == GameMode.pointLimit
|
|
? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}'
|
|
: AppLocalizations.of(context).unlimited),
|
|
),
|
|
const SizedBox(width: 5),
|
|
const CupertinoListTileChevron()
|
|
],
|
|
),
|
|
onPressed: () async {
|
|
final selectedMode = await Navigator.push(
|
|
context,
|
|
CupertinoPageRoute(
|
|
builder: (context) => ModeSelectionMenu(
|
|
pointLimit: ConfigService.getPointLimit(),
|
|
showDeselection: true,
|
|
),
|
|
),
|
|
);
|
|
|
|
setState(() {
|
|
defaultMode = selectedMode ?? GameMode.none;
|
|
});
|
|
ConfigService.setGameMode(defaultMode);
|
|
},
|
|
),
|
|
CustomFormRow(
|
|
prefixText:
|
|
AppLocalizations.of(context).reset_to_default,
|
|
prefixIcon: CupertinoIcons.arrow_counterclockwise,
|
|
onPressed: () {
|
|
ConfigService.resetConfig();
|
|
setState(() {
|
|
_stepperKey1 = UniqueKey();
|
|
_stepperKey2 = UniqueKey();
|
|
defaultMode = ConfigService.getGameMode();
|
|
});
|
|
},
|
|
)
|
|
])),
|
|
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, 10),
|
|
child: CupertinoFormSection.insetGrouped(
|
|
backgroundColor: CustomTheme.backgroundColor,
|
|
margin: EdgeInsets.zero,
|
|
children: [
|
|
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,
|
|
prefixIcon: CupertinoIcons.square_arrow_up,
|
|
onPressed: () => LocalStorageService.exportGameData(),
|
|
suffixWidget: const CupertinoListTileChevron(),
|
|
),
|
|
CustomFormRow(
|
|
prefixText: AppLocalizations.of(context).delete_data,
|
|
prefixIcon: CupertinoIcons.trash,
|
|
onPressed: () => _deleteAllGames(),
|
|
),
|
|
])),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
|
|
child: Text(
|
|
AppLocalizations.of(context).app,
|
|
style: CustomTheme.rowTitle,
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(10, 15, 10, 0),
|
|
child: CupertinoFormSection.insetGrouped(
|
|
backgroundColor: CustomTheme.backgroundColor,
|
|
margin: EdgeInsets.zero,
|
|
children: [
|
|
CustomFormRow(
|
|
prefixText: AppLocalizations.of(context).wiki,
|
|
prefixIcon: CupertinoIcons.book,
|
|
onPressed: () =>
|
|
launchUrl(Uri.parse(Constants.kGithubWikiLink)),
|
|
suffixWidget: const CupertinoListTileChevron(),
|
|
),
|
|
CustomFormRow(
|
|
prefixText: AppLocalizations.of(context).privacy_policy,
|
|
prefixIcon: CupertinoIcons.doc_append,
|
|
onPressed: () =>
|
|
launchUrl(Uri.parse(Constants.kPrivacyPolicyLink)),
|
|
suffixWidget: const CupertinoListTileChevron(),
|
|
),
|
|
CustomFormRow(
|
|
prefixText: AppLocalizations.of(context).error_found,
|
|
prefixIcon: FontAwesomeIcons.github,
|
|
onPressed: () =>
|
|
launchUrl(Uri.parse(Constants.kGithubIssuesLink)),
|
|
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) {
|
|
if (status == ImportStatus.canceled) return;
|
|
final (title, message) = _getDialogContent(status);
|
|
|
|
showCupertinoDialog(
|
|
context: context,
|
|
builder: (context) {
|
|
return CupertinoAlertDialog(
|
|
title: Text(title),
|
|
content: Text(message),
|
|
actions: [
|
|
CupertinoDialogAction(
|
|
child: Text(AppLocalizations.of(context).ok),
|
|
onPressed: () => Navigator.pop(context),
|
|
),
|
|
],
|
|
);
|
|
});
|
|
}
|
|
|
|
(String, String) _getDialogContent(ImportStatus status) {
|
|
switch (status) {
|
|
case ImportStatus.success:
|
|
return (
|
|
AppLocalizations.of(context).import_success_title,
|
|
AppLocalizations.of(context).import_success_message
|
|
);
|
|
case ImportStatus.validationError:
|
|
return (
|
|
AppLocalizations.of(context).import_validation_error_title,
|
|
AppLocalizations.of(context).import_validation_error_message
|
|
);
|
|
|
|
case ImportStatus.formatError:
|
|
return (
|
|
AppLocalizations.of(context).import_format_error_title,
|
|
AppLocalizations.of(context).import_format_error_message
|
|
);
|
|
case ImportStatus.genericError:
|
|
return (
|
|
AppLocalizations.of(context).import_generic_error_title,
|
|
AppLocalizations.of(context).import_generic_error_message
|
|
);
|
|
case ImportStatus.canceled:
|
|
return ('', '');
|
|
}
|
|
}
|
|
}
|