From 9cf4a6947a4c70bbaec106623678c0b943bd4458 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 29 Jun 2025 01:55:45 +0200 Subject: [PATCH 001/353] Updated function and limited name length to 12 --- lib/data/game_session.dart | 7 +++++-- lib/views/create_game_view.dart | 1 + test/data/game_session_test.dart | 3 +-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 4896e02..cdbb461 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -73,11 +73,14 @@ class GameSession extends ChangeNotifier { (json['roundList'] as List).map((e) => Round.fromJson(e)).toList(); /// Returns the length of all player names combined. - int getLengthOfPlayerNames() { + int getMaxLengthOfPlayerNames() { int length = 0; for (String player in players) { - length += player.length; + if (player.length >= length) { + length = player.length; + } } + print('Maximale Länge der Spielernamen: $length'); return length; } diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 5ac5026..adcbf86 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -183,6 +183,7 @@ class _CreateGameState extends State { Expanded( child: CupertinoTextField( controller: _playerNameTextControllers[index], + maxLength: 12, placeholder: '${AppLocalizations.of(context).player} ${index + 1}', padding: const EdgeInsets.all(12), diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index 0e9bfa1..0ab65d0 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -62,8 +62,7 @@ void main() { group('Helper Functions', () { test('getLengthOfPlayerNames', () { - expect(session.getLengthOfPlayerNames(), - equals(15)); // Alice(5) + Bob(3) + Charlie(7) + expect(session.getMaxLengthOfPlayerNames(), equals(7)); // Charlie(7) }); test('increaseRound', () { From 3da8c886ff923a8e89c1913948c48bf7aba9c390 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 29 Jun 2025 01:56:32 +0200 Subject: [PATCH 002/353] Updated responsive design in segmented control --- devtools_options.yaml | 3 +++ lib/views/round_view.dart | 54 ++++++++++++++++++++++++++++----------- pubspec.yaml | 2 +- 3 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 devtools_options.yaml diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index 056d0a1..b945ec4 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -67,6 +67,7 @@ class _RoundViewState extends State { @override Widget build(BuildContext context) { final bottomInset = MediaQuery.of(context).viewInsets.bottom; + final maxLength = widget.gameSession.getMaxLengthOfPlayerNames(); return CupertinoPageScaffold( resizeToAvoidBottomInset: false, @@ -122,15 +123,8 @@ class _RoundViewState extends State { index, Padding( padding: EdgeInsets.symmetric( - horizontal: widget.gameSession - .getLengthOfPlayerNames() > - 20 - ? (widget.gameSession - .getLengthOfPlayerNames() > - 32 - ? 5 - : 10) - : 15, + horizontal: + _getSegmendetControlPadding(maxLength), vertical: 6, ), child: Text( @@ -139,11 +133,9 @@ class _RoundViewState extends State { maxLines: 1, style: TextStyle( fontWeight: FontWeight.bold, - fontSize: widget.gameSession - .getLengthOfPlayerNames() > - 28 - ? 14 - : 18, + fontSize: _getSegmendetControlFontSize( + widget.gameSession + .getMaxLengthOfPlayerNames()), ), ), ), @@ -191,7 +183,13 @@ class _RoundViewState extends State { borderRadius: BorderRadius.circular(12), child: CupertinoListTile( backgroundColor: CupertinoColors.secondaryLabel, - title: Row(children: [Text(name)]), + title: Row(children: [ + Expanded( + child: Text( + name, + overflow: TextOverflow.ellipsis, + )) + ]), subtitle: Text( '${widget.gameSession.playerScores[index]}' ' ${AppLocalizations.of(context).points}'), @@ -395,6 +393,32 @@ class _RoundViewState extends State { } } + double _getSegmendetControlFontSize(int maxLength) { + if (maxLength > 8) { + // 9 - 12 characters + return 9.0; + } else if (maxLength > 4) { + // 5 - 8 characters + return 15.0; + } else { + // 0 - 4 characters + return 18.0; + } + } + + double _getSegmendetControlPadding(int maxLength) { + if (maxLength > 8) { + // 9 - 12 characters + return 0.0; + } else if (maxLength > 4) { + // 5 - 8 characters + return 5.0; + } else { + // 0 - 4 characters + return 8.0; + } + } + @override void dispose() { for (final controller in _scoreControllerList) { diff --git a/pubspec.yaml b/pubspec.yaml index b0bf86a..ffc7346 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.2+244 +version: 0.3.2+248 environment: sdk: ^3.5.4 From 9fcd919847cd2c1740c00be179896c8de78924a4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 21:29:10 +0200 Subject: [PATCH 003/353] Implemented FittedBox Widget --- lib/views/round_view.dart | 22 ++++++++++++---------- pubspec.yaml | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index b945ec4..b1b98e3 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -123,19 +123,21 @@ class _RoundViewState extends State { index, Padding( padding: EdgeInsets.symmetric( - horizontal: + horizontal: 4 + _getSegmendetControlPadding(maxLength), vertical: 6, ), - child: Text( - name, - textAlign: TextAlign.center, - maxLines: 1, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: _getSegmendetControlFontSize( - widget.gameSession - .getMaxLengthOfPlayerNames()), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text( + name, + textAlign: TextAlign.center, + maxLines: 1, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: _getSegmendetControlFontSize( + maxLength), + ), ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index ffc7346..0ba04e5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.2+248 +version: 0.3.3+255 environment: sdk: ^3.5.4 @@ -26,6 +26,7 @@ dependencies: sdk: flutter intl: any syncfusion_flutter_charts: ^30.1.37 + auto_size_text: ^3.0.0 dev_dependencies: flutter_test: From 722b8357ac0d8b902b105d55ac99a5a203981207 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 21:46:01 +0200 Subject: [PATCH 004/353] Added navigation on the big plus button in home menu --- lib/views/main_menu_view.dart | 22 +++++++++++++++------- pubspec.yaml | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 90c384c..2f5eee9 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -50,7 +50,9 @@ class _MainMenuViewState extends State { CupertinoPageRoute( builder: (context) => const SettingsView(), ), - ); + ).then((_) { + setState(() {}); + }); }, icon: const Icon(CupertinoIcons.settings, size: 30)), middle: const Text('Cabo Counter'), @@ -77,7 +79,12 @@ class _MainMenuViewState extends State { const SizedBox(height: 30), // Abstand von oben Center( child: GestureDetector( - onTap: () => setState(() {}), + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const CreateGame(), + ), + ), child: Icon( CupertinoIcons.plus, size: 60, @@ -85,15 +92,16 @@ class _MainMenuViewState extends State { ), )), const SizedBox(height: 10), // Abstand von oben - const Padding( - padding: EdgeInsets.symmetric(horizontal: 70), + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 70), child: Text( - 'Ganz schön leer hier...\nFüge über den Button oben rechts eine neue Runde hinzu.', + '${AppLocalizations.of(context).empty_text_1}\n${AppLocalizations.of(context).empty_text_2}', textAlign: TextAlign.center, - style: TextStyle(fontSize: 16), + style: const TextStyle(fontSize: 16), ), ), - ], + ], //Ganz schön leer hier... Füge über den Button oben rechts eine neue Runde hinzu. ) : ListView.builder( itemCount: gameManager.gameList.length, diff --git a/pubspec.yaml b/pubspec.yaml index b0bf86a..89087f1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.2+244 +version: 0.3.2+245 environment: sdk: ^3.5.4 From 4e43ead072888b2f36514eac810105b15dec1e40 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:22:56 +0200 Subject: [PATCH 005/353] Updated import method --- lib/services/local_storage_service.dart | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index e3fddcc..eafcdc4 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -111,7 +111,7 @@ class LocalStorageService { } /// Opens the file picker to import a JSON file and loads the game data from it. - static Future importJsonFile() async { + static Future importJsonFile() async { final result = await FilePicker.platform.pickFiles( dialogTitle: 'Wähle eine Datei mit Spieldaten aus', type: FileType.custom, @@ -121,14 +121,14 @@ class LocalStorageService { if (result == null) { print( '[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen'); - return false; + return 0; } try { final jsonString = await _readFileContent(result.files.single); if (!await validateJsonSchema(jsonString)) { - return false; + return -1; } final jsonData = json.decode(jsonString) as List; gameManager.gameList = jsonData @@ -137,15 +137,16 @@ class LocalStorageService { .toList(); print( '[local_storage_service.dart] Die Datei wurde erfolgreich Importiertn'); - return true; + await saveGameSessions(); + return 1; } on FormatException catch (e) { print( '[local_storage_service.dart] Ungültiges JSON-Format. Exception: $e'); - return false; + return -2; } on Exception catch (e) { print( '[local_storage_service.dart] Fehler beim Dateizugriff. Exception: $e'); - return false; + return -3; } } From dc8efbdd6130db0425dcc62772bf81970be1edf4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:23:12 +0200 Subject: [PATCH 006/353] Implemented feedback dialog --- lib/views/settings_view.dart | 59 +++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 53eb92d..2b185ef 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -1,3 +1,4 @@ +import 'package:analyzer_plugin/utilities/pair.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; @@ -125,27 +126,7 @@ class _SettingsViewState extends State { onPressed: () async { final success = await LocalStorageService.importJsonFile(); - if (!success && context.mounted) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text( - AppLocalizations.of(context) - .error), - content: Text( - AppLocalizations.of(context) - .error_import), - actions: [ - CupertinoDialogAction( - child: Text( - AppLocalizations.of(context) - .ok), - onPressed: () => - Navigator.pop(context), - ), - ], - )); - } + showFeedbackDialog(success); }), const SizedBox( width: 20, @@ -236,4 +217,40 @@ class _SettingsViewState extends State { Future _getPackageInfo() async { return await PackageInfo.fromPlatform(); } + + void showFeedbackDialog(int success) { + if (success == 0) return; + final content = _getDialogContent(success); + + showCupertinoDialog( + context: context, + builder: (context) { + return CupertinoAlertDialog( + title: Text(content.first), + content: Text(content.last), + actions: [ + CupertinoDialogAction( + child: const Text('OK'), + onPressed: () => Navigator.pop(context), + ), + ], + ); + }); + } + + Pair _getDialogContent(int success) { + if (success == 1) { + return Pair(AppLocalizations.of(context).import_sucess_title, + AppLocalizations.of(context).import_sucess_message); + } else if (success == -1) { + return Pair(AppLocalizations.of(context).import_validation_error_title, + AppLocalizations.of(context).import_validation_error_title); + } else if (success == -2) { + return Pair(AppLocalizations.of(context).import_format_error_title, + AppLocalizations.of(context).import_format_error_title); + } else { + return Pair(AppLocalizations.of(context).import_generic_error_title, + AppLocalizations.of(context).import_generic_error_title); + } + } } From 98bc9bd837ed70fe3c4793755458fbcfaf1f7b6a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:25:29 +0200 Subject: [PATCH 007/353] Added localization --- lib/l10n/app_de.arb | 11 ++++++- lib/l10n/app_en.arb | 11 ++++++- lib/l10n/app_localizations.dart | 48 ++++++++++++++++++++++++++++-- lib/l10n/app_localizations_de.dart | 26 +++++++++++++++- lib/l10n/app_localizations_en.dart | 26 +++++++++++++++- lib/views/settings_view.dart | 2 +- pubspec.yaml | 3 +- 7 files changed, 118 insertions(+), 9 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 3cb8c5e..26d9320 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -81,7 +81,16 @@ "import_data": "Daten importieren", "export_data": "Daten exportieren", "error": "Fehler", - "error_import": "Datei konnte nicht importiert werden", + + "import_sucess_title": "Import erfolgreich", + "import_sucess_message":"Die Spieldaten wurden erfolgreich importiert.", + "import_validation_error_title": "Validierung fehlgeschlagen", + "import_validation_error_message": "Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.", + "import_format_error_title": "Falsches Format", + "import_format_error_message": "Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.", + "import_generic_error_title": "Import fehlgeschlagen", + "import_generic_error_message": "Der Import ist fehlgeschlagen.", + "error_export": "Datei konnte nicht exportiert werden", "error_found": "Fehler gefunden?", "create_issue": "Issue erstellen", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f76e04a..120d8a0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -81,7 +81,16 @@ "import_data": "Import Data", "export_data": "Export Data", "error": "Error", - "error_import": "Could not import file", + + "import_sucess_title": "Import successful", + "import_sucess_message":"The game data has been successfully imported.", + "import_validation_error_title": "Validation failed", + "import_validation_error_message": "No Cabo-Counter game data was found. Please make sure that this is a valid Cabo-Counter export file.", + "import_format_error_title": "Wrong format", + "import_format_error_message": "The file is not a valid JSON format or contains invalid data.", + "import_generic_error_title": "Import failed", + "import_generic_error_message": "The import has failed.", + "error_export": "Could not export file", "error_found": "Found a bug?", "create_issue": "Create Issue", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 1751ab7..84b9a42 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -452,11 +452,53 @@ abstract class AppLocalizations { /// **'Fehler'** String get error; - /// No description provided for @error_import. + /// No description provided for @import_sucess_title. /// /// In de, this message translates to: - /// **'Datei konnte nicht importiert werden'** - String get error_import; + /// **'Import erfolgreich'** + String get import_sucess_title; + + /// No description provided for @import_sucess_message. + /// + /// In de, this message translates to: + /// **'Die Spieldaten wurden erfolgreich importiert.'** + String get import_sucess_message; + + /// No description provided for @import_validation_error_title. + /// + /// In de, this message translates to: + /// **'Validierung fehlgeschlagen'** + String get import_validation_error_title; + + /// No description provided for @import_validation_error_message. + /// + /// In de, this message translates to: + /// **'Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.'** + String get import_validation_error_message; + + /// No description provided for @import_format_error_title. + /// + /// In de, this message translates to: + /// **'Falsches Format'** + String get import_format_error_title; + + /// No description provided for @import_format_error_message. + /// + /// In de, this message translates to: + /// **'Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.'** + String get import_format_error_message; + + /// No description provided for @import_generic_error_title. + /// + /// In de, this message translates to: + /// **'Import fehlgeschlagen'** + String get import_generic_error_title; + + /// No description provided for @import_generic_error_message. + /// + /// In de, this message translates to: + /// **'Der Import ist fehlgeschlagen.'** + String get import_generic_error_message; /// No description provided for @error_export. /// diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 434b5f1..e7719b1 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -195,7 +195,31 @@ class AppLocalizationsDe extends AppLocalizations { String get error => 'Fehler'; @override - String get error_import => 'Datei konnte nicht importiert werden'; + String get import_sucess_title => 'Import erfolgreich'; + + @override + String get import_sucess_message => + 'Die Spieldaten wurden erfolgreich importiert.'; + + @override + String get import_validation_error_title => 'Validierung fehlgeschlagen'; + + @override + String get import_validation_error_message => + 'Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.'; + + @override + String get import_format_error_title => 'Falsches Format'; + + @override + String get import_format_error_message => + 'Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.'; + + @override + String get import_generic_error_title => 'Import fehlgeschlagen'; + + @override + String get import_generic_error_message => 'Der Import ist fehlgeschlagen.'; @override String get error_export => 'Datei konnte nicht exportiert werden'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 64cdb77..9f9ff13 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -192,7 +192,31 @@ class AppLocalizationsEn extends AppLocalizations { String get error => 'Error'; @override - String get error_import => 'Could not import file'; + String get import_sucess_title => 'Import successful'; + + @override + String get import_sucess_message => + 'The game data has been successfully imported.'; + + @override + String get import_validation_error_title => 'Validation failed'; + + @override + String get import_validation_error_message => + 'No Cabo-Counter game data was found. Please make sure that this is a valid Cabo-Counter export file.'; + + @override + String get import_format_error_title => 'Wrong format'; + + @override + String get import_format_error_message => + 'The file is not a valid JSON format or contains invalid data.'; + + @override + String get import_generic_error_title => 'Import failed'; + + @override + String get import_generic_error_message => 'The import has failed.'; @override String get error_export => 'Could not export file'; diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 2b185ef..0f41d21 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -230,7 +230,7 @@ class _SettingsViewState extends State { content: Text(content.last), actions: [ CupertinoDialogAction( - child: const Text('OK'), + child: Text(AppLocalizations.of(context).ok), onPressed: () => Navigator.pop(context), ), ], diff --git a/pubspec.yaml b/pubspec.yaml index 89087f1..e464e51 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.2+245 +version: 0.3.2+252 environment: sdk: ^3.5.4 @@ -26,6 +26,7 @@ dependencies: sdk: flutter intl: any syncfusion_flutter_charts: ^30.1.37 + analyzer_plugin: ^0.13.4 dev_dependencies: flutter_test: From 59c710a43fde69752c8b8a51ebebea3fbf6369c7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:29:23 +0200 Subject: [PATCH 008/353] Removed print --- lib/data/game_session.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index cdbb461..80f1152 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -80,7 +80,6 @@ class GameSession extends ChangeNotifier { length = player.length; } } - print('Maximale Länge der Spielernamen: $length'); return length; } From 3e0482e963f2005c580e49a23ddd971d939651ab Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:29:31 +0200 Subject: [PATCH 009/353] Refactored method names --- lib/views/round_view.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index b1b98e3..c40db1b 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -124,7 +124,7 @@ class _RoundViewState extends State { Padding( padding: EdgeInsets.symmetric( horizontal: 4 + - _getSegmendetControlPadding(maxLength), + _getSegmentedControlPadding(maxLength), vertical: 6, ), child: FittedBox( @@ -135,7 +135,7 @@ class _RoundViewState extends State { maxLines: 1, style: TextStyle( fontWeight: FontWeight.bold, - fontSize: _getSegmendetControlFontSize( + fontSize: _getSegmentedControlFontSize( maxLength), ), ), @@ -395,7 +395,7 @@ class _RoundViewState extends State { } } - double _getSegmendetControlFontSize(int maxLength) { + double _getSegmentedControlFontSize(int maxLength) { if (maxLength > 8) { // 9 - 12 characters return 9.0; @@ -408,7 +408,7 @@ class _RoundViewState extends State { } } - double _getSegmendetControlPadding(int maxLength) { + double _getSegmentedControlPadding(int maxLength) { if (maxLength > 8) { // 9 - 12 characters return 0.0; From f7ea02603724c1386c11621e8e606c72e3dff90a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:32:33 +0200 Subject: [PATCH 010/353] Corrected typos --- lib/l10n/app_de.arb | 4 ++-- lib/l10n/app_en.arb | 4 ++-- lib/l10n/app_localizations.dart | 8 ++++---- lib/l10n/app_localizations_de.dart | 4 ++-- lib/l10n/app_localizations_en.dart | 4 ++-- lib/views/settings_view.dart | 10 +++++----- pubspec.yaml | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 26d9320..51147d0 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -82,8 +82,8 @@ "export_data": "Daten exportieren", "error": "Fehler", - "import_sucess_title": "Import erfolgreich", - "import_sucess_message":"Die Spieldaten wurden erfolgreich importiert.", + "import_success_title": "Import erfolgreich", + "import_success_message":"Die Spieldaten wurden erfolgreich importiert.", "import_validation_error_title": "Validierung fehlgeschlagen", "import_validation_error_message": "Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.", "import_format_error_title": "Falsches Format", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 120d8a0..a6b1a8f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -82,8 +82,8 @@ "export_data": "Export Data", "error": "Error", - "import_sucess_title": "Import successful", - "import_sucess_message":"The game data has been successfully imported.", + "import_success_title": "Import successful", + "import_success_message":"The game data has been successfully imported.", "import_validation_error_title": "Validation failed", "import_validation_error_message": "No Cabo-Counter game data was found. Please make sure that this is a valid Cabo-Counter export file.", "import_format_error_title": "Wrong format", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 84b9a42..a4e1edb 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -452,17 +452,17 @@ abstract class AppLocalizations { /// **'Fehler'** String get error; - /// No description provided for @import_sucess_title. + /// No description provided for @import_success_title. /// /// In de, this message translates to: /// **'Import erfolgreich'** - String get import_sucess_title; + String get import_success_title; - /// No description provided for @import_sucess_message. + /// No description provided for @import_success_message. /// /// In de, this message translates to: /// **'Die Spieldaten wurden erfolgreich importiert.'** - String get import_sucess_message; + String get import_success_message; /// No description provided for @import_validation_error_title. /// diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index e7719b1..b06d454 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -195,10 +195,10 @@ class AppLocalizationsDe extends AppLocalizations { String get error => 'Fehler'; @override - String get import_sucess_title => 'Import erfolgreich'; + String get import_success_title => 'Import erfolgreich'; @override - String get import_sucess_message => + String get import_success_message => 'Die Spieldaten wurden erfolgreich importiert.'; @override diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 9f9ff13..2dfc72d 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -192,10 +192,10 @@ class AppLocalizationsEn extends AppLocalizations { String get error => 'Error'; @override - String get import_sucess_title => 'Import successful'; + String get import_success_title => 'Import successful'; @override - String get import_sucess_message => + String get import_success_message => 'The game data has been successfully imported.'; @override diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 0f41d21..7172969 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -240,17 +240,17 @@ class _SettingsViewState extends State { Pair _getDialogContent(int success) { if (success == 1) { - return Pair(AppLocalizations.of(context).import_sucess_title, - AppLocalizations.of(context).import_sucess_message); + return Pair(AppLocalizations.of(context).import_success_title, + AppLocalizations.of(context).import_success_message); } else if (success == -1) { return Pair(AppLocalizations.of(context).import_validation_error_title, - AppLocalizations.of(context).import_validation_error_title); + AppLocalizations.of(context).import_validation_error_message); } else if (success == -2) { return Pair(AppLocalizations.of(context).import_format_error_title, - AppLocalizations.of(context).import_format_error_title); + AppLocalizations.of(context).import_format_error_message); } else { return Pair(AppLocalizations.of(context).import_generic_error_title, - AppLocalizations.of(context).import_generic_error_title); + AppLocalizations.of(context).import_generic_error_message); } } } diff --git a/pubspec.yaml b/pubspec.yaml index e464e51..ecff07a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.2+252 +version: 0.3.2+253 environment: sdk: ^3.5.4 From 3c09d1f7f2e238915e8d229fe734afde9a973a64 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:34:42 +0200 Subject: [PATCH 011/353] Corrected tests --- test/data/game_session_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index 0ab65d0..de4e284 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -61,8 +61,8 @@ void main() { }); group('Helper Functions', () { - test('getLengthOfPlayerNames', () { - expect(session.getMaxLengthOfPlayerNames(), equals(7)); // Charlie(7) + test('getMaxLengthOfPlayerNames', () { + expect(session.getMaxLengthOfPlayerNames(), equals(7)); // Charlie (7) }); test('increaseRound', () { From 9d3d6b3ca3688643408ef920596487be087a0ba6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:34:49 +0200 Subject: [PATCH 012/353] Corrected docs --- lib/data/game_session.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 80f1152..a741ae8 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -72,7 +72,7 @@ class GameSession extends ChangeNotifier { roundList = (json['roundList'] as List).map((e) => Round.fromJson(e)).toList(); - /// Returns the length of all player names combined. + /// Returns the length of the longest player name. int getMaxLengthOfPlayerNames() { int length = 0; for (String player in players) { From aca46fec0f730dd4f83553c68a26fa4c3c5ace07 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:35:00 +0200 Subject: [PATCH 013/353] Removed unused package --- pubspec.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index f0a8fd2..7dc76bd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,7 +26,6 @@ dependencies: sdk: flutter intl: any syncfusion_flutter_charts: ^30.1.37 - auto_size_text: ^3.0.0 dev_dependencies: flutter_test: From 854afe1e7f6041d064f9119203e8d638a016f434 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:39:15 +0200 Subject: [PATCH 014/353] Replaced pair with tuple --- lib/views/settings_view.dart | 31 +++++++++++++++++++------------ pubspec.yaml | 3 +-- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 7172969..4876cc7 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -1,4 +1,3 @@ -import 'package:analyzer_plugin/utilities/pair.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; @@ -226,8 +225,8 @@ class _SettingsViewState extends State { context: context, builder: (context) { return CupertinoAlertDialog( - title: Text(content.first), - content: Text(content.last), + title: Text(content.$1), + content: Text(content.$2), actions: [ CupertinoDialogAction( child: Text(AppLocalizations.of(context).ok), @@ -238,19 +237,27 @@ class _SettingsViewState extends State { }); } - Pair _getDialogContent(int success) { + (String, String) _getDialogContent(int success) { if (success == 1) { - return Pair(AppLocalizations.of(context).import_success_title, - AppLocalizations.of(context).import_success_message); + return ( + AppLocalizations.of(context).import_success_title, + AppLocalizations.of(context).import_success_message + ); } else if (success == -1) { - return Pair(AppLocalizations.of(context).import_validation_error_title, - AppLocalizations.of(context).import_validation_error_message); + return ( + AppLocalizations.of(context).import_validation_error_title, + AppLocalizations.of(context).import_validation_error_message + ); } else if (success == -2) { - return Pair(AppLocalizations.of(context).import_format_error_title, - AppLocalizations.of(context).import_format_error_message); + return ( + AppLocalizations.of(context).import_format_error_title, + AppLocalizations.of(context).import_format_error_message + ); } else { - return Pair(AppLocalizations.of(context).import_generic_error_title, - AppLocalizations.of(context).import_generic_error_message); + return ( + AppLocalizations.of(context).import_generic_error_title, + AppLocalizations.of(context).import_generic_error_message + ); } } } diff --git a/pubspec.yaml b/pubspec.yaml index ecff07a..c55a475 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.2+253 +version: 0.3.2+254 environment: sdk: ^3.5.4 @@ -26,7 +26,6 @@ dependencies: sdk: flutter intl: any syncfusion_flutter_charts: ^30.1.37 - analyzer_plugin: ^0.13.4 dev_dependencies: flutter_test: From c72db61997d4a6f3b471ebaceff177a42826562a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:45:17 +0200 Subject: [PATCH 015/353] Destructed record --- lib/views/settings_view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 4876cc7..068138a 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -219,14 +219,14 @@ class _SettingsViewState extends State { void showFeedbackDialog(int success) { if (success == 0) return; - final content = _getDialogContent(success); + final (title, message) = _getDialogContent(success); showCupertinoDialog( context: context, builder: (context) { return CupertinoAlertDialog( - title: Text(content.$1), - content: Text(content.$2), + title: Text(title), + content: Text(message), actions: [ CupertinoDialogAction( child: Text(AppLocalizations.of(context).ok), From ac2b071a7ec5b2d3d0b9dd7f0bc76042592b34fb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:56:59 +0200 Subject: [PATCH 016/353] Implemented enum for import status --- lib/services/local_storage_service.dart | 20 +++++++---- lib/views/settings_view.dart | 48 +++++++++++++------------ 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index eafcdc4..6039a7b 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -9,6 +9,14 @@ import 'package:flutter/services.dart'; import 'package:json_schema/json_schema.dart'; import 'package:path_provider/path_provider.dart'; +enum ImportStatus { + success, + canceled, + validationError, + formatError, + genericError +} + class LocalStorageService { static const String _fileName = 'game_data.json'; @@ -111,7 +119,7 @@ class LocalStorageService { } /// Opens the file picker to import a JSON file and loads the game data from it. - static Future importJsonFile() async { + static Future importJsonFile() async { final result = await FilePicker.platform.pickFiles( dialogTitle: 'Wähle eine Datei mit Spieldaten aus', type: FileType.custom, @@ -121,14 +129,14 @@ class LocalStorageService { if (result == null) { print( '[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen'); - return 0; + return ImportStatus.canceled; } try { final jsonString = await _readFileContent(result.files.single); if (!await validateJsonSchema(jsonString)) { - return -1; + return ImportStatus.validationError; } final jsonData = json.decode(jsonString) as List; gameManager.gameList = jsonData @@ -138,15 +146,15 @@ class LocalStorageService { print( '[local_storage_service.dart] Die Datei wurde erfolgreich Importiertn'); await saveGameSessions(); - return 1; + return ImportStatus.success; } on FormatException catch (e) { print( '[local_storage_service.dart] Ungültiges JSON-Format. Exception: $e'); - return -2; + return ImportStatus.formatError; } on Exception catch (e) { print( '[local_storage_service.dart] Fehler beim Dateizugriff. Exception: $e'); - return -3; + return ImportStatus.genericError; } } diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 068138a..270118f 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -217,7 +217,7 @@ class _SettingsViewState extends State { return await PackageInfo.fromPlatform(); } - void showFeedbackDialog(int success) { + void showFeedbackDialog(ImportStatus success) { if (success == 0) return; final (title, message) = _getDialogContent(success); @@ -237,27 +237,31 @@ class _SettingsViewState extends State { }); } - (String, String) _getDialogContent(int success) { - if (success == 1) { - return ( - AppLocalizations.of(context).import_success_title, - AppLocalizations.of(context).import_success_message - ); - } else if (success == -1) { - return ( - AppLocalizations.of(context).import_validation_error_title, - AppLocalizations.of(context).import_validation_error_message - ); - } else if (success == -2) { - return ( - AppLocalizations.of(context).import_format_error_title, - AppLocalizations.of(context).import_format_error_message - ); - } else { - return ( - AppLocalizations.of(context).import_generic_error_title, - AppLocalizations.of(context).import_generic_error_message - ); + (String, String) _getDialogContent(ImportStatus success) { + switch (success) { + 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 ('', ''); } } } From dc0482e9b7482ae1989e57aee00cff4d3dc7e5cc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 22:59:54 +0200 Subject: [PATCH 017/353] Renamed input var --- lib/views/settings_view.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 270118f..b36347d 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -217,9 +217,9 @@ class _SettingsViewState extends State { return await PackageInfo.fromPlatform(); } - void showFeedbackDialog(ImportStatus success) { - if (success == 0) return; - final (title, message) = _getDialogContent(success); + void showFeedbackDialog(ImportStatus status) { + if (status == ImportStatus.canceled) return; + final (title, message) = _getDialogContent(status); showCupertinoDialog( context: context, @@ -237,8 +237,8 @@ class _SettingsViewState extends State { }); } - (String, String) _getDialogContent(ImportStatus success) { - switch (success) { + (String, String) _getDialogContent(ImportStatus status) { + switch (status) { case ImportStatus.success: return ( AppLocalizations.of(context).import_success_title, From 711e23a18a70f4fc410afedaf43d808d3af2602c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 1 Jul 2025 23:05:36 +0200 Subject: [PATCH 018/353] Changed swipe to delete direction --- lib/views/main_menu_view.dart | 6 +++--- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 2f5eee9..2c1dba2 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -114,15 +114,15 @@ class _MainMenuViewState extends State { key: Key(session.gameTitle), background: Container( color: CupertinoColors.destructiveRed, - alignment: Alignment.centerLeft, + alignment: Alignment.centerRight, padding: - const EdgeInsets.only(left: 20.0), + const EdgeInsets.only(right: 20.0), child: const Icon( CupertinoIcons.delete, color: CupertinoColors.white, ), ), - direction: DismissDirection.startToEnd, + direction: DismissDirection.endToStart, confirmDismiss: (direction) async { final String gameTitle = gameManager .gameList[index].gameTitle; diff --git a/pubspec.yaml b/pubspec.yaml index 39afb1b..af1107f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.3+265 +version: 0.3.4+267 environment: sdk: ^3.5.4 From a0206e613f934e6e39413137aac43d2da5c762f7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 2 Jul 2025 15:51:26 +0200 Subject: [PATCH 019/353] Removed forgotten string comment --- lib/views/main_menu_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 2c1dba2..ab52d4e 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -101,7 +101,7 @@ class _MainMenuViewState extends State { style: const TextStyle(fontSize: 16), ), ), - ], //Ganz schön leer hier... Füge über den Button oben rechts eine neue Runde hinzu. + ], ) : ListView.builder( itemCount: gameManager.gameList.length, From d6413c096d4ec2132ff59efe7a01db4e9983ad58 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 2 Jul 2025 16:30:29 +0200 Subject: [PATCH 020/353] Implemented new game same settings features --- lib/views/active_game_view.dart | 25 +++++++++++++++++------ lib/views/create_game_view.dart | 36 ++++++++++++++++++++++++++------- lib/views/main_menu_view.dart | 5 +++-- pubspec.yaml | 2 +- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 6266348..d4ff7bd 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -1,6 +1,7 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; +import 'package:cabo_counter/views/create_game_view.dart'; import 'package:cabo_counter/views/graph_view.dart'; import 'package:cabo_counter/views/round_view.dart'; import 'package:flutter/cupertino.dart'; @@ -141,12 +142,24 @@ class _ActiveGameViewState extends State { onTap: () {}, ), CupertinoListTile( - title: Text( - AppLocalizations.of(context) - .new_game_same_settings, - style: const TextStyle( - color: Colors.white30, - ))), + title: Text( + AppLocalizations.of(context) + .new_game_same_settings, + ), + onTap: () { + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (_) => CreateGameView( + gameTitle: + widget.gameSession.gameTitle, + isPointsLimitEnabled: widget + .gameSession + .isPointsLimitEnabled, + players: widget.gameSession.players, + ))); + }, + ), CupertinoListTile( title: Text(AppLocalizations.of(context).export_game, diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index adcbf86..70c65b4 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -7,18 +7,25 @@ import 'package:cabo_counter/views/active_game_view.dart'; import 'package:cabo_counter/views/mode_selection_view.dart'; import 'package:flutter/cupertino.dart'; -class CreateGame extends StatefulWidget { - const CreateGame({super.key}); +class CreateGameView extends StatefulWidget { + final String? gameTitle; + final bool? isPointsLimitEnabled; + final List? players; + + const CreateGameView({ + super.key, + this.gameTitle, + this.isPointsLimitEnabled, + this.players, + }); @override // ignore: library_private_types_in_public_api - _CreateGameState createState() => _CreateGameState(); + _CreateGameViewState createState() => _CreateGameViewState(); } -class _CreateGameState extends State { - final List _playerNameTextControllers = [ - TextEditingController() - ]; +class _CreateGameViewState extends State { + late List _playerNameTextControllers = []; final TextEditingController _gameTitleTextController = TextEditingController(); @@ -28,6 +35,21 @@ class _CreateGameState extends State { /// Variable to store the selected game mode. bool? selectedMode; + @override + void initState() { + selectedMode = widget.isPointsLimitEnabled; + _gameTitleTextController.text = widget.gameTitle ?? ''; + if (widget.players != null) { + _playerNameTextControllers = []; + for (var player in widget.players!) { + _playerNameTextControllers.add(TextEditingController(text: player)); + } + } else { + _playerNameTextControllers = [TextEditingController()]; + } + super.initState(); + } + @override Widget build(BuildContext context) { return CupertinoPageScaffold( diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index ab52d4e..f41a0ef 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -61,7 +61,7 @@ class _MainMenuViewState extends State { Navigator.push( context, CupertinoPageRoute( - builder: (context) => const CreateGame(), + builder: (context) => const CreateGameView(), ), ) }, @@ -82,7 +82,8 @@ class _MainMenuViewState extends State { onTap: () => Navigator.push( context, CupertinoPageRoute( - builder: (context) => const CreateGame(), + builder: (context) => + const CreateGameView(), ), ), child: Icon( diff --git a/pubspec.yaml b/pubspec.yaml index af1107f..a7c91ae 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.4+267 +version: 0.3.5+269 environment: sdk: ^3.5.4 From 8d411fcdb23c76f2c6690fcc412b3f9ab15556ce Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 2 Jul 2025 17:15:23 +0200 Subject: [PATCH 021/353] Refactoring & dispose updated --- lib/views/create_game_view.dart | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 70c65b4..609e9b0 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -33,11 +33,11 @@ class _CreateGameViewState extends State { final int maxPlayers = 5; /// Variable to store the selected game mode. - bool? selectedMode; + bool? _isPointsLimitEnabled; @override void initState() { - selectedMode = widget.isPointsLimitEnabled; + _isPointsLimitEnabled = widget.isPointsLimitEnabled; _gameTitleTextController.text = widget.gameTitle ?? ''; if (widget.players != null) { _playerNameTextControllers = []; @@ -91,9 +91,9 @@ class _CreateGameViewState extends State { suffix: Row( children: [ Text( - selectedMode == null + _isPointsLimitEnabled == null ? AppLocalizations.of(context).select_mode - : (selectedMode! + : (_isPointsLimitEnabled! ? '${Globals.pointLimit} ${AppLocalizations.of(context).points}' : AppLocalizations.of(context).unlimited), ), @@ -102,7 +102,7 @@ class _CreateGameViewState extends State { ], ), onTap: () async { - final selected = await Navigator.push( + final selectedMode = await Navigator.push( context, CupertinoPageRoute( builder: (context) => ModeSelectionMenu( @@ -111,9 +111,9 @@ class _CreateGameViewState extends State { ), ); - if (selected != null) { + if (selectedMode != null) { setState(() { - selectedMode = selected; + _isPointsLimitEnabled = selectedMode; }); } }, @@ -252,7 +252,7 @@ class _CreateGameViewState extends State { ); return; } - if (selectedMode == null) { + if (_isPointsLimitEnabled == null) { showCupertinoDialog( context: context, builder: (context) => CupertinoAlertDialog( @@ -315,7 +315,7 @@ class _CreateGameViewState extends State { players: players, pointLimit: Globals.pointLimit, caboPenalty: Globals.caboPenalty, - isPointsLimitEnabled: selectedMode!, + isPointsLimitEnabled: _isPointsLimitEnabled!, ); final index = await gameManager.addGameSession(gameSession); if (context.mounted) { @@ -343,6 +343,7 @@ class _CreateGameViewState extends State { @override void dispose() { + _gameTitleTextController.dispose(); for (var controller in _playerNameTextControllers) { controller.dispose(); } From 694fa3394bbca66f3d6a79811632b2da07afa00d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 2 Jul 2025 17:20:02 +0200 Subject: [PATCH 022/353] Removed unnessecary code --- lib/views/create_game_view.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 609e9b0..7377178 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -25,7 +25,9 @@ class CreateGameView extends StatefulWidget { } class _CreateGameViewState extends State { - late List _playerNameTextControllers = []; + final List _playerNameTextControllers = [ + TextEditingController() + ]; final TextEditingController _gameTitleTextController = TextEditingController(); @@ -39,13 +41,12 @@ class _CreateGameViewState extends State { void initState() { _isPointsLimitEnabled = widget.isPointsLimitEnabled; _gameTitleTextController.text = widget.gameTitle ?? ''; + if (widget.players != null) { - _playerNameTextControllers = []; + _playerNameTextControllers.clear(); for (var player in widget.players!) { _playerNameTextControllers.add(TextEditingController(text: player)); } - } else { - _playerNameTextControllers = [TextEditingController()]; } super.initState(); } From de423aaec3483fa284b003b9481cc27db46a9df5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 2 Jul 2025 17:41:05 +0200 Subject: [PATCH 023/353] Small changes --- lib/views/create_game_view.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 7377178..6c52890 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -34,11 +34,13 @@ class _CreateGameViewState extends State { /// Maximum number of players allowed in the game. final int maxPlayers = 5; - /// Variable to store the selected game mode. + /// Variable to store whether the points limit feature is enabled. bool? _isPointsLimitEnabled; @override void initState() { + super.initState(); + _isPointsLimitEnabled = widget.isPointsLimitEnabled; _gameTitleTextController.text = widget.gameTitle ?? ''; @@ -48,7 +50,6 @@ class _CreateGameViewState extends State { _playerNameTextControllers.add(TextEditingController(text: player)); } } - super.initState(); } @override @@ -348,6 +349,7 @@ class _CreateGameViewState extends State { for (var controller in _playerNameTextControllers) { controller.dispose(); } + super.dispose(); } } From 38e43f54d884d1c1dd227034aaaea9c0281b8e21 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 11:52:40 +0200 Subject: [PATCH 024/353] Added uuid to gameSession class & json scheme --- assets/schema.json | 3 +++ lib/data/game_session.dart | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/assets/schema.json b/assets/schema.json index 17d7faa..a9a07e5 100644 --- a/assets/schema.json +++ b/assets/schema.json @@ -5,6 +5,9 @@ "items": { "type": "object", "properties": { + "id": { + "type": "string" + }, "createdAt": { "type": "string" }, diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index a741ae8..ada34dc 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -1,5 +1,6 @@ import 'package:cabo_counter/data/round.dart'; import 'package:flutter/cupertino.dart'; +import 'package:uuid/uuid.dart'; /// This class represents a game session for Cabo game. /// [createdAt] is the timestamp of when the game session was created. @@ -12,6 +13,7 @@ import 'package:flutter/cupertino.dart'; /// [isGameFinished] is a boolean indicating if the game has ended yet. /// [winner] is the name of the player who won the game. class GameSession extends ChangeNotifier { + late String id; final DateTime createdAt; final String gameTitle; final List players; @@ -33,17 +35,21 @@ class GameSession extends ChangeNotifier { required this.isPointsLimitEnabled, }) { playerScores = List.filled(players.length, 0); + var uuid = const Uuid(); + id = uuid.v1(); + print('GameSession created with ID: $id'); } @override toString() { - return ('GameSession: [createdAt: $createdAt, gameTitle: $gameTitle, ' + return ('GameSession: [id: $id, createdAt: $createdAt, gameTitle: $gameTitle, ' 'isPointsLimitEnabled: $isPointsLimitEnabled, pointLimit: $pointLimit, caboPenalty: $caboPenalty,' ' players: $players, playerScores: $playerScores, roundList: $roundList, winner: $winner]'); } /// Converts the GameSession object to a JSON map. Map toJson() => { + 'id': id, 'createdAt': createdAt.toIso8601String(), 'gameTitle': gameTitle, 'players': players, @@ -59,7 +65,8 @@ class GameSession extends ChangeNotifier { /// Creates a GameSession object from a JSON map. GameSession.fromJson(Map json) - : createdAt = DateTime.parse(json['createdAt']), + : id = json['id'] ?? const Uuid().v1(), + createdAt = DateTime.parse(json['createdAt']), gameTitle = json['gameTitle'], players = List.from(json['players']), pointLimit = json['pointLimit'], From 9eb3cac0981d9253d2dbceeda201996138a7d72e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 11:52:50 +0200 Subject: [PATCH 025/353] Addewd temp print --- lib/services/local_storage_service.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 6039a7b..71dd332 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -86,6 +86,11 @@ class LocalStorageService { GameSession.fromJson(jsonItem as Map)) .toList(); + for (GameSession session in gameManager.gameList) { + print( + '[local_storage_service.dart] Geladene Session: ${session.gameTitle} - ${session.id}'); + } + print( '[local_storage_service.dart] Die Spieldaten wurden erfolgreich geladen und verarbeitet'); return true; From a756c493970d62c1563c50c9cd31c2657894b34f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 11:53:30 +0200 Subject: [PATCH 026/353] Added function getGameSessionIndexById() and renamed removeGameSessionByIndex() --- lib/data/game_manager.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 94b6287..f00d73c 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -30,12 +30,19 @@ class GameManager extends ChangeNotifier { /// Takes a [index] as input. It then removes the session at the specified index from the `gameList`, /// sorts the list in descending order based on the creation date, and notifies listeners of the change. /// It also saves the updated game sessions to local storage. - void removeGameSession(int index) { + void removeGameSessionByIndex(int index) { gameList[index].removeListener(notifyListeners); gameList.removeAt(index); notifyListeners(); LocalStorageService.saveGameSessions(); } + + /// Removes a game session by its ID. + /// Takes a String [id] as input. It finds the index of the game session with the matching ID + /// in the `gameList`, and then calls `removeGameSessionByIndex` with that index. + int getGameSessionIndexById(String id) { + return gameList.indexWhere((session) => session.id.toString() == id); + } } final gameManager = GameManager(); From f7842404113dc1d535acd343777550512834e765 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 11:53:46 +0200 Subject: [PATCH 027/353] Refactoring --- lib/views/main_menu_view.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index f41a0ef..6597a68 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -131,7 +131,8 @@ class _MainMenuViewState extends State { gameTitle); }, onDismissed: (direction) { - gameManager.removeGameSession(index); + gameManager + .removeGameSessionByIndex(index); }, dismissThresholds: const { DismissDirection.startToEnd: 0.6 From f9fac719b0da671ffeefb3b6a24a10d20aad4be9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 11:58:25 +0200 Subject: [PATCH 028/353] Changed function and altered return type --- lib/data/game_manager.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index f00d73c..f29270c 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -40,8 +40,12 @@ class GameManager extends ChangeNotifier { /// Removes a game session by its ID. /// Takes a String [id] as input. It finds the index of the game session with the matching ID /// in the `gameList`, and then calls `removeGameSessionByIndex` with that index. - int getGameSessionIndexById(String id) { - return gameList.indexWhere((session) => session.id.toString() == id); + bool removeGameSessionById(String id) { + final int index = + gameList.indexWhere((session) => session.id.toString() == id); + if (index == -1) return false; + removeGameSessionByIndex(index); + return true; } } From 2c1d65c4034761f8710d38d23c99dd5179790064 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 13:05:28 +0200 Subject: [PATCH 029/353] Changed state handling --- lib/views/main_menu_view.dart | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 6597a68..3a9441f 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -169,18 +169,19 @@ class _MainMenuViewState extends State { CupertinoIcons.person_2_fill), ], ), - onTap: () async { - //ignore: unused_local_variable - final val = await Navigator.push( + onTap: () { + final session = + gameManager.gameList[index]; + Navigator.push( context, CupertinoPageRoute( builder: (context) => ActiveGameView( - gameSession: gameManager - .gameList[index]), + gameSession: session), ), - ); - setState(() {}); + ).then((_) { + setState(() {}); + }); }, ), ), From d34c6fff53c480bd5f402804a6083d9271fd155a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 13:06:12 +0200 Subject: [PATCH 030/353] Added function gameExistsInGameList --- lib/data/game_manager.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index f29270c..1ccc9dc 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -15,14 +15,9 @@ class GameManager extends ChangeNotifier { notifyListeners(); // Propagate session changes }); gameList.add(session); - print( - '[game_manager.dart] Added game session: ${session.gameTitle} at ${session.createdAt}'); gameList.sort((a, b) => b.createdAt.compareTo(a.createdAt)); - print( - '[game_manager.dart] Sorted game sessions by creation date. Total sessions: ${gameList.length}'); notifyListeners(); await LocalStorageService.saveGameSessions(); - print('[game_manager.dart] Saved game sessions to local storage.'); return gameList.indexOf(session); } @@ -40,12 +35,17 @@ class GameManager extends ChangeNotifier { /// Removes a game session by its ID. /// Takes a String [id] as input. It finds the index of the game session with the matching ID /// in the `gameList`, and then calls `removeGameSessionByIndex` with that index. - bool removeGameSessionById(String id) { + void removeGameSessionById(String id) { final int index = gameList.indexWhere((session) => session.id.toString() == id); - if (index == -1) return false; + if (index == -1) return; removeGameSessionByIndex(index); - return true; + } + + bool gameExistsInGameList(String id) { + return gameList.any((session) => session.id.toString() == id) == -1 + ? false + : true; } } From e45fc8abc886644229019cbca319d7f52edbb971 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 13:06:40 +0200 Subject: [PATCH 031/353] Input changed to copy instead of reference --- lib/views/create_game_view.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 6c52890..fd59529 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -320,12 +320,13 @@ class _CreateGameViewState extends State { isPointsLimitEnabled: _isPointsLimitEnabled!, ); final index = await gameManager.addGameSession(gameSession); + final session = gameManager.gameList[index]; if (context.mounted) { Navigator.pushReplacement( context, CupertinoPageRoute( - builder: (context) => ActiveGameView( - gameSession: gameManager.gameList[index]))); + builder: (context) => + ActiveGameView(gameSession: session))); } }, ), From 5389ce1d442fda7107fa6690948dc0a2a27fbd81 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 13:07:01 +0200 Subject: [PATCH 032/353] Implemented deletion button --- lib/main.dart | 1 + lib/views/active_game_view.dart | 123 ++++++++++++++++++++++++-------- pubspec.yaml | 3 +- 3 files changed, 96 insertions(+), 31 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 27c3835..2a2a91e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -65,6 +65,7 @@ class _AppState extends State with WidgetsBindingObserver { return supportedLocales.first; }, theme: CupertinoThemeData( + applyThemeToAll: true, brightness: Brightness.dark, primaryColor: CustomTheme.primaryColor, scaffoldBackgroundColor: CustomTheme.backgroundColor, diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index d4ff7bd..b5eafc3 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; @@ -17,15 +18,24 @@ class ActiveGameView extends StatefulWidget { } class _ActiveGameViewState extends State { + late final GameSession gameSession; + bool _deleted = false; + + @override + void initState() { + super.initState(); + gameSession = widget.gameSession; + } + @override Widget build(BuildContext context) { return ListenableBuilder( - listenable: widget.gameSession, + listenable: gameSession, builder: (context, _) { List sortedPlayerIndices = _getSortedPlayerIndices(); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - middle: Text(widget.gameSession.gameTitle), + middle: Text(gameSession.gameTitle), ), child: SafeArea( child: SingleChildScrollView( @@ -42,7 +52,7 @@ class _ActiveGameViewState extends State { ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemCount: widget.gameSession.players.length, + itemCount: gameSession.players.length, itemBuilder: (BuildContext context, int index) { int playerIndex = sortedPlayerIndices[index]; return CupertinoListTile( @@ -51,7 +61,7 @@ class _ActiveGameViewState extends State { _getPlacementPrefix(index), const SizedBox(width: 5), Text( - widget.gameSession.players[playerIndex], + gameSession.players[playerIndex], style: const TextStyle( fontWeight: FontWeight.bold), ), @@ -60,8 +70,7 @@ class _ActiveGameViewState extends State { trailing: Row( children: [ const SizedBox(width: 5), - Text( - '${widget.gameSession.playerScores[playerIndex]} ' + Text('${gameSession.playerScores[playerIndex]} ' '${AppLocalizations.of(context).points}') ], ), @@ -78,7 +87,7 @@ class _ActiveGameViewState extends State { ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemCount: widget.gameSession.roundNumber, + itemCount: gameSession.roundNumber, itemBuilder: (BuildContext context, int index) { return Padding( padding: const EdgeInsets.all(1), @@ -88,14 +97,13 @@ class _ActiveGameViewState extends State { title: Text( '${AppLocalizations.of(context).round} ${index + 1}', ), - trailing: index + 1 != - widget.gameSession.roundNumber || - widget.gameSession.isGameFinished == - true - ? (const Text('\u{2705}', - style: TextStyle(fontSize: 22))) - : const Text('\u{23F3}', - style: TextStyle(fontSize: 22)), + trailing: + index + 1 != gameSession.roundNumber || + gameSession.isGameFinished == true + ? (const Text('\u{2705}', + style: TextStyle(fontSize: 22))) + : const Text('\u{23F3}', + style: TextStyle(fontSize: 22)), onTap: () async { // ignore: unused_local_variable final val = await Navigator.of(context, @@ -104,7 +112,7 @@ class _ActiveGameViewState extends State { CupertinoPageRoute( fullscreenDialog: true, builder: (context) => RoundView( - gameSession: widget.gameSession, + gameSession: gameSession, roundNumber: index + 1), ), ); @@ -129,17 +137,21 @@ class _ActiveGameViewState extends State { ), onTap: () => Navigator.push( context, - MaterialPageRoute( + CupertinoPageRoute( builder: (_) => GraphView( - gameSession: widget.gameSession, + gameSession: gameSession, )))), CupertinoListTile( - title: - Text(AppLocalizations.of(context).delete_game, - style: const TextStyle( - color: Colors.white30, - )), - onTap: () {}, + title: Text( + AppLocalizations.of(context).delete_game, + ), + onTap: () { + _showDeleteGameDialog().then((value) { + if (value) { + _removeGameSession(gameSession); + } + }); + }, ), CupertinoListTile( title: Text( @@ -151,12 +163,11 @@ class _ActiveGameViewState extends State { context, CupertinoPageRoute( builder: (_) => CreateGameView( - gameTitle: - widget.gameSession.gameTitle, + gameTitle: gameSession.gameTitle, isPointsLimitEnabled: widget .gameSession .isPointsLimitEnabled, - players: widget.gameSession.players, + players: gameSession.players, ))); }, ), @@ -180,11 +191,11 @@ class _ActiveGameViewState extends State { /// ascending order. List _getSortedPlayerIndices() { List playerIndices = - List.generate(widget.gameSession.players.length, (index) => index); + List.generate(gameSession.players.length, (index) => index); // Sort the indices based on the summed points playerIndices.sort((a, b) { - int scoreA = widget.gameSession.playerScores[a]; - int scoreB = widget.gameSession.playerScores[b]; + int scoreA = gameSession.playerScores[a]; + int scoreB = gameSession.playerScores[b]; return scoreA.compareTo(scoreB); }); return playerIndices; @@ -217,4 +228,56 @@ class _ActiveGameViewState extends State { ); } } + + Future _showDeleteGameDialog() async { + return await showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).delete_game), + content: Text( + 'Möchtes du das Spiel "${gameSession.gameTitle}" wirklich löschen?'), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).cancel), + onPressed: () => Navigator.pop(context, false), + ), + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).delete), + onPressed: () { + Navigator.pop(context, true); + }, + ), + ], + ); + }, + ) ?? + false; + } + + Future _removeGameSession(GameSession gameSession) async { + if (gameManager.gameExistsInGameList(gameSession.id)) { + Navigator.pop(context); + + WidgetsBinding.instance.addPostFrameCallback((_) { + gameManager.removeGameSessionById(gameSession.id); + }); + } else { + showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: const Text('ID Fehler'), + content: const Text( + 'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () => Navigator.pop(context), + ), + ], + ); + }); + } + } } diff --git a/pubspec.yaml b/pubspec.yaml index a7c91ae..a52beee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.5+269 +version: 0.3.5+312 environment: sdk: ^3.5.4 @@ -26,6 +26,7 @@ dependencies: sdk: flutter intl: any syncfusion_flutter_charts: ^30.1.37 + uuid: ^4.5.1 dev_dependencies: flutter_test: From 6f0cd817149882377e18bc048a16ab291cb0b9a8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 13:08:56 +0200 Subject: [PATCH 033/353] Removed variable --- lib/views/active_game_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index b5eafc3..c44ef26 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -19,7 +19,6 @@ class ActiveGameView extends StatefulWidget { class _ActiveGameViewState extends State { late final GameSession gameSession; - bool _deleted = false; @override void initState() { From 3aab4721979e9edb4f5e9fe7dd914ff4e5b12a50 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 13:09:09 +0200 Subject: [PATCH 034/353] Shortened return --- lib/data/game_manager.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 1ccc9dc..24c55da 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -43,9 +43,7 @@ class GameManager extends ChangeNotifier { } bool gameExistsInGameList(String id) { - return gameList.any((session) => session.id.toString() == id) == -1 - ? false - : true; + return gameList.any((session) => session.id.toString() == id); } } From 9e9693ae42e5b8869170f71b3486cff8b994c196 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 17:26:27 +0200 Subject: [PATCH 035/353] Updated localizations --- lib/l10n/app_de.arb | 9 ++++++--- lib/l10n/app_en.arb | 6 ++++-- lib/l10n/app_localizations.dart | 30 +++++++++++++++++++++--------- lib/l10n/app_localizations_de.dart | 17 ++++++++++++----- lib/l10n/app_localizations_en.dart | 15 +++++++++++---- pubspec.yaml | 2 +- 6 files changed, 55 insertions(+), 24 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 51147d0..c10a52a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -22,7 +22,7 @@ "empty_text_1": "Ganz schön leer hier...", "empty_text_2": "Füge über den Button oben rechts eine neue Runde hinzu", "delete_game_title": "Spiel löschen?", - "delete_game_message": "Bist du sicher, dass du die Runde {gameTitle} löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.", + "delete_game_message": "Bist du sicher, dass du das Spiel {gameTitle} löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.", "@delete_game_message": { "placeholders": { "gameTitle": { @@ -68,6 +68,9 @@ "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", "export_game": "Spiel exportieren", + "id_error_title": "ID Fehler", + "id_error_message": "Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.", + "game_process": "Spielverlauf", @@ -80,7 +83,6 @@ "game_data": "Spieldaten", "import_data": "Daten importieren", "export_data": "Daten exportieren", - "error": "Fehler", "import_success_title": "Import erfolgreich", "import_success_message":"Die Spieldaten wurden erfolgreich importiert.", @@ -91,7 +93,8 @@ "import_generic_error_title": "Import fehlgeschlagen", "import_generic_error_message": "Der Import ist fehlgeschlagen.", - "error_export": "Datei konnte nicht exportiert werden", + "export_error_title": "Fehler", + "export_error_message": "Datei konnte nicht exportiert werden", "error_found": "Fehler gefunden?", "create_issue": "Issue erstellen", "app_version": "App-Version", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index a6b1a8f..73d1c96 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -80,7 +80,8 @@ "game_data": "Game Data", "import_data": "Import Data", "export_data": "Export Data", - "error": "Error", + "id_error_title": "ID Error", + "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", "import_success_title": "Import successful", "import_success_message":"The game data has been successfully imported.", @@ -91,7 +92,8 @@ "import_generic_error_title": "Import failed", "import_generic_error_message": "The import has failed.", - "error_export": "Could not export file", + "export_error_title": "Fehler", + "export_error_message": "Could not export file", "error_found": "Found a bug?", "create_issue": "Create Issue", "app_version": "App Version", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index a4e1edb..2659d08 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -215,7 +215,7 @@ abstract class AppLocalizations { /// No description provided for @delete_game_message. /// /// In de, this message translates to: - /// **'Bist du sicher, dass du die Runde {gameTitle} löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'** + /// **'Bist du sicher, dass du das Spiel {gameTitle} löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'** String delete_game_message(String gameTitle); /// No description provided for @overview. @@ -386,6 +386,18 @@ abstract class AppLocalizations { /// **'Spiel exportieren'** String get export_game; + /// No description provided for @id_error_title. + /// + /// In de, this message translates to: + /// **'ID Fehler'** + String get id_error_title; + + /// No description provided for @id_error_message. + /// + /// In de, this message translates to: + /// **'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'** + String get id_error_message; + /// No description provided for @game_process. /// /// In de, this message translates to: @@ -446,12 +458,6 @@ abstract class AppLocalizations { /// **'Daten exportieren'** String get export_data; - /// No description provided for @error. - /// - /// In de, this message translates to: - /// **'Fehler'** - String get error; - /// No description provided for @import_success_title. /// /// In de, this message translates to: @@ -500,11 +506,17 @@ abstract class AppLocalizations { /// **'Der Import ist fehlgeschlagen.'** String get import_generic_error_message; - /// No description provided for @error_export. + /// No description provided for @export_error_title. + /// + /// In de, this message translates to: + /// **'Fehler'** + String get export_error_title; + + /// No description provided for @export_error_message. /// /// In de, this message translates to: /// **'Datei konnte nicht exportiert werden'** - String get error_export; + String get export_error_message; /// No description provided for @error_found. /// diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index b06d454..6d5f1a0 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -68,7 +68,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String delete_game_message(String gameTitle) { - return 'Bist du sicher, dass du die Runde $gameTitle löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'; + return 'Bist du sicher, dass du das Spiel $gameTitle löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'; } @override @@ -161,6 +161,13 @@ class AppLocalizationsDe extends AppLocalizations { @override String get export_game => 'Spiel exportieren'; + @override + String get id_error_title => 'ID Fehler'; + + @override + String get id_error_message => + 'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'; + @override String get game_process => 'Spielverlauf'; @@ -191,9 +198,6 @@ class AppLocalizationsDe extends AppLocalizations { @override String get export_data => 'Daten exportieren'; - @override - String get error => 'Fehler'; - @override String get import_success_title => 'Import erfolgreich'; @@ -222,7 +226,10 @@ class AppLocalizationsDe extends AppLocalizations { String get import_generic_error_message => 'Der Import ist fehlgeschlagen.'; @override - String get error_export => 'Datei konnte nicht exportiert werden'; + String get export_error_title => 'Fehler'; + + @override + String get export_error_message => 'Datei konnte nicht exportiert werden'; @override String get error_found => 'Fehler gefunden?'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 2dfc72d..63553ff 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -158,6 +158,13 @@ class AppLocalizationsEn extends AppLocalizations { @override String get export_game => 'Export Game'; + @override + String get id_error_title => 'ID Error'; + + @override + String get id_error_message => + 'The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.'; + @override String get game_process => 'Spielverlauf'; @@ -188,9 +195,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get export_data => 'Export Data'; - @override - String get error => 'Error'; - @override String get import_success_title => 'Import successful'; @@ -219,7 +223,10 @@ class AppLocalizationsEn extends AppLocalizations { String get import_generic_error_message => 'The import has failed.'; @override - String get error_export => 'Could not export file'; + String get export_error_title => 'Fehler'; + + @override + String get export_error_message => 'Could not export file'; @override String get error_found => 'Found a bug?'; diff --git a/pubspec.yaml b/pubspec.yaml index a52beee..88e2991 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.5+312 +version: 0.3.5+317 environment: sdk: ^3.5.4 From 5c1ed94d446da1570c22063b586c6c5ed5a93251 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 17:26:39 +0200 Subject: [PATCH 036/353] Implemented localizations --- lib/views/active_game_view.dart | 11 ++++++----- lib/views/settings_view.dart | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index c44ef26..3f9c613 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -233,9 +233,11 @@ class _ActiveGameViewState extends State { context: context, builder: (BuildContext context) { return CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).delete_game), + title: Text(AppLocalizations.of(context).delete_game_title), content: Text( - 'Möchtes du das Spiel "${gameSession.gameTitle}" wirklich löschen?'), + AppLocalizations.of(context) + .delete_game_message(gameSession.gameTitle), + ), actions: [ CupertinoDialogAction( child: Text(AppLocalizations.of(context).cancel), @@ -266,9 +268,8 @@ class _ActiveGameViewState extends State { context: context, builder: (BuildContext context) { return CupertinoAlertDialog( - title: const Text('ID Fehler'), - content: const Text( - 'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'), + title: Text(AppLocalizations.of(context).id_error_title), + content: Text(AppLocalizations.of(context).id_error_message), actions: [ CupertinoDialogAction( child: Text(AppLocalizations.of(context).ok), diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index b36347d..b9ae02c 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -145,10 +145,10 @@ class _SettingsViewState extends State { showCupertinoDialog( context: context, builder: (context) => CupertinoAlertDialog( - title: - Text(AppLocalizations.of(context).error), + title: Text(AppLocalizations.of(context) + .export_error_title), content: Text(AppLocalizations.of(context) - .error_export), + .export_error_message), actions: [ CupertinoDialogAction( child: From 7d6c3e5f14b5593eb91696a264147e0d003e0af0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 17:32:52 +0200 Subject: [PATCH 037/353] Added quotation marks to String --- lib/l10n/app_de.arb | 2 +- lib/l10n/app_en.arb | 2 +- lib/l10n/app_localizations.dart | 2 +- lib/l10n/app_localizations_de.dart | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index c10a52a..7fa3710 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -22,7 +22,7 @@ "empty_text_1": "Ganz schön leer hier...", "empty_text_2": "Füge über den Button oben rechts eine neue Runde hinzu", "delete_game_title": "Spiel löschen?", - "delete_game_message": "Bist du sicher, dass du das Spiel {gameTitle} löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.", + "delete_game_message": "Bist du sicher, dass du das Spiel \"{gameTitle}\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.", "@delete_game_message": { "placeholders": { "gameTitle": { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 73d1c96..ce99202 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -22,7 +22,7 @@ "empty_text_1": "Pretty empty here...", "empty_text_2": "Add a new round using the button in the top right corner.", "delete_game_title": "Delete game?", - "delete_game_message": "Are you sure you want to delete the game {gameTitle}? This action cannot be undone.", + "delete_game_message": "Are you sure you want to delete the game \"{gameTitle}\"? This action cannot be undone.", "@delete_game_message": { "placeholders": { "gameTitle": { diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 2659d08..eb858f5 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -215,7 +215,7 @@ abstract class AppLocalizations { /// No description provided for @delete_game_message. /// /// In de, this message translates to: - /// **'Bist du sicher, dass du das Spiel {gameTitle} löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'** + /// **'Bist du sicher, dass du das Spiel \"{gameTitle}\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'** String delete_game_message(String gameTitle); /// No description provided for @overview. diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 6d5f1a0..f72adbb 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -68,7 +68,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String delete_game_message(String gameTitle) { - return 'Bist du sicher, dass du das Spiel $gameTitle löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'; + return 'Bist du sicher, dass du das Spiel \"$gameTitle\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'; } @override From 4f2f2c8d3c5d2cfc45b815cc3af03f00e2cae06f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 17:33:19 +0200 Subject: [PATCH 038/353] Updated delete popup style --- lib/views/active_game_view.dart | 6 +++++- lib/views/main_menu_view.dart | 6 +++++- pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 3f9c613..1b5e546 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -244,7 +244,11 @@ class _ActiveGameViewState extends State { onPressed: () => Navigator.pop(context, false), ), CupertinoDialogAction( - child: Text(AppLocalizations.of(context).delete), + child: Text( + AppLocalizations.of(context).delete, + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.red), + ), onPressed: () { Navigator.pop(context, true); }, diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 3a9441f..3281c6f 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -226,7 +226,11 @@ class _MainMenuViewState extends State { onPressed: () { Navigator.pop(context, true); }, - child: Text(AppLocalizations.of(context).delete), + child: Text( + AppLocalizations.of(context).delete, + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.red), + ), ), ], ); diff --git a/pubspec.yaml b/pubspec.yaml index 88e2991..56b89bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.5+317 +version: 0.3.6+318 environment: sdk: ^3.5.4 From 1c2803eb85dcd93d2dad90eaf11dcef12e3e2b79 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 17:34:12 +0200 Subject: [PATCH 039/353] Deleted print --- lib/data/game_session.dart | 1 - lib/l10n/app_localizations_en.dart | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index ada34dc..36c4c4e 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -37,7 +37,6 @@ class GameSession extends ChangeNotifier { playerScores = List.filled(players.length, 0); var uuid = const Uuid(); id = uuid.v1(); - print('GameSession created with ID: $id'); } @override diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 63553ff..27d675b 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -68,7 +68,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String delete_game_message(String gameTitle) { - return 'Are you sure you want to delete the game $gameTitle? This action cannot be undone.'; + return 'Are you sure you want to delete the game \"$gameTitle\"? This action cannot be undone.'; } @override From 69b213ffe3f2cc436faa6b8a123bb26e93849bd2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 3 Jul 2025 17:38:05 +0200 Subject: [PATCH 040/353] Updated translation --- lib/l10n/app_en.arb | 2 +- lib/l10n/app_localizations_en.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ce99202..f8dbb2f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -92,7 +92,7 @@ "import_generic_error_title": "Import failed", "import_generic_error_message": "The import has failed.", - "export_error_title": "Fehler", + "export_error_title": "Export failed", "export_error_message": "Could not export file", "error_found": "Found a bug?", "create_issue": "Create Issue", diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 27d675b..657f2ce 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -223,7 +223,7 @@ class AppLocalizationsEn extends AppLocalizations { String get import_generic_error_message => 'The import has failed.'; @override - String get export_error_title => 'Fehler'; + String get export_error_title => 'Export failed'; @override String get export_error_message => 'Could not export file'; From 9897c744438b9cab46bb2078666ab4705187da8e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 4 Jul 2025 00:11:57 +0200 Subject: [PATCH 041/353] Updated createGameView ListBuilder --- lib/views/create_game_view.dart | 261 +++++++++++++++++--------------- pubspec.yaml | 2 +- 2 files changed, 137 insertions(+), 126 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index fd59529..0050ff0 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -130,28 +130,70 @@ class _CreateGameViewState extends State { ), Expanded( child: ListView.builder( - itemCount: _playerNameTextControllers.length + - 1, // +1 für den + Button + itemCount: _playerNameTextControllers.length + 2, itemBuilder: (context, index) { + if (index == _playerNameTextControllers.length + 1) { + return CupertinoButton( + padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context).create_game, + style: const TextStyle( + color: CupertinoColors.activeGreen, + ), + ), + ], + ), + onPressed: () { + _checkAllGameAttributes(); + }, + ); + } if (index == _playerNameTextControllers.length) { - // + Button als letztes Element return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 5), child: CupertinoButton( padding: EdgeInsets.zero, child: Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, children: [ - const Icon( - CupertinoIcons.add_circled, - color: CupertinoColors.activeGreen, - size: 25, + Align( + alignment: Alignment.centerLeft, + child: CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + size: 25, + ), + ), ), - const SizedBox(width: 8), - Text( - AppLocalizations.of(context).add_player, - style: const TextStyle( - color: CupertinoColors.activeGreen, + Expanded( + child: Align( + alignment: Alignment.center, + child: Text( + AppLocalizations.of(context).add_player, + textAlign: TextAlign.center, + style: const TextStyle( + color: CupertinoColors.activeGreen, + ), + ), + ), + ), + const Align( + alignment: Alignment.centerLeft, + child: CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.add_circled_solid, + color: CupertinoColors.transparent, + size: 25, + ), ), ), ], @@ -187,7 +229,7 @@ class _CreateGameViewState extends State { // Spieler-Einträge return Padding( padding: const EdgeInsets.symmetric( - vertical: 8.0, horizontal: 5), + vertical: 4.0, horizontal: 5), child: Row( children: [ CupertinoButton( @@ -221,120 +263,89 @@ class _CreateGameViewState extends State { }, ), ), - Center( - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context).create_game, - style: const TextStyle( - color: CupertinoColors.activeGreen, - ), - ), - ], - ), - onPressed: () async { - if (_gameTitleTextController.text == '') { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text( - AppLocalizations.of(context).no_gameTitle_title), - content: Text( - AppLocalizations.of(context).no_gameTitle_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - if (_isPointsLimitEnabled == null) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).no_mode_title), - content: - Text(AppLocalizations.of(context).no_mode_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - if (_playerNameTextControllers.length < 2) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text( - AppLocalizations.of(context).min_players_title), - content: Text( - AppLocalizations.of(context).min_players_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - if (!everyPlayerHasAName()) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).no_name_title), - content: - Text(AppLocalizations.of(context).no_name_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - - List players = []; - for (var controller in _playerNameTextControllers) { - players.add(controller.text); - } - GameSession gameSession = GameSession( - createdAt: DateTime.now(), - gameTitle: _gameTitleTextController.text, - players: players, - pointLimit: Globals.pointLimit, - caboPenalty: Globals.caboPenalty, - isPointsLimitEnabled: _isPointsLimitEnabled!, - ); - final index = await gameManager.addGameSession(gameSession); - final session = gameManager.gameList[index]; - if (context.mounted) { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => - ActiveGameView(gameSession: session))); - } - }, - ), - ), ], )))); } + void _checkAllGameAttributes() { + if (_gameTitleTextController.text == '') { + _showDialog(( + AppLocalizations.of(context).no_gameTitle_title, + AppLocalizations.of(context).no_gameTitle_message + )); + return; + } + + if (_isPointsLimitEnabled == null) { + _showDialog( + ( + AppLocalizations.of(context).no_mode_title, + AppLocalizations.of(context).no_mode_message + ), + ); + return; + } + + if (_playerNameTextControllers.length < 2) { + _showDialog( + ( + AppLocalizations.of(context).min_players_title, + AppLocalizations.of(context).min_players_message + ), + ); + return; + } + + if (!everyPlayerHasAName()) { + _showDialog(( + AppLocalizations.of(context).no_name_title, + AppLocalizations.of(context).no_name_message + )); + return; + } + + _createGame(); + } + + void _showDialog((String, String) content) { + final (title, message) = content; + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: Text(title), + content: Text(message), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () => Navigator.pop(context), + ), + ], + ), + ); + } + + Future _createGame() async { + List players = []; + for (var controller in _playerNameTextControllers) { + players.add(controller.text); + } + GameSession gameSession = GameSession( + createdAt: DateTime.now(), + gameTitle: _gameTitleTextController.text, + players: players, + pointLimit: Globals.pointLimit, + caboPenalty: Globals.caboPenalty, + isPointsLimitEnabled: _isPointsLimitEnabled!, + ); + final index = await gameManager.addGameSession(gameSession); + final session = gameManager.gameList[index]; + + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView(gameSession: session))); + } + bool everyPlayerHasAName() { for (var controller in _playerNameTextControllers) { if (controller.text == '') { diff --git a/pubspec.yaml b/pubspec.yaml index 56b89bc..607b026 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.6+318 +version: 0.3.6+321 environment: sdk: ^3.5.4 From 7d497e17fe2d1f3ba6cd70c3f05e0ad8cb9c5bd9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 4 Jul 2025 00:36:10 +0200 Subject: [PATCH 042/353] Added ReorderableListView --- lib/views/create_game_view.dart | 223 ++++++++++++++++---------------- pubspec.yaml | 2 +- 2 files changed, 113 insertions(+), 112 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 0050ff0..deb86cf 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -6,6 +6,7 @@ import 'package:cabo_counter/utility/globals.dart'; import 'package:cabo_counter/views/active_game_view.dart'; import 'package:cabo_counter/views/mode_selection_view.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; class CreateGameView extends StatefulWidget { final String? gameTitle; @@ -129,137 +130,137 @@ class _CreateGameViewState extends State { ), ), Expanded( - child: ListView.builder( + child: ReorderableListView.builder( + physics: const NeverScrollableScrollPhysics(), itemCount: _playerNameTextControllers.length + 2, - itemBuilder: (context, index) { - if (index == _playerNameTextControllers.length + 1) { - return CupertinoButton( - padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context).create_game, - style: const TextStyle( - color: CupertinoColors.activeGreen, - ), - ), - ], - ), - onPressed: () { - _checkAllGameAttributes(); - }, - ); + onReorder: (oldIndex, newIndex) { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + setState(() { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + }); } - if (index == _playerNameTextControllers.length) { - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 5), + }, + itemBuilder: (context, index) { + // Create game button + if (index == _playerNameTextControllers.length + 1) { + return Container( + key: const ValueKey('create_game_button'), child: CupertinoButton( - padding: EdgeInsets.zero, + padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), child: Row( - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Align( - alignment: Alignment.centerLeft, - child: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: null, - child: Icon( - CupertinoIcons.add_circled_solid, - color: CustomTheme.primaryColor, - size: 25, - ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: CustomTheme.primaryColor, ), - ), - Expanded( - child: Align( - alignment: Alignment.center, - child: Text( - AppLocalizations.of(context).add_player, - textAlign: TextAlign.center, - style: const TextStyle( - color: CupertinoColors.activeGreen, - ), - ), - ), - ), - const Align( - alignment: Alignment.centerLeft, - child: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: null, - child: Icon( - CupertinoIcons.add_circled_solid, - color: CupertinoColors.transparent, - size: 25, + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 8), + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.backgroundColor, ), ), ), ], ), onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context) - .max_players_title), - content: Text(AppLocalizations.of(context) - .max_players_message), - actions: [ - CupertinoDialogAction( - child: - Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - } + _checkAllGameAttributes(); }, ), ); - } else { - // Spieler-Einträge - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 5), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { + } + // Add player button + if (index == _playerNameTextControllers.length) { + return Container( + key: const ValueKey('add_player_button'), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 10), + child: CupertinoButton( + padding: EdgeInsets.zero, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 6), + Text( + AppLocalizations.of(context).add_player, + style: + TextStyle(color: CustomTheme.primaryColor), + ), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < + maxPlayers) { setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); + _playerNameTextControllers + .add(TextEditingController()); }); - }, - ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), - ), - ], + } else { + _showDialog(( + AppLocalizations.of(context).max_players_title, + AppLocalizations.of(context).max_players_message + )); + } + }, + ), ), ); } + // Player name input field + return Padding( + key: ValueKey('player_${index + 1}'), + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 5), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, + ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), + ), + const SizedBox(width: 8), + ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + size: 20, + color: CupertinoColors.systemGrey, + ), + ), + ], + ), + ); }, ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 607b026..9d42205 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.6+321 +version: 0.3.6+323 environment: sdk: ^3.5.4 From 05f0a0011faf53ab8db4229d5f8ddd066d08b9ff Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:01:09 +0200 Subject: [PATCH 043/353] Increment build no --- pubspec.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9d42205..6160db1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.6+323 +version: 0.3.6+328 environment: sdk: ^3.5.4 @@ -27,6 +27,7 @@ dependencies: intl: any syncfusion_flutter_charts: ^30.1.37 uuid: ^4.5.1 + reorderables: ^0.4.2 dev_dependencies: flutter_test: From 181a135c07bbd7b44970981b0eef6e4f83fe96b4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:32:25 +0200 Subject: [PATCH 044/353] Implemented delete game button --- lib/data/game_manager.dart | 18 +++++++++ lib/l10n/app_de.arb | 4 +- lib/l10n/app_en.arb | 3 ++ lib/l10n/app_localizations.dart | 18 +++++++++ lib/l10n/app_localizations_de.dart | 10 +++++ lib/l10n/app_localizations_en.dart | 10 +++++ lib/views/active_game_view.dart | 62 +++++++++++++++++++++++++++++- pubspec.yaml | 2 +- 8 files changed, 123 insertions(+), 4 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 24c55da..ea18be7 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -42,9 +42,27 @@ class GameManager extends ChangeNotifier { removeGameSessionByIndex(index); } + /// Retrieves a game session by its ID. + /// Takes a String [id] as input. It finds the game session with the matching id bool gameExistsInGameList(String id) { return gameList.any((session) => session.id.toString() == id); } + + /// Ends a game session if its in unlimited mode. + /// Takes a String [id] as input. It finds the index of the game + /// session with the matching ID marks it as finished, + void endGame(String id) { + final int index = + gameList.indexWhere((session) => session.id.toString() == id); + + // Game session not found or not in unlimited mode + if (index == -1 || gameList[index].isPointsLimitEnabled == false) return; + + gameList[index].roundNumber--; + gameList[index].isGameFinished = true; + notifyListeners(); + LocalStorageService.saveGameSessions(); + } } final gameManager = GameManager(); diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 7fa3710..d300ab0 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -65,12 +65,14 @@ "next_round": "Nächste Runde", "statistics": "Statistiken", + "end_game": "Spiel beenden", "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", "export_game": "Spiel exportieren", "id_error_title": "ID Fehler", "id_error_message": "Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.", - + "end_game_title": "Spiel beenden?", + "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.", "game_process": "Spielverlauf", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f8dbb2f..8b328ba 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -65,6 +65,7 @@ "next_round": "Next Round", "statistics": "Statistics", + "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", "export_game": "Export Game", @@ -82,6 +83,8 @@ "export_data": "Export Data", "id_error_title": "ID Error", "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", + "end_game_title": "End the game?", + "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", "import_success_title": "Import successful", "import_success_message":"The game data has been successfully imported.", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index eb858f5..02e1d3c 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -368,6 +368,12 @@ abstract class AppLocalizations { /// **'Statistiken'** String get statistics; + /// No description provided for @end_game. + /// + /// In de, this message translates to: + /// **'Spiel beenden'** + String get end_game; + /// No description provided for @delete_game. /// /// In de, this message translates to: @@ -398,6 +404,18 @@ abstract class AppLocalizations { /// **'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'** String get id_error_message; + /// No description provided for @end_game_title. + /// + /// In de, this message translates to: + /// **'Spiel beenden?'** + String get end_game_title; + + /// No description provided for @end_game_message. + /// + /// In de, this message translates to: + /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.'** + String get end_game_message; + /// No description provided for @game_process. /// /// In de, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index f72adbb..1b91ed4 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -152,6 +152,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get statistics => 'Statistiken'; + @override + String get end_game => 'Spiel beenden'; + @override String get delete_game => 'Spiel löschen'; @@ -168,6 +171,13 @@ class AppLocalizationsDe extends AppLocalizations { String get id_error_message => 'Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.'; + @override + String get end_game_title => 'Spiel beenden?'; + + @override + String get end_game_message => + 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.'; + @override String get game_process => 'Spielverlauf'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 657f2ce..c98dddd 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -149,6 +149,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get statistics => 'Statistics'; + @override + String get end_game => 'End Game'; + @override String get delete_game => 'Delete Game'; @@ -165,6 +168,13 @@ class AppLocalizationsEn extends AppLocalizations { String get id_error_message => 'The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.'; + @override + String get end_game_title => 'End the game?'; + + @override + String get end_game_message => + 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; + @override String get game_process => 'Spielverlauf'; diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 1b5e546..dc0e078 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -129,21 +129,40 @@ class _ActiveGameViewState extends State { Column( children: [ CupertinoListTile( - backgroundColorActivated: - CustomTheme.backgroundColor, title: Text( AppLocalizations.of(context).statistics, ), + backgroundColorActivated: + CustomTheme.backgroundColor, onTap: () => Navigator.push( context, CupertinoPageRoute( builder: (_) => GraphView( gameSession: gameSession, )))), + if (!gameSession.isPointsLimitEnabled) + CupertinoListTile( + title: Text( + AppLocalizations.of(context).end_game, + style: gameSession.roundNumber > 1 && + !gameSession.isGameFinished + ? const TextStyle(color: Colors.white) + : const TextStyle(color: Colors.white30), + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () => { + gameSession.roundNumber > 1 && + !gameSession.isGameFinished + ? _showEndGameDialog() + : null + }), CupertinoListTile( title: Text( AppLocalizations.of(context).delete_game, ), + backgroundColorActivated: + CustomTheme.backgroundColor, onTap: () { _showDeleteGameDialog().then((value) { if (value) { @@ -157,6 +176,8 @@ class _ActiveGameViewState extends State { AppLocalizations.of(context) .new_game_same_settings, ), + backgroundColorActivated: + CustomTheme.backgroundColor, onTap: () { Navigator.pushReplacement( context, @@ -176,6 +197,8 @@ class _ActiveGameViewState extends State { style: const TextStyle( color: Colors.white30, )), + backgroundColorActivated: + CustomTheme.backgroundColor, ), ], ) @@ -186,6 +209,41 @@ class _ActiveGameViewState extends State { }); } + /// Shows a dialog to confirm ending the game. + /// If the user confirms, it calls the `endGame` method on the game manager + void _showEndGameDialog() { + showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).end_game_title), + content: Text(AppLocalizations.of(context).end_game_message), + actions: [ + CupertinoDialogAction( + child: Text( + AppLocalizations.of(context).end_game, + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.red), + ), + onPressed: () { + setState(() { + gameSession.isGameFinished = true; + gameSession.roundNumber--; + gameManager.endGame(gameSession.id); + }); + Navigator.pop(context); + }, + ), + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).cancel), + onPressed: () => Navigator.pop(context), + ), + ], + ); + }, + ); + } + /// Returns a list of player indices sorted by their scores in /// ascending order. List _getSortedPlayerIndices() { diff --git a/pubspec.yaml b/pubspec.yaml index 56b89bc..e3b4a67 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.6+318 +version: 0.3.6+322 environment: sdk: ^3.5.4 From aa338451130f25ce99dce315f9e3b921b16bae4a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:35:17 +0200 Subject: [PATCH 045/353] Updated version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index e3b4a67..e9ef18c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.6+322 +version: 0.3.7+322 environment: sdk: ^3.5.4 From 003e80c6ff2af03070311764109b96989b66ab25 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:39:55 +0200 Subject: [PATCH 046/353] Updated onTap Handler --- lib/views/active_game_view.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index dc0e078..aaea85d 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -151,12 +151,12 @@ class _ActiveGameViewState extends State { ), backgroundColorActivated: CustomTheme.backgroundColor, - onTap: () => { - gameSession.roundNumber > 1 && - !gameSession.isGameFinished - ? _showEndGameDialog() - : null - }), + onTap: () { + if (gameSession.roundNumber > 1 && + !gameSession.isGameFinished) { + _showEndGameDialog(); + } + }), CupertinoListTile( title: Text( AppLocalizations.of(context).delete_game, From 554f6e243c2cd70b8f8e6328ea339bc61f2420c4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:41:26 +0200 Subject: [PATCH 047/353] Updated typo --- lib/l10n/app_de.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index d300ab0..9281ac1 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -72,7 +72,7 @@ "id_error_title": "ID Fehler", "id_error_message": "Das Spiel hat bisher noch keine ID zugewiesen bekommen. Falls du das Spiel löschen möchtest, mache das bitte über das Hauptmenü. Alle neu erstellten Spiele haben eine ID.", "end_game_title": "Spiel beenden?", - "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.", + "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", "game_process": "Spielverlauf", From 32aa2e607062f52007c8cbcd86faa3021a29be68 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:43:32 +0200 Subject: [PATCH 048/353] Updated endGame method --- lib/data/game_manager.dart | 2 +- lib/views/active_game_view.dart | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index ea18be7..b3a1933 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -56,7 +56,7 @@ class GameManager extends ChangeNotifier { gameList.indexWhere((session) => session.id.toString() == id); // Game session not found or not in unlimited mode - if (index == -1 || gameList[index].isPointsLimitEnabled == false) return; + if (index == -1 || gameList[index].isPointsLimitEnabled == true) return; gameList[index].roundNumber--; gameList[index].isGameFinished = true; diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index aaea85d..586eab3 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -227,8 +227,6 @@ class _ActiveGameViewState extends State { ), onPressed: () { setState(() { - gameSession.isGameFinished = true; - gameSession.roundNumber--; gameManager.endGame(gameSession.id); }); Navigator.pop(context); From 6f340a0d3917dd94ff5fa5f1b43e48ebf072a7e0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:43:42 +0200 Subject: [PATCH 049/353] Updated localization --- lib/l10n/app_localizations.dart | 2 +- lib/l10n/app_localizations_de.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 02e1d3c..c836194 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -413,7 +413,7 @@ abstract class AppLocalizations { /// No description provided for @end_game_message. /// /// In de, this message translates to: - /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.'** + /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'** String get end_game_message; /// No description provided for @game_process. diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 1b91ed4..5b9d841 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -176,7 +176,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get end_game_message => - 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht forgeführt werden.'; + 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'; @override String get game_process => 'Spielverlauf'; diff --git a/pubspec.yaml b/pubspec.yaml index e9ef18c..160097c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.7+322 +version: 0.3.7+323 environment: sdk: ^3.5.4 From 7a3c8b2e806a57040586c08d645a5a9271e88a48 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 22:40:24 +0200 Subject: [PATCH 050/353] Implementing single game export --- lib/services/local_storage_service.dart | 25 +++++++++++++++++++++++-- lib/views/active_game_view.dart | 18 ++++++++++-------- lib/views/settings_view.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 71dd332..074caf6 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -103,12 +103,12 @@ class LocalStorageService { } /// Opens the file picker to save a JSON file with the current game data. - static Future exportJsonFile() async { + static Future exportGameData() async { final jsonString = getJsonFile(); try { final bytes = Uint8List.fromList(utf8.encode(jsonString)); final result = await FileSaver.instance.saveAs( - name: 'cabo_counter_data', + name: 'cabo_counter-game_data', bytes: bytes, ext: 'json', mimeType: MimeType.json, @@ -123,6 +123,27 @@ class LocalStorageService { } } + /// Opens the file picker to save a single game session as a JSON file. + static Future exportSingleGameSession(GameSession session) async { + final jsonString = json.encode(session.toJson()); + try { + final bytes = Uint8List.fromList(utf8.encode(jsonString)); + final result = await FileSaver.instance.saveAs( + name: 'cabo_counter-game_${session.id.substring(0, 7)}', + bytes: bytes, + ext: 'json', + mimeType: MimeType.json, + ); + print( + '[local_storage_service.dart] Die Spieldaten der Session wurden exportiert. Dateipfad: $result'); + return true; + } catch (e) { + print( + '[local_storage_service.dart] Fehler beim Exportieren der Spieldaten der Session. Exception: $e'); + return false; + } + } + /// Opens the file picker to import a JSON file and loads the game data from it. static Future importJsonFile() async { final result = await FilePicker.platform.pickFiles( diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 586eab3..2ae9665 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -1,6 +1,7 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:cabo_counter/views/create_game_view.dart'; import 'package:cabo_counter/views/graph_view.dart'; @@ -192,14 +193,15 @@ class _ActiveGameViewState extends State { }, ), CupertinoListTile( - title: - Text(AppLocalizations.of(context).export_game, - style: const TextStyle( - color: Colors.white30, - )), - backgroundColorActivated: - CustomTheme.backgroundColor, - ), + title: Text( + AppLocalizations.of(context).export_game, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () { + LocalStorageService.exportSingleGameSession( + widget.gameSession); + }), ], ) ], diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index b9ae02c..f98c542 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -140,7 +140,7 @@ class _SettingsViewState extends State { ), onPressed: () async { final success = - await LocalStorageService.exportJsonFile(); + await LocalStorageService.exportGameData(); if (!success && context.mounted) { showCupertinoDialog( context: context, diff --git a/pubspec.yaml b/pubspec.yaml index 160097c..b786c31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.7+323 +version: 0.3.7+325 environment: sdk: ^3.5.4 From e8210babe66a9cc1b010aeb989c3335401ba6002 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 23:00:53 +0200 Subject: [PATCH 051/353] Removed doubled code and merged methods --- lib/services/local_storage_service.dart | 61 +++++++++++++------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 074caf6..338a0c3 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -20,8 +20,8 @@ enum ImportStatus { class LocalStorageService { static const String _fileName = 'game_data.json'; - /// Writes the game session list to a JSON file and returns it as string. - static String getJsonFile() { + /// Writes the game session list to a JSON file and returns it as string. + static String getGameDataAsJsonFile() { final jsonFile = gameManager.gameList.map((session) => session.toJson()).toList(); return json.encode(jsonFile); @@ -39,7 +39,7 @@ class LocalStorageService { print('[local_storage_service.dart] Versuche, Daten zu speichern...'); try { final file = await _getFilePath(); - final jsonFile = getJsonFile(); + final jsonFile = getGameDataAsJsonFile(); await file.writeAsString(jsonFile); print( '[local_storage_service.dart] Die Spieldaten wurden zwischengespeichert.'); @@ -102,19 +102,27 @@ class LocalStorageService { } } - /// Opens the file picker to save a JSON file with the current game data. - static Future exportGameData() async { - final jsonString = getJsonFile(); + /// Opens the file picker to export game data as a JSON file. + /// This method will export the given [jsonString] as a JSON file. It opens + /// the file picker with the choosen [fileName]. + static Future exportJsonData( + String jsonString, + String fileName, + ) async { try { final bytes = Uint8List.fromList(utf8.encode(jsonString)); - final result = await FileSaver.instance.saveAs( - name: 'cabo_counter-game_data', + final path = await FileSaver.instance.saveAs( + name: fileName, bytes: bytes, ext: 'json', mimeType: MimeType.json, ); - print( - '[local_storage_service.dart] Die Spieldaten wurden exportiert. Dateipfad: $result'); + if (path == null) { + print('[local_storage_service.dart]: Export abgebrochen'); + } else { + print( + '[local_storage_service.dart] Die Spieldaten wurden exportiert. Dateipfad: $path'); + } return true; } catch (e) { print( @@ -123,43 +131,36 @@ class LocalStorageService { } } + /// Opens the file picker to export all game sessions as a JSON file. + static Future exportGameData() async { + String jsonString = getGameDataAsJsonFile(); + String fileName = 'cabo_counter-game_data'; + return exportJsonData(jsonString, fileName); + } + /// Opens the file picker to save a single game session as a JSON file. static Future exportSingleGameSession(GameSession session) async { - final jsonString = json.encode(session.toJson()); - try { - final bytes = Uint8List.fromList(utf8.encode(jsonString)); - final result = await FileSaver.instance.saveAs( - name: 'cabo_counter-game_${session.id.substring(0, 7)}', - bytes: bytes, - ext: 'json', - mimeType: MimeType.json, - ); - print( - '[local_storage_service.dart] Die Spieldaten der Session wurden exportiert. Dateipfad: $result'); - return true; - } catch (e) { - print( - '[local_storage_service.dart] Fehler beim Exportieren der Spieldaten der Session. Exception: $e'); - return false; - } + String jsonString = json.encode(session.toJson()); + String fileName = 'cabo_counter-game_${session.id.substring(0, 7)}'; + return exportJsonData(jsonString, fileName); } /// Opens the file picker to import a JSON file and loads the game data from it. static Future importJsonFile() async { - final result = await FilePicker.platform.pickFiles( + final path = await FilePicker.platform.pickFiles( dialogTitle: 'Wähle eine Datei mit Spieldaten aus', type: FileType.custom, allowedExtensions: ['json'], ); - if (result == null) { + if (path == null) { print( '[local_storage_service.dart] Der Filepicker-Dialog wurde abgebrochen'); return ImportStatus.canceled; } try { - final jsonString = await _readFileContent(result.files.single); + final jsonString = await _readFileContent(path.files.single); if (!await validateJsonSchema(jsonString)) { return ImportStatus.validationError; From c8d0c56ddf8c4109e833186c538f1536113f8ea0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 23:01:16 +0200 Subject: [PATCH 052/353] Added user feedback for exporting --- lib/views/active_game_view.dart | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 2ae9665..68dfeeb 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -198,9 +198,29 @@ class _ActiveGameViewState extends State { ), backgroundColorActivated: CustomTheme.backgroundColor, - onTap: () { - LocalStorageService.exportSingleGameSession( - widget.gameSession); + onTap: () async { + final success = await LocalStorageService + .exportSingleGameSession( + widget.gameSession); + if (!success && context.mounted) { + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: Text(AppLocalizations.of(context) + .export_error_title), + content: Text(AppLocalizations.of(context) + .export_error_message), + actions: [ + CupertinoDialogAction( + child: Text( + AppLocalizations.of(context).ok), + onPressed: () => + Navigator.pop(context), + ), + ], + ), + ); + } }), ], ) From ace157dc4730d0896df26155838583d2466f672b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 23:14:11 +0200 Subject: [PATCH 053/353] Moved config values to ConfigService --- lib/main.dart | 5 ++--- lib/services/config_service.dart | 13 ++++++++----- lib/utility/globals.dart | 2 -- lib/views/create_game_view.dart | 10 +++++----- lib/views/main_menu_view.dart | 4 ++-- lib/views/settings_view.dart | 8 ++++---- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 2a2a91e..cd3d05f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,6 @@ import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/utility/globals.dart'; import 'package:cabo_counter/views/tab_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; @@ -12,8 +11,8 @@ Future main() async { await SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); await ConfigService.initConfig(); - Globals.pointLimit = await ConfigService.getPointLimit(); - Globals.caboPenalty = await ConfigService.getCaboPenalty(); + ConfigService.pointLimit = await ConfigService.getPointLimit(); + ConfigService.caboPenalty = await ConfigService.getCaboPenalty(); runApp(const App()); } diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 1c8275a..70f6133 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -1,4 +1,3 @@ -import 'package:cabo_counter/utility/globals.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// This class handles the configuration settings for the app. @@ -7,8 +6,12 @@ import 'package:shared_preferences/shared_preferences.dart'; class ConfigService { static const String _keyPointLimit = 'pointLimit'; static const String _keyCaboPenalty = 'caboPenalty'; - static const int _defaultPointLimit = 100; // Default Value - static const int _defaultCaboPenalty = 5; // Default Value + // Actual values used in the app + static int pointLimit = 100; + static int caboPenalty = 5; + // Default values + static const int _defaultPointLimit = 100; + static const int _defaultCaboPenalty = 5; static Future initConfig() async { final prefs = await SharedPreferences.getInstance(); @@ -48,8 +51,8 @@ class ConfigService { /// Resets the configuration to default values. static Future resetConfig() async { - Globals.pointLimit = _defaultPointLimit; - Globals.caboPenalty = _defaultCaboPenalty; + ConfigService.pointLimit = _defaultPointLimit; + ConfigService.caboPenalty = _defaultCaboPenalty; final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyPointLimit, _defaultPointLimit); await prefs.setInt(_keyCaboPenalty, _defaultCaboPenalty); diff --git a/lib/utility/globals.dart b/lib/utility/globals.dart index 54cf2d0..e11a118 100644 --- a/lib/utility/globals.dart +++ b/lib/utility/globals.dart @@ -1,5 +1,3 @@ class Globals { - static int pointLimit = 100; - static int caboPenalty = 5; static String appDevPhase = 'Beta'; } diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index fd59529..21e8d54 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -1,8 +1,8 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/utility/globals.dart'; import 'package:cabo_counter/views/active_game_view.dart'; import 'package:cabo_counter/views/mode_selection_view.dart'; import 'package:flutter/cupertino.dart'; @@ -96,7 +96,7 @@ class _CreateGameViewState extends State { _isPointsLimitEnabled == null ? AppLocalizations.of(context).select_mode : (_isPointsLimitEnabled! - ? '${Globals.pointLimit} ${AppLocalizations.of(context).points}' + ? '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}' : AppLocalizations.of(context).unlimited), ), const SizedBox(width: 3), @@ -108,7 +108,7 @@ class _CreateGameViewState extends State { context, CupertinoPageRoute( builder: (context) => ModeSelectionMenu( - pointLimit: Globals.pointLimit, + pointLimit: ConfigService.pointLimit, ), ), ); @@ -315,8 +315,8 @@ class _CreateGameViewState extends State { createdAt: DateTime.now(), gameTitle: _gameTitleTextController.text, players: players, - pointLimit: Globals.pointLimit, - caboPenalty: Globals.caboPenalty, + pointLimit: ConfigService.pointLimit, + caboPenalty: ConfigService.caboPenalty, isPointsLimitEnabled: _isPointsLimitEnabled!, ); final index = await gameManager.addGameSession(gameSession); diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 3281c6f..e087cfc 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -1,8 +1,8 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/utility/globals.dart'; import 'package:cabo_counter/views/active_game_view.dart'; import 'package:cabo_counter/views/create_game_view.dart'; import 'package:cabo_counter/views/settings_view.dart'; @@ -199,7 +199,7 @@ class _MainMenuViewState extends State { /// If [pointLimit] is true, it returns '101 Punkte', otherwise it returns 'Unbegrenzt'. String _translateGameMode(bool pointLimit) { if (pointLimit) { - return '${Globals.pointLimit} ${AppLocalizations.of(context).points}'; + return '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}'; } return AppLocalizations.of(context).unlimited; } diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index f98c542..2e86122 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -52,14 +52,14 @@ class _SettingsViewState extends State { AppLocalizations.of(context).cabo_penalty_subtitle), trailing: Stepper( key: _stepperKey1, - initialValue: Globals.caboPenalty, + initialValue: ConfigService.caboPenalty, minValue: 0, maxValue: 50, step: 1, onChanged: (newCaboPenalty) { setState(() { ConfigService.setCaboPenalty(newCaboPenalty); - Globals.caboPenalty = newCaboPenalty; + ConfigService.caboPenalty = newCaboPenalty; }); }, ), @@ -73,14 +73,14 @@ class _SettingsViewState extends State { Text(AppLocalizations.of(context).point_limit_subtitle), trailing: Stepper( key: _stepperKey2, - initialValue: Globals.pointLimit, + initialValue: ConfigService.pointLimit, minValue: 30, maxValue: 1000, step: 10, onChanged: (newPointLimit) { setState(() { ConfigService.setPointLimit(newPointLimit); - Globals.pointLimit = newPointLimit; + ConfigService.pointLimit = newPointLimit; }); }, ), From 751f490c44df32065c5cf8f57acf348b08028df9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 23:18:15 +0200 Subject: [PATCH 054/353] Renamed current json scheme --- assets/{schema.json => game_list-schema.json} | 0 lib/services/local_storage_service.dart | 3 ++- pubspec.yaml | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) rename assets/{schema.json => game_list-schema.json} (100%) diff --git a/assets/schema.json b/assets/game_list-schema.json similarity index 100% rename from assets/schema.json rename to assets/game_list-schema.json diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 338a0c3..e145571 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -196,7 +196,8 @@ class LocalStorageService { /// Validates the JSON data against the schema. static Future validateJsonSchema(String jsonString) async { try { - final schemaString = await rootBundle.loadString('assets/schema.json'); + final schemaString = + await rootBundle.loadString('assets/game_list-schema.json'); final schema = JsonSchema.create(json.decode(schemaString)); final jsonData = json.decode(jsonString); final result = schema.validate(jsonData); diff --git a/pubspec.yaml b/pubspec.yaml index b786c31..144adf4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.7+325 +version: 0.3.7+326 environment: sdk: ^3.5.4 @@ -39,4 +39,4 @@ flutter: uses-material-design: false assets: - assets/cabo_counter-logo_rounded.png - - assets/schema.json + - assets/game_list-schema.json From 5bfac732af215514a976b64d8d051a35adaa56ff Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 23:19:30 +0200 Subject: [PATCH 055/353] Added new schema file --- assets/game-schema.json | 291 +++++++++++++++++++++++++++++++++++ assets/game_list-schema.json | 2 +- 2 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 assets/game-schema.json diff --git a/assets/game-schema.json b/assets/game-schema.json new file mode 100644 index 0000000..9991c74 --- /dev/null +++ b/assets/game-schema.json @@ -0,0 +1,291 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Generated schema for a single cabo counter game", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "gameTitle": { + "type": "string" + }, + "players": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "pointLimit": { + "type": "integer" + }, + "caboPenalty": { + "type": "integer" + }, + "isPointsLimitEnabled": { + "type": "boolean" + }, + "isGameFinished": { + "type": "boolean" + }, + "winner": { + "type": "string" + }, + "roundNumber": { + "type": "integer" + }, + "playerScores": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + }, + "roundList": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "roundNum": { + "type": "integer" + }, + "caboPlayerIndex": { + "type": "integer" + }, + "kamikazePlayerIndex": { + "type": "null" + }, + "scores": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + }, + "scoreUpdates": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + } + }, + "required": [ + "roundNum", + "caboPlayerIndex", + "kamikazePlayerIndex", + "scores", + "scoreUpdates" + ] + }, + { + "type": "object", + "properties": { + "roundNum": { + "type": "integer" + }, + "caboPlayerIndex": { + "type": "integer" + }, + "kamikazePlayerIndex": { + "type": "null" + }, + "scores": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + }, + "scoreUpdates": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + } + }, + "required": [ + "roundNum", + "caboPlayerIndex", + "kamikazePlayerIndex", + "scores", + "scoreUpdates" + ] + }, + { + "type": "object", + "properties": { + "roundNum": { + "type": "integer" + }, + "caboPlayerIndex": { + "type": "integer" + }, + "kamikazePlayerIndex": { + "type": "null" + }, + "scores": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + }, + "scoreUpdates": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + } + }, + "required": [ + "roundNum", + "caboPlayerIndex", + "kamikazePlayerIndex", + "scores", + "scoreUpdates" + ] + }, + { + "type": "object", + "properties": { + "roundNum": { + "type": "integer" + }, + "caboPlayerIndex": { + "type": "integer" + }, + "kamikazePlayerIndex": { + "type": "null" + }, + "scores": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + }, + "scoreUpdates": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + } + }, + "required": [ + "roundNum", + "caboPlayerIndex", + "kamikazePlayerIndex", + "scores", + "scoreUpdates" + ] + }, + { + "type": "object", + "properties": { + "roundNum": { + "type": "integer" + }, + "caboPlayerIndex": { + "type": "integer" + }, + "kamikazePlayerIndex": { + "type": "null" + }, + "scores": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + }, + "scoreUpdates": { + "type": "array", + "items": [ + { + "type": "integer" + }, + { + "type": "integer" + } + ] + } + }, + "required": [ + "roundNum", + "caboPlayerIndex", + "kamikazePlayerIndex", + "scores", + "scoreUpdates" + ] + } + ] + } + }, + "required": [ + "id", + "createdAt", + "gameTitle", + "players", + "pointLimit", + "caboPenalty", + "isPointsLimitEnabled", + "isGameFinished", + "winner", + "roundNumber", + "playerScores", + "roundList" + ] +} + diff --git a/assets/game_list-schema.json b/assets/game_list-schema.json index a9a07e5..26e4278 100644 --- a/assets/game_list-schema.json +++ b/assets/game_list-schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Generated schema for cabo game data", + "title": "Generated schema for the cabo counter game data", "type": "array", "items": { "type": "object", From 4a6f69ab85d9ff8fd3eb62a8363dc15f335d6ffd Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 23:31:04 +0200 Subject: [PATCH 056/353] Implemented single game detection --- lib/services/local_storage_service.dart | 54 ++++++++++++++++++++----- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index e145571..68097da 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -70,7 +70,7 @@ class LocalStorageService { return false; } - if (!await validateJsonSchema(jsonString)) { + if (!await validateJsonSchema(jsonString, true)) { print( '[local_storage_service.dart] Die Datei konnte nicht validiert werden'); gameManager.gameList = []; @@ -161,17 +161,29 @@ class LocalStorageService { try { final jsonString = await _readFileContent(path.files.single); + final jsonData = json.decode(jsonString) as List; - if (!await validateJsonSchema(jsonString)) { + if (await validateJsonSchema(jsonString, true)) { + print( + '[local_storage_service.dart] Die Datei wurde erfolgreich als Liste validiert'); + List tempList = jsonData + .map((jsonItem) => + GameSession.fromJson(jsonItem as Map)) + .toList(); + + for (GameSession s in tempList) { + importSession(s); + } + } else if (await validateJsonSchema(jsonString, false)) { + print( + '[local_storage_service.dart] Die Datei wurde erfolgreich als einzelnes Spiel validiert'); + importSession(GameSession.fromJson(jsonData as Map)); + } else { return ImportStatus.validationError; } - final jsonData = json.decode(jsonString) as List; - gameManager.gameList = jsonData - .map((jsonItem) => - GameSession.fromJson(jsonItem as Map)) - .toList(); + print( - '[local_storage_service.dart] Die Datei wurde erfolgreich Importiertn'); + '[local_storage_service.dart] Die Datei wurde erfolgreich Importiert'); await saveGameSessions(); return ImportStatus.success; } on FormatException catch (e) { @@ -185,6 +197,18 @@ class LocalStorageService { } } + /// Imports a single game session into the gameList. + static Future importSession(GameSession session) async { + if (gameManager.gameList.any((s) => s.id == session.id)) { + print( + '[local_storage_service.dart] Die Session mit der ID ${session.id} existiert bereits. Sie wird aktualisiert.'); + gameManager.gameList.removeWhere((s) => s.id == session.id); + } + gameManager.gameList.add(session); + print( + '[local_storage_service.dart] Die Session mit der ID ${session.id} wurde erfolgreich importiert.'); + } + /// Helper method to read file content from either bytes or path static Future _readFileContent(PlatformFile file) async { if (file.bytes != null) return utf8.decode(file.bytes!); @@ -194,10 +218,18 @@ class LocalStorageService { } /// Validates the JSON data against the schema. - static Future validateJsonSchema(String jsonString) async { - try { - final schemaString = + static Future validateJsonSchema( + String jsonString, bool isGameList) async { + final String schemaString; + + if (isGameList) { + schemaString = await rootBundle.loadString('assets/game_list-schema.json'); + } else { + schemaString = await rootBundle.loadString('assets/game-schema.json'); + } + + try { final schema = JsonSchema.create(json.decode(schemaString)); final jsonData = json.decode(jsonString); final result = schema.validate(jsonData); From c279acfdebcb225156c9ea45ae4d23b82ea95df4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 7 Jul 2025 23:47:55 +0200 Subject: [PATCH 057/353] Organized LocalStorageService --- lib/services/local_storage_service.dart | 30 ++++++++++++++----------- pubspec.yaml | 3 ++- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 68097da..12130a1 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -161,23 +161,23 @@ class LocalStorageService { try { final jsonString = await _readFileContent(path.files.single); - final jsonData = json.decode(jsonString) as List; if (await validateJsonSchema(jsonString, true)) { - print( - '[local_storage_service.dart] Die Datei wurde erfolgreich als Liste validiert'); - List tempList = jsonData + // Checks if the JSON String is in the gameList format + + final jsonData = json.decode(jsonString) as List; + List importedList = jsonData .map((jsonItem) => GameSession.fromJson(jsonItem as Map)) .toList(); - for (GameSession s in tempList) { + for (GameSession s in importedList) { importSession(s); } } else if (await validateJsonSchema(jsonString, false)) { - print( - '[local_storage_service.dart] Die Datei wurde erfolgreich als einzelnes Spiel validiert'); - importSession(GameSession.fromJson(jsonData as Map)); + // Checks if the JSON String is in the single game format + final jsonData = json.decode(jsonString) as Map; + importSession(GameSession.fromJson(jsonData)); } else { return ImportStatus.validationError; } @@ -199,12 +199,12 @@ class LocalStorageService { /// Imports a single game session into the gameList. static Future importSession(GameSession session) async { - if (gameManager.gameList.any((s) => s.id == session.id)) { + if (gameManager.gameExistsInGameList(session.id)) { print( - '[local_storage_service.dart] Die Session mit der ID ${session.id} existiert bereits. Sie wird aktualisiert.'); - gameManager.gameList.removeWhere((s) => s.id == session.id); + '[local_storage_service.dart] Die Session mit der ID ${session.id} existiert bereits. Sie wird überschrieben.'); + gameManager.removeGameSessionById(session.id); } - gameManager.gameList.add(session); + gameManager.addGameSession(session); print( '[local_storage_service.dart] Die Session mit der ID ${session.id} wurde erfolgreich importiert.'); } @@ -218,6 +218,9 @@ class LocalStorageService { } /// Validates the JSON data against the schema. + /// This method checks if the provided [jsonString] is valid against the + /// JSON schema. It takes a boolean [isGameList] to determine + /// which schema to use (game list or single game). static Future validateJsonSchema( String jsonString, bool isGameList) async { final String schemaString; @@ -235,7 +238,8 @@ class LocalStorageService { final result = schema.validate(jsonData); if (result.isValid) { - print('[local_storage_service.dart] JSON ist erfolgreich validiert.'); + print( + '[local_storage_service.dart] JSON ist erfolgreich validiert. Typ: ${isGameList ? 'Game List' : 'Single Game'}'); return true; } print( diff --git a/pubspec.yaml b/pubspec.yaml index 144adf4..7ac98ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.7+326 +version: 0.3.8+327 environment: sdk: ^3.5.4 @@ -40,3 +40,4 @@ flutter: assets: - assets/cabo_counter-logo_rounded.png - assets/game_list-schema.json + - assets/game-schema.json From c2f46ef6f4f08e568cffdece9ca88efbb57cb949 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 8 Jul 2025 00:11:45 +0200 Subject: [PATCH 058/353] Updated popups and refactored --- lib/views/create_game_view.dart | 141 +++++++++++++++----------------- 1 file changed, 67 insertions(+), 74 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 21e8d54..f6099f4 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -7,6 +7,14 @@ import 'package:cabo_counter/views/active_game_view.dart'; import 'package:cabo_counter/views/mode_selection_view.dart'; import 'package:flutter/cupertino.dart'; +enum CreateStatus { + noGameTitle, + noModeSelected, + minPlayers, + maxPlayers, + noPlayerName, +} + class CreateGameView extends StatefulWidget { final String? gameTitle; final bool? isPointsLimitEnabled; @@ -163,22 +171,7 @@ class _CreateGameViewState extends State { .add(TextEditingController()); }); } else { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context) - .max_players_title), - content: Text(AppLocalizations.of(context) - .max_players_message), - actions: [ - CupertinoDialogAction( - child: - Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); + showFeedbackDialog(CreateStatus.maxPlayers); } }, ), @@ -237,73 +230,19 @@ class _CreateGameViewState extends State { ), onPressed: () async { if (_gameTitleTextController.text == '') { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text( - AppLocalizations.of(context).no_gameTitle_title), - content: Text( - AppLocalizations.of(context).no_gameTitle_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); + showFeedbackDialog(CreateStatus.noGameTitle); return; } if (_isPointsLimitEnabled == null) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).no_mode_title), - content: - Text(AppLocalizations.of(context).no_mode_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); + showFeedbackDialog(CreateStatus.noModeSelected); return; } if (_playerNameTextControllers.length < 2) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text( - AppLocalizations.of(context).min_players_title), - content: Text( - AppLocalizations.of(context).min_players_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); + showFeedbackDialog(CreateStatus.minPlayers); return; } if (!everyPlayerHasAName()) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).no_name_title), - content: - Text(AppLocalizations.of(context).no_name_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); + showFeedbackDialog(CreateStatus.noPlayerName); return; } @@ -335,6 +274,60 @@ class _CreateGameViewState extends State { )))); } + /// Displays a feedback dialog based on the [CreateStatus]. + void showFeedbackDialog(CreateStatus status) { + 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), + ), + ], + ); + }); + } + + /// Returns the title and message for the dialog based on the [CreateStatus]. + (String, String) _getDialogContent(CreateStatus status) { + switch (status) { + case CreateStatus.noGameTitle: + return ( + AppLocalizations.of(context).no_gameTitle_title, + AppLocalizations.of(context).no_gameTitle_message + ); + case CreateStatus.noModeSelected: + return ( + AppLocalizations.of(context).no_mode_title, + AppLocalizations.of(context).no_mode_message + ); + + case CreateStatus.minPlayers: + return ( + AppLocalizations.of(context).min_players_title, + AppLocalizations.of(context).min_players_message + ); + case CreateStatus.maxPlayers: + return ( + AppLocalizations.of(context).max_players_title, + AppLocalizations.of(context).max_players_message + ); + case CreateStatus.noPlayerName: + return ( + AppLocalizations.of(context).no_name_title, + AppLocalizations.of(context).no_name_message + ); + } + } + + /// Checks if every player has a name. + /// Returns true if all players have a name, false otherwise. bool everyPlayerHasAName() { for (var controller in _playerNameTextControllers) { if (controller.text == '') { From 1683a8464b2cff6403ba388fa8300efbeda1624e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 8 Jul 2025 21:41:38 +0200 Subject: [PATCH 059/353] Implemented openRoundView method --- lib/views/active_game_view.dart | 33 ++++++++++++++++++++++----------- lib/views/round_view.dart | 15 ++++----------- pubspec.yaml | 2 +- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 68dfeeb..5945a3e 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -105,17 +105,7 @@ class _ActiveGameViewState extends State { : const Text('\u{23F3}', style: TextStyle(fontSize: 22)), onTap: () async { - // ignore: unused_local_variable - final val = await Navigator.of(context, - rootNavigator: true) - .push( - CupertinoPageRoute( - fullscreenDialog: true, - builder: (context) => RoundView( - gameSession: gameSession, - roundNumber: index + 1), - ), - ); + _openRoundView(index + 1); }, )); }, @@ -362,4 +352,25 @@ class _ActiveGameViewState extends State { }); } } + + /// Recursively opens the RoundView for the specified round number. + /// It starts with the given [roundNumber] and continues to open the next round + /// until the user navigates back or the round number is invalid. + void _openRoundView(int roundNumber) async { + final val = await Navigator.of(context, rootNavigator: true).push( + CupertinoPageRoute( + fullscreenDialog: true, + builder: (context) => RoundView( + gameSession: gameSession, + roundNumber: roundNumber, + ), + ), + ); + if (val != null && val >= 0) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + await Future.delayed(const Duration(milliseconds: 600)); + _openRoundView(val); + }); + } + } } diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index c40db1b..beb6577 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -290,7 +290,7 @@ class _RoundViewState extends State { ? () { _finishRound(); LocalStorageService.saveGameSessions(); - Navigator.pop(context, widget.gameSession); + Navigator.pop(context, -1); } : null, child: Text(AppLocalizations.of(context).done), @@ -301,17 +301,10 @@ class _RoundViewState extends State { _finishRound(); LocalStorageService.saveGameSessions(); if (widget.gameSession.isGameFinished == true) { - Navigator.pop(context, widget.gameSession); + Navigator.pop(context, -1); } else { - Navigator.of(context, rootNavigator: true) - .pushReplacement( - CupertinoPageRoute( - builder: (context) => RoundView( - gameSession: widget.gameSession, - roundNumber: widget.roundNumber + 1, - ), - ), - ); + Navigator.pop( + context, widget.roundNumber + 1); } } : null, diff --git a/pubspec.yaml b/pubspec.yaml index 7ac98ec..006a846 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.8+327 +version: 0.3.9+330 environment: sdk: ^3.5.4 From 75e5512f35c292c187ba523da8a7575028255756 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 8 Jul 2025 21:52:51 +0200 Subject: [PATCH 060/353] Updated pop return type in roundView --- lib/views/round_view.dart | 10 ++++------ pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index beb6577..4e114fe 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -76,10 +76,8 @@ class _RoundViewState extends State { middle: Text(AppLocalizations.of(context).results), leading: CupertinoButton( padding: EdgeInsets.zero, - onPressed: () => { - LocalStorageService.saveGameSessions(), - Navigator.pop(context, widget.gameSession) - }, + onPressed: () => + {LocalStorageService.saveGameSessions(), Navigator.pop(context)}, child: Text(AppLocalizations.of(context).cancel), ), ), @@ -290,7 +288,7 @@ class _RoundViewState extends State { ? () { _finishRound(); LocalStorageService.saveGameSessions(); - Navigator.pop(context, -1); + Navigator.pop(context); } : null, child: Text(AppLocalizations.of(context).done), @@ -301,7 +299,7 @@ class _RoundViewState extends State { _finishRound(); LocalStorageService.saveGameSessions(); if (widget.gameSession.isGameFinished == true) { - Navigator.pop(context, -1); + Navigator.pop(context); } else { Navigator.pop( context, widget.roundNumber + 1); diff --git a/pubspec.yaml b/pubspec.yaml index 006a846..562b189 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.9+330 +version: 0.3.9+331 environment: sdk: ^3.5.4 From 0a316035c065ac7c9d249f7b537fa227b8aae347 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 8 Jul 2025 22:28:46 +0200 Subject: [PATCH 061/353] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5e187d..20b0cae 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.3.0-orange) +![Version](https://img.shields.io/badge/Version-0.3.8-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) From a3003047ae4ebe81eaa06bbae54e917f258ec664 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 8 Jul 2025 22:28:59 +0200 Subject: [PATCH 062/353] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5e187d..20b0cae 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.3.0-orange) +![Version](https://img.shields.io/badge/Version-0.3.8-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) From 34207997f62db9560a9a1570b2278601f836edc8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 14:15:36 +0200 Subject: [PATCH 063/353] Tried new design for im- and export-button --- lib/views/settings_view.dart | 39 ++++++++++++++++++++++++++++++++++-- pubspec.yaml | 2 +- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 2e86122..8185d8a 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -107,7 +107,7 @@ class _SettingsViewState extends State { style: CustomTheme.rowTitle, ), ), - Padding( + /*Padding( padding: const EdgeInsets.only(top: 30), child: Center( heightFactor: 1, @@ -163,7 +163,42 @@ class _SettingsViewState extends State { ), ], )), - ) + ),*/ + Padding( + padding: const EdgeInsets.fromLTRB(10, 15, 10, 0), + child: CupertinoFormSection.insetGrouped( + backgroundColor: CustomTheme.backgroundColor, + margin: EdgeInsets.zero, + children: [ + CupertinoFormRow( + prefix: Row( + children: [ + Icon( + CupertinoIcons.square_arrow_up, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 10), + const Text('Spieldaten exportieren'), + ], + ), + padding: const EdgeInsets.symmetric( + vertical: 10, horizontal: 15), + child: const CupertinoListTileChevron()), + CupertinoFormRow( + prefix: Row( + children: [ + Icon( + CupertinoIcons.square_arrow_down, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 10), + const Text('Spieldaten importieren'), + ], + ), + padding: const EdgeInsets.symmetric( + vertical: 10, horizontal: 15), + child: const CupertinoListTileChevron()) + ])), ], ), Positioned( diff --git a/pubspec.yaml b/pubspec.yaml index 562b189..9b8aaa4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.9+331 +version: 0.3.9+333 environment: sdk: ^3.5.4 From 1bae1be93b7d6e5957f4c6502210537ea596baea Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 14:17:54 +0200 Subject: [PATCH 064/353] Moved views to presentation folder --- lib/main.dart | 2 +- lib/{ => presentation}/views/active_game_view.dart | 6 +++--- lib/{ => presentation}/views/create_game_view.dart | 4 ++-- lib/{ => presentation}/views/graph_view.dart | 0 lib/{ => presentation}/views/information_view.dart | 0 lib/{ => presentation}/views/main_menu_view.dart | 6 +++--- lib/{ => presentation}/views/mode_selection_view.dart | 0 lib/{ => presentation}/views/round_view.dart | 0 lib/{ => presentation}/views/settings_view.dart | 0 lib/{ => presentation}/views/tab_view.dart | 4 ++-- 10 files changed, 11 insertions(+), 11 deletions(-) rename lib/{ => presentation}/views/active_game_view.dart (98%) rename lib/{ => presentation}/views/create_game_view.dart (98%) rename lib/{ => presentation}/views/graph_view.dart (100%) rename lib/{ => presentation}/views/information_view.dart (100%) rename lib/{ => presentation}/views/main_menu_view.dart (98%) rename lib/{ => presentation}/views/mode_selection_view.dart (100%) rename lib/{ => presentation}/views/round_view.dart (100%) rename lib/{ => presentation}/views/settings_view.dart (100%) rename lib/{ => presentation}/views/tab_view.dart (90%) diff --git a/lib/main.dart b/lib/main.dart index cd3d05f..06e2d2b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,8 @@ import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/tab_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/tab_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; diff --git a/lib/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart similarity index 98% rename from lib/views/active_game_view.dart rename to lib/presentation/views/active_game_view.dart index 5945a3e..ddc0299 100644 --- a/lib/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -1,11 +1,11 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/create_game_view.dart'; +import 'package:cabo_counter/presentation/views/graph_view.dart'; +import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/create_game_view.dart'; -import 'package:cabo_counter/views/graph_view.dart'; -import 'package:cabo_counter/views/round_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart similarity index 98% rename from lib/views/create_game_view.dart rename to lib/presentation/views/create_game_view.dart index f6099f4..2c04e74 100644 --- a/lib/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -1,10 +1,10 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/active_game_view.dart'; +import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/active_game_view.dart'; -import 'package:cabo_counter/views/mode_selection_view.dart'; import 'package:flutter/cupertino.dart'; enum CreateStatus { diff --git a/lib/views/graph_view.dart b/lib/presentation/views/graph_view.dart similarity index 100% rename from lib/views/graph_view.dart rename to lib/presentation/views/graph_view.dart diff --git a/lib/views/information_view.dart b/lib/presentation/views/information_view.dart similarity index 100% rename from lib/views/information_view.dart rename to lib/presentation/views/information_view.dart diff --git a/lib/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart similarity index 98% rename from lib/views/main_menu_view.dart rename to lib/presentation/views/main_menu_view.dart index e087cfc..230c4de 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -1,11 +1,11 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/active_game_view.dart'; +import 'package:cabo_counter/presentation/views/create_game_view.dart'; +import 'package:cabo_counter/presentation/views/settings_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/active_game_view.dart'; -import 'package:cabo_counter/views/create_game_view.dart'; -import 'package:cabo_counter/views/settings_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart similarity index 100% rename from lib/views/mode_selection_view.dart rename to lib/presentation/views/mode_selection_view.dart diff --git a/lib/views/round_view.dart b/lib/presentation/views/round_view.dart similarity index 100% rename from lib/views/round_view.dart rename to lib/presentation/views/round_view.dart diff --git a/lib/views/settings_view.dart b/lib/presentation/views/settings_view.dart similarity index 100% rename from lib/views/settings_view.dart rename to lib/presentation/views/settings_view.dart diff --git a/lib/views/tab_view.dart b/lib/presentation/views/tab_view.dart similarity index 90% rename from lib/views/tab_view.dart rename to lib/presentation/views/tab_view.dart index 4abd411..efa4311 100644 --- a/lib/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -1,7 +1,7 @@ import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/information_view.dart'; +import 'package:cabo_counter/presentation/views/main_menu_view.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/information_view.dart'; -import 'package:cabo_counter/views/main_menu_view.dart'; import 'package:flutter/cupertino.dart'; class TabView extends StatefulWidget { From ed8aced8a870426bdb50d5528c38912f33f450bb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 14:18:28 +0200 Subject: [PATCH 065/353] Moved widgets to presentation folder --- lib/presentation/views/settings_view.dart | 2 +- lib/{ => presentation}/widgets/stepper.dart | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/{ => presentation}/widgets/stepper.dart (100%) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 8185d8a..7875890 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,9 +1,9 @@ import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/presentation/widgets/stepper.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:cabo_counter/utility/globals.dart'; -import 'package:cabo_counter/widgets/stepper.dart'; import 'package:flutter/cupertino.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/lib/widgets/stepper.dart b/lib/presentation/widgets/stepper.dart similarity index 100% rename from lib/widgets/stepper.dart rename to lib/presentation/widgets/stepper.dart From 0c774366594d944e2250fd35ae3585fd1a04ec29 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 15:20:05 +0200 Subject: [PATCH 066/353] Implemented CustomRowForm Widget --- lib/presentation/widgets/custom_form_row.dart | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lib/presentation/widgets/custom_form_row.dart diff --git a/lib/presentation/widgets/custom_form_row.dart b/lib/presentation/widgets/custom_form_row.dart new file mode 100644 index 0000000..61d0fdb --- /dev/null +++ b/lib/presentation/widgets/custom_form_row.dart @@ -0,0 +1,49 @@ +import 'package:cabo_counter/utility/custom_theme.dart'; +import 'package:flutter/cupertino.dart'; + +class CustomFormRow extends StatefulWidget { + final String prefixText; + final IconData prefixIcon; + final Widget? suffixWidget; + final void Function()? onTap; + const CustomFormRow({ + super.key, + required this.prefixText, + required this.prefixIcon, + required this.onTap, + this.suffixWidget, + }); + + @override + State createState() => _CustomFormRowState(); +} + +class _CustomFormRowState extends State { + late Widget suffixWidget; + @override + void initState() { + super.initState(); + suffixWidget = widget.suffixWidget ?? const SizedBox.shrink(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: widget.onTap, + child: CupertinoFormRow( + prefix: Row( + children: [ + Icon( + widget.prefixIcon, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 10), + Text(widget.prefixText), + ], + ), + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + child: suffixWidget, + ), + ); + } +} From 7fa95f4bcaf7c27438955dd413b37cc366de4c09 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 15:20:28 +0200 Subject: [PATCH 067/353] Used new custom form row --- lib/presentation/views/settings_view.dart | 106 +++++----------------- pubspec.yaml | 2 +- 2 files changed, 22 insertions(+), 86 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 7875890..4c44e1b 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,10 +1,12 @@ import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/presentation/widgets/custom_form_row.dart'; import 'package:cabo_counter/presentation/widgets/stepper.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:cabo_counter/utility/globals.dart'; import 'package:flutter/cupertino.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -107,97 +109,31 @@ class _SettingsViewState extends State { style: CustomTheme.rowTitle, ), ), - /*Padding( - padding: const EdgeInsets.only(top: 30), - child: Center( - heightFactor: 1, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CupertinoButton( - color: CustomTheme.primaryColor, - sizeStyle: CupertinoButtonSize.medium, - child: Text( - AppLocalizations.of(context).import_data, - style: - TextStyle(color: CustomTheme.backgroundColor), - ), - onPressed: () async { - final success = - await LocalStorageService.importJsonFile(); - showFeedbackDialog(success); - }), - const SizedBox( - width: 20, - ), - CupertinoButton( - color: CustomTheme.primaryColor, - sizeStyle: CupertinoButtonSize.medium, - child: Text( - AppLocalizations.of(context).export_data, - style: - TextStyle(color: CustomTheme.backgroundColor), - ), - onPressed: () async { - final success = - await LocalStorageService.exportGameData(); - if (!success && context.mounted) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context) - .export_error_title), - content: Text(AppLocalizations.of(context) - .export_error_message), - actions: [ - CupertinoDialogAction( - child: - Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - } - }, - ), - ], - )), - ),*/ Padding( padding: const EdgeInsets.fromLTRB(10, 15, 10, 0), child: CupertinoFormSection.insetGrouped( backgroundColor: CustomTheme.backgroundColor, margin: EdgeInsets.zero, children: [ - CupertinoFormRow( - prefix: Row( - children: [ - Icon( - CupertinoIcons.square_arrow_up, - color: CustomTheme.primaryColor, - ), - const SizedBox(width: 10), - const Text('Spieldaten exportieren'), - ], - ), - padding: const EdgeInsets.symmetric( - vertical: 10, horizontal: 15), - child: const CupertinoListTileChevron()), - CupertinoFormRow( - prefix: Row( - children: [ - Icon( - CupertinoIcons.square_arrow_down, - color: CustomTheme.primaryColor, - ), - const SizedBox(width: 10), - const Text('Spieldaten importieren'), - ], - ), - padding: const EdgeInsets.symmetric( - vertical: 10, horizontal: 15), - child: const CupertinoListTileChevron()) + CustomFormRow( + prefixText: 'Spieldaten importieren', + prefixIcon: CupertinoIcons.square_arrow_down, + onTap: () {}, + suffixWidget: CupertinoListTileChevron(), + ), + CustomFormRow( + prefixText: 'Spieldaten exportieren', + prefixIcon: CupertinoIcons.square_arrow_up, + onTap: () {}, + suffixWidget: const CupertinoListTileChevron(), + ), + CustomFormRow( + prefixText: AppLocalizations.of(context).create_issue, + prefixIcon: FontAwesomeIcons.github, + onTap: () => launchUrl(Uri.parse( + 'https://github.com/flixcoo/Cabo-Counter/issues')), + suffixWidget: const CupertinoListTileChevron(), + ), ])), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 9b8aaa4..2bae78c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.9+333 +version: 0.3.9+337 environment: sdk: ^3.5.4 From 2d34ebf35b71d52b9f1702e70668da5cc6aba869 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 15:21:46 +0200 Subject: [PATCH 068/353] Removed double information --- lib/presentation/views/settings_view.dart | 60 +++++++++-------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 4c44e1b..baaf24e 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -141,44 +141,28 @@ class _SettingsViewState extends State { bottom: 30, left: 0, right: 0, - child: Column( - children: [ - Center( - child: Text(AppLocalizations.of(context).error_found), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 30), - child: Center( - child: CupertinoButton( - onPressed: () => launchUrl(Uri.parse( - 'https://github.com/flixcoo/Cabo-Counter/issues')), - child: Text(AppLocalizations.of(context).create_issue), - ), - ), - ), - FutureBuilder( - future: _getPackageInfo(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text( - '${Globals.appDevPhase} ${snapshot.data!.version} ' - '(${AppLocalizations.of(context).build} ${snapshot.data!.buildNumber})', - textAlign: TextAlign.center, - ); - } else if (snapshot.hasError) { - return Text( - '${AppLocalizations.of(context).app_version} -.-.- (${AppLocalizations.of(context).build} -)', - textAlign: TextAlign.center, - ); - } - return Text( - AppLocalizations.of(context).load_version, - textAlign: TextAlign.center, - ); - }, - ) - ], - )), + child: Center( + child: FutureBuilder( + future: _getPackageInfo(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text( + '${Globals.appDevPhase} ${snapshot.data!.version} ' + '(${AppLocalizations.of(context).build} ${snapshot.data!.buildNumber})', + textAlign: TextAlign.center, + ); + } else if (snapshot.hasError) { + return Text( + '${AppLocalizations.of(context).app_version} -.-.- (${AppLocalizations.of(context).build} -)', + textAlign: TextAlign.center, + ); + } + return Text( + AppLocalizations.of(context).load_version, + textAlign: TextAlign.center, + ); + }, + ))), ], )), ); From ee5ec4d0d99cdc3f5649c9273e3a153de560d459 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 16:19:16 +0200 Subject: [PATCH 069/353] Refactored methods to private --- lib/services/local_storage_service.dart | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 12130a1..29ac58b 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -21,7 +21,7 @@ class LocalStorageService { static const String _fileName = 'game_data.json'; /// Writes the game session list to a JSON file and returns it as string. - static String getGameDataAsJsonFile() { + static String _getGameDataAsJsonFile() { final jsonFile = gameManager.gameList.map((session) => session.toJson()).toList(); return json.encode(jsonFile); @@ -39,7 +39,7 @@ class LocalStorageService { print('[local_storage_service.dart] Versuche, Daten zu speichern...'); try { final file = await _getFilePath(); - final jsonFile = getGameDataAsJsonFile(); + final jsonFile = _getGameDataAsJsonFile(); await file.writeAsString(jsonFile); print( '[local_storage_service.dart] Die Spieldaten wurden zwischengespeichert.'); @@ -70,7 +70,7 @@ class LocalStorageService { return false; } - if (!await validateJsonSchema(jsonString, true)) { + if (!await _validateJsonSchema(jsonString, true)) { print( '[local_storage_service.dart] Die Datei konnte nicht validiert werden'); gameManager.gameList = []; @@ -105,7 +105,7 @@ class LocalStorageService { /// Opens the file picker to export game data as a JSON file. /// This method will export the given [jsonString] as a JSON file. It opens /// the file picker with the choosen [fileName]. - static Future exportJsonData( + static Future _exportJsonData( String jsonString, String fileName, ) async { @@ -133,16 +133,16 @@ class LocalStorageService { /// Opens the file picker to export all game sessions as a JSON file. static Future exportGameData() async { - String jsonString = getGameDataAsJsonFile(); + String jsonString = _getGameDataAsJsonFile(); String fileName = 'cabo_counter-game_data'; - return exportJsonData(jsonString, fileName); + return _exportJsonData(jsonString, fileName); } /// Opens the file picker to save a single game session as a JSON file. static Future exportSingleGameSession(GameSession session) async { String jsonString = json.encode(session.toJson()); String fileName = 'cabo_counter-game_${session.id.substring(0, 7)}'; - return exportJsonData(jsonString, fileName); + return _exportJsonData(jsonString, fileName); } /// Opens the file picker to import a JSON file and loads the game data from it. @@ -162,7 +162,7 @@ class LocalStorageService { try { final jsonString = await _readFileContent(path.files.single); - if (await validateJsonSchema(jsonString, true)) { + if (await _validateJsonSchema(jsonString, true)) { // Checks if the JSON String is in the gameList format final jsonData = json.decode(jsonString) as List; @@ -172,12 +172,12 @@ class LocalStorageService { .toList(); for (GameSession s in importedList) { - importSession(s); + _importSession(s); } - } else if (await validateJsonSchema(jsonString, false)) { + } else if (await _validateJsonSchema(jsonString, false)) { // Checks if the JSON String is in the single game format final jsonData = json.decode(jsonString) as Map; - importSession(GameSession.fromJson(jsonData)); + _importSession(GameSession.fromJson(jsonData)); } else { return ImportStatus.validationError; } @@ -198,7 +198,7 @@ class LocalStorageService { } /// Imports a single game session into the gameList. - static Future importSession(GameSession session) async { + static Future _importSession(GameSession session) async { if (gameManager.gameExistsInGameList(session.id)) { print( '[local_storage_service.dart] Die Session mit der ID ${session.id} existiert bereits. Sie wird überschrieben.'); @@ -221,7 +221,7 @@ class LocalStorageService { /// This method checks if the provided [jsonString] is valid against the /// JSON schema. It takes a boolean [isGameList] to determine /// which schema to use (game list or single game). - static Future validateJsonSchema( + static Future _validateJsonSchema( String jsonString, bool isGameList) async { final String schemaString; From 249609276411d0399e57ca44a5c9c2e2ae1dde9f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 16:21:14 +0200 Subject: [PATCH 070/353] Changed label --- lib/l10n/app_de.arb | 6 +++--- lib/l10n/app_en.arb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9281ac1..632988c 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -82,9 +82,9 @@ "point_limit": "Punkte-Limit", "point_limit_subtitle": "... hier ist Schluss", "reset_to_default": "Auf Standard zurücksetzen", - "game_data": "Spieldaten", - "import_data": "Daten importieren", - "export_data": "Daten exportieren", + "app": "App", + "import_data": "Spieldaten importieren", + "export_data": "Spieldaten exportieren", "import_success_title": "Import erfolgreich", "import_success_message":"Die Spieldaten wurden erfolgreich importiert.", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8b328ba..1948270 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -78,7 +78,7 @@ "point_limit": "Point Limit", "point_limit_subtitle": "... the game ends here.", "reset_to_default": "Reset to Default", - "game_data": "Game Data", + "app": "App", "import_data": "Import Data", "export_data": "Export Data", "id_error_title": "ID Error", From 847e3dcd19b834e86d25aa6378fa064fed0a6bb2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 16:21:32 +0200 Subject: [PATCH 071/353] Modified paddings and text color --- lib/presentation/widgets/stepper.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/presentation/widgets/stepper.dart b/lib/presentation/widgets/stepper.dart index 879235e..8ca2635 100644 --- a/lib/presentation/widgets/stepper.dart +++ b/lib/presentation/widgets/stepper.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; // Für iOS-Style class Stepper extends StatefulWidget { @@ -34,18 +35,20 @@ class _StepperState extends State { Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, children: [ CupertinoButton( - padding: const EdgeInsets.all(8), + padding: EdgeInsets.zero, onPressed: _decrement, child: const Icon(CupertinoIcons.minus), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Text('$_value', style: const TextStyle(fontSize: 18)), + child: Text('$_value', + style: TextStyle(fontSize: 18, color: CustomTheme.white)), ), CupertinoButton( - padding: const EdgeInsets.all(8), + padding: EdgeInsets.zero, onPressed: _increment, child: const Icon(CupertinoIcons.add), ), From 21920d2ac4807e6f40ce4842bb024e74e0741b5f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 17:14:20 +0200 Subject: [PATCH 072/353] Changed string --- lib/l10n/app_de.arb | 5 +++-- lib/l10n/app_en.arb | 13 +++++++------ lib/l10n/app_localizations.dart | 22 ++++++++++++++-------- lib/l10n/app_localizations_de.dart | 11 +++++++---- lib/l10n/app_localizations_en.dart | 7 +++++-- 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 632988c..b83c646 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -82,9 +82,10 @@ "point_limit": "Punkte-Limit", "point_limit_subtitle": "... hier ist Schluss", "reset_to_default": "Auf Standard zurücksetzen", - "app": "App", + "data": "Daten", "import_data": "Spieldaten importieren", "export_data": "Spieldaten exportieren", + "app": "App", "import_success_title": "Import erfolgreich", "import_success_message":"Die Spieldaten wurden erfolgreich importiert.", @@ -101,7 +102,7 @@ "create_issue": "Issue erstellen", "app_version": "App-Version", "build": "Build", - "load_version": "Lade Version...", + "loading": "Lädt...", "about_text": "Hey :) Danke, dass du als eine:r der ersten User meiner ersten eigenen App dabei bist! Ich hab sehr viel Arbeit in dieses Projekt gesteckt und auch, wenn ich (hoffentlich) an vieles Gedacht hab, wird auf jeden Fall noch nicht alles 100% funktionieren. Solltest du also irgendwelche Fehler entdecken oder Feedback zum Design oder der Benutzerfreundlichkeit haben, teile Sie mir gern über die Testflight App oder auf den dir bekannten Wegen mit. Danke! " } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1948270..1c111e2 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -71,6 +71,10 @@ "export_game": "Export Game", "game_process": "Spielverlauf", + "id_error_title": "ID Error", + "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", + "end_game_title": "End the game?", + "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", "settings": "Settings", "cabo_penalty": "Cabo Penalty", @@ -78,13 +82,10 @@ "point_limit": "Point Limit", "point_limit_subtitle": "... the game ends here.", "reset_to_default": "Reset to Default", - "app": "App", + "data": "Data", "import_data": "Import Data", "export_data": "Export Data", - "id_error_title": "ID Error", - "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", - "end_game_title": "End the game?", - "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", + "app": "App", "import_success_title": "Import successful", "import_success_message":"The game data has been successfully imported.", @@ -100,7 +101,7 @@ "error_found": "Found a bug?", "create_issue": "Create Issue", "app_version": "App Version", - "load_version": "Loading version...", + "loading": "Loading...", "build": "Build", "about_text": "Hey :) Thanks for being one of the first users of my app! I’ve put a lot of work into this project, and even though I tried to think of everything, it might not work perfectly just yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the TestFlight app or by sending me a message or email. Thank you very much!" diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index c836194..84295df 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -458,24 +458,30 @@ abstract class AppLocalizations { /// **'Auf Standard zurücksetzen'** String get reset_to_default; - /// No description provided for @game_data. + /// No description provided for @data. /// /// In de, this message translates to: - /// **'Spieldaten'** - String get game_data; + /// **'Daten'** + String get data; /// No description provided for @import_data. /// /// In de, this message translates to: - /// **'Daten importieren'** + /// **'Spieldaten importieren'** String get import_data; /// No description provided for @export_data. /// /// In de, this message translates to: - /// **'Daten exportieren'** + /// **'Spieldaten exportieren'** String get export_data; + /// No description provided for @app. + /// + /// In de, this message translates to: + /// **'App'** + String get app; + /// No description provided for @import_success_title. /// /// In de, this message translates to: @@ -560,11 +566,11 @@ abstract class AppLocalizations { /// **'Build'** String get build; - /// No description provided for @load_version. + /// No description provided for @loading. /// /// In de, this message translates to: - /// **'Lade Version...'** - String get load_version; + /// **'Lädt...'** + String get loading; /// No description provided for @about_text. /// diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 5b9d841..f4a2bbd 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -200,13 +200,16 @@ class AppLocalizationsDe extends AppLocalizations { String get reset_to_default => 'Auf Standard zurücksetzen'; @override - String get game_data => 'Spieldaten'; + String get data => 'Daten'; @override - String get import_data => 'Daten importieren'; + String get import_data => 'Spieldaten importieren'; @override - String get export_data => 'Daten exportieren'; + String get export_data => 'Spieldaten exportieren'; + + @override + String get app => 'App'; @override String get import_success_title => 'Import erfolgreich'; @@ -254,7 +257,7 @@ class AppLocalizationsDe extends AppLocalizations { String get build => 'Build'; @override - String get load_version => 'Lade Version...'; + String get loading => 'Lädt...'; @override String get about_text => diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index c98dddd..aac55f2 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -197,7 +197,7 @@ class AppLocalizationsEn extends AppLocalizations { String get reset_to_default => 'Reset to Default'; @override - String get game_data => 'Game Data'; + String get data => 'Data'; @override String get import_data => 'Import Data'; @@ -205,6 +205,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get export_data => 'Export Data'; + @override + String get app => 'App'; + @override String get import_success_title => 'Import successful'; @@ -251,7 +254,7 @@ class AppLocalizationsEn extends AppLocalizations { String get build => 'Build'; @override - String get load_version => 'Loading version...'; + String get loading => 'Loading...'; @override String get about_text => From 9bc80a8cd94e827576bc726d506b9319b5ba1220 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 17:15:00 +0200 Subject: [PATCH 073/353] Updated CustomFormRow padding and pressed handler --- lib/presentation/widgets/custom_form_row.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/presentation/widgets/custom_form_row.dart b/lib/presentation/widgets/custom_form_row.dart index 61d0fdb..f03b453 100644 --- a/lib/presentation/widgets/custom_form_row.dart +++ b/lib/presentation/widgets/custom_form_row.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/presentation/widgets/stepper.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; @@ -5,12 +6,12 @@ class CustomFormRow extends StatefulWidget { final String prefixText; final IconData prefixIcon; final Widget? suffixWidget; - final void Function()? onTap; + final void Function()? onPressed; const CustomFormRow({ super.key, required this.prefixText, required this.prefixIcon, - required this.onTap, + this.onPressed, this.suffixWidget, }); @@ -28,8 +29,9 @@ class _CustomFormRowState extends State { @override Widget build(BuildContext context) { - return GestureDetector( - onTap: widget.onTap, + return CupertinoButton( + padding: EdgeInsets.zero, + onPressed: widget.onPressed, child: CupertinoFormRow( prefix: Row( children: [ @@ -41,7 +43,9 @@ class _CustomFormRowState extends State { Text(widget.prefixText), ], ), - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + padding: suffixWidget is Stepper + ? const EdgeInsets.fromLTRB(15, 0, 0, 0) + : const EdgeInsets.symmetric(vertical: 10, horizontal: 15), child: suffixWidget, ), ); From 696ade5b9b1c60f52cda8aed76d21c708d0c6842 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 17:15:30 +0200 Subject: [PATCH 074/353] Implemented various new forms of CustomFormRow into SettingsView --- lib/presentation/views/settings_view.dart | 234 +++++++++++++--------- pubspec.yaml | 2 +- 2 files changed, 139 insertions(+), 97 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index baaf24e..34540a4 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -46,66 +46,89 @@ class _SettingsViewState extends State { ), ), Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoListTile( - padding: EdgeInsets.zero, - title: Text(AppLocalizations.of(context).cabo_penalty), - subtitle: Text( - AppLocalizations.of(context).cabo_penalty_subtitle), - trailing: Stepper( - key: _stepperKey1, - initialValue: ConfigService.caboPenalty, - minValue: 0, - maxValue: 50, - step: 1, - onChanged: (newCaboPenalty) { - setState(() { - ConfigService.setCaboPenalty(newCaboPenalty); - ConfigService.caboPenalty = newCaboPenalty; - }); - }, - ), - )), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoListTile( - padding: EdgeInsets.zero, - title: Text(AppLocalizations.of(context).point_limit), - subtitle: - Text(AppLocalizations.of(context).point_limit_subtitle), - trailing: Stepper( - key: _stepperKey2, - initialValue: ConfigService.pointLimit, - minValue: 30, - maxValue: 1000, - step: 10, - onChanged: (newPointLimit) { - setState(() { - ConfigService.setPointLimit(newPointLimit); - ConfigService.pointLimit = newPointLimit; - }); - }, - ), - )), - Padding( - padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), - child: Center( - heightFactor: 0.9, - child: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: () => setState(() { - ConfigService.resetConfig(); - _stepperKey1 = UniqueKey(); - _stepperKey2 = UniqueKey(); - }), - child: - Text(AppLocalizations.of(context).reset_to_default), - ), - )), + padding: const EdgeInsets.fromLTRB(10, 15, 10, 10), + child: CupertinoFormSection.insetGrouped( + backgroundColor: CustomTheme.backgroundColor, + margin: EdgeInsets.zero, + children: [ + CustomFormRow( + key: _stepperKey1, + prefixText: 'Cabo-Strafe', + prefixIcon: CupertinoIcons.minus_square, + suffixWidget: Stepper( + initialValue: ConfigService.caboPenalty, + minValue: 0, + maxValue: 50, + step: 1, + onChanged: (newCaboPenalty) { + setState(() { + ConfigService.setCaboPenalty(newCaboPenalty); + ConfigService.caboPenalty = newCaboPenalty; + }); + }, + ), + ), + CustomFormRow( + key: _stepperKey2, + prefixText: 'Punkte-Limit', + prefixIcon: FontAwesomeIcons.bullseye, + suffixWidget: Stepper( + 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(() { + _stepperKey1 = UniqueKey(); + _stepperKey2 = UniqueKey(); + print('Config reset to default'); + }); + }, + ) + ])), Padding( padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), child: Text( - AppLocalizations.of(context).game_data, + AppLocalizations.of(context).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: () => LocalStorageService.importJsonFile(), + suffixWidget: const CupertinoListTileChevron(), + ), + CustomFormRow( + prefixText: AppLocalizations.of(context).export_data, + prefixIcon: CupertinoIcons.square_arrow_up, + onPressed: () => LocalStorageService.importJsonFile(), + suffixWidget: const CupertinoListTileChevron(), + ), + ])), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).app, style: CustomTheme.rowTitle, ), ), @@ -115,54 +138,73 @@ class _SettingsViewState extends State { backgroundColor: CustomTheme.backgroundColor, margin: EdgeInsets.zero, children: [ - CustomFormRow( - prefixText: 'Spieldaten importieren', - prefixIcon: CupertinoIcons.square_arrow_down, - onTap: () {}, - suffixWidget: CupertinoListTileChevron(), - ), - CustomFormRow( - prefixText: 'Spieldaten exportieren', - prefixIcon: CupertinoIcons.square_arrow_up, - onTap: () {}, - suffixWidget: const CupertinoListTileChevron(), - ), CustomFormRow( prefixText: AppLocalizations.of(context).create_issue, prefixIcon: FontAwesomeIcons.github, - onTap: () => launchUrl(Uri.parse( + onPressed: () => launchUrl(Uri.parse( 'https://github.com/flixcoo/Cabo-Counter/issues')), suffixWidget: const CupertinoListTileChevron(), ), + CustomFormRow( + prefixText: 'App-Version', + prefixIcon: CupertinoIcons.info, + onPressed: null, + suffixWidget: FutureBuilder( + future: _getPackageInfo(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text( + '${Globals.appDevPhase} ${snapshot.data!.version} ', + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ); + } else if (snapshot.hasError) { + return Text( + '${AppLocalizations.of(context).app_version} -.-.-', + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ); + } + return Text( + AppLocalizations.of(context).loading, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ); + }, + )), + CustomFormRow( + prefixText: 'Build-Nr.', + prefixIcon: CupertinoIcons.info, + onPressed: null, + suffixWidget: FutureBuilder( + future: _getPackageInfo(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text( + snapshot.data!.buildNumber, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ); + } else if (snapshot.hasError) { + return Text( + '-', + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ); + } + return Text( + AppLocalizations.of(context).loading, + ); + }, + )), ])), ], ), - Positioned( - bottom: 30, - left: 0, - right: 0, - child: Center( - child: FutureBuilder( - future: _getPackageInfo(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text( - '${Globals.appDevPhase} ${snapshot.data!.version} ' - '(${AppLocalizations.of(context).build} ${snapshot.data!.buildNumber})', - textAlign: TextAlign.center, - ); - } else if (snapshot.hasError) { - return Text( - '${AppLocalizations.of(context).app_version} -.-.- (${AppLocalizations.of(context).build} -)', - textAlign: TextAlign.center, - ); - } - return Text( - AppLocalizations.of(context).load_version, - textAlign: TextAlign.center, - ); - }, - ))), ], )), ); diff --git a/pubspec.yaml b/pubspec.yaml index 2bae78c..fdf9916 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.9+337 +version: 0.4.0+371 environment: sdk: ^3.5.4 From aba4bf9c0bd8b09a67e0f104145fa81e08d86e1a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 17:30:28 +0200 Subject: [PATCH 075/353] Implemented VersionService --- lib/main.dart | 2 + lib/presentation/views/settings_view.dart | 64 ++++------------------- lib/services/version_service.dart | 32 ++++++++++++ pubspec.yaml | 2 +- 4 files changed, 44 insertions(+), 56 deletions(-) create mode 100644 lib/services/version_service.dart diff --git a/lib/main.dart b/lib/main.dart index 06e2d2b..b826072 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/presentation/views/tab_view.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:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; @@ -13,6 +14,7 @@ Future main() async { await ConfigService.initConfig(); ConfigService.pointLimit = await ConfigService.getPointLimit(); ConfigService.caboPenalty = await ConfigService.getCaboPenalty(); + await VersionService.init(); runApp(const App()); } diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 34540a4..2ed422f 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -3,11 +3,10 @@ import 'package:cabo_counter/presentation/widgets/custom_form_row.dart'; import 'package:cabo_counter/presentation/widgets/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:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/utility/globals.dart'; import 'package:flutter/cupertino.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; class SettingsView extends StatefulWidget { @@ -149,59 +148,18 @@ class _SettingsViewState extends State { prefixText: 'App-Version', prefixIcon: CupertinoIcons.info, onPressed: null, - suffixWidget: FutureBuilder( - future: _getPackageInfo(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text( - '${Globals.appDevPhase} ${snapshot.data!.version} ', - style: TextStyle( - color: CustomTheme.primaryColor, - ), - ); - } else if (snapshot.hasError) { - return Text( - '${AppLocalizations.of(context).app_version} -.-.-', - style: TextStyle( - color: CustomTheme.primaryColor, - ), - ); - } - return Text( - AppLocalizations.of(context).loading, - style: TextStyle( - color: CustomTheme.primaryColor, - ), - ); - }, - )), + suffixWidget: Text(VersionService.getVersion(), + style: TextStyle( + color: CustomTheme.primaryColor, + ))), CustomFormRow( prefixText: 'Build-Nr.', prefixIcon: CupertinoIcons.info, onPressed: null, - suffixWidget: FutureBuilder( - future: _getPackageInfo(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text( - snapshot.data!.buildNumber, - style: TextStyle( - color: CustomTheme.primaryColor, - ), - ); - } else if (snapshot.hasError) { - return Text( - '-', - style: TextStyle( - color: CustomTheme.primaryColor, - ), - ); - } - return Text( - AppLocalizations.of(context).loading, - ); - }, - )), + suffixWidget: Text(VersionService.getBuildNumber(), + style: TextStyle( + color: CustomTheme.primaryColor, + ))), ])), ], ), @@ -210,10 +168,6 @@ class _SettingsViewState extends State { ); } - Future _getPackageInfo() async { - return await PackageInfo.fromPlatform(); - } - void showFeedbackDialog(ImportStatus status) { if (status == ImportStatus.canceled) return; final (title, message) = _getDialogContent(status); diff --git a/lib/services/version_service.dart b/lib/services/version_service.dart new file mode 100644 index 0000000..c23d187 --- /dev/null +++ b/lib/services/version_service.dart @@ -0,0 +1,32 @@ +import 'package:cabo_counter/utility/globals.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +class VersionService { + static String _version = '-.-.-'; + static String _buildNumber = '-'; + + static Future init() async { + var packageInfo = await PackageInfo.fromPlatform(); + _version = packageInfo.version; + _buildNumber = packageInfo.buildNumber; + } + + static String getVersionNumber() { + return _version; + } + + static String getVersion() { + if (_version == '-.-.-') { + return getVersionNumber(); + } + return '${Globals.appDevPhase} $_version'; + } + + static String getBuildNumber() { + return _buildNumber; + } + + static String getVersionWithBuild() { + return '$_version ($_buildNumber)'; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index fdf9916..414389d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+371 +version: 0.4.0+376 environment: sdk: ^3.5.4 From 55f3da8052c067b86650aa91d40e787f129c1a6a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 17:41:54 +0200 Subject: [PATCH 076/353] Updated strings, added wiki button --- lib/l10n/app_de.arb | 6 ++++-- lib/l10n/app_en.arb | 5 +++-- lib/l10n/app_localizations.dart | 14 ++++++++++---- lib/l10n/app_localizations_de.dart | 7 +++++-- lib/l10n/app_localizations_en.dart | 7 +++++-- lib/presentation/views/settings_view.dart | 18 +++++++++++++----- pubspec.yaml | 4 ++-- 7 files changed, 42 insertions(+), 19 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index b83c646..9c88d6a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -82,7 +82,7 @@ "point_limit": "Punkte-Limit", "point_limit_subtitle": "... hier ist Schluss", "reset_to_default": "Auf Standard zurücksetzen", - "data": "Daten", + "game_data": "Spieldaten", "import_data": "Spieldaten importieren", "export_data": "Spieldaten exportieren", "app": "App", @@ -98,10 +98,12 @@ "export_error_title": "Fehler", "export_error_message": "Datei konnte nicht exportiert werden", + "error_found": "Fehler gefunden?", "create_issue": "Issue erstellen", + "wiki": "Wiki", "app_version": "App-Version", - "build": "Build", + "build": "Build-Nr.", "loading": "Lädt...", "about_text": "Hey :) Danke, dass du als eine:r der ersten User meiner ersten eigenen App dabei bist! Ich hab sehr viel Arbeit in dieses Projekt gesteckt und auch, wenn ich (hoffentlich) an vieles Gedacht hab, wird auf jeden Fall noch nicht alles 100% funktionieren. Solltest du also irgendwelche Fehler entdecken oder Feedback zum Design oder der Benutzerfreundlichkeit haben, teile Sie mir gern über die Testflight App oder auf den dir bekannten Wegen mit. Danke! " diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1c111e2..60fc593 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -82,7 +82,7 @@ "point_limit": "Point Limit", "point_limit_subtitle": "... the game ends here.", "reset_to_default": "Reset to Default", - "data": "Data", + "game_data": "Game Data", "import_data": "Import Data", "export_data": "Export Data", "app": "App", @@ -100,9 +100,10 @@ "export_error_message": "Could not export file", "error_found": "Found a bug?", "create_issue": "Create Issue", + "wiki": "Wiki", "app_version": "App Version", "loading": "Loading...", - "build": "Build", + "build": "Build No.", "about_text": "Hey :) Thanks for being one of the first users of my app! I’ve put a lot of work into this project, and even though I tried to think of everything, it might not work perfectly just yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the TestFlight app or by sending me a message or email. Thank you very much!" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 84295df..9f85aab 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -458,11 +458,11 @@ abstract class AppLocalizations { /// **'Auf Standard zurücksetzen'** String get reset_to_default; - /// No description provided for @data. + /// No description provided for @game_data. /// /// In de, this message translates to: - /// **'Daten'** - String get data; + /// **'Spieldaten'** + String get game_data; /// No description provided for @import_data. /// @@ -554,6 +554,12 @@ abstract class AppLocalizations { /// **'Issue erstellen'** String get create_issue; + /// No description provided for @wiki. + /// + /// In de, this message translates to: + /// **'Wiki'** + String get wiki; + /// No description provided for @app_version. /// /// In de, this message translates to: @@ -563,7 +569,7 @@ abstract class AppLocalizations { /// No description provided for @build. /// /// In de, this message translates to: - /// **'Build'** + /// **'Build-Nr.'** String get build; /// No description provided for @loading. diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index f4a2bbd..23b41ac 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -200,7 +200,7 @@ class AppLocalizationsDe extends AppLocalizations { String get reset_to_default => 'Auf Standard zurücksetzen'; @override - String get data => 'Daten'; + String get game_data => 'Spieldaten'; @override String get import_data => 'Spieldaten importieren'; @@ -250,11 +250,14 @@ class AppLocalizationsDe extends AppLocalizations { @override String get create_issue => 'Issue erstellen'; + @override + String get wiki => 'Wiki'; + @override String get app_version => 'App-Version'; @override - String get build => 'Build'; + String get build => 'Build-Nr.'; @override String get loading => 'Lädt...'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index aac55f2..eea3896 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -197,7 +197,7 @@ class AppLocalizationsEn extends AppLocalizations { String get reset_to_default => 'Reset to Default'; @override - String get data => 'Data'; + String get game_data => 'Game Data'; @override String get import_data => 'Import Data'; @@ -247,11 +247,14 @@ class AppLocalizationsEn extends AppLocalizations { @override String get create_issue => 'Create Issue'; + @override + String get wiki => 'Wiki'; + @override String get app_version => 'App Version'; @override - String get build => 'Build'; + String get build => 'Build No.'; @override String get loading => 'Loading...'; diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 2ed422f..0d32971 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -101,7 +101,7 @@ class _SettingsViewState extends State { Padding( padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), child: Text( - AppLocalizations.of(context).data, + AppLocalizations.of(context).game_data, style: CustomTheme.rowTitle, ), ), @@ -145,16 +145,24 @@ class _SettingsViewState extends State { suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( - prefixText: 'App-Version', - prefixIcon: CupertinoIcons.info, + prefixText: AppLocalizations.of(context).wiki, + prefixIcon: CupertinoIcons.book, + onPressed: () => launchUrl(Uri.parse( + 'https://github.com/flixcoo/Cabo-Counter/wiki')), + suffixWidget: const CupertinoListTileChevron(), + ), + CustomFormRow( + prefixText: + AppLocalizations.of(context).app_version, + prefixIcon: CupertinoIcons.number, onPressed: null, suffixWidget: Text(VersionService.getVersion(), style: TextStyle( color: CustomTheme.primaryColor, ))), CustomFormRow( - prefixText: 'Build-Nr.', - prefixIcon: CupertinoIcons.info, + prefixText: AppLocalizations.of(context).build, + prefixIcon: CupertinoIcons.number, onPressed: null, suffixWidget: Text(VersionService.getBuildNumber(), style: TextStyle( diff --git a/pubspec.yaml b/pubspec.yaml index 414389d..a692f21 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,8 @@ name: cabo_counter -description: "Mobile app for the card game Cabo" +description: "Mobile game_data for the card game Cabo" publish_to: 'none' -version: 0.4.0+376 +version: 0.4.0+378 environment: sdk: ^3.5.4 From 17072fb5844c263048f87f849a6eb308b1cb4b8e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 17:42:18 +0200 Subject: [PATCH 077/353] Corrected replaced string --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index a692f21..ce04a55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: cabo_counter -description: "Mobile game_data for the card game Cabo" +description: "Mobile app for the card game Cabo" publish_to: 'none' version: 0.4.0+378 From fd8efb2a56464d8e818bee4891cecb93b63c6a48 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 18:46:58 +0200 Subject: [PATCH 078/353] Added import dialog feedback (got lost in refactoring) --- lib/presentation/views/settings_view.dart | 6 +++++- pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 0d32971..9b4f91a 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -114,7 +114,11 @@ class _SettingsViewState extends State { CustomFormRow( prefixText: AppLocalizations.of(context).import_data, prefixIcon: CupertinoIcons.square_arrow_down, - onPressed: () => LocalStorageService.importJsonFile(), + onPressed: () async { + final status = + await LocalStorageService.importJsonFile(); + showFeedbackDialog(status); + }, suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( diff --git a/pubspec.yaml b/pubspec.yaml index ce04a55..e393fb9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+378 +version: 0.4.0+380 environment: sdk: ^3.5.4 From 42e51a092b7436d4737b9ad45f193395820d1ba0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 18:49:13 +0200 Subject: [PATCH 079/353] Corrected function duplication --- lib/l10n/app_de.arb | 2 +- lib/l10n/app_en.arb | 1 + lib/presentation/views/settings_view.dart | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9c88d6a..0a76696 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -93,7 +93,7 @@ "import_validation_error_message": "Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.", "import_format_error_title": "Falsches Format", "import_format_error_message": "Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.", - "import_generic_error_title": "Import fehlgeschlagen", + "import_generic_error_title": "Import fehlgeschlagen", "import_generic_error_message": "Der Import ist fehlgeschlagen.", "export_error_title": "Fehler", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 60fc593..edca935 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -98,6 +98,7 @@ "export_error_title": "Export failed", "export_error_message": "Could not export file", + "error_found": "Found a bug?", "create_issue": "Create Issue", "wiki": "Wiki", diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 9b4f91a..7c1df2e 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -124,7 +124,7 @@ class _SettingsViewState extends State { CustomFormRow( prefixText: AppLocalizations.of(context).export_data, prefixIcon: CupertinoIcons.square_arrow_up, - onPressed: () => LocalStorageService.importJsonFile(), + onPressed: () => LocalStorageService.exportGameData(), suffixWidget: const CupertinoListTileChevron(), ), ])), From 74a27aea24b6fda2979bb72db6c55e9aa4d425c9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 18:51:34 +0200 Subject: [PATCH 080/353] changed suffixWidget assignment and moved stepperKeys --- lib/presentation/views/settings_view.dart | 4 ++-- lib/presentation/widgets/custom_form_row.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 7c1df2e..72365ea 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -51,10 +51,10 @@ class _SettingsViewState extends State { margin: EdgeInsets.zero, children: [ CustomFormRow( - key: _stepperKey1, prefixText: 'Cabo-Strafe', prefixIcon: CupertinoIcons.minus_square, suffixWidget: Stepper( + key: _stepperKey1, initialValue: ConfigService.caboPenalty, minValue: 0, maxValue: 50, @@ -68,10 +68,10 @@ class _SettingsViewState extends State { ), ), CustomFormRow( - key: _stepperKey2, prefixText: 'Punkte-Limit', prefixIcon: FontAwesomeIcons.bullseye, suffixWidget: Stepper( + key: _stepperKey2, initialValue: ConfigService.pointLimit, minValue: 30, maxValue: 1000, diff --git a/lib/presentation/widgets/custom_form_row.dart b/lib/presentation/widgets/custom_form_row.dart index f03b453..7a266ae 100644 --- a/lib/presentation/widgets/custom_form_row.dart +++ b/lib/presentation/widgets/custom_form_row.dart @@ -24,11 +24,11 @@ class _CustomFormRowState extends State { @override void initState() { super.initState(); - suffixWidget = widget.suffixWidget ?? const SizedBox.shrink(); } @override Widget build(BuildContext context) { + suffixWidget = widget.suffixWidget ?? const SizedBox.shrink(); return CupertinoButton( padding: EdgeInsets.zero, onPressed: widget.onPressed, diff --git a/pubspec.yaml b/pubspec.yaml index e393fb9..7b8621b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+380 +version: 0.4.0+381 environment: sdk: ^3.5.4 From d1ad5511f4682709d901b06a5792c0cac4a6b5f7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 19:01:12 +0200 Subject: [PATCH 081/353] Changed icons --- lib/presentation/views/settings_view.dart | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 72365ea..84916c2 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -52,7 +52,7 @@ class _SettingsViewState extends State { children: [ CustomFormRow( prefixText: 'Cabo-Strafe', - prefixIcon: CupertinoIcons.minus_square, + prefixIcon: CupertinoIcons.bolt_fill, suffixWidget: Stepper( key: _stepperKey1, initialValue: ConfigService.caboPenalty, @@ -158,7 +158,7 @@ class _SettingsViewState extends State { CustomFormRow( prefixText: AppLocalizations.of(context).app_version, - prefixIcon: CupertinoIcons.number, + prefixIcon: CupertinoIcons.tag, onPressed: null, suffixWidget: Text(VersionService.getVersion(), style: TextStyle( diff --git a/pubspec.yaml b/pubspec.yaml index 7b8621b..5edeba0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+381 +version: 0.4.0+382 environment: sdk: ^3.5.4 From 68dbed1e560123882c05c4d725c6d4b7c555830c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 21:04:47 +0200 Subject: [PATCH 082/353] Added rate_my_app package --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 5edeba0..175eebe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,7 @@ dependencies: intl: any syncfusion_flutter_charts: ^30.1.37 uuid: ^4.5.1 + rate_my_app: ^2.3.2 dev_dependencies: flutter_test: From 61d844c289bd253c448bf21835c91ef4c265945e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 21:06:55 +0200 Subject: [PATCH 083/353] Renamed folder --- lib/{utility => core}/custom_theme.dart | 0 lib/{utility => core}/globals.dart | 0 lib/main.dart | 2 +- lib/presentation/views/active_game_view.dart | 2 +- lib/presentation/views/create_game_view.dart | 2 +- lib/presentation/views/main_menu_view.dart | 2 +- lib/presentation/views/mode_selection_view.dart | 2 +- lib/presentation/views/round_view.dart | 2 +- lib/presentation/views/settings_view.dart | 2 +- lib/presentation/views/tab_view.dart | 2 +- lib/presentation/widgets/custom_form_row.dart | 2 +- lib/presentation/widgets/stepper.dart | 2 +- lib/services/version_service.dart | 2 +- 13 files changed, 11 insertions(+), 11 deletions(-) rename lib/{utility => core}/custom_theme.dart (100%) rename lib/{utility => core}/globals.dart (100%) diff --git a/lib/utility/custom_theme.dart b/lib/core/custom_theme.dart similarity index 100% rename from lib/utility/custom_theme.dart rename to lib/core/custom_theme.dart diff --git a/lib/utility/globals.dart b/lib/core/globals.dart similarity index 100% rename from lib/utility/globals.dart rename to lib/core/globals.dart diff --git a/lib/main.dart b/lib/main.dart index b826072..2b6a163 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,9 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/presentation/views/tab_view.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:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index ddc0299..37fd652 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; @@ -5,7 +6,6 @@ import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/graph_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 2c04e74..37123ca 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -1,10 +1,10 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:cabo_counter/services/config_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; enum CreateStatus { diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 230c4de..425cf46 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; @@ -5,7 +6,6 @@ import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/settings_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/presentation/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart index 93cdc7a..cc2ac52 100644 --- a/lib/presentation/views/mode_selection_view.dart +++ b/lib/presentation/views/mode_selection_view.dart @@ -1,5 +1,5 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; class ModeSelectionMenu extends StatelessWidget { diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 4e114fe..4dfb45c 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -1,7 +1,7 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 84916c2..20c97ec 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,10 +1,10 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/presentation/widgets/custom_form_row.dart'; import 'package:cabo_counter/presentation/widgets/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:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index efa4311..a3d06de 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -1,7 +1,7 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/presentation/views/information_view.dart'; import 'package:cabo_counter/presentation/views/main_menu_view.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; class TabView extends StatefulWidget { diff --git a/lib/presentation/widgets/custom_form_row.dart b/lib/presentation/widgets/custom_form_row.dart index 7a266ae..96067c3 100644 --- a/lib/presentation/widgets/custom_form_row.dart +++ b/lib/presentation/widgets/custom_form_row.dart @@ -1,5 +1,5 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/presentation/widgets/stepper.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; class CustomFormRow extends StatefulWidget { diff --git a/lib/presentation/widgets/stepper.dart b/lib/presentation/widgets/stepper.dart index 8ca2635..5d0bce8 100644 --- a/lib/presentation/widgets/stepper.dart +++ b/lib/presentation/widgets/stepper.dart @@ -1,4 +1,4 @@ -import 'package:cabo_counter/utility/custom_theme.dart'; +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:flutter/cupertino.dart'; // Für iOS-Style class Stepper extends StatefulWidget { diff --git a/lib/services/version_service.dart b/lib/services/version_service.dart index c23d187..b116d9b 100644 --- a/lib/services/version_service.dart +++ b/lib/services/version_service.dart @@ -1,4 +1,4 @@ -import 'package:cabo_counter/utility/globals.dart'; +import 'package:cabo_counter/core/globals.dart'; import 'package:package_info_plus/package_info_plus.dart'; class VersionService { From ceb0be123e239a2b88e25463d200e409fce20d52 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 22:04:54 +0200 Subject: [PATCH 084/353] Implement native rating dialog --- lib/core/globals.dart | 8 ++++++++ lib/presentation/views/main_menu_view.dart | 8 ++++++++ pubspec.yaml | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/core/globals.dart b/lib/core/globals.dart index e11a118..6bfd077 100644 --- a/lib/core/globals.dart +++ b/lib/core/globals.dart @@ -1,3 +1,11 @@ +import 'package:rate_my_app/rate_my_app.dart'; + class Globals { static String appDevPhase = 'Beta'; + static RateMyApp rateMyApp = RateMyApp( + appStoreIdentifier: '6747105718', + minDays: 15, + remindDays: 45, + minLaunches: 15, + remindLaunches: 40); } diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 425cf46..05665ce 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -1,4 +1,5 @@ import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/core/globals.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; @@ -29,6 +30,13 @@ class _MainMenuViewState extends State { }); }); gameManager.addListener(_updateView); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + await Globals.rateMyApp.init(); + if (mounted && Globals.rateMyApp.shouldOpenDialog) { + Globals.rateMyApp.showStarRateDialog(context); + } + }); } void _updateView() { diff --git a/pubspec.yaml b/pubspec.yaml index 175eebe..92ed456 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+382 +version: 0.4.0+411 environment: sdk: ^3.5.4 From f66b725f791c18fad7588880c06d5ff03480c90c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 23:11:06 +0200 Subject: [PATCH 085/353] Implemented logic for pre rating and refactored rating dialog --- analysis_options.yaml | 3 +- lib/presentation/views/main_menu_view.dart | 68 +++++++++++++++++++++- pubspec.yaml | 2 +- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 2ce6b52..f9adae0 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,6 +11,5 @@ linter: prefer_const_literals_to_create_immutables: true unnecessary_const: true lines_longer_than_80_chars: false + constant_identifier_names: false -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 05665ce..ea330e5 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -9,6 +9,7 @@ import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart' as url; class MainMenuView extends StatefulWidget { const MainMenuView({super.key}); @@ -20,6 +21,9 @@ class MainMenuView extends StatefulWidget { class _MainMenuViewState extends State { bool _isLoading = true; + static const int RATING_DIALOG_YES = 1; + static const int RATING_DIALOG_NO = 0; + static const int RATING_DIALOG_CANCEL = -1; @override initState() { @@ -33,8 +37,11 @@ class _MainMenuViewState extends State { WidgetsBinding.instance.addPostFrameCallback((_) async { await Globals.rateMyApp.init(); - if (mounted && Globals.rateMyApp.shouldOpenDialog) { - Globals.rateMyApp.showStarRateDialog(context); + + if (Globals.rateMyApp.shouldOpenDialog) { + await Future.delayed(const Duration(milliseconds: 600)); + if (!mounted) return; + _handleFeedbackDialog(context); } }); } @@ -248,6 +255,63 @@ class _MainMenuViewState extends State { return shouldDelete; } + Future _showPreRatingDialog(BuildContext context) async { + int? answer = await showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: const Text('Gefällt dir die App?'), + content: const Text('Dein Feedback hilft uns weiter.'), + actions: [ + CupertinoDialogAction( + child: const Text('Ja'), + onPressed: () { + Navigator.of(context).pop(RATING_DIALOG_YES); + }, + ), + CupertinoDialogAction( + child: const Text('Nein'), + onPressed: () { + Navigator.of(context).pop(RATING_DIALOG_NO); + }, + ), + CupertinoDialogAction( + isDestructiveAction: true, + onPressed: () { + Navigator.of(context).pop(RATING_DIALOG_CANCEL); + }, + child: Text(AppLocalizations.of(context).cancel), + ), + ], + ); + }, + ); + return answer ?? RATING_DIALOG_CANCEL; + } + + /// Handles the feedback dialog when the conditions for rating are met. + /// It shows a dialog asking the user if they like the app, + /// and based on their response, it either opens the rating dialog or an email client for feedback. + Future _handleFeedbackDialog(BuildContext context) async { + int decision = await _showPreRatingDialog(context); + + final Uri emailUri = Uri( + scheme: 'mailto', + path: 'cabo-counter@felixkirchner.de', + query: 'subject=Feedback: Cabo Counter App' + '&body=Ich habe folgendes Feedback...', + ); + + switch (decision) { + case RATING_DIALOG_YES: + Globals.rateMyApp.showStarRateDialog(context); + case RATING_DIALOG_NO: + url.launchUrl(emailUri, mode: url.LaunchMode.externalApplication); + case RATING_DIALOG_CANCEL: + break; + } + } + @override void dispose() { gameManager.removeListener(_updateView); diff --git a/pubspec.yaml b/pubspec.yaml index 92ed456..bb9ffcf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+411 +version: 0.4.0+437 environment: sdk: ^3.5.4 From 158e687f9f023ce5746377771ef5d33dc356dc06 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 23:40:22 +0200 Subject: [PATCH 086/353] updated launch mode --- lib/presentation/views/information_view.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/information_view.dart b/lib/presentation/views/information_view.dart index 1d0918b..2c5c739 100644 --- a/lib/presentation/views/information_view.dart +++ b/lib/presentation/views/information_view.dart @@ -53,16 +53,19 @@ class InformationView extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( - onPressed: () => - launchUrl(Uri.parse('https://www.instagram.com/fx.kr')), + onPressed: () => launchUrl( + Uri.parse('https://www.instagram.com/flixcoo'), + mode: LaunchMode.externalApplication), icon: const Icon(FontAwesomeIcons.instagram)), IconButton( onPressed: () => launchUrl( - Uri.parse('mailto:felix.kirchner.fk@gmail.com')), + Uri.parse('mailto:felix.kirchner.fk@gmail.com'), + mode: LaunchMode.externalApplication), icon: const Icon(CupertinoIcons.envelope)), IconButton( - onPressed: () => - launchUrl(Uri.parse('https://www.github.com/flixcoo')), + onPressed: () => launchUrl( + Uri.parse('https://www.github.com/flixcoo'), + mode: LaunchMode.externalApplication), icon: const Icon(FontAwesomeIcons.github)), ], ), From 33c4b773dd991d35303a4c4a1e7150c9a98126e0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 23:40:35 +0200 Subject: [PATCH 087/353] Small changes --- lib/presentation/views/main_menu_view.dart | 7 ++++--- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index ea330e5..17813df 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -9,7 +9,7 @@ import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart' as url; +import 'package:url_launcher/url_launcher.dart'; class MainMenuView extends StatefulWidget { const MainMenuView({super.key}); @@ -304,9 +304,10 @@ class _MainMenuViewState extends State { switch (decision) { case RATING_DIALOG_YES: - Globals.rateMyApp.showStarRateDialog(context); + if (context.mounted) Globals.rateMyApp.showStarRateDialog(context); + break; case RATING_DIALOG_NO: - url.launchUrl(emailUri, mode: url.LaunchMode.externalApplication); + launchUrl(emailUri, mode: LaunchMode.externalApplication); case RATING_DIALOG_CANCEL: break; } diff --git a/pubspec.yaml b/pubspec.yaml index bb9ffcf..71d1689 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+437 +version: 0.4.0+438 environment: sdk: ^3.5.4 From 37c539607f30603b57ec02cb2e543bd97f0907c3 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 9 Jul 2025 23:40:40 +0200 Subject: [PATCH 088/353] Updated launch mode --- lib/presentation/views/settings_view.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 20c97ec..5b2a331 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -144,15 +144,19 @@ class _SettingsViewState extends State { CustomFormRow( prefixText: AppLocalizations.of(context).create_issue, prefixIcon: FontAwesomeIcons.github, - onPressed: () => launchUrl(Uri.parse( - 'https://github.com/flixcoo/Cabo-Counter/issues')), + onPressed: () => launchUrl( + Uri.parse( + 'https://github.com/flixcoo/Cabo-Counter/issues'), + mode: LaunchMode.externalApplication), suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( prefixText: AppLocalizations.of(context).wiki, prefixIcon: CupertinoIcons.book, - onPressed: () => launchUrl(Uri.parse( - 'https://github.com/flixcoo/Cabo-Counter/wiki')), + onPressed: () => launchUrl( + Uri.parse( + 'https://github.com/flixcoo/Cabo-Counter/wiki'), + mode: LaunchMode.externalApplication), suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( From bb6d718c9e7925d9a1d4a7f5fe98cefab734991e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 16:37:56 +0200 Subject: [PATCH 089/353] Updated linting rules --- analysis_options.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 2ce6b52..46e2dbe 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,6 +11,4 @@ linter: prefer_const_literals_to_create_immutables: true unnecessary_const: true lines_longer_than_80_chars: false - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options + constant_identifier_names: false From e4dba146427c392d9db2a3d7009867980487c020 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 16:38:41 +0200 Subject: [PATCH 090/353] Renamed folders --- lib/main.dart | 2 +- lib/presentation/views/active_game_view.dart | 2 +- lib/presentation/views/create_game_view.dart | 2 +- lib/presentation/views/graph_view.dart | 2 +- lib/presentation/views/main_menu_view.dart | 2 +- .../views/mode_selection_view.dart | 2 +- lib/presentation/views/round_view.dart | 2 +- lib/presentation/views/settings_view.dart | 28 ++++++++++++------- lib/presentation/views/tab_view.dart | 2 +- lib/services/version_service.dart | 4 +-- lib/utility/constants.dart | 15 ++++++++++ lib/utility/globals.dart | 3 -- 12 files changed, 43 insertions(+), 23 deletions(-) create mode 100644 lib/utility/constants.dart delete mode 100644 lib/utility/globals.dart diff --git a/lib/main.dart b/lib/main.dart index b826072..b714d58 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,4 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/tab_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index ddc0299..effea40 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -1,6 +1,6 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/graph_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 2c04e74..6a19222 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -1,6 +1,6 @@ import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:cabo_counter/services/config_service.dart'; diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 345c670..1007007 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -1,5 +1,5 @@ import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 230c4de..c1c14a9 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -1,5 +1,5 @@ import 'package:cabo_counter/data/game_manager.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/settings_view.dart'; diff --git a/lib/presentation/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart index 93cdc7a..547b0c7 100644 --- a/lib/presentation/views/mode_selection_view.dart +++ b/lib/presentation/views/mode_selection_view.dart @@ -1,4 +1,4 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 4e114fe..a989139 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -1,5 +1,5 @@ import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 84916c2..41532f3 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,9 +1,10 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/widgets/custom_form_row.dart'; import 'package:cabo_counter/presentation/widgets/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:cabo_counter/utility/constants.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -93,7 +94,6 @@ class _SettingsViewState extends State { setState(() { _stepperKey1 = UniqueKey(); _stepperKey2 = UniqueKey(); - print('Config reset to default'); }); }, ) @@ -142,17 +142,25 @@ class _SettingsViewState extends State { margin: EdgeInsets.zero, children: [ CustomFormRow( - prefixText: AppLocalizations.of(context).create_issue, - prefixIcon: FontAwesomeIcons.github, - onPressed: () => launchUrl(Uri.parse( - 'https://github.com/flixcoo/Cabo-Counter/issues')), + prefixText: AppLocalizations.of(context).wiki, + prefixIcon: CupertinoIcons.book, + onPressed: () => + launchUrl(Uri.parse(Constants.GITHUB_WIKI_LINK)), suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( - prefixText: AppLocalizations.of(context).wiki, - prefixIcon: CupertinoIcons.book, - onPressed: () => launchUrl(Uri.parse( - 'https://github.com/flixcoo/Cabo-Counter/wiki')), + 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( diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index efa4311..999a90e 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -1,4 +1,4 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/information_view.dart'; import 'package:cabo_counter/presentation/views/main_menu_view.dart'; import 'package:cabo_counter/utility/custom_theme.dart'; diff --git a/lib/services/version_service.dart b/lib/services/version_service.dart index c23d187..7c306e3 100644 --- a/lib/services/version_service.dart +++ b/lib/services/version_service.dart @@ -1,4 +1,4 @@ -import 'package:cabo_counter/utility/globals.dart'; +import 'package:cabo_counter/utility/constants.dart'; import 'package:package_info_plus/package_info_plus.dart'; class VersionService { @@ -19,7 +19,7 @@ class VersionService { if (_version == '-.-.-') { return getVersionNumber(); } - return '${Globals.appDevPhase} $_version'; + return '${Constants.appDevPhase} $_version'; } static String getBuildNumber() { diff --git a/lib/utility/constants.dart b/lib/utility/constants.dart new file mode 100644 index 0000000..215de73 --- /dev/null +++ b/lib/utility/constants.dart @@ -0,0 +1,15 @@ +import 'dart:core'; + +class Constants { + static String appDevPhase = 'Beta'; + static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; + static const String GITHUB_LINK = 'https://github.felixkirchner.de'; + static const String GITHUB_REPO_LINK = 'https://github.felixkirchner.de'; + static const String GITHUB_ISSUES_LINK = + 'https://github.com/flixcoo/Cabo-Counter/issues'; + static const String GITHUB_WIKI_LINK = + 'https://github.com/flixcoo/Cabo-Counter/issues'; + static const String EMAIL = 'cabocounter@felixkirchner.de'; + static const String PRIVACY_POLICY_LINK = + 'https://github.felixkirchner.de/Cabo-Counter/wiki/Privacy-Policy'; +} diff --git a/lib/utility/globals.dart b/lib/utility/globals.dart deleted file mode 100644 index e11a118..0000000 --- a/lib/utility/globals.dart +++ /dev/null @@ -1,3 +0,0 @@ -class Globals { - static String appDevPhase = 'Beta'; -} From b98b5b0ac99cd7bf80b1e67c3edf4bd5dae2f7fc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 16:38:56 +0200 Subject: [PATCH 091/353] Changed l10n files location --- l10n.yaml | 7 ++++--- lib/l10n/{ => arb}/untranslated_messages.json | 0 lib/l10n/{ => generated}/app_localizations.dart | 8 +++++++- lib/l10n/{ => generated}/app_localizations_de.dart | 3 +++ lib/l10n/{ => generated}/app_localizations_en.dart | 3 +++ 5 files changed, 17 insertions(+), 4 deletions(-) rename lib/l10n/{ => arb}/untranslated_messages.json (100%) rename lib/l10n/{ => generated}/app_localizations.dart (98%) rename lib/l10n/{ => generated}/app_localizations_de.dart (98%) rename lib/l10n/{ => generated}/app_localizations_en.dart (98%) diff --git a/l10n.yaml b/l10n.yaml index 239fdc6..f69305d 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,5 +1,6 @@ -arb-dir: lib/l10n +arb-dir: lib/l10n/arb template-arb-file: app_de.arb -untranslated-messages-file: lib/l10n/untranslated_messages.json +untranslated-messages-file: lib/l10n/arb/untranslated_messages.json nullable-getter: false -output-localization-file: app_localizations.dart \ No newline at end of file +output-localization-file: app_localizations.dart +output-dir: lib/l10n/generated \ No newline at end of file diff --git a/lib/l10n/untranslated_messages.json b/lib/l10n/arb/untranslated_messages.json similarity index 100% rename from lib/l10n/untranslated_messages.json rename to lib/l10n/arb/untranslated_messages.json diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/generated/app_localizations.dart similarity index 98% rename from lib/l10n/app_localizations.dart rename to lib/l10n/generated/app_localizations.dart index 9f85aab..ff14253 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -18,7 +18,7 @@ import 'app_localizations_en.dart'; /// `supportedLocales` list. For example: /// /// ```dart -/// import 'l10n/app_localizations.dart'; +/// import 'generated/app_localizations.dart'; /// /// return MaterialApp( /// localizationsDelegates: AppLocalizations.localizationsDelegates, @@ -566,6 +566,12 @@ abstract class AppLocalizations { /// **'App-Version'** String get app_version; + /// No description provided for @privacy_policy. + /// + /// In de, this message translates to: + /// **'Datenschutzerklärung'** + String get privacy_policy; + /// No description provided for @build. /// /// In de, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart similarity index 98% rename from lib/l10n/app_localizations_de.dart rename to lib/l10n/generated/app_localizations_de.dart index 23b41ac..898df64 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -256,6 +256,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get app_version => 'App-Version'; + @override + String get privacy_policy => 'Datenschutzerklärung'; + @override String get build => 'Build-Nr.'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart similarity index 98% rename from lib/l10n/app_localizations_en.dart rename to lib/l10n/generated/app_localizations_en.dart index eea3896..c057432 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -253,6 +253,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get app_version => 'App Version'; + @override + String get privacy_policy => 'Privacy Policy'; + @override String get build => 'Build No.'; From 38d5151a3e86b38be678a8f4f026daade49b60b5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 16:39:12 +0200 Subject: [PATCH 092/353] Implemented new link constants --- lib/l10n/{ => arb}/app_de.arb | 1 + lib/l10n/{ => arb}/app_en.arb | 1 + lib/presentation/views/information_view.dart | 11 ++++++----- pubspec.yaml | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) rename lib/l10n/{ => arb}/app_de.arb (99%) rename lib/l10n/{ => arb}/app_en.arb (99%) diff --git a/lib/l10n/app_de.arb b/lib/l10n/arb/app_de.arb similarity index 99% rename from lib/l10n/app_de.arb rename to lib/l10n/arb/app_de.arb index 0a76696..7615b27 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -103,6 +103,7 @@ "create_issue": "Issue erstellen", "wiki": "Wiki", "app_version": "App-Version", + "privacy_policy": "Datenschutzerklärung", "build": "Build-Nr.", "loading": "Lädt...", diff --git a/lib/l10n/app_en.arb b/lib/l10n/arb/app_en.arb similarity index 99% rename from lib/l10n/app_en.arb rename to lib/l10n/arb/app_en.arb index edca935..ee01699 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -103,6 +103,7 @@ "create_issue": "Create Issue", "wiki": "Wiki", "app_version": "App Version", + "privacy_policy": "Privacy Policy", "loading": "Loading...", "build": "Build No.", diff --git a/lib/presentation/views/information_view.dart b/lib/presentation/views/information_view.dart index 1d0918b..d31d7f6 100644 --- a/lib/presentation/views/information_view.dart +++ b/lib/presentation/views/information_view.dart @@ -1,4 +1,5 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/utility/constants.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -54,15 +55,15 @@ class InformationView extends StatelessWidget { children: [ IconButton( onPressed: () => - launchUrl(Uri.parse('https://www.instagram.com/fx.kr')), + launchUrl(Uri.parse(Constants.INSTAGRAM_LINK)), icon: const Icon(FontAwesomeIcons.instagram)), IconButton( - onPressed: () => launchUrl( - Uri.parse('mailto:felix.kirchner.fk@gmail.com')), + onPressed: () => + launchUrl(Uri.parse('mailto:${Constants.EMAIL}')), icon: const Icon(CupertinoIcons.envelope)), IconButton( onPressed: () => - launchUrl(Uri.parse('https://www.github.com/flixcoo')), + launchUrl(Uri.parse(Constants.GITHUB_LINK)), icon: const Icon(FontAwesomeIcons.github)), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 5edeba0..c24fb24 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+382 +version: 0.4.0+386 environment: sdk: ^3.5.4 From 08917f18b0a5f475385f49ae2c839a17b33f990d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 16:40:09 +0200 Subject: [PATCH 093/353] Changed privacy policy link --- lib/utility/constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utility/constants.dart b/lib/utility/constants.dart index 215de73..f4f0c0f 100644 --- a/lib/utility/constants.dart +++ b/lib/utility/constants.dart @@ -11,5 +11,5 @@ class Constants { 'https://github.com/flixcoo/Cabo-Counter/issues'; static const String EMAIL = 'cabocounter@felixkirchner.de'; static const String PRIVACY_POLICY_LINK = - 'https://github.felixkirchner.de/Cabo-Counter/wiki/Privacy-Policy'; + 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; } From ef2c9065155ecf79e74b47aa8607639d15deb57a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:15:38 +0200 Subject: [PATCH 094/353] Corrected wiki link --- lib/utility/constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utility/constants.dart b/lib/utility/constants.dart index f4f0c0f..d8562d5 100644 --- a/lib/utility/constants.dart +++ b/lib/utility/constants.dart @@ -8,7 +8,7 @@ class Constants { static const String GITHUB_ISSUES_LINK = 'https://github.com/flixcoo/Cabo-Counter/issues'; static const String GITHUB_WIKI_LINK = - 'https://github.com/flixcoo/Cabo-Counter/issues'; + 'https://github.com/flixcoo/Cabo-Counter/wiki'; static const String EMAIL = 'cabocounter@felixkirchner.de'; static const String PRIVACY_POLICY_LINK = 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; From 3d63fd13a8c42be2f72b7ca702763f340dc8af26 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:15:58 +0200 Subject: [PATCH 095/353] Removed import --- lib/utility/constants.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/utility/constants.dart b/lib/utility/constants.dart index d8562d5..329642e 100644 --- a/lib/utility/constants.dart +++ b/lib/utility/constants.dart @@ -1,5 +1,3 @@ -import 'dart:core'; - class Constants { static String appDevPhase = 'Beta'; static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; From 5b3b84069d66e5e9563f63169c5ca86f064c301a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:23:08 +0200 Subject: [PATCH 096/353] Updated links --- lib/utility/constants.dart | 3 +-- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/utility/constants.dart b/lib/utility/constants.dart index 329642e..fd6ebbc 100644 --- a/lib/utility/constants.dart +++ b/lib/utility/constants.dart @@ -1,8 +1,7 @@ class Constants { static String appDevPhase = 'Beta'; static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; - static const String GITHUB_LINK = 'https://github.felixkirchner.de'; - static const String GITHUB_REPO_LINK = 'https://github.felixkirchner.de'; + static const String GITHUB_LINK = 'https://github1.felixkirchner.de'; static const String GITHUB_ISSUES_LINK = 'https://github.com/flixcoo/Cabo-Counter/issues'; static const String GITHUB_WIKI_LINK = diff --git a/pubspec.yaml b/pubspec.yaml index c24fb24..5faec22 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+386 +version: 0.4.0+387 environment: sdk: ^3.5.4 From 16b6dbb150ca5448a14a0f4f5d1f9131bcda5c43 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:24:50 +0200 Subject: [PATCH 097/353] Updated links to subdomains --- lib/utility/constants.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/utility/constants.dart b/lib/utility/constants.dart index fd6ebbc..4a79399 100644 --- a/lib/utility/constants.dart +++ b/lib/utility/constants.dart @@ -3,9 +3,8 @@ class Constants { static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; static const String GITHUB_LINK = 'https://github1.felixkirchner.de'; static const String GITHUB_ISSUES_LINK = - 'https://github.com/flixcoo/Cabo-Counter/issues'; - static const String GITHUB_WIKI_LINK = - 'https://github.com/flixcoo/Cabo-Counter/wiki'; + 'cabocounter-issues.felixkirchner.de'; + static const String GITHUB_WIKI_LINK = 'cabocounter-wiki.felixkirchner.de '; static const String EMAIL = 'cabocounter@felixkirchner.de'; static const String PRIVACY_POLICY_LINK = 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; From 7b787a6a4f4b1b2bdedf65c62ed25e43868b8cee Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:31:07 +0200 Subject: [PATCH 098/353] Updated file paths --- lib/core/constants.dart | 10 ++++++++++ lib/core/globals.dart | 11 ----------- lib/main.dart | 1 - lib/presentation/views/information_view.dart | 2 +- lib/presentation/views/main_menu_view.dart | 8 ++++---- lib/presentation/views/mode_selection_view.dart | 2 -- lib/presentation/views/settings_view.dart | 4 +--- lib/presentation/views/tab_view.dart | 1 - lib/services/version_service.dart | 3 +-- 9 files changed, 17 insertions(+), 25 deletions(-) delete mode 100644 lib/core/globals.dart diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 4a79399..ce8c30a 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,5 +1,8 @@ +import 'package:rate_my_app/rate_my_app.dart'; + class Constants { static String appDevPhase = 'Beta'; + static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; static const String GITHUB_LINK = 'https://github1.felixkirchner.de'; static const String GITHUB_ISSUES_LINK = @@ -8,4 +11,11 @@ class Constants { static const String EMAIL = 'cabocounter@felixkirchner.de'; static const String PRIVACY_POLICY_LINK = 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; + + static RateMyApp rateMyApp = RateMyApp( + appStoreIdentifier: '6747105718', + minDays: 15, + remindDays: 45, + minLaunches: 15, + remindLaunches: 40); } diff --git a/lib/core/globals.dart b/lib/core/globals.dart deleted file mode 100644 index 6bfd077..0000000 --- a/lib/core/globals.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:rate_my_app/rate_my_app.dart'; - -class Globals { - static String appDevPhase = 'Beta'; - static RateMyApp rateMyApp = RateMyApp( - appStoreIdentifier: '6747105718', - minDays: 15, - remindDays: 45, - minLaunches: 15, - remindLaunches: 40); -} diff --git a/lib/main.dart b/lib/main.dart index 4002dda..9279426 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,4 @@ import 'package:cabo_counter/core/custom_theme.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/tab_view.dart'; import 'package:cabo_counter/services/config_service.dart'; diff --git a/lib/presentation/views/information_view.dart b/lib/presentation/views/information_view.dart index d31d7f6..712d709 100644 --- a/lib/presentation/views/information_view.dart +++ b/lib/presentation/views/information_view.dart @@ -1,5 +1,5 @@ +import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/utility/constants.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 925b9ed..fee5c72 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -1,5 +1,5 @@ +import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/core/custom_theme.dart'; -import 'package:cabo_counter/core/globals.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; @@ -36,9 +36,9 @@ class _MainMenuViewState extends State { gameManager.addListener(_updateView); WidgetsBinding.instance.addPostFrameCallback((_) async { - await Globals.rateMyApp.init(); + await Constants.rateMyApp.init(); - if (Globals.rateMyApp.shouldOpenDialog) { + if (Constants.rateMyApp.shouldOpenDialog) { await Future.delayed(const Duration(milliseconds: 600)); if (!mounted) return; _handleFeedbackDialog(context); @@ -304,7 +304,7 @@ class _MainMenuViewState extends State { switch (decision) { case RATING_DIALOG_YES: - if (context.mounted) Globals.rateMyApp.showStarRateDialog(context); + if (context.mounted) Constants.rateMyApp.showStarRateDialog(context); break; case RATING_DIALOG_NO: launchUrl(emailUri, mode: LaunchMode.externalApplication); diff --git a/lib/presentation/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart index 67ab5fb..a7d3ce7 100644 --- a/lib/presentation/views/mode_selection_view.dart +++ b/lib/presentation/views/mode_selection_view.dart @@ -1,7 +1,5 @@ import 'package:cabo_counter/core/custom_theme.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; class ModeSelectionMenu extends StatelessWidget { diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 2f55ba3..c9a409d 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,13 +1,11 @@ +import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/core/custom_theme.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/widgets/custom_form_row.dart'; import 'package:cabo_counter/presentation/widgets/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:cabo_counter/utility/constants.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 1fd84d2..15d4637 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -1,5 +1,4 @@ import 'package:cabo_counter/core/custom_theme.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/information_view.dart'; import 'package:cabo_counter/presentation/views/main_menu_view.dart'; diff --git a/lib/services/version_service.dart b/lib/services/version_service.dart index ade934d..6511c69 100644 --- a/lib/services/version_service.dart +++ b/lib/services/version_service.dart @@ -1,5 +1,4 @@ -import 'package:cabo_counter/core/globals.dart'; -import 'package:cabo_counter/utility/constants.dart'; +import 'package:cabo_counter/core/constants.dart'; import 'package:package_info_plus/package_info_plus.dart'; class VersionService { From d5d318929e2b601d20095c4d1b1730c6b4611ed9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:42:05 +0200 Subject: [PATCH 099/353] Updated strings --- lib/l10n/arb/app_de.arb | 5 ++++ lib/l10n/arb/app_en.arb | 5 ++++ lib/l10n/generated/app_localizations.dart | 24 ++++++++++++++++++++ lib/l10n/generated/app_localizations_de.dart | 13 +++++++++++ lib/l10n/generated/app_localizations_en.dart | 13 +++++++++++ lib/presentation/views/main_menu_view.dart | 8 +++---- pubspec.yaml | 2 +- 7 files changed, 65 insertions(+), 5 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 7615b27..64a6d02 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -30,6 +30,11 @@ } } }, + "rating_title": "Gefällt dir die App?", + "rating_message": "Feedback hilft mir, die App zu verbessern. Vielen Dank!", + "yes": "Ja", + "no": "Nein", + "overview": "Übersicht", "new_game": "Neues Spiel", "game_title": "Titel des Spiels", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index ee01699..805a178 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -30,6 +30,11 @@ } } }, + "rating_title": "Do you like the app?", + "rating_message": "Feedback helps me to continuously improve the app. Thank you!", + "yes": "Yes", + "no": "No", + "overview": "Overview", "new_game": "New Game", "game_title": "Game Title", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index ff14253..c349078 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -218,6 +218,30 @@ abstract class AppLocalizations { /// **'Bist du sicher, dass du das Spiel \"{gameTitle}\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'** String delete_game_message(String gameTitle); + /// No description provided for @rating_title. + /// + /// In de, this message translates to: + /// **'Gefällt dir die App?'** + String get rating_title; + + /// No description provided for @rating_message. + /// + /// In de, this message translates to: + /// **'Feedback hilft mir, die App zu verbessern. Vielen Dank!'** + String get rating_message; + + /// No description provided for @yes. + /// + /// In de, this message translates to: + /// **'Ja'** + String get yes; + + /// No description provided for @no. + /// + /// In de, this message translates to: + /// **'Nein'** + String get no; + /// No description provided for @overview. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 898df64..d6fcf72 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -71,6 +71,19 @@ class AppLocalizationsDe extends AppLocalizations { return 'Bist du sicher, dass du das Spiel \"$gameTitle\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'; } + @override + String get rating_title => 'Gefällt dir die App?'; + + @override + String get rating_message => + 'Feedback hilft mir, die App zu verbessern. Vielen Dank!'; + + @override + String get yes => 'Ja'; + + @override + String get no => 'Nein'; + @override String get overview => 'Übersicht'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index c057432..4adaa4b 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -71,6 +71,19 @@ class AppLocalizationsEn extends AppLocalizations { return 'Are you sure you want to delete the game \"$gameTitle\"? This action cannot be undone.'; } + @override + String get rating_title => 'Do you like the app?'; + + @override + String get rating_message => + 'Feedback helps me to continuously improve the app. Thank you!'; + + @override + String get yes => 'Yes'; + + @override + String get no => 'No'; + @override String get overview => 'Overview'; diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index fee5c72..bf417f7 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -260,17 +260,17 @@ class _MainMenuViewState extends State { context: context, builder: (BuildContext context) { return CupertinoAlertDialog( - title: const Text('Gefällt dir die App?'), - content: const Text('Dein Feedback hilft uns weiter.'), + title: Text(AppLocalizations.of(context).rating_title), + content: Text(AppLocalizations.of(context).rating_message), actions: [ CupertinoDialogAction( - child: const Text('Ja'), + child: Text(AppLocalizations.of(context).yes), onPressed: () { Navigator.of(context).pop(RATING_DIALOG_YES); }, ), CupertinoDialogAction( - child: const Text('Nein'), + child: Text(AppLocalizations.of(context).no), onPressed: () { Navigator.of(context).pop(RATING_DIALOG_NO); }, diff --git a/pubspec.yaml b/pubspec.yaml index 35eac0b..f0d4ba4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+443 +version: 0.4.0+451 environment: sdk: ^3.5.4 From 08c2b1d91a1d91f20b63ec4db506cd6a10fdbc9e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:42:47 +0200 Subject: [PATCH 100/353] Updated identifiers --- lib/l10n/arb/app_de.arb | 4 ++-- lib/l10n/arb/app_en.arb | 4 ++-- lib/l10n/generated/app_localizations.dart | 8 ++++---- lib/l10n/generated/app_localizations_de.dart | 4 ++-- lib/l10n/generated/app_localizations_en.dart | 4 ++-- lib/presentation/views/main_menu_view.dart | 4 ++-- pubspec.yaml | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 64a6d02..c4f5692 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -30,8 +30,8 @@ } } }, - "rating_title": "Gefällt dir die App?", - "rating_message": "Feedback hilft mir, die App zu verbessern. Vielen Dank!", + "pre_rating_title": "Gefällt dir die App?", + "pre_rating_message": "Feedback hilft mir, die App zu verbessern. Vielen Dank!", "yes": "Ja", "no": "Nein", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 805a178..d5ccd1a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -30,8 +30,8 @@ } } }, - "rating_title": "Do you like the app?", - "rating_message": "Feedback helps me to continuously improve the app. Thank you!", + "pre_rating_title": "Do you like the app?", + "pre_rating_message": "Feedback helps me to continuously improve the app. Thank you!", "yes": "Yes", "no": "No", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index c349078..74df468 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -218,17 +218,17 @@ abstract class AppLocalizations { /// **'Bist du sicher, dass du das Spiel \"{gameTitle}\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'** String delete_game_message(String gameTitle); - /// No description provided for @rating_title. + /// No description provided for @pre_rating_title. /// /// In de, this message translates to: /// **'Gefällt dir die App?'** - String get rating_title; + String get pre_rating_title; - /// No description provided for @rating_message. + /// No description provided for @pre_rating_message. /// /// In de, this message translates to: /// **'Feedback hilft mir, die App zu verbessern. Vielen Dank!'** - String get rating_message; + String get pre_rating_message; /// No description provided for @yes. /// diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index d6fcf72..ef180b1 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -72,10 +72,10 @@ class AppLocalizationsDe extends AppLocalizations { } @override - String get rating_title => 'Gefällt dir die App?'; + String get pre_rating_title => 'Gefällt dir die App?'; @override - String get rating_message => + String get pre_rating_message => 'Feedback hilft mir, die App zu verbessern. Vielen Dank!'; @override diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 4adaa4b..12d45bc 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -72,10 +72,10 @@ class AppLocalizationsEn extends AppLocalizations { } @override - String get rating_title => 'Do you like the app?'; + String get pre_rating_title => 'Do you like the app?'; @override - String get rating_message => + String get pre_rating_message => 'Feedback helps me to continuously improve the app. Thank you!'; @override diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index bf417f7..166c48e 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -260,8 +260,8 @@ class _MainMenuViewState extends State { context: context, builder: (BuildContext context) { return CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).rating_title), - content: Text(AppLocalizations.of(context).rating_message), + title: Text(AppLocalizations.of(context).pre_rating_title), + content: Text(AppLocalizations.of(context).pre_rating_message), actions: [ CupertinoDialogAction( child: Text(AppLocalizations.of(context).yes), diff --git a/pubspec.yaml b/pubspec.yaml index f0d4ba4..795551a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+451 +version: 0.4.0+452 environment: sdk: ^3.5.4 From 4a918fbbdb04514280fb0712ecab9f38de05b344 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 17:43:09 +0200 Subject: [PATCH 101/353] Added break in switch case --- lib/presentation/views/main_menu_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 166c48e..085a209 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -308,6 +308,7 @@ class _MainMenuViewState extends State { break; case RATING_DIALOG_NO: launchUrl(emailUri, mode: LaunchMode.externalApplication); + break; case RATING_DIALOG_CANCEL: break; } From 9519a6a531c0fedcee1761f4b81c63194f18f017 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 18:51:37 +0200 Subject: [PATCH 102/353] Updated strings --- lib/l10n/arb/app_de.arb | 5 ++++ lib/l10n/arb/app_en.arb | 5 ++++ lib/l10n/generated/app_localizations.dart | 30 ++++++++++++++++++++ lib/l10n/generated/app_localizations_de.dart | 16 +++++++++++ lib/l10n/generated/app_localizations_en.dart | 16 +++++++++++ 5 files changed, 72 insertions(+) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index c4f5692..d89399b 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -34,6 +34,11 @@ "pre_rating_message": "Feedback hilft mir, die App zu verbessern. Vielen Dank!", "yes": "Ja", "no": "Nein", + "bad_rating_title": "Unzufrieden mit der App?", + "bad_rating_message": "Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!", + "contact_email": "E-Mail schreiben", + "email_subject": "Feedback: Cabo Counter App", + "email_body": "Ich habe folgendes Feedback...", "overview": "Übersicht", "new_game": "Neues Spiel", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index d5ccd1a..3f24635 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -34,6 +34,11 @@ "pre_rating_message": "Feedback helps me to continuously improve the app. Thank you!", "yes": "Yes", "no": "No", + "bad_rating_title": "Not satisfied?", + "bad_rating_message": "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.", + "contact_email": "Contac vía E-Mail", + "email_subject": "Feedback: Cabo Counter App", + "email_body": "I have the following feedback...", "overview": "Overview", "new_game": "New Game", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 74df468..af778ae 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -242,6 +242,36 @@ abstract class AppLocalizations { /// **'Nein'** String get no; + /// No description provided for @bad_rating_title. + /// + /// In de, this message translates to: + /// **'Unzufrieden mit der App?'** + String get bad_rating_title; + + /// No description provided for @bad_rating_message. + /// + /// In de, this message translates to: + /// **'Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!'** + String get bad_rating_message; + + /// No description provided for @contact_email. + /// + /// In de, this message translates to: + /// **'E-Mail schreiben'** + String get contact_email; + + /// No description provided for @email_subject. + /// + /// In de, this message translates to: + /// **'Feedback: Cabo Counter App'** + String get email_subject; + + /// No description provided for @email_body. + /// + /// In de, this message translates to: + /// **'Ich habe folgendes Feedback...'** + String get email_body; + /// No description provided for @overview. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index ef180b1..afe558f 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -84,6 +84,22 @@ class AppLocalizationsDe extends AppLocalizations { @override String get no => 'Nein'; + @override + String get bad_rating_title => 'Unzufrieden mit der App?'; + + @override + String get bad_rating_message => + 'Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!'; + + @override + String get contact_email => 'E-Mail schreiben'; + + @override + String get email_subject => 'Feedback: Cabo Counter App'; + + @override + String get email_body => 'Ich habe folgendes Feedback...'; + @override String get overview => 'Übersicht'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 12d45bc..d3e433b 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -84,6 +84,22 @@ class AppLocalizationsEn extends AppLocalizations { @override String get no => 'No'; + @override + String get bad_rating_title => 'Not satisfied?'; + + @override + String get bad_rating_message => + '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 + String get contact_email => 'Contac vía E-Mail'; + + @override + String get email_subject => 'Feedback: Cabo Counter App'; + + @override + String get email_body => 'I have the following feedback...'; + @override String get overview => 'Overview'; From 6ca7f2d9780ed279f09826ad44b7e4e5ff785627 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 18:51:52 +0200 Subject: [PATCH 103/353] Implemented new popup --- lib/presentation/views/main_menu_view.dart | 117 +++++++++++++++------ 1 file changed, 86 insertions(+), 31 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 085a209..05c4a07 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -21,9 +21,11 @@ class MainMenuView extends StatefulWidget { class _MainMenuViewState extends State { bool _isLoading = true; - static const int RATING_DIALOG_YES = 1; - static const int RATING_DIALOG_NO = 0; - static const int RATING_DIALOG_CANCEL = -1; + static const int PRE_RATING_DIALOG_YES = 10; + static const int PRE_RATING_DIALOG_NO = 11; + static const int PRE_RATING_DIALOG_CANCEL = 12; + static const int BAD_RATING_DIALOG_EMAIL = 20; + static const int BAD_RATING_DIALOG_CANCEL = 21; @override initState() { @@ -94,13 +96,15 @@ class _MainMenuViewState extends State { const SizedBox(height: 30), // Abstand von oben Center( child: GestureDetector( - onTap: () => Navigator.push( + onTap: () => _handleFeedbackDialog( + context) /*Navigator.push( context, CupertinoPageRoute( builder: (context) => const CreateGameView(), ), - ), + )*/ + , child: Icon( CupertinoIcons.plus, size: 60, @@ -255,6 +259,48 @@ class _MainMenuViewState extends State { return shouldDelete; } + /// Handles the feedback dialog when the conditions for rating are met. + /// It shows a dialog asking the user if they like the app, + /// and based on their response, it either opens the rating dialog or an email client for feedback. + Future _handleFeedbackDialog(BuildContext context) async { + final String emailSubject = AppLocalizations.of(context).email_subject; + final String emailBody = AppLocalizations.of(context).email_body; + + final Uri emailUri = Uri( + scheme: 'mailto', + path: Constants.EMAIL, + query: 'subject=$emailSubject' + '&body=$emailBody', + ); + + int decision = await _showPreRatingDialog(context); + int decision2 = 0; + + // so that the bad rating dialog is not shown immediately + await Future.delayed(const Duration(milliseconds: 300)); + + switch (decision) { + case PRE_RATING_DIALOG_YES: + if (context.mounted) Constants.rateMyApp.showStarRateDialog(context); + break; + case PRE_RATING_DIALOG_NO: + if (context.mounted) decision2 = await _showBadRatingDialog(context); + if (decision2 == BAD_RATING_DIALOG_EMAIL) { + if (context.mounted) { + launchUrl(emailUri); + } + } + break; + case PRE_RATING_DIALOG_CANCEL: + break; + } + } + + /// Shows a dialog asking the user if they like the app. + /// Returns the user's decision as an integer. + /// - PRE_RATING_DIALOG_YES: User likes the app and wants to rate it. + /// - PRE_RATING_DIALOG_NO: User does not like the app and wants to provide feedback. + /// - PRE_RATING_DIALOG_CANCEL: User cancels the dialog. Future _showPreRatingDialog(BuildContext context) async { int? answer = await showCupertinoDialog( context: context, @@ -266,19 +312,19 @@ class _MainMenuViewState extends State { CupertinoDialogAction( child: Text(AppLocalizations.of(context).yes), onPressed: () { - Navigator.of(context).pop(RATING_DIALOG_YES); + Navigator.of(context).pop(PRE_RATING_DIALOG_YES); }, ), CupertinoDialogAction( child: Text(AppLocalizations.of(context).no), onPressed: () { - Navigator.of(context).pop(RATING_DIALOG_NO); + Navigator.of(context).pop(PRE_RATING_DIALOG_NO); }, ), CupertinoDialogAction( isDestructiveAction: true, onPressed: () { - Navigator.of(context).pop(RATING_DIALOG_CANCEL); + Navigator.of(context).pop(PRE_RATING_DIALOG_CANCEL); }, child: Text(AppLocalizations.of(context).cancel), ), @@ -286,32 +332,41 @@ class _MainMenuViewState extends State { ); }, ); - return answer ?? RATING_DIALOG_CANCEL; + return answer ?? PRE_RATING_DIALOG_CANCEL; } - /// Handles the feedback dialog when the conditions for rating are met. - /// It shows a dialog asking the user if they like the app, - /// and based on their response, it either opens the rating dialog or an email client for feedback. - Future _handleFeedbackDialog(BuildContext context) async { - int decision = await _showPreRatingDialog(context); - - final Uri emailUri = Uri( - scheme: 'mailto', - path: 'cabo-counter@felixkirchner.de', - query: 'subject=Feedback: Cabo Counter App' - '&body=Ich habe folgendes Feedback...', + /// Shows a dialog asking the user for feedback if they do not like the app. + /// Returns the user's decision as an integer. + /// - BAD_RATING_DIALOG_EMAIL: User wants to send an email with feedback. + /// - BAD_RATING_DIALOG_CANCEL: User cancels the dialog. + Future _showBadRatingDialog(BuildContext context) async { + int? answer = await showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).bad_rating_title), + content: Text(AppLocalizations.of(context).bad_rating_message), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).contact_email, + style: const TextStyle(fontWeight: FontWeight.bold)), + onPressed: () { + Navigator.of(context).pop(BAD_RATING_DIALOG_EMAIL); + }, + ), + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).cancel, + style: + const TextStyle(color: CupertinoColors.destructiveRed)), + onPressed: () { + Navigator.of(context).pop(BAD_RATING_DIALOG_CANCEL); + }, + ), + ], + ); + }, ); - - switch (decision) { - case RATING_DIALOG_YES: - if (context.mounted) Constants.rateMyApp.showStarRateDialog(context); - break; - case RATING_DIALOG_NO: - launchUrl(emailUri, mode: LaunchMode.externalApplication); - break; - case RATING_DIALOG_CANCEL: - break; - } + return answer ?? PRE_RATING_DIALOG_CANCEL; } @override From ca9c3a15f3ad7b0c3dd91fcd9e8f887a566c8292 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 18:51:59 +0200 Subject: [PATCH 104/353] Corrected links --- lib/core/constants.dart | 5 +++-- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index ce8c30a..10b062d 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -6,8 +6,9 @@ class Constants { static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; static const String GITHUB_LINK = 'https://github1.felixkirchner.de'; static const String GITHUB_ISSUES_LINK = - 'cabocounter-issues.felixkirchner.de'; - static const String GITHUB_WIKI_LINK = 'cabocounter-wiki.felixkirchner.de '; + 'https://cabocounter-issues.felixkirchner.de'; + static const String GITHUB_WIKI_LINK = + 'https://cabocounter-wiki.felixkirchner.de'; static const String EMAIL = 'cabocounter@felixkirchner.de'; static const String PRIVACY_POLICY_LINK = 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; diff --git a/pubspec.yaml b/pubspec.yaml index 795551a..4625269 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+452 +version: 0.4.0+456 environment: sdk: ^3.5.4 From 51a2a789e7615549eeced90c274c03eaac6799a7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 18:52:03 +0200 Subject: [PATCH 105/353] Changed color --- lib/presentation/views/active_game_view.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 35404bb..9ecae1b 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -235,7 +235,8 @@ class _ActiveGameViewState extends State { child: Text( AppLocalizations.of(context).end_game, style: const TextStyle( - fontWeight: FontWeight.bold, color: Colors.red), + fontWeight: FontWeight.bold, + color: CupertinoColors.destructiveRed), ), onPressed: () { setState(() { From 89cdb4f824b65bb4f184d9cf7d82289ecbe8f1a9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 18:55:24 +0200 Subject: [PATCH 106/353] Ensured rating dialog wont show in Beta --- lib/presentation/views/main_menu_view.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 05c4a07..61ec010 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -40,7 +40,8 @@ class _MainMenuViewState extends State { WidgetsBinding.instance.addPostFrameCallback((_) async { await Constants.rateMyApp.init(); - if (Constants.rateMyApp.shouldOpenDialog) { + if (Constants.rateMyApp.shouldOpenDialog && + Constants.appDevPhase != 'Beta') { await Future.delayed(const Duration(milliseconds: 600)); if (!mounted) return; _handleFeedbackDialog(context); @@ -96,15 +97,13 @@ class _MainMenuViewState extends State { const SizedBox(height: 30), // Abstand von oben Center( child: GestureDetector( - onTap: () => _handleFeedbackDialog( - context) /*Navigator.push( + onTap: () => Navigator.push( context, CupertinoPageRoute( builder: (context) => const CreateGameView(), ), - )*/ - , + ), child: Icon( CupertinoIcons.plus, size: 60, From 5fc951844bd985de8110ab278a21b76cfca6a3e0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:04:35 +0200 Subject: [PATCH 107/353] Refactoring --- lib/presentation/views/main_menu_view.dart | 171 ++++++++++----------- 1 file changed, 79 insertions(+), 92 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 61ec010..fac1d7c 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -21,11 +21,11 @@ class MainMenuView extends StatefulWidget { class _MainMenuViewState extends State { bool _isLoading = true; - static const int PRE_RATING_DIALOG_YES = 10; - static const int PRE_RATING_DIALOG_NO = 11; - static const int PRE_RATING_DIALOG_CANCEL = 12; - static const int BAD_RATING_DIALOG_EMAIL = 20; - static const int BAD_RATING_DIALOG_CANCEL = 21; + static const int PRE_RATING_DIALOG_YES = 1; + static const int PRE_RATING_DIALOG_NO = 0; + static const int PRE_RATING_DIALOG_CANCEL = -1; + static const int BAD_RATING_DIALOG_EMAIL = 1; + static const int BAD_RATING_DIALOG_CANCEL = 0; @override initState() { @@ -222,42 +222,6 @@ class _MainMenuViewState extends State { return AppLocalizations.of(context).unlimited; } - /// Shows a confirmation dialog to delete all game sessions. - /// Returns true if the user confirms the deletion, false otherwise. - /// [gameTitle] is the title of the game session to be deleted. - Future _showDeleteGamePopup(String gameTitle) async { - bool? shouldDelete = await showCupertinoDialog( - context: context, - builder: (context) { - return CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).delete_game_title), - content: Text( - AppLocalizations.of(context).delete_game_message(gameTitle)), - actions: [ - CupertinoDialogAction( - onPressed: () { - Navigator.pop(context, false); - }, - child: Text(AppLocalizations.of(context).cancel), - ), - CupertinoDialogAction( - onPressed: () { - Navigator.pop(context, true); - }, - child: Text( - AppLocalizations.of(context).delete, - style: const TextStyle( - fontWeight: FontWeight.bold, color: Colors.red), - ), - ), - ], - ); - }, - ) ?? - false; - return shouldDelete; - } - /// Handles the feedback dialog when the conditions for rating are met. /// It shows a dialog asking the user if they like the app, /// and based on their response, it either opens the rating dialog or an email client for feedback. @@ -295,43 +259,76 @@ class _MainMenuViewState extends State { } } + /// Shows a Cupertino dialog with a title, content, and a list of actions. + Future _showCupertinoChoiceDialog({ + required String title, + required String content, + required List<({String label, VoidCallback onPressed})> actions, + }) { + return showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(title), + content: Text(content), + actions: actions + .map((action) => CupertinoDialogAction( + onPressed: action.onPressed, + child: Text(action.label), + )) + .toList(), + ); + }, + ); + } + + /// Shows a confirmation dialog to delete all game sessions. + /// Returns true if the user confirms the deletion, false otherwise. + /// [gameTitle] is the title of the game session to be deleted. + Future _showDeleteGamePopup(String gameTitle) async { + return await _showCupertinoChoiceDialog( + title: AppLocalizations.of(context).delete_game_title, + content: AppLocalizations.of(context).delete_game_message(gameTitle), + actions: [ + ( + label: AppLocalizations.of(context).cancel, + onPressed: () => Navigator.of(context).pop(false) + ), + ( + label: AppLocalizations.of(context).delete, + onPressed: () => Navigator.of(context).pop(true) + ), + ], + ) ?? + false; + } + /// Shows a dialog asking the user if they like the app. /// Returns the user's decision as an integer. /// - PRE_RATING_DIALOG_YES: User likes the app and wants to rate it. /// - PRE_RATING_DIALOG_NO: User does not like the app and wants to provide feedback. /// - PRE_RATING_DIALOG_CANCEL: User cancels the dialog. Future _showPreRatingDialog(BuildContext context) async { - int? answer = await showCupertinoDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).pre_rating_title), - content: Text(AppLocalizations.of(context).pre_rating_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).yes), - onPressed: () { - Navigator.of(context).pop(PRE_RATING_DIALOG_YES); - }, + return await _showCupertinoChoiceDialog( + title: AppLocalizations.of(context).pre_rating_title, + content: AppLocalizations.of(context).pre_rating_message, + actions: [ + ( + label: AppLocalizations.of(context).yes, + onPressed: () => Navigator.of(context).pop(PRE_RATING_DIALOG_YES) ), - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).no), - onPressed: () { - Navigator.of(context).pop(PRE_RATING_DIALOG_NO); - }, + ( + label: AppLocalizations.of(context).no, + onPressed: () => Navigator.of(context).pop(PRE_RATING_DIALOG_NO) ), - CupertinoDialogAction( - isDestructiveAction: true, - onPressed: () { - Navigator.of(context).pop(PRE_RATING_DIALOG_CANCEL); - }, - child: Text(AppLocalizations.of(context).cancel), + ( + label: AppLocalizations.of(context).cancel, + onPressed: () => + Navigator.of(context).pop(PRE_RATING_DIALOG_CANCEL) ), ], - ); - }, - ); - return answer ?? PRE_RATING_DIALOG_CANCEL; + ) ?? + PRE_RATING_DIALOG_CANCEL; } /// Shows a dialog asking the user for feedback if they do not like the app. @@ -339,33 +336,23 @@ class _MainMenuViewState extends State { /// - BAD_RATING_DIALOG_EMAIL: User wants to send an email with feedback. /// - BAD_RATING_DIALOG_CANCEL: User cancels the dialog. Future _showBadRatingDialog(BuildContext context) async { - int? answer = await showCupertinoDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).bad_rating_title), - content: Text(AppLocalizations.of(context).bad_rating_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).contact_email, - style: const TextStyle(fontWeight: FontWeight.bold)), - onPressed: () { - Navigator.of(context).pop(BAD_RATING_DIALOG_EMAIL); - }, + return await _showCupertinoChoiceDialog( + title: AppLocalizations.of(context).bad_rating_title, + content: AppLocalizations.of(context).bad_rating_message, + actions: [ + ( + label: AppLocalizations.of(context).contact_email, + onPressed: () => + Navigator.of(context).pop(BAD_RATING_DIALOG_EMAIL) ), - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).cancel, - style: - const TextStyle(color: CupertinoColors.destructiveRed)), - onPressed: () { - Navigator.of(context).pop(BAD_RATING_DIALOG_CANCEL); - }, + ( + label: AppLocalizations.of(context).cancel, + onPressed: () => + Navigator.of(context).pop(BAD_RATING_DIALOG_CANCEL) ), ], - ); - }, - ); - return answer ?? PRE_RATING_DIALOG_CANCEL; + ) ?? + BAD_RATING_DIALOG_CANCEL; } @override From a9584a531ddb9ede73bd2f181066574b3cba2cee Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:08:44 +0200 Subject: [PATCH 108/353] Adding const --- lib/core/constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 10b062d..0d32ceb 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,7 +1,7 @@ import 'package:rate_my_app/rate_my_app.dart'; class Constants { - static String appDevPhase = 'Beta'; + static const String appDevPhase = 'Beta'; static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; static const String GITHUB_LINK = 'https://github1.felixkirchner.de'; From 7e76af7a2068ee82f35f4969ad5dc66106154918 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:10:04 +0200 Subject: [PATCH 109/353] Renamed variables --- lib/presentation/views/main_menu_view.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index fac1d7c..979c854 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -236,19 +236,21 @@ class _MainMenuViewState extends State { '&body=$emailBody', ); - int decision = await _showPreRatingDialog(context); - int decision2 = 0; + int preRatingDecision = await _showPreRatingDialog(context); + int badRatingDecision = BAD_RATING_DIALOG_CANCEL; // so that the bad rating dialog is not shown immediately await Future.delayed(const Duration(milliseconds: 300)); - switch (decision) { + switch (preRatingDecision) { case PRE_RATING_DIALOG_YES: if (context.mounted) Constants.rateMyApp.showStarRateDialog(context); break; case PRE_RATING_DIALOG_NO: - if (context.mounted) decision2 = await _showBadRatingDialog(context); - if (decision2 == BAD_RATING_DIALOG_EMAIL) { + if (context.mounted) { + badRatingDecision = await _showBadRatingDialog(context); + } + if (badRatingDecision == BAD_RATING_DIALOG_EMAIL) { if (context.mounted) { launchUrl(emailUri); } From d3693c20f12f9e5fa031116c33adad25768537b1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:10:49 +0200 Subject: [PATCH 110/353] Corrected links --- lib/core/constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 0d32ceb..5b6e90e 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -4,7 +4,7 @@ class Constants { static const String appDevPhase = 'Beta'; static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; - static const String GITHUB_LINK = 'https://github1.felixkirchner.de'; + static const String GITHUB_LINK = 'https://github.felixkirchner.de'; static const String GITHUB_ISSUES_LINK = 'https://cabocounter-issues.felixkirchner.de'; static const String GITHUB_WIKI_LINK = From b5ef2df0c6880f919af9511e370cef03586e7101 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:16:57 +0200 Subject: [PATCH 111/353] updated Dialog function --- lib/presentation/views/main_menu_view.dart | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 979c854..09e4c26 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -265,7 +265,7 @@ class _MainMenuViewState extends State { Future _showCupertinoChoiceDialog({ required String title, required String content, - required List<({String label, VoidCallback onPressed})> actions, + required List<({Widget content, VoidCallback onPressed})> actions, }) { return showCupertinoDialog( context: context, @@ -276,7 +276,7 @@ class _MainMenuViewState extends State { actions: actions .map((action) => CupertinoDialogAction( onPressed: action.onPressed, - child: Text(action.label), + child: action.content, )) .toList(), ); @@ -293,13 +293,17 @@ class _MainMenuViewState extends State { content: AppLocalizations.of(context).delete_game_message(gameTitle), actions: [ ( - label: AppLocalizations.of(context).cancel, + content: Text(AppLocalizations.of(context).cancel), onPressed: () => Navigator.of(context).pop(false) ), ( - label: AppLocalizations.of(context).delete, - onPressed: () => Navigator.of(context).pop(true) - ), + content: Text(AppLocalizations.of(context).delete, + style: const TextStyle( + color: CupertinoColors.destructiveRed, + fontWeight: FontWeight.bold, + )), + onPressed: () => Navigator.of(context).pop(false) + ) ], ) ?? false; @@ -316,15 +320,15 @@ class _MainMenuViewState extends State { content: AppLocalizations.of(context).pre_rating_message, actions: [ ( - label: AppLocalizations.of(context).yes, + content: Text(AppLocalizations.of(context).yes), onPressed: () => Navigator.of(context).pop(PRE_RATING_DIALOG_YES) ), ( - label: AppLocalizations.of(context).no, + content: Text(AppLocalizations.of(context).no), onPressed: () => Navigator.of(context).pop(PRE_RATING_DIALOG_NO) ), ( - label: AppLocalizations.of(context).cancel, + content: Text(AppLocalizations.of(context).cancel), onPressed: () => Navigator.of(context).pop(PRE_RATING_DIALOG_CANCEL) ), @@ -343,12 +347,12 @@ class _MainMenuViewState extends State { content: AppLocalizations.of(context).bad_rating_message, actions: [ ( - label: AppLocalizations.of(context).contact_email, + content: Text(AppLocalizations.of(context).contact_email), onPressed: () => Navigator.of(context).pop(BAD_RATING_DIALOG_EMAIL) ), ( - label: AppLocalizations.of(context).cancel, + content: Text(AppLocalizations.of(context).cancel), onPressed: () => Navigator.of(context).pop(BAD_RATING_DIALOG_CANCEL) ), From ac6db7fdd90d13792059c730a2e1d928b97744ea Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:26:58 +0200 Subject: [PATCH 112/353] Added version number in about view --- .../views/{information_view.dart => about_view.dart} | 11 ++++++++--- lib/presentation/views/tab_view.dart | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) rename lib/presentation/views/{information_view.dart => about_view.dart} (87%) diff --git a/lib/presentation/views/information_view.dart b/lib/presentation/views/about_view.dart similarity index 87% rename from lib/presentation/views/information_view.dart rename to lib/presentation/views/about_view.dart index 712d709..128f91f 100644 --- a/lib/presentation/views/information_view.dart +++ b/lib/presentation/views/about_view.dart @@ -1,12 +1,13 @@ import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/services/version_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; -class InformationView extends StatelessWidget { - const InformationView({super.key}); +class AboutView extends StatelessWidget { + const AboutView({super.key}); @override Widget build(BuildContext context) { @@ -29,9 +30,13 @@ class InformationView extends StatelessWidget { ), ), ), + Text( + '${AppLocalizations.of(context).app_version} ${VersionService.getVersionWithBuild()}', + style: TextStyle(fontSize: 15, color: Colors.grey[300]), + ), Padding( padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 30), + const EdgeInsets.symmetric(horizontal: 20, vertical: 15), child: SizedBox( height: 200, child: Image.asset('assets/cabo_counter-logo_rounded.png'), diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 15d4637..0c98cc7 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -1,6 +1,6 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/presentation/views/information_view.dart'; +import 'package:cabo_counter/presentation/views/about_view.dart'; import 'package:cabo_counter/presentation/views/main_menu_view.dart'; import 'package:flutter/cupertino.dart'; @@ -39,7 +39,7 @@ class _TabViewState extends State { if (index == 0) { return const MainMenuView(); } else { - return const InformationView(); + return const AboutView(); } }); }, diff --git a/pubspec.yaml b/pubspec.yaml index 4625269..52ae1fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+456 +version: 0.4.0+459 environment: sdk: ^3.5.4 From 034ce19c60dbca5425f1c28549561dc4d3fa3258 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:36:17 +0200 Subject: [PATCH 113/353] Changed order and corrected return --- lib/presentation/views/main_menu_view.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 09e4c26..1e8a67a 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -292,16 +292,16 @@ class _MainMenuViewState extends State { title: AppLocalizations.of(context).delete_game_title, content: AppLocalizations.of(context).delete_game_message(gameTitle), actions: [ - ( - content: Text(AppLocalizations.of(context).cancel), - onPressed: () => Navigator.of(context).pop(false) - ), ( content: Text(AppLocalizations.of(context).delete, style: const TextStyle( color: CupertinoColors.destructiveRed, fontWeight: FontWeight.bold, )), + onPressed: () => Navigator.of(context).pop(true) + ), + ( + content: Text(AppLocalizations.of(context).cancel), onPressed: () => Navigator.of(context).pop(false) ) ], From 3a74ca0d9801bfe69e174d4224063d5fcf2f8d02 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 19:37:53 +0200 Subject: [PATCH 114/353] Changed translation --- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/generated/app_localizations_en.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 3f24635..467135e 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -36,7 +36,7 @@ "no": "No", "bad_rating_title": "Not satisfied?", "bad_rating_message": "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.", - "contact_email": "Contac vía E-Mail", + "contact_email": "Contac via E-Mail", "email_subject": "Feedback: Cabo Counter App", "email_body": "I have the following feedback...", diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index d3e433b..a986058 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -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.'; @override - String get contact_email => 'Contac vía E-Mail'; + String get contact_email => 'Contac via E-Mail'; @override String get email_subject => 'Feedback: Cabo Counter App'; diff --git a/pubspec.yaml b/pubspec.yaml index 52ae1fc..33ef0fe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+459 +version: 0.4.0+461 environment: sdk: ^3.5.4 From 5ede7e92780efa001326b6422e335f0c04225915 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 20:03:58 +0200 Subject: [PATCH 115/353] Changed popups because of unmounted context errors --- lib/presentation/views/main_menu_view.dart | 166 ++++++++++----------- pubspec.yaml | 2 +- 2 files changed, 82 insertions(+), 86 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 1e8a67a..2a95346 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -75,14 +75,12 @@ class _MainMenuViewState extends State { icon: const Icon(CupertinoIcons.settings, size: 30)), middle: const Text('Cabo Counter'), trailing: IconButton( - onPressed: () => { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const CreateGameView(), - ), - ) - }, + onPressed: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const CreateGameView(), + ), + ), icon: const Icon(CupertinoIcons.add)), ), child: CupertinoPageScaffold( @@ -146,7 +144,7 @@ class _MainMenuViewState extends State { final String gameTitle = gameManager .gameList[index].gameTitle; return await _showDeleteGamePopup( - gameTitle); + gameTitle, context); }, onDismissed: (direction) { gameManager @@ -261,50 +259,37 @@ class _MainMenuViewState extends State { } } - /// Shows a Cupertino dialog with a title, content, and a list of actions. - Future _showCupertinoChoiceDialog({ - required String title, - required String content, - required List<({Widget content, VoidCallback onPressed})> actions, - }) { - return showCupertinoDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text(title), - content: Text(content), - actions: actions - .map((action) => CupertinoDialogAction( - onPressed: action.onPressed, - child: action.content, - )) - .toList(), - ); - }, - ); - } - /// Shows a confirmation dialog to delete all game sessions. /// Returns true if the user confirms the deletion, false otherwise. /// [gameTitle] is the title of the game session to be deleted. - Future _showDeleteGamePopup(String gameTitle) async { - return await _showCupertinoChoiceDialog( - title: AppLocalizations.of(context).delete_game_title, - content: AppLocalizations.of(context).delete_game_message(gameTitle), - actions: [ - ( - content: Text(AppLocalizations.of(context).delete, - style: const TextStyle( - color: CupertinoColors.destructiveRed, - fontWeight: FontWeight.bold, - )), - onPressed: () => Navigator.of(context).pop(true) - ), - ( - content: Text(AppLocalizations.of(context).cancel), - onPressed: () => Navigator.of(context).pop(false) - ) - ], + Future _showDeleteGamePopup( + String gameTitle, BuildContext context) async { + return await showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text( + AppLocalizations.of(context).delete_game_title, + ), + content: Text(AppLocalizations.of(context) + .delete_game_message(gameTitle)), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).cancel), + onPressed: () { + Navigator.of(context).pop(false); + }), + CupertinoDialogAction( + isDestructiveAction: true, + isDefaultAction: true, + child: Text( + AppLocalizations.of(context).delete, + ), + onPressed: () { + Navigator.of(context).pop(true); + }) + ]); + }, ) ?? false; } @@ -315,25 +300,32 @@ class _MainMenuViewState extends State { /// - PRE_RATING_DIALOG_NO: User does not like the app and wants to provide feedback. /// - PRE_RATING_DIALOG_CANCEL: User cancels the dialog. Future _showPreRatingDialog(BuildContext context) async { - return await _showCupertinoChoiceDialog( - title: AppLocalizations.of(context).pre_rating_title, - content: AppLocalizations.of(context).pre_rating_message, - actions: [ - ( - content: Text(AppLocalizations.of(context).yes), - onPressed: () => Navigator.of(context).pop(PRE_RATING_DIALOG_YES) - ), - ( - content: Text(AppLocalizations.of(context).no), - onPressed: () => Navigator.of(context).pop(PRE_RATING_DIALOG_NO) - ), - ( - content: Text(AppLocalizations.of(context).cancel), - onPressed: () => - Navigator.of(context).pop(PRE_RATING_DIALOG_CANCEL) - ), - ], - ) ?? + return await showCupertinoDialog( + context: context, + builder: (BuildContext context) => CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).pre_rating_title), + content: + Text(AppLocalizations.of(context).pre_rating_message), + actions: [ + CupertinoDialogAction( + onPressed: () => + Navigator.of(context).pop(PRE_RATING_DIALOG_YES), + isDefaultAction: true, + child: Text(AppLocalizations.of(context).yes), + ), + CupertinoDialogAction( + onPressed: () => + Navigator.of(context).pop(PRE_RATING_DIALOG_NO), + child: Text(AppLocalizations.of(context).no), + ), + CupertinoDialogAction( + onPressed: () => + Navigator.of(context).pop(PRE_RATING_DIALOG_CANCEL), + isDestructiveAction: true, + child: Text(AppLocalizations.of(context).cancel), + ) + ], + )) ?? PRE_RATING_DIALOG_CANCEL; } @@ -342,22 +334,26 @@ class _MainMenuViewState extends State { /// - BAD_RATING_DIALOG_EMAIL: User wants to send an email with feedback. /// - BAD_RATING_DIALOG_CANCEL: User cancels the dialog. Future _showBadRatingDialog(BuildContext context) async { - return await _showCupertinoChoiceDialog( - title: AppLocalizations.of(context).bad_rating_title, - content: AppLocalizations.of(context).bad_rating_message, - actions: [ - ( - content: Text(AppLocalizations.of(context).contact_email), - onPressed: () => - Navigator.of(context).pop(BAD_RATING_DIALOG_EMAIL) - ), - ( - content: Text(AppLocalizations.of(context).cancel), - onPressed: () => - Navigator.of(context).pop(BAD_RATING_DIALOG_CANCEL) - ), - ], - ) ?? + return await showCupertinoDialog( + context: context, + builder: (BuildContext context) => CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).bad_rating_title), + content: + Text(AppLocalizations.of(context).bad_rating_message), + actions: [ + CupertinoDialogAction( + isDefaultAction: true, + onPressed: () => + Navigator.of(context).pop(BAD_RATING_DIALOG_EMAIL), + child: Text(AppLocalizations.of(context).contact_email), + ), + CupertinoDialogAction( + isDestructiveAction: true, + onPressed: () => + Navigator.of(context).pop(BAD_RATING_DIALOG_CANCEL), + child: Text(AppLocalizations.of(context).cancel)) + ], + )) ?? BAD_RATING_DIALOG_CANCEL; } diff --git a/pubspec.yaml b/pubspec.yaml index 33ef0fe..31146e6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+461 +version: 0.4.0+467 environment: sdk: ^3.5.4 From f3114c6c32a3d1633b44a6d330a8471d89ed541e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 20:04:11 +0200 Subject: [PATCH 116/353] corrected string typo --- lib/l10n/arb/app_en.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 467135e..e01e242 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -36,7 +36,7 @@ "no": "No", "bad_rating_title": "Not satisfied?", "bad_rating_message": "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.", - "contact_email": "Contac via E-Mail", + "contact_email": "Contact via E-Mail", "email_subject": "Feedback: Cabo Counter App", "email_body": "I have the following feedback...", From a8ca853c24c24226bc6475da9c99b1fdc0ee0049 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 20:12:58 +0200 Subject: [PATCH 117/353] Replaced int constants with enums --- lib/presentation/views/main_menu_view.dart | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 2a95346..ee36d1f 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -11,6 +11,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; +enum PreRatingDialogDecision { yes, no, cancel } + +enum BadRatingDialogDecision { email, cancel } + class MainMenuView extends StatefulWidget { const MainMenuView({super.key}); @@ -21,11 +25,6 @@ class MainMenuView extends StatefulWidget { class _MainMenuViewState extends State { bool _isLoading = true; - static const int PRE_RATING_DIALOG_YES = 1; - static const int PRE_RATING_DIALOG_NO = 0; - static const int PRE_RATING_DIALOG_CANCEL = -1; - static const int BAD_RATING_DIALOG_EMAIL = 1; - static const int BAD_RATING_DIALOG_CANCEL = 0; @override initState() { @@ -234,27 +233,28 @@ class _MainMenuViewState extends State { '&body=$emailBody', ); - int preRatingDecision = await _showPreRatingDialog(context); - int badRatingDecision = BAD_RATING_DIALOG_CANCEL; + PreRatingDialogDecision preRatingDecision = + await _showPreRatingDialog(context); + BadRatingDialogDecision badRatingDecision = BadRatingDialogDecision.cancel; // so that the bad rating dialog is not shown immediately await Future.delayed(const Duration(milliseconds: 300)); switch (preRatingDecision) { - case PRE_RATING_DIALOG_YES: + case PreRatingDialogDecision.yes: if (context.mounted) Constants.rateMyApp.showStarRateDialog(context); break; - case PRE_RATING_DIALOG_NO: + case PreRatingDialogDecision.no: if (context.mounted) { badRatingDecision = await _showBadRatingDialog(context); } - if (badRatingDecision == BAD_RATING_DIALOG_EMAIL) { + if (badRatingDecision == BadRatingDialogDecision.email) { if (context.mounted) { launchUrl(emailUri); } } break; - case PRE_RATING_DIALOG_CANCEL: + case PreRatingDialogDecision.cancel: break; } } @@ -262,7 +262,7 @@ class _MainMenuViewState extends State { /// Shows a confirmation dialog to delete all game sessions. /// Returns true if the user confirms the deletion, false otherwise. /// [gameTitle] is the title of the game session to be deleted. - Future _showDeleteGamePopup( + Future _showDeleteGamePopup( String gameTitle, BuildContext context) async { return await showCupertinoDialog( context: context, @@ -299,8 +299,9 @@ class _MainMenuViewState extends State { /// - PRE_RATING_DIALOG_YES: User likes the app and wants to rate it. /// - PRE_RATING_DIALOG_NO: User does not like the app and wants to provide feedback. /// - PRE_RATING_DIALOG_CANCEL: User cancels the dialog. - Future _showPreRatingDialog(BuildContext context) async { - return await showCupertinoDialog( + Future _showPreRatingDialog( + BuildContext context) async { + return await showCupertinoDialog( context: context, builder: (BuildContext context) => CupertinoAlertDialog( title: Text(AppLocalizations.of(context).pre_rating_title), @@ -308,33 +309,33 @@ class _MainMenuViewState extends State { Text(AppLocalizations.of(context).pre_rating_message), actions: [ CupertinoDialogAction( - onPressed: () => - Navigator.of(context).pop(PRE_RATING_DIALOG_YES), + onPressed: () => Navigator.of(context) + .pop(PreRatingDialogDecision.yes), isDefaultAction: true, child: Text(AppLocalizations.of(context).yes), ), CupertinoDialogAction( onPressed: () => - Navigator.of(context).pop(PRE_RATING_DIALOG_NO), + Navigator.of(context).pop(PreRatingDialogDecision.no), child: Text(AppLocalizations.of(context).no), ), CupertinoDialogAction( - onPressed: () => - Navigator.of(context).pop(PRE_RATING_DIALOG_CANCEL), + onPressed: () => Navigator.of(context).pop(), isDestructiveAction: true, child: Text(AppLocalizations.of(context).cancel), ) ], )) ?? - PRE_RATING_DIALOG_CANCEL; + PreRatingDialogDecision.cancel; } /// Shows a dialog asking the user for feedback if they do not like the app. /// Returns the user's decision as an integer. /// - BAD_RATING_DIALOG_EMAIL: User wants to send an email with feedback. /// - BAD_RATING_DIALOG_CANCEL: User cancels the dialog. - Future _showBadRatingDialog(BuildContext context) async { - return await showCupertinoDialog( + Future _showBadRatingDialog( + BuildContext context) async { + return await showCupertinoDialog( context: context, builder: (BuildContext context) => CupertinoAlertDialog( title: Text(AppLocalizations.of(context).bad_rating_title), @@ -343,18 +344,17 @@ class _MainMenuViewState extends State { actions: [ CupertinoDialogAction( isDefaultAction: true, - onPressed: () => - Navigator.of(context).pop(BAD_RATING_DIALOG_EMAIL), + onPressed: () => Navigator.of(context) + .pop(BadRatingDialogDecision.email), child: Text(AppLocalizations.of(context).contact_email), ), CupertinoDialogAction( isDestructiveAction: true, - onPressed: () => - Navigator.of(context).pop(BAD_RATING_DIALOG_CANCEL), + onPressed: () => Navigator.of(context).pop(), child: Text(AppLocalizations.of(context).cancel)) ], )) ?? - BAD_RATING_DIALOG_CANCEL; + BadRatingDialogDecision.cancel; } @override From 2f225c9b23412245a94aac5996b4964b34ea1979 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 20:13:54 +0200 Subject: [PATCH 118/353] Renamed Stepper to CustomStepper --- lib/presentation/views/settings_view.dart | 6 +++--- lib/presentation/widgets/custom_form_row.dart | 4 ++-- .../widgets/{stepper.dart => custom_stepper.dart} | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) rename lib/presentation/widgets/{stepper.dart => custom_stepper.dart} (90%) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index c9a409d..9bed7fc 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -2,7 +2,7 @@ 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/widgets/custom_form_row.dart'; -import 'package:cabo_counter/presentation/widgets/stepper.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'; @@ -54,7 +54,7 @@ class _SettingsViewState extends State { CustomFormRow( prefixText: 'Cabo-Strafe', prefixIcon: CupertinoIcons.bolt_fill, - suffixWidget: Stepper( + suffixWidget: CustomStepper( key: _stepperKey1, initialValue: ConfigService.caboPenalty, minValue: 0, @@ -71,7 +71,7 @@ class _SettingsViewState extends State { CustomFormRow( prefixText: 'Punkte-Limit', prefixIcon: FontAwesomeIcons.bullseye, - suffixWidget: Stepper( + suffixWidget: CustomStepper( key: _stepperKey2, initialValue: ConfigService.pointLimit, minValue: 30, diff --git a/lib/presentation/widgets/custom_form_row.dart b/lib/presentation/widgets/custom_form_row.dart index 96067c3..7a2526b 100644 --- a/lib/presentation/widgets/custom_form_row.dart +++ b/lib/presentation/widgets/custom_form_row.dart @@ -1,5 +1,5 @@ import 'package:cabo_counter/core/custom_theme.dart'; -import 'package:cabo_counter/presentation/widgets/stepper.dart'; +import 'package:cabo_counter/presentation/widgets/custom_stepper.dart'; import 'package:flutter/cupertino.dart'; class CustomFormRow extends StatefulWidget { @@ -43,7 +43,7 @@ class _CustomFormRowState extends State { Text(widget.prefixText), ], ), - padding: suffixWidget is Stepper + padding: suffixWidget is CustomStepper ? const EdgeInsets.fromLTRB(15, 0, 0, 0) : const EdgeInsets.symmetric(vertical: 10, horizontal: 15), child: suffixWidget, diff --git a/lib/presentation/widgets/stepper.dart b/lib/presentation/widgets/custom_stepper.dart similarity index 90% rename from lib/presentation/widgets/stepper.dart rename to lib/presentation/widgets/custom_stepper.dart index 5d0bce8..a05a4cb 100644 --- a/lib/presentation/widgets/stepper.dart +++ b/lib/presentation/widgets/custom_stepper.dart @@ -1,13 +1,13 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:flutter/cupertino.dart'; // Für iOS-Style -class Stepper extends StatefulWidget { +class CustomStepper extends StatefulWidget { final int minValue; final int maxValue; final int? initialValue; final int step; final ValueChanged onChanged; - const Stepper({ + const CustomStepper({ super.key, required this.minValue, required this.maxValue, @@ -18,10 +18,10 @@ class Stepper extends StatefulWidget { @override // ignore: library_private_types_in_public_api - _StepperState createState() => _StepperState(); + _CustomStepperState createState() => _CustomStepperState(); } -class _StepperState extends State { +class _CustomStepperState extends State { late int _value; @override From 1c505916f3a42a2a3fda44af57b8047ed6c3788c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 20:14:50 +0200 Subject: [PATCH 119/353] Changed argument order --- lib/presentation/views/main_menu_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index ee36d1f..f6c1a32 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -143,7 +143,7 @@ class _MainMenuViewState extends State { final String gameTitle = gameManager .gameList[index].gameTitle; return await _showDeleteGamePopup( - gameTitle, context); + context, gameTitle); }, onDismissed: (direction) { gameManager @@ -263,7 +263,7 @@ class _MainMenuViewState extends State { /// Returns true if the user confirms the deletion, false otherwise. /// [gameTitle] is the title of the game session to be deleted. Future _showDeleteGamePopup( - String gameTitle, BuildContext context) async { + BuildContext context, String gameTitle) async { return await showCupertinoDialog( context: context, builder: (BuildContext context) { From 964c179e6929d6274b4a22de83d67cd9bf84dd9c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 10 Jul 2025 20:46:11 +0200 Subject: [PATCH 120/353] Reordered properties --- lib/presentation/views/main_menu_view.dart | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index f6c1a32..1f8b5d0 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -275,19 +275,21 @@ class _MainMenuViewState extends State { .delete_game_message(gameTitle)), actions: [ CupertinoDialogAction( - child: Text(AppLocalizations.of(context).cancel), - onPressed: () { - Navigator.of(context).pop(false); - }), + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(AppLocalizations.of(context).cancel), + ), CupertinoDialogAction( - isDestructiveAction: true, - isDefaultAction: true, - child: Text( - AppLocalizations.of(context).delete, - ), - onPressed: () { - Navigator.of(context).pop(true); - }) + isDestructiveAction: true, + isDefaultAction: true, + onPressed: () { + Navigator.of(context).pop(true); + }, + child: Text( + AppLocalizations.of(context).delete, + ), + ) ]); }, ) ?? From b3c70f711ad98be4f8a37c4aadfdb99c55d93c66 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 10:18:29 +0200 Subject: [PATCH 121/353] Implemented empty builder for GraphView --- lib/l10n/arb/app_de.arb | 1 + lib/l10n/arb/app_en.arb | 6 ++- lib/l10n/generated/app_localizations.dart | 6 +++ lib/l10n/generated/app_localizations_de.dart | 4 ++ lib/l10n/generated/app_localizations_en.dart | 8 +++- lib/presentation/views/graph_view.dart | 46 ++++++++++++++------ pubspec.yaml | 2 +- 7 files changed, 54 insertions(+), 19 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index d89399b..acff3c1 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -85,6 +85,7 @@ "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", "game_process": "Spielverlauf", + "empty_graph_text": "Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", "settings": "Einstellungen", "cabo_penalty": "Cabo-Strafe", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index e01e242..4a0735a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -74,18 +74,20 @@ "done": "Done", "next_round": "Next Round", + "statistics": "Statistics", "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", "export_game": "Export Game", - - "game_process": "Spielverlauf", "id_error_title": "ID Error", "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", "end_game_title": "End the game?", "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", + "game_process": "Scoring History", + "empty_graph_text": "You must play at least two rounds for the game progress graph to be displayed.", + "settings": "Settings", "cabo_penalty": "Cabo Penalty", "cabo_penalty_subtitle": "... for falsely calling Cabo.", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index af778ae..c139891 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -476,6 +476,12 @@ abstract class AppLocalizations { /// **'Spielverlauf'** String get game_process; + /// No description provided for @empty_graph_text. + /// + /// In de, this message translates to: + /// **'Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'** + String get empty_graph_text; + /// No description provided for @settings. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index afe558f..b61feb0 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -210,6 +210,10 @@ class AppLocalizationsDe extends AppLocalizations { @override String get game_process => 'Spielverlauf'; + @override + String get empty_graph_text => + 'Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'; + @override String get settings => 'Einstellungen'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index a986058..fcfd494 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -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.'; @override - String get contact_email => 'Contac via E-Mail'; + String get contact_email => 'Contact via E-Mail'; @override String get email_subject => 'Feedback: Cabo Counter App'; @@ -205,7 +205,11 @@ class AppLocalizationsEn extends AppLocalizations { 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; @override - String get game_process => 'Spielverlauf'; + String get game_process => 'Scoring History'; + + @override + String get empty_graph_text => + 'You must play at least two rounds for the game progress graph to be displayed.'; @override String get settings => 'Settings'; diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 1007007..9ee0bbc 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -26,21 +26,39 @@ class _GraphViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).game_process), - previousPageTitle: AppLocalizations.of(context).back, - ), - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), - child: SfCartesianChart( - legend: - const Legend(isVisible: true, position: LegendPosition.bottom), - primaryXAxis: const NumericAxis(), - primaryYAxis: const NumericAxis(), - series: getCumulativeScores(), + navigationBar: CupertinoNavigationBar( + middle: Text(AppLocalizations.of(context).game_process), + previousPageTitle: AppLocalizations.of(context).back, ), - ), - ); + child: widget.gameSession.roundNumber > 2 + ? Padding( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: SfCartesianChart( + legend: const Legend( + isVisible: true, position: LegendPosition.bottom), + primaryXAxis: const NumericAxis(), + primaryYAxis: const NumericAxis(), + series: getCumulativeScores(), + ), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Center( + child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), + ), + const SizedBox(height: 10), // Abstand von oben + Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: Text( + AppLocalizations.of(context).empty_graph_text, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ), + ), + ], + )); } /// Returns a list of LineSeries representing the cumulative scores of each player. diff --git a/pubspec.yaml b/pubspec.yaml index 31146e6..802d487 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+467 +version: 0.4.0+470 environment: sdk: ^3.5.4 From 668328300ad4c4821529b1b17da7320af3ee91bc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 10:34:39 +0200 Subject: [PATCH 122/353] Added jitterStip to prevent the graphs overlaying each other --- lib/core/custom_theme.dart | 7 ++++++ lib/presentation/views/graph_view.dart | 34 ++++++++++++++++---------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 77a2f5b..259d5fd 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -6,6 +6,13 @@ class CustomTheme { static Color backgroundColor = const Color(0xFF101010); static Color backgroundTintColor = CupertinoColors.darkBackgroundGray; + // graph colors + static const Color graphColor1 = Color(0xFFF44336); + static const Color graphColor2 = Color(0xFF2196F3); //FF2196F3 + static const Color graphColor3 = Color(0xFFFFA726); //FFFFA726 + static const Color graphColor4 = Color(0xFF9C27B0); //9C27B0 + static final Color graphColor5 = primaryColor; + static TextStyle modeTitle = TextStyle( color: primaryColor, fontSize: 20, diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 9ee0bbc..1e91a98 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -1,7 +1,7 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; class GraphView extends StatefulWidget { @@ -15,12 +15,12 @@ class GraphView extends StatefulWidget { class _GraphViewState extends State { /// List of colors for the graph lines. - List lineColors = [ - Colors.red, - Colors.blue, - Colors.orange.shade400, - Colors.purple, - Colors.green, + final List lineColors = [ + CustomTheme.graphColor1, + CustomTheme.graphColor2, + CustomTheme.graphColor3, + CustomTheme.graphColor4, + CustomTheme.graphColor5 ]; @override @@ -36,7 +36,10 @@ class _GraphViewState extends State { child: SfCartesianChart( legend: const Legend( isVisible: true, position: LegendPosition.bottom), - primaryXAxis: const NumericAxis(), + primaryXAxis: const NumericAxis( + interval: 1, + decimalPlaces: 0, + ), primaryYAxis: const NumericAxis(), series: getCumulativeScores(), ), @@ -64,7 +67,7 @@ class _GraphViewState extends State { /// Returns a list of LineSeries representing the cumulative scores of each player. /// Each series contains data points for each round, showing the cumulative score up to that round. /// The x-axis represents the round number, and the y-axis represents the cumulative score. - List> getCumulativeScores() { + List> getCumulativeScores() { final rounds = widget.gameSession.roundList; final playerCount = widget.gameSession.players.length; final playerNames = widget.gameSession.players; @@ -79,21 +82,26 @@ class _GraphViewState extends State { } } + const double jitterStep = 0.15; + /// Create a list of LineSeries for each player /// Each series contains data points for each round return List.generate(playerCount, (i) { final data = List.generate( cumulativeScores[i].length, - (j) => (j + 1, cumulativeScores[i][j]), // (round, score) + (j) => ( + j + 1, + cumulativeScores[i][j] + (i - playerCount ~/ 2) * jitterStep + ), ); /// Create a LineSeries for the player /// The xValueMapper maps the round number, and the yValueMapper maps the cumulative score. - return LineSeries<(int, int), int>( + return LineSeries<(int, num), int>( name: playerNames[i], dataSource: data, - xValueMapper: (record, _) => record.$1, // Runde - yValueMapper: (record, _) => record.$2, // Punktestand + xValueMapper: (record, _) => record.$1, + yValueMapper: (record, _) => record.$2, markerSettings: const MarkerSettings(isVisible: true), color: lineColors[i], ); From 4448fd2c39df7a01f3f50f5a8e54351de8bf8580 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 10:44:21 +0200 Subject: [PATCH 123/353] Removed german comments --- lib/presentation/views/graph_view.dart | 2 +- lib/presentation/views/main_menu_view.dart | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 1e91a98..50fb12a 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -51,7 +51,7 @@ class _GraphViewState extends State { const Center( child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), ), - const SizedBox(height: 10), // Abstand von oben + const SizedBox(height: 10), Padding( padding: const EdgeInsets.symmetric(horizontal: 40), child: Text( diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 1f8b5d0..fa537c6 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -88,10 +88,9 @@ class _MainMenuViewState extends State { ? const Center(child: CupertinoActivityIndicator()) : gameManager.gameList.isEmpty ? Column( - mainAxisAlignment: - MainAxisAlignment.center, // Oben ausrichten + mainAxisAlignment: MainAxisAlignment.center, children: [ - const SizedBox(height: 30), // Abstand von oben + const SizedBox(height: 30), Center( child: GestureDetector( onTap: () => Navigator.push( @@ -107,7 +106,7 @@ class _MainMenuViewState extends State { color: CustomTheme.primaryColor, ), )), - const SizedBox(height: 10), // Abstand von oben + const SizedBox(height: 10), Padding( padding: const EdgeInsets.symmetric(horizontal: 70), From 5fa8d1fa3de4ce8fb186a65c1dc8255b6f5d77d7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 10:49:19 +0200 Subject: [PATCH 124/353] Added comment to jitter calculation --- lib/presentation/views/graph_view.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 50fb12a..7736bb1 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -91,6 +91,9 @@ class _GraphViewState extends State { cumulativeScores[i].length, (j) => ( j + 1, + + // Add a small jitter to the cumulative scores to prevent overlapping data points in the graph. + // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. cumulativeScores[i][j] + (i - playerCount ~/ 2) * jitterStep ), ); From 1494cb08a5943af1e36c2918d94798a1d901a18e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 10:50:11 +0200 Subject: [PATCH 125/353] Overhauled comments in CustomTheme --- lib/core/custom_theme.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 259d5fd..a00340b 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -6,11 +6,11 @@ class CustomTheme { static Color backgroundColor = const Color(0xFF101010); static Color backgroundTintColor = CupertinoColors.darkBackgroundGray; - // graph colors + // Line Colors for GraphView static const Color graphColor1 = Color(0xFFF44336); - static const Color graphColor2 = Color(0xFF2196F3); //FF2196F3 - static const Color graphColor3 = Color(0xFFFFA726); //FFFFA726 - static const Color graphColor4 = Color(0xFF9C27B0); //9C27B0 + static const Color graphColor2 = Color(0xFF2196F3); + static const Color graphColor3 = Color(0xFFFFA726); + static const Color graphColor4 = Color(0xFF9C27B0); static final Color graphColor5 = primaryColor; static TextStyle modeTitle = TextStyle( From ebe3dd6954506cc25f06e0dd2b73198f2a269b44 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 10:52:47 +0200 Subject: [PATCH 126/353] Updated version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 802d487..fbacd1e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+470 +version: 0.4.1+470 environment: sdk: ^3.5.4 From 55a61be44b2a3876a7b7fbee5ad244cf8f95d5ff Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 11:10:06 +0200 Subject: [PATCH 127/353] Added Delete all games button to Settings --- lib/l10n/arb/app_de.arb | 3 + lib/l10n/arb/app_en.arb | 3 + lib/l10n/generated/app_localizations.dart | 18 ++ lib/l10n/generated/app_localizations_de.dart | 10 + lib/l10n/generated/app_localizations_en.dart | 12 +- lib/presentation/views/settings_view.dart | 321 ++++++++++--------- pubspec.yaml | 2 +- 7 files changed, 222 insertions(+), 147 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index d89399b..113cce1 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -95,6 +95,9 @@ "game_data": "Spieldaten", "import_data": "Spieldaten importieren", "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", "import_success_title": "Import erfolgreich", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index e01e242..1f5fe3c 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -95,6 +95,9 @@ "game_data": "Game Data", "import_data": "Import 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", "import_success_title": "Import successful", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index af778ae..979d46b 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -530,6 +530,24 @@ abstract class AppLocalizations { /// **'Spieldaten exportieren'** 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. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index afe558f..c4b2491 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -237,6 +237,16 @@ class AppLocalizationsDe extends AppLocalizations { @override 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 String get app => 'App'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index a986058..3cbde9c 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -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.'; @override - String get contact_email => 'Contac via E-Mail'; + String get contact_email => 'Contact via E-Mail'; @override String get email_subject => 'Feedback: Cabo Counter App'; @@ -234,6 +234,16 @@ class AppLocalizationsEn extends AppLocalizations { @override 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 String get app => 'App'; diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 9bed7fc..ab8ec7d 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -32,162 +32,193 @@ class _SettingsViewState extends State { middle: Text(AppLocalizations.of(context).settings), ), child: SafeArea( - child: Stack( - children: [ - 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, - ), + 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: 'Cabo-Strafe', - prefixIcon: CupertinoIcons.bolt_fill, - suffixWidget: CustomStepper( - key: _stepperKey1, - initialValue: ConfigService.caboPenalty, - minValue: 0, - maxValue: 50, - step: 1, - onChanged: (newCaboPenalty) { - setState(() { - 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(); + ), + 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.caboPenalty, + minValue: 0, + maxValue: 50, + step: 1, + onChanged: (newCaboPenalty) { setState(() { - _stepperKey1 = UniqueKey(); - _stepperKey2 = UniqueKey(); + ConfigService.setCaboPenalty(newCaboPenalty); + ConfigService.caboPenalty = newCaboPenalty; }); }, - ) - ])), - 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); + ), + ), + CustomFormRow( + prefixText: AppLocalizations.of(context).point_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; + }); }, - suffixWidget: const CupertinoListTileChevron(), ), - CustomFormRow( - prefixText: AppLocalizations.of(context).export_data, - prefixIcon: CupertinoIcons.square_arrow_up, - onPressed: () => LocalStorageService.exportGameData(), - suffixWidget: const CupertinoListTileChevron(), - ), - ])), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).app, - style: CustomTheme.rowTitle, - ), + ), + CustomFormRow( + prefixText: + AppLocalizations.of(context).reset_to_default, + prefixIcon: CupertinoIcons.arrow_counterclockwise, + onPressed: () { + ConfigService.resetConfig(); + setState(() { + _stepperKey1 = UniqueKey(); + _stepperKey2 = UniqueKey(); + }); + }, + ) + ])), + 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), - child: CupertinoFormSection.insetGrouped( - backgroundColor: CustomTheme.backgroundColor, - margin: EdgeInsets.zero, - children: [ - CustomFormRow( - 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, - ))), - ])), - ], - ), - ], + ), + 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.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) { if (status == ImportStatus.canceled) return; final (title, message) = _getDialogContent(status); diff --git a/pubspec.yaml b/pubspec.yaml index 31146e6..ca5ef95 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+467 +version: 0.4.2+470 environment: sdk: ^3.5.4 From 9e0b8f937420588bfc212e915b58c7503bcfe3c6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 11:12:44 +0200 Subject: [PATCH 128/353] Updated version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 1f8766a..12dae39 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.1+473 +version: 0.4.2+473 environment: sdk: ^3.5.4 From 00b9ac62f73b3226e8b21de265e2ba921d2e5a81 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 11:16:12 +0200 Subject: [PATCH 129/353] Updated en string --- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/generated/app_localizations_en.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 27efba1..782008a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -99,7 +99,7 @@ "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.", + "delete_data_message": "Are you sure you want to delete all game data? This action cannot be undone.", "app": "App", "import_success_title": "Import successful", diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 983a90e..138c633 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -246,7 +246,7 @@ class AppLocalizationsEn extends AppLocalizations { @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.'; + 'Are you sure you want to delete all game data? This action cannot be undone.'; @override String get app => 'App'; From 340a02207086e73ddf64375f1815b5dff701d586 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 11:40:26 +0200 Subject: [PATCH 130/353] Updated RoundView buttons when game is finished --- lib/presentation/views/round_view.dart | 33 ++++++++++++++------------ pubspec.yaml | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 1e02cc3..6a31c2a 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -73,7 +73,8 @@ class _RoundViewState extends State { resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( transitionBetweenRoutes: true, - middle: Text(AppLocalizations.of(context).results), + middle: Text( + '${AppLocalizations.of(context).results}${gameSession.isGameFinished ? ' \u{1F512}' : ''}'), leading: CupertinoButton( padding: EdgeInsets.zero, onPressed: () => @@ -293,21 +294,23 @@ class _RoundViewState extends State { : null, child: Text(AppLocalizations.of(context).done), ), - CupertinoButton( - onPressed: _areRoundInputsValid() - ? () { - _finishRound(); - LocalStorageService.saveGameSessions(); - if (widget.gameSession.isGameFinished == true) { - Navigator.pop(context); - } else { - Navigator.pop( - context, widget.roundNumber + 1); + if (!widget.gameSession.isGameFinished) + CupertinoButton( + onPressed: _areRoundInputsValid() + ? () { + _finishRound(); + LocalStorageService.saveGameSessions(); + if (widget.gameSession.isGameFinished == + true) { + Navigator.pop(context); + } else { + Navigator.pop( + context, widget.roundNumber + 1); + } } - } - : null, - child: Text(AppLocalizations.of(context).next_round), - ), + : null, + child: Text(AppLocalizations.of(context).next_round), + ), ], ), ); diff --git a/pubspec.yaml b/pubspec.yaml index 12dae39..71d96fb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.2+473 +version: 0.4.2+474 environment: sdk: ^3.5.4 From 5a1c3ef09aaaabaa3a28af138a67656c2b2595ff Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 11:51:21 +0200 Subject: [PATCH 131/353] Changed lock emoji to CuperinoIcons.lock and placed it in trailing of app bar --- lib/presentation/views/round_view.dart | 9 +++++++-- pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 6a31c2a..0f4e809 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -73,14 +73,19 @@ class _RoundViewState extends State { resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( transitionBetweenRoutes: true, - middle: Text( - '${AppLocalizations.of(context).results}${gameSession.isGameFinished ? ' \u{1F512}' : ''}'), leading: CupertinoButton( padding: EdgeInsets.zero, onPressed: () => {LocalStorageService.saveGameSessions(), Navigator.pop(context)}, child: Text(AppLocalizations.of(context).cancel), ), + middle: Text(AppLocalizations.of(context).results), + trailing: widget.gameSession.isGameFinished + ? const Icon( + CupertinoIcons.lock, + size: 25, + ) + : null, ), child: Stack( children: [ diff --git a/pubspec.yaml b/pubspec.yaml index 71d96fb..553ec0f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.2+474 +version: 0.4.2+476 environment: sdk: ^3.5.4 From df3a16151d39200ce1aa338d4c264af2b64667c8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 11:51:54 +0200 Subject: [PATCH 132/353] Simplified comparison --- lib/presentation/views/round_view.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 0f4e809..b4d2212 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -305,8 +305,7 @@ class _RoundViewState extends State { ? () { _finishRound(); LocalStorageService.saveGameSessions(); - if (widget.gameSession.isGameFinished == - true) { + if (widget.gameSession.isGameFinished) { Navigator.pop(context); } else { Navigator.pop( From 1e1601e431920f3a5b2958c8d493aa0424cc1720 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 11:52:23 +0200 Subject: [PATCH 133/353] Updated version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 553ec0f..8e8a264 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.2+476 +version: 0.4.3+476 environment: sdk: ^3.5.4 From cf0d7af343ced4affd85b195b0e5b46fb46fb6e9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 13:56:02 +0200 Subject: [PATCH 134/353] Corrected scaling --- lib/presentation/views/round_view.dart | 36 +++----------------------- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index b4d2212..39e5cc8 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -67,7 +67,6 @@ class _RoundViewState extends State { @override Widget build(BuildContext context) { final bottomInset = MediaQuery.of(context).viewInsets.bottom; - final maxLength = widget.gameSession.getMaxLengthOfPlayerNames(); return CupertinoPageScaffold( resizeToAvoidBottomInset: false, @@ -126,9 +125,8 @@ class _RoundViewState extends State { return MapEntry( index, Padding( - padding: EdgeInsets.symmetric( - horizontal: 4 + - _getSegmentedControlPadding(maxLength), + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 6, ), child: FittedBox( @@ -137,10 +135,8 @@ class _RoundViewState extends State { name, textAlign: TextAlign.center, maxLines: 1, - style: TextStyle( + style: const TextStyle( fontWeight: FontWeight.bold, - fontSize: _getSegmentedControlFontSize( - maxLength), ), ), ), @@ -393,32 +389,6 @@ class _RoundViewState extends State { } } - double _getSegmentedControlFontSize(int maxLength) { - if (maxLength > 8) { - // 9 - 12 characters - return 9.0; - } else if (maxLength > 4) { - // 5 - 8 characters - return 15.0; - } else { - // 0 - 4 characters - return 18.0; - } - } - - double _getSegmentedControlPadding(int maxLength) { - if (maxLength > 8) { - // 9 - 12 characters - return 0.0; - } else if (maxLength > 4) { - // 5 - 8 characters - return 5.0; - } else { - // 0 - 4 characters - return 8.0; - } - } - @override void dispose() { for (final controller in _scoreControllerList) { diff --git a/pubspec.yaml b/pubspec.yaml index 8e8a264..ab51129 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.3+476 +version: 0.4.3+477 environment: sdk: ^3.5.4 From 546ac1d9967e7d289eb9af82bd8f2ca697d09d40 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 11 Jul 2025 14:06:06 +0200 Subject: [PATCH 135/353] Updates constant names and lint rule --- analysis_options.yaml | 1 - lib/core/constants.dart | 12 ++++++------ lib/presentation/views/about_view.dart | 6 +++--- lib/presentation/views/main_menu_view.dart | 2 +- lib/presentation/views/settings_view.dart | 6 +++--- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 46e2dbe..b3623a1 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,4 +11,3 @@ linter: prefer_const_literals_to_create_immutables: true unnecessary_const: true lines_longer_than_80_chars: false - constant_identifier_names: false diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 5b6e90e..e716464 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -3,14 +3,14 @@ import 'package:rate_my_app/rate_my_app.dart'; class Constants { static const String appDevPhase = 'Beta'; - static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de'; - static const String GITHUB_LINK = 'https://github.felixkirchner.de'; - static const String GITHUB_ISSUES_LINK = + static const String kInstagramLink = 'https://instagram.felixkirchner.de'; + static const String kGithubLink = 'https://github.felixkirchner.de'; + static const String kGithubIssuesLink = 'https://cabocounter-issues.felixkirchner.de'; - static const String GITHUB_WIKI_LINK = + static const String kGithubWikiLink = 'https://cabocounter-wiki.felixkirchner.de'; - static const String EMAIL = 'cabocounter@felixkirchner.de'; - static const String PRIVACY_POLICY_LINK = + static const String kEmail = 'cabocounter@felixkirchner.de'; + static const String kPrivacyPolicyLink = 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; static RateMyApp rateMyApp = RateMyApp( diff --git a/lib/presentation/views/about_view.dart b/lib/presentation/views/about_view.dart index 128f91f..481e294 100644 --- a/lib/presentation/views/about_view.dart +++ b/lib/presentation/views/about_view.dart @@ -60,15 +60,15 @@ class AboutView extends StatelessWidget { children: [ IconButton( onPressed: () => - launchUrl(Uri.parse(Constants.INSTAGRAM_LINK)), + launchUrl(Uri.parse(Constants.kInstagramLink)), icon: const Icon(FontAwesomeIcons.instagram)), IconButton( onPressed: () => - launchUrl(Uri.parse('mailto:${Constants.EMAIL}')), + launchUrl(Uri.parse('mailto:${Constants.kEmail}')), icon: const Icon(CupertinoIcons.envelope)), IconButton( onPressed: () => - launchUrl(Uri.parse(Constants.GITHUB_LINK)), + launchUrl(Uri.parse(Constants.kGithubLink)), icon: const Icon(FontAwesomeIcons.github)), ], ), diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index fa537c6..86ff208 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -227,7 +227,7 @@ class _MainMenuViewState extends State { final Uri emailUri = Uri( scheme: 'mailto', - path: Constants.EMAIL, + path: Constants.kEmail, query: 'subject=$emailSubject' '&body=$emailBody', ); diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index ab8ec7d..d6f0833 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -149,21 +149,21 @@ class _SettingsViewState extends State { prefixText: AppLocalizations.of(context).wiki, prefixIcon: CupertinoIcons.book, onPressed: () => - launchUrl(Uri.parse(Constants.GITHUB_WIKI_LINK)), + launchUrl(Uri.parse(Constants.kGithubWikiLink)), suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( prefixText: AppLocalizations.of(context).privacy_policy, prefixIcon: CupertinoIcons.doc_append, onPressed: () => - launchUrl(Uri.parse(Constants.PRIVACY_POLICY_LINK)), + launchUrl(Uri.parse(Constants.kPrivacyPolicyLink)), suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( prefixText: AppLocalizations.of(context).error_found, prefixIcon: FontAwesomeIcons.github, onPressed: () => - launchUrl(Uri.parse(Constants.GITHUB_ISSUES_LINK)), + launchUrl(Uri.parse(Constants.kGithubIssuesLink)), suffixWidget: const CupertinoListTileChevron(), ), CustomFormRow( From c155d8c5cadec5cadda27d925dfa7472d2d84b6f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 12 Jul 2025 20:46:32 +0200 Subject: [PATCH 136/353] HOTFIX: Graph showed wrong data --- lib/presentation/views/graph_view.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 7736bb1..e9ed4d1 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -77,7 +77,7 @@ class _GraphViewState extends State { for (var round in rounds) { for (int i = 0; i < playerCount; i++) { - runningTotals[i] += round.scores[i]; + runningTotals[i] += round.scoreUpdates[i]; cumulativeScores[i].add(runningTotals[i]); } } diff --git a/pubspec.yaml b/pubspec.yaml index ab51129..2f82cdf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.3+477 +version: 0.4.3+479 environment: sdk: ^3.5.4 From b9c3e1dd4e70ba142569637b23f76b78867acc19 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 12 Jul 2025 21:03:27 +0200 Subject: [PATCH 137/353] Graph starts at round 0 now where all players have 0 points --- lib/presentation/views/graph_view.dart | 25 +++++++++++++++++++------ pubspec.yaml | 2 +- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index e9ed4d1..4c03dd4 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -88,15 +88,28 @@ class _GraphViewState extends State { /// Each series contains data points for each round return List.generate(playerCount, (i) { final data = List.generate( + cumulativeScores[i].length + 1, + (j) => ( + j, + j == 0 + ? 0 // 0 Points at at the start of the game + + // Adds a small jitter to the cumulative scores to prevent overlapping data points in the graph. + // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. + : cumulativeScores[i][j - 1] + (i - playerCount ~/ 2) * jitterStep + ), + ); /*List.generate( cumulativeScores[i].length, (j) => ( - j + 1, - - // Add a small jitter to the cumulative scores to prevent overlapping data points in the graph. - // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. - cumulativeScores[i][j] + (i - playerCount ~/ 2) * jitterStep + j, + j == 0 + ? 0 // In Runde 0 immer 0 Punkte + : + // Add a small jitter to the cumulative scores to prevent overlapping data points in the graph. + // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. + cumulativeScores[i][j] + (i - playerCount ~/ 2) * jitterStep ), - ); + );*/ /// Create a LineSeries for the player /// The xValueMapper maps the round number, and the yValueMapper maps the cumulative score. diff --git a/pubspec.yaml b/pubspec.yaml index 2f82cdf..1440d14 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.3+479 +version: 0.4.3+481 environment: sdk: ^3.5.4 From 5780155954c386d11ff81ab411b8fd5290a4b574 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 12 Jul 2025 21:03:51 +0200 Subject: [PATCH 138/353] Adjusted jitterStep --- lib/presentation/views/graph_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 4c03dd4..9fa4e0a 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -82,7 +82,7 @@ class _GraphViewState extends State { } } - const double jitterStep = 0.15; + const double jitterStep = 0.05; /// Create a list of LineSeries for each player /// Each series contains data points for each round From 97da4cadffa6efa410cf41a034529ccc14acd038 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 00:21:37 +0200 Subject: [PATCH 139/353] Removed dead code --- lib/presentation/views/graph_view.dart | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 9fa4e0a..a6e6042 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -98,18 +98,7 @@ class _GraphViewState extends State { // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. : cumulativeScores[i][j - 1] + (i - playerCount ~/ 2) * jitterStep ), - ); /*List.generate( - cumulativeScores[i].length, - (j) => ( - j, - j == 0 - ? 0 // In Runde 0 immer 0 Punkte - : - // Add a small jitter to the cumulative scores to prevent overlapping data points in the graph. - // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. - cumulativeScores[i][j] + (i - playerCount ~/ 2) * jitterStep - ), - );*/ + ); /// Create a LineSeries for the player /// The xValueMapper maps the round number, and the yValueMapper maps the cumulative score. From 0b1b71e227f7785a00a41e1dfd383ab72ae5dd62 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 00:37:16 +0200 Subject: [PATCH 140/353] Updated Y-Axis and removed values under y = 0 --- lib/presentation/views/graph_view.dart | 11 +++++++---- pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index a6e6042..21f37d8 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -40,7 +40,10 @@ class _GraphViewState extends State { interval: 1, decimalPlaces: 0, ), - primaryYAxis: const NumericAxis(), + primaryYAxis: const NumericAxis( + interval: 1, + decimalPlaces: 0, + ), series: getCumulativeScores(), ), ) @@ -82,7 +85,7 @@ class _GraphViewState extends State { } } - const double jitterStep = 0.05; + const double jitterStep = 0.03; /// Create a list of LineSeries for each player /// Each series contains data points for each round @@ -91,8 +94,8 @@ class _GraphViewState extends State { cumulativeScores[i].length + 1, (j) => ( j, - j == 0 - ? 0 // 0 Points at at the start of the game + j == 0 || cumulativeScores[i][j - 1] == 0 + ? 0 // 0 Points at at the start of the game OR value is 0 (dont subtract jitter step) // Adds a small jitter to the cumulative scores to prevent overlapping data points in the graph. // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. diff --git a/pubspec.yaml b/pubspec.yaml index 1440d14..c793316 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.3+481 +version: 0.4.3+483 environment: sdk: ^3.5.4 From af630539dbf31edd8d6298f6ba20106c8cfe0d21 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 00:46:32 +0200 Subject: [PATCH 141/353] Changed overflow mode --- lib/presentation/views/graph_view.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 21f37d8..09aba16 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -35,7 +35,9 @@ class _GraphViewState extends State { padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), child: SfCartesianChart( legend: const Legend( - isVisible: true, position: LegendPosition.bottom), + overflowMode: LegendItemOverflowMode.wrap, + isVisible: true, + position: LegendPosition.bottom), primaryXAxis: const NumericAxis( interval: 1, decimalPlaces: 0, From 7733d3bd5c8ba7f4c8f11dd4b3dca22ad52fac65 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 00:55:28 +0200 Subject: [PATCH 142/353] Replaced string & if statement with visibility widget --- lib/presentation/views/active_game_view.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 9ecae1b..704952a 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -121,7 +121,7 @@ class _ActiveGameViewState extends State { children: [ CupertinoListTile( title: Text( - AppLocalizations.of(context).statistics, + AppLocalizations.of(context).game_process, ), backgroundColorActivated: CustomTheme.backgroundColor, @@ -131,8 +131,9 @@ class _ActiveGameViewState extends State { builder: (_) => GraphView( gameSession: gameSession, )))), - if (!gameSession.isPointsLimitEnabled) - CupertinoListTile( + Visibility( + visible: !gameSession.isPointsLimitEnabled, + child: CupertinoListTile( title: Text( AppLocalizations.of(context).end_game, style: gameSession.roundNumber > 1 && @@ -148,6 +149,7 @@ class _ActiveGameViewState extends State { _showEndGameDialog(); } }), + ), CupertinoListTile( title: Text( AppLocalizations.of(context).delete_game, From fee6cc3a339f45c503255627f3c8bd01b5a77716 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 00:56:32 +0200 Subject: [PATCH 143/353] updated accessability of graph view --- lib/presentation/views/graph_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 09aba16..fe36de9 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -30,7 +30,7 @@ class _GraphViewState extends State { middle: Text(AppLocalizations.of(context).game_process), previousPageTitle: AppLocalizations.of(context).back, ), - child: widget.gameSession.roundNumber > 2 + child: widget.gameSession.roundNumber > 1 ? Padding( padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), child: SfCartesianChart( From ee5319533a9e6f16b755e1469169bfb8617e5a90 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 00:57:08 +0200 Subject: [PATCH 144/353] Changed string for GraphView title --- lib/l10n/arb/app_de.arb | 3 +-- lib/l10n/arb/app_en.arb | 4 +--- lib/l10n/generated/app_localizations.dart | 2 +- lib/l10n/generated/app_localizations_de.dart | 2 +- lib/l10n/generated/app_localizations_en.dart | 2 +- pubspec.yaml | 2 +- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 4b55a8d..b072d63 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -74,7 +74,6 @@ "done": "Fertig", "next_round": "Nächste Runde", - "statistics": "Statistiken", "end_game": "Spiel beenden", "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", @@ -85,7 +84,7 @@ "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", "game_process": "Spielverlauf", - "empty_graph_text": "Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", + "empty_graph_text": "Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", "settings": "Einstellungen", "cabo_penalty": "Cabo-Strafe", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 782008a..a649362 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -74,8 +74,6 @@ "done": "Done", "next_round": "Next Round", - - "statistics": "Statistics", "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", @@ -86,7 +84,7 @@ "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", "game_process": "Scoring History", - "empty_graph_text": "You must play at least two rounds for the game progress graph to be displayed.", + "empty_graph_text": "You must play at least one round for the game progress graph to be displayed.", "settings": "Settings", "cabo_penalty": "Cabo Penalty", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index d805b45..c54cca0 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -479,7 +479,7 @@ abstract class AppLocalizations { /// No description provided for @empty_graph_text. /// /// In de, this message translates to: - /// **'Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'** + /// **'Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'** String get empty_graph_text; /// No description provided for @settings. diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 4acdb1c..7bd7af0 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -212,7 +212,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get empty_graph_text => - 'Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'; + 'Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'; @override String get settings => 'Einstellungen'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 138c633..5403a95 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -209,7 +209,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get empty_graph_text => - 'You must play at least two rounds for the game progress graph to be displayed.'; + 'You must play at least one round for the game progress graph to be displayed.'; @override String get settings => 'Settings'; diff --git a/pubspec.yaml b/pubspec.yaml index c793316..8241466 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.3+483 +version: 0.4.4+484 environment: sdk: ^3.5.4 From 1157ab70ec41a30e93500c1a7143ff57c1b7b27a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 11:49:47 +0200 Subject: [PATCH 145/353] Updated comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- lib/presentation/views/graph_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index fe36de9..d322bd0 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -97,7 +97,7 @@ class _GraphViewState extends State { (j) => ( j, j == 0 || cumulativeScores[i][j - 1] == 0 - ? 0 // 0 Points at at the start of the game OR value is 0 (dont subtract jitter step) + ? 0 // 0 points at the start of the game or when the value is 0 (don't subtract jitter step) // Adds a small jitter to the cumulative scores to prevent overlapping data points in the graph. // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. From 75568a1a4bf3657bdd8bdf6ddfece0339dfcb85e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 11:55:46 +0200 Subject: [PATCH 146/353] Updated generated files --- lib/l10n/generated/app_localizations.dart | 6 ------ lib/l10n/generated/app_localizations_de.dart | 3 --- lib/l10n/generated/app_localizations_en.dart | 3 --- pubspec.yaml | 2 +- 4 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index c54cca0..2059f1b 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -416,12 +416,6 @@ abstract class AppLocalizations { /// **'Nächste Runde'** String get next_round; - /// No description provided for @statistics. - /// - /// In de, this message translates to: - /// **'Statistiken'** - String get statistics; - /// No description provided for @end_game. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 7bd7af0..068711f 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -178,9 +178,6 @@ class AppLocalizationsDe extends AppLocalizations { @override String get next_round => 'Nächste Runde'; - @override - String get statistics => 'Statistiken'; - @override String get end_game => 'Spiel beenden'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 5403a95..06b5c03 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -175,9 +175,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get next_round => 'Next Round'; - @override - String get statistics => 'Statistics'; - @override String get end_game => 'End Game'; diff --git a/pubspec.yaml b/pubspec.yaml index 8241466..da2c087 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.4+484 +version: 0.4.4+485 environment: sdk: ^3.5.4 From 01e0c70ac89e52c07e0223a303915d5633265612 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 12:30:34 +0200 Subject: [PATCH 147/353] Updated version in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20b0cae..23ec7d3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.3.8-orange) +![Version](https://img.shields.io/badge/Version-0.4.4-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) From 8565382fab793c55cac5981a34826601a4293bd0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 12:48:24 +0200 Subject: [PATCH 148/353] Beta-Version 0.4.4 (#105) * Update README.md * Tried new design for im- and export-button * Moved views to presentation folder * Moved widgets to presentation folder * Implemented CustomRowForm Widget * Used new custom form row * Removed double information * Refactored methods to private * Changed label * Modified paddings and text color * Changed string * Updated CustomFormRow padding and pressed handler * Implemented various new forms of CustomFormRow into SettingsView * Implemented VersionService * Updated strings, added wiki button * Corrected replaced string * Added import dialog feedback (got lost in refactoring) * Corrected function duplication * changed suffixWidget assignment and moved stepperKeys * Changed icons * Added rate_my_app package * Renamed folder * Implement native rating dialog * Implemented logic for pre rating and refactored rating dialog * updated launch mode * Small changes * Updated launch mode * Updated linting rules * Renamed folders * Changed l10n files location * Implemented new link constants * Changed privacy policy link * Corrected wiki link * Removed import * Updated links * Updated links to subdomains * Updated file paths * Updated strings * Updated identifiers * Added break in switch case * Updated strings * Implemented new popup * Corrected links * Changed color * Ensured rating dialog wont show in Beta * Refactoring * Adding const * Renamed variables * Corrected links * updated Dialog function * Added version number in about view * Changed order and corrected return * Changed translation * Changed popups because of unmounted context errors * corrected string typo * Replaced int constants with enums * Renamed Stepper to CustomStepper * Changed argument order * Reordered properties * Implemented empty builder for GraphView * Added jitterStip to prevent the graphs overlaying each other * Removed german comments * Added comment to jitter calculation * Overhauled comments in CustomTheme * Updated version * Added Delete all games button to Settings * Updated version * Updated en string * Updated RoundView buttons when game is finished * Changed lock emoji to CuperinoIcons.lock and placed it in trailing of app bar * Simplified comparison * Updated version * Corrected scaling * Updates constant names and lint rule * HOTFIX: Graph showed wrong data * Graph starts at round 0 now where all players have 0 points * Adjusted jitterStep * Removed dead code * Updated Y-Axis and removed values under y = 0 * Changed overflow mode * Replaced string & if statement with visibility widget * updated accessability of graph view * Changed string for GraphView title * Updated comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Updated generated files * Updated version in README --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- analysis_options.yaml | 3 - l10n.yaml | 7 +- lib/core/constants.dart | 22 ++ lib/{utility => core}/custom_theme.dart | 7 + lib/l10n/{ => arb}/app_de.arb | 29 +- lib/l10n/{ => arb}/app_en.arb | 33 ++- lib/l10n/{ => arb}/untranslated_messages.json | 0 .../{ => generated}/app_localizations.dart | 116 +++++++- .../{ => generated}/app_localizations_de.dart | 63 +++- .../{ => generated}/app_localizations_en.dart | 61 +++- lib/main.dart | 8 +- .../views/about_view.dart} | 22 +- .../views/active_game_view.dart | 21 +- .../views/create_game_view.dart | 8 +- lib/presentation/views/graph_view.dart | 120 ++++++++ .../views/main_menu_view.dart | 202 ++++++++++--- .../views/mode_selection_view.dart | 4 +- lib/{ => presentation}/views/round_view.dart | 77 ++--- lib/presentation/views/settings_view.dart | 269 ++++++++++++++++++ lib/{ => presentation}/views/tab_view.dart | 10 +- lib/presentation/widgets/custom_form_row.dart | 53 ++++ .../widgets/custom_stepper.dart} | 17 +- lib/services/local_storage_service.dart | 26 +- lib/services/version_service.dart | 32 +++ lib/utility/globals.dart | 3 - lib/views/graph_view.dart | 84 ------ lib/views/settings_view.dart | 267 ----------------- pubspec.yaml | 3 +- 29 files changed, 1024 insertions(+), 545 deletions(-) create mode 100644 lib/core/constants.dart rename lib/{utility => core}/custom_theme.dart (71%) rename lib/l10n/{ => arb}/app_de.arb (80%) rename lib/l10n/{ => arb}/app_en.arb (80%) rename lib/l10n/{ => arb}/untranslated_messages.json (100%) rename lib/l10n/{ => generated}/app_localizations.dart (85%) rename lib/l10n/{ => generated}/app_localizations_de.dart (81%) rename lib/l10n/{ => generated}/app_localizations_en.dart (80%) rename lib/{views/information_view.dart => presentation/views/about_view.dart} (74%) rename lib/{ => presentation}/views/active_game_view.dart (95%) rename lib/{ => presentation}/views/create_game_view.dart (97%) create mode 100644 lib/presentation/views/graph_view.dart rename lib/{ => presentation}/views/main_menu_view.dart (57%) rename lib/{ => presentation}/views/mode_selection_view.dart (92%) rename lib/{ => presentation}/views/round_view.dart (89%) create mode 100644 lib/presentation/views/settings_view.dart rename lib/{ => presentation}/views/tab_view.dart (80%) create mode 100644 lib/presentation/widgets/custom_form_row.dart rename lib/{widgets/stepper.dart => presentation/widgets/custom_stepper.dart} (75%) create mode 100644 lib/services/version_service.dart delete mode 100644 lib/utility/globals.dart delete mode 100644 lib/views/graph_view.dart delete mode 100644 lib/views/settings_view.dart diff --git a/README.md b/README.md index 20b0cae..23ec7d3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.3.8-orange) +![Version](https://img.shields.io/badge/Version-0.4.4-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) diff --git a/analysis_options.yaml b/analysis_options.yaml index 2ce6b52..b3623a1 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,6 +11,3 @@ linter: prefer_const_literals_to_create_immutables: true unnecessary_const: true lines_longer_than_80_chars: false - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/l10n.yaml b/l10n.yaml index 239fdc6..f69305d 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,5 +1,6 @@ -arb-dir: lib/l10n +arb-dir: lib/l10n/arb template-arb-file: app_de.arb -untranslated-messages-file: lib/l10n/untranslated_messages.json +untranslated-messages-file: lib/l10n/arb/untranslated_messages.json nullable-getter: false -output-localization-file: app_localizations.dart \ No newline at end of file +output-localization-file: app_localizations.dart +output-dir: lib/l10n/generated \ No newline at end of file diff --git a/lib/core/constants.dart b/lib/core/constants.dart new file mode 100644 index 0000000..e716464 --- /dev/null +++ b/lib/core/constants.dart @@ -0,0 +1,22 @@ +import 'package:rate_my_app/rate_my_app.dart'; + +class Constants { + static const String appDevPhase = 'Beta'; + + static const String kInstagramLink = 'https://instagram.felixkirchner.de'; + static const String kGithubLink = 'https://github.felixkirchner.de'; + static const String kGithubIssuesLink = + 'https://cabocounter-issues.felixkirchner.de'; + static const String kGithubWikiLink = + 'https://cabocounter-wiki.felixkirchner.de'; + static const String kEmail = 'cabocounter@felixkirchner.de'; + static const String kPrivacyPolicyLink = + 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; + + static RateMyApp rateMyApp = RateMyApp( + appStoreIdentifier: '6747105718', + minDays: 15, + remindDays: 45, + minLaunches: 15, + remindLaunches: 40); +} diff --git a/lib/utility/custom_theme.dart b/lib/core/custom_theme.dart similarity index 71% rename from lib/utility/custom_theme.dart rename to lib/core/custom_theme.dart index 77a2f5b..a00340b 100644 --- a/lib/utility/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -6,6 +6,13 @@ class CustomTheme { static Color backgroundColor = const Color(0xFF101010); static Color backgroundTintColor = CupertinoColors.darkBackgroundGray; + // Line Colors for GraphView + static const Color graphColor1 = Color(0xFFF44336); + static const Color graphColor2 = Color(0xFF2196F3); + static const Color graphColor3 = Color(0xFFFFA726); + static const Color graphColor4 = Color(0xFF9C27B0); + static final Color graphColor5 = primaryColor; + static TextStyle modeTitle = TextStyle( color: primaryColor, fontSize: 20, diff --git a/lib/l10n/app_de.arb b/lib/l10n/arb/app_de.arb similarity index 80% rename from lib/l10n/app_de.arb rename to lib/l10n/arb/app_de.arb index 9281ac1..b072d63 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -30,6 +30,16 @@ } } }, + "pre_rating_title": "Gefällt dir die App?", + "pre_rating_message": "Feedback hilft mir, die App zu verbessern. Vielen Dank!", + "yes": "Ja", + "no": "Nein", + "bad_rating_title": "Unzufrieden mit der App?", + "bad_rating_message": "Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!", + "contact_email": "E-Mail schreiben", + "email_subject": "Feedback: Cabo Counter App", + "email_body": "Ich habe folgendes Feedback...", + "overview": "Übersicht", "new_game": "Neues Spiel", "game_title": "Titel des Spiels", @@ -64,7 +74,6 @@ "done": "Fertig", "next_round": "Nächste Runde", - "statistics": "Statistiken", "end_game": "Spiel beenden", "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", @@ -75,6 +84,7 @@ "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", "game_process": "Spielverlauf", + "empty_graph_text": "Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", "settings": "Einstellungen", "cabo_penalty": "Cabo-Strafe", @@ -83,8 +93,12 @@ "point_limit_subtitle": "... hier ist Schluss", "reset_to_default": "Auf Standard zurücksetzen", "game_data": "Spieldaten", - "import_data": "Daten importieren", - "export_data": "Daten exportieren", + "import_data": "Spieldaten importieren", + "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", "import_success_title": "Import erfolgreich", "import_success_message":"Die Spieldaten wurden erfolgreich importiert.", @@ -92,16 +106,19 @@ "import_validation_error_message": "Es wurden keine Cabo-Counter Spieldaten gefunden. Bitte stellen Sie sicher, dass es sich um eine gültige Cabo-Counter Exportdatei handelt.", "import_format_error_title": "Falsches Format", "import_format_error_message": "Die Datei ist kein gültiges JSON-Format oder enthält ungültige Daten.", - "import_generic_error_title": "Import fehlgeschlagen", + "import_generic_error_title": "Import fehlgeschlagen", "import_generic_error_message": "Der Import ist fehlgeschlagen.", "export_error_title": "Fehler", "export_error_message": "Datei konnte nicht exportiert werden", + "error_found": "Fehler gefunden?", "create_issue": "Issue erstellen", + "wiki": "Wiki", "app_version": "App-Version", - "build": "Build", - "load_version": "Lade Version...", + "privacy_policy": "Datenschutzerklärung", + "build": "Build-Nr.", + "loading": "Lädt...", "about_text": "Hey :) Danke, dass du als eine:r der ersten User meiner ersten eigenen App dabei bist! Ich hab sehr viel Arbeit in dieses Projekt gesteckt und auch, wenn ich (hoffentlich) an vieles Gedacht hab, wird auf jeden Fall noch nicht alles 100% funktionieren. Solltest du also irgendwelche Fehler entdecken oder Feedback zum Design oder der Benutzerfreundlichkeit haben, teile Sie mir gern über die Testflight App oder auf den dir bekannten Wegen mit. Danke! " } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/arb/app_en.arb similarity index 80% rename from lib/l10n/app_en.arb rename to lib/l10n/arb/app_en.arb index 8b328ba..a649362 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -30,6 +30,16 @@ } } }, + "pre_rating_title": "Do you like the app?", + "pre_rating_message": "Feedback helps me to continuously improve the app. Thank you!", + "yes": "Yes", + "no": "No", + "bad_rating_title": "Not satisfied?", + "bad_rating_message": "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.", + "contact_email": "Contact via E-Mail", + "email_subject": "Feedback: Cabo Counter App", + "email_body": "I have the following feedback...", + "overview": "Overview", "new_game": "New Game", "game_title": "Game Title", @@ -64,13 +74,17 @@ "done": "Done", "next_round": "Next Round", - "statistics": "Statistics", "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", "export_game": "Export Game", + "id_error_title": "ID Error", + "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", + "end_game_title": "End the game?", + "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", - "game_process": "Spielverlauf", + "game_process": "Scoring History", + "empty_graph_text": "You must play at least one round for the game progress graph to be displayed.", "settings": "Settings", "cabo_penalty": "Cabo Penalty", @@ -81,10 +95,10 @@ "game_data": "Game Data", "import_data": "Import Data", "export_data": "Export Data", - "id_error_title": "ID Error", - "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", - "end_game_title": "End the game?", - "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", + "delete_data": "Delete all Game Data", + "delete_data_title": "Delete game data?", + "delete_data_message": "Are you sure you want to delete all game data? This action cannot be undone.", + "app": "App", "import_success_title": "Import successful", "import_success_message":"The game data has been successfully imported.", @@ -97,11 +111,14 @@ "export_error_title": "Export failed", "export_error_message": "Could not export file", + "error_found": "Found a bug?", "create_issue": "Create Issue", + "wiki": "Wiki", "app_version": "App Version", - "load_version": "Loading version...", - "build": "Build", + "privacy_policy": "Privacy Policy", + "loading": "Loading...", + "build": "Build No.", "about_text": "Hey :) Thanks for being one of the first users of my app! I’ve put a lot of work into this project, and even though I tried to think of everything, it might not work perfectly just yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the TestFlight app or by sending me a message or email. Thank you very much!" } diff --git a/lib/l10n/untranslated_messages.json b/lib/l10n/arb/untranslated_messages.json similarity index 100% rename from lib/l10n/untranslated_messages.json rename to lib/l10n/arb/untranslated_messages.json diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/generated/app_localizations.dart similarity index 85% rename from lib/l10n/app_localizations.dart rename to lib/l10n/generated/app_localizations.dart index c836194..2059f1b 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -18,7 +18,7 @@ import 'app_localizations_en.dart'; /// `supportedLocales` list. For example: /// /// ```dart -/// import 'l10n/app_localizations.dart'; +/// import 'generated/app_localizations.dart'; /// /// return MaterialApp( /// localizationsDelegates: AppLocalizations.localizationsDelegates, @@ -218,6 +218,60 @@ abstract class AppLocalizations { /// **'Bist du sicher, dass du das Spiel \"{gameTitle}\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'** String delete_game_message(String gameTitle); + /// No description provided for @pre_rating_title. + /// + /// In de, this message translates to: + /// **'Gefällt dir die App?'** + String get pre_rating_title; + + /// No description provided for @pre_rating_message. + /// + /// In de, this message translates to: + /// **'Feedback hilft mir, die App zu verbessern. Vielen Dank!'** + String get pre_rating_message; + + /// No description provided for @yes. + /// + /// In de, this message translates to: + /// **'Ja'** + String get yes; + + /// No description provided for @no. + /// + /// In de, this message translates to: + /// **'Nein'** + String get no; + + /// No description provided for @bad_rating_title. + /// + /// In de, this message translates to: + /// **'Unzufrieden mit der App?'** + String get bad_rating_title; + + /// No description provided for @bad_rating_message. + /// + /// In de, this message translates to: + /// **'Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!'** + String get bad_rating_message; + + /// No description provided for @contact_email. + /// + /// In de, this message translates to: + /// **'E-Mail schreiben'** + String get contact_email; + + /// No description provided for @email_subject. + /// + /// In de, this message translates to: + /// **'Feedback: Cabo Counter App'** + String get email_subject; + + /// No description provided for @email_body. + /// + /// In de, this message translates to: + /// **'Ich habe folgendes Feedback...'** + String get email_body; + /// No description provided for @overview. /// /// In de, this message translates to: @@ -362,12 +416,6 @@ abstract class AppLocalizations { /// **'Nächste Runde'** String get next_round; - /// No description provided for @statistics. - /// - /// In de, this message translates to: - /// **'Statistiken'** - String get statistics; - /// No description provided for @end_game. /// /// In de, this message translates to: @@ -422,6 +470,12 @@ abstract class AppLocalizations { /// **'Spielverlauf'** String get game_process; + /// No description provided for @empty_graph_text. + /// + /// In de, this message translates to: + /// **'Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'** + String get empty_graph_text; + /// No description provided for @settings. /// /// In de, this message translates to: @@ -467,15 +521,39 @@ abstract class AppLocalizations { /// No description provided for @import_data. /// /// In de, this message translates to: - /// **'Daten importieren'** + /// **'Spieldaten importieren'** String get import_data; /// No description provided for @export_data. /// /// In de, this message translates to: - /// **'Daten exportieren'** + /// **'Spieldaten exportieren'** 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. + /// + /// In de, this message translates to: + /// **'App'** + String get app; + /// No description provided for @import_success_title. /// /// In de, this message translates to: @@ -548,23 +626,35 @@ abstract class AppLocalizations { /// **'Issue erstellen'** String get create_issue; + /// No description provided for @wiki. + /// + /// In de, this message translates to: + /// **'Wiki'** + String get wiki; + /// No description provided for @app_version. /// /// In de, this message translates to: /// **'App-Version'** String get app_version; + /// No description provided for @privacy_policy. + /// + /// In de, this message translates to: + /// **'Datenschutzerklärung'** + String get privacy_policy; + /// No description provided for @build. /// /// In de, this message translates to: - /// **'Build'** + /// **'Build-Nr.'** String get build; - /// No description provided for @load_version. + /// No description provided for @loading. /// /// In de, this message translates to: - /// **'Lade Version...'** - String get load_version; + /// **'Lädt...'** + String get loading; /// No description provided for @about_text. /// diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart similarity index 81% rename from lib/l10n/app_localizations_de.dart rename to lib/l10n/generated/app_localizations_de.dart index 5b9d841..068711f 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -71,6 +71,35 @@ class AppLocalizationsDe extends AppLocalizations { return 'Bist du sicher, dass du das Spiel \"$gameTitle\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'; } + @override + String get pre_rating_title => 'Gefällt dir die App?'; + + @override + String get pre_rating_message => + 'Feedback hilft mir, die App zu verbessern. Vielen Dank!'; + + @override + String get yes => 'Ja'; + + @override + String get no => 'Nein'; + + @override + String get bad_rating_title => 'Unzufrieden mit der App?'; + + @override + String get bad_rating_message => + 'Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!'; + + @override + String get contact_email => 'E-Mail schreiben'; + + @override + String get email_subject => 'Feedback: Cabo Counter App'; + + @override + String get email_body => 'Ich habe folgendes Feedback...'; + @override String get overview => 'Übersicht'; @@ -149,9 +178,6 @@ class AppLocalizationsDe extends AppLocalizations { @override String get next_round => 'Nächste Runde'; - @override - String get statistics => 'Statistiken'; - @override String get end_game => 'Spiel beenden'; @@ -181,6 +207,10 @@ class AppLocalizationsDe extends AppLocalizations { @override String get game_process => 'Spielverlauf'; + @override + String get empty_graph_text => + 'Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'; + @override String get settings => 'Einstellungen'; @@ -203,10 +233,23 @@ class AppLocalizationsDe extends AppLocalizations { String get game_data => 'Spieldaten'; @override - String get import_data => 'Daten importieren'; + String get import_data => 'Spieldaten importieren'; @override - String get export_data => 'Daten 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 + String get app => 'App'; @override String get import_success_title => 'Import erfolgreich'; @@ -247,14 +290,20 @@ class AppLocalizationsDe extends AppLocalizations { @override String get create_issue => 'Issue erstellen'; + @override + String get wiki => 'Wiki'; + @override String get app_version => 'App-Version'; @override - String get build => 'Build'; + String get privacy_policy => 'Datenschutzerklärung'; @override - String get load_version => 'Lade Version...'; + String get build => 'Build-Nr.'; + + @override + String get loading => 'Lädt...'; @override String get about_text => diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart similarity index 80% rename from lib/l10n/app_localizations_en.dart rename to lib/l10n/generated/app_localizations_en.dart index c98dddd..06b5c03 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -71,6 +71,35 @@ class AppLocalizationsEn extends AppLocalizations { return 'Are you sure you want to delete the game \"$gameTitle\"? This action cannot be undone.'; } + @override + String get pre_rating_title => 'Do you like the app?'; + + @override + String get pre_rating_message => + 'Feedback helps me to continuously improve the app. Thank you!'; + + @override + String get yes => 'Yes'; + + @override + String get no => 'No'; + + @override + String get bad_rating_title => 'Not satisfied?'; + + @override + String get bad_rating_message => + '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 + String get contact_email => 'Contact via E-Mail'; + + @override + String get email_subject => 'Feedback: Cabo Counter App'; + + @override + String get email_body => 'I have the following feedback...'; + @override String get overview => 'Overview'; @@ -146,9 +175,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get next_round => 'Next Round'; - @override - String get statistics => 'Statistics'; - @override String get end_game => 'End Game'; @@ -176,7 +202,11 @@ class AppLocalizationsEn extends AppLocalizations { 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; @override - String get game_process => 'Spielverlauf'; + String get game_process => 'Scoring History'; + + @override + String get empty_graph_text => + 'You must play at least one round for the game progress graph to be displayed.'; @override String get settings => 'Settings'; @@ -205,6 +235,19 @@ class AppLocalizationsEn extends AppLocalizations { @override 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 => + 'Are you sure you want to delete all game data? This action cannot be undone.'; + + @override + String get app => 'App'; + @override String get import_success_title => 'Import successful'; @@ -244,14 +287,20 @@ class AppLocalizationsEn extends AppLocalizations { @override String get create_issue => 'Create Issue'; + @override + String get wiki => 'Wiki'; + @override String get app_version => 'App Version'; @override - String get build => 'Build'; + String get privacy_policy => 'Privacy Policy'; @override - String get load_version => 'Loading version...'; + String get build => 'Build No.'; + + @override + String get loading => 'Loading...'; @override String get about_text => diff --git a/lib/main.dart b/lib/main.dart index cd3d05f..9279426 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,9 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/tab_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/tab_view.dart'; +import 'package:cabo_counter/services/version_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; @@ -13,6 +14,7 @@ Future main() async { await ConfigService.initConfig(); ConfigService.pointLimit = await ConfigService.getPointLimit(); ConfigService.caboPenalty = await ConfigService.getCaboPenalty(); + await VersionService.init(); runApp(const App()); } diff --git a/lib/views/information_view.dart b/lib/presentation/views/about_view.dart similarity index 74% rename from lib/views/information_view.dart rename to lib/presentation/views/about_view.dart index 1d0918b..481e294 100644 --- a/lib/views/information_view.dart +++ b/lib/presentation/views/about_view.dart @@ -1,11 +1,13 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/core/constants.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/services/version_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; -class InformationView extends StatelessWidget { - const InformationView({super.key}); +class AboutView extends StatelessWidget { + const AboutView({super.key}); @override Widget build(BuildContext context) { @@ -28,9 +30,13 @@ class InformationView extends StatelessWidget { ), ), ), + Text( + '${AppLocalizations.of(context).app_version} ${VersionService.getVersionWithBuild()}', + style: TextStyle(fontSize: 15, color: Colors.grey[300]), + ), Padding( padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 30), + const EdgeInsets.symmetric(horizontal: 20, vertical: 15), child: SizedBox( height: 200, child: Image.asset('assets/cabo_counter-logo_rounded.png'), @@ -54,15 +60,15 @@ class InformationView extends StatelessWidget { children: [ IconButton( onPressed: () => - launchUrl(Uri.parse('https://www.instagram.com/fx.kr')), + launchUrl(Uri.parse(Constants.kInstagramLink)), icon: const Icon(FontAwesomeIcons.instagram)), IconButton( - onPressed: () => launchUrl( - Uri.parse('mailto:felix.kirchner.fk@gmail.com')), + onPressed: () => + launchUrl(Uri.parse('mailto:${Constants.kEmail}')), icon: const Icon(CupertinoIcons.envelope)), IconButton( onPressed: () => - launchUrl(Uri.parse('https://www.github.com/flixcoo')), + launchUrl(Uri.parse(Constants.kGithubLink)), icon: const Icon(FontAwesomeIcons.github)), ], ), diff --git a/lib/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart similarity index 95% rename from lib/views/active_game_view.dart rename to lib/presentation/views/active_game_view.dart index 5945a3e..704952a 100644 --- a/lib/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -1,11 +1,11 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/create_game_view.dart'; +import 'package:cabo_counter/presentation/views/graph_view.dart'; +import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/create_game_view.dart'; -import 'package:cabo_counter/views/graph_view.dart'; -import 'package:cabo_counter/views/round_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -121,7 +121,7 @@ class _ActiveGameViewState extends State { children: [ CupertinoListTile( title: Text( - AppLocalizations.of(context).statistics, + AppLocalizations.of(context).game_process, ), backgroundColorActivated: CustomTheme.backgroundColor, @@ -131,8 +131,9 @@ class _ActiveGameViewState extends State { builder: (_) => GraphView( gameSession: gameSession, )))), - if (!gameSession.isPointsLimitEnabled) - CupertinoListTile( + Visibility( + visible: !gameSession.isPointsLimitEnabled, + child: CupertinoListTile( title: Text( AppLocalizations.of(context).end_game, style: gameSession.roundNumber > 1 && @@ -148,6 +149,7 @@ class _ActiveGameViewState extends State { _showEndGameDialog(); } }), + ), CupertinoListTile( title: Text( AppLocalizations.of(context).delete_game, @@ -235,7 +237,8 @@ class _ActiveGameViewState extends State { child: Text( AppLocalizations.of(context).end_game, style: const TextStyle( - fontWeight: FontWeight.bold, color: Colors.red), + fontWeight: FontWeight.bold, + color: CupertinoColors.destructiveRed), ), onPressed: () { setState(() { diff --git a/lib/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart similarity index 97% rename from lib/views/create_game_view.dart rename to lib/presentation/views/create_game_view.dart index f6099f4..0d23494 100644 --- a/lib/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -1,10 +1,10 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/active_game_view.dart'; +import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:cabo_counter/services/config_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/active_game_view.dart'; -import 'package:cabo_counter/views/mode_selection_view.dart'; import 'package:flutter/cupertino.dart'; enum CreateStatus { diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart new file mode 100644 index 0000000..d322bd0 --- /dev/null +++ b/lib/presentation/views/graph_view.dart @@ -0,0 +1,120 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/data/game_session.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; + +class GraphView extends StatefulWidget { + final GameSession gameSession; + + const GraphView({super.key, required this.gameSession}); + + @override + State createState() => _GraphViewState(); +} + +class _GraphViewState extends State { + /// List of colors for the graph lines. + final List lineColors = [ + CustomTheme.graphColor1, + CustomTheme.graphColor2, + CustomTheme.graphColor3, + CustomTheme.graphColor4, + CustomTheme.graphColor5 + ]; + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(AppLocalizations.of(context).game_process), + previousPageTitle: AppLocalizations.of(context).back, + ), + child: widget.gameSession.roundNumber > 1 + ? Padding( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: SfCartesianChart( + legend: const Legend( + overflowMode: LegendItemOverflowMode.wrap, + isVisible: true, + position: LegendPosition.bottom), + primaryXAxis: const NumericAxis( + interval: 1, + decimalPlaces: 0, + ), + primaryYAxis: const NumericAxis( + interval: 1, + decimalPlaces: 0, + ), + series: getCumulativeScores(), + ), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Center( + child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), + ), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: Text( + AppLocalizations.of(context).empty_graph_text, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ), + ), + ], + )); + } + + /// Returns a list of LineSeries representing the cumulative scores of each player. + /// Each series contains data points for each round, showing the cumulative score up to that round. + /// The x-axis represents the round number, and the y-axis represents the cumulative score. + List> getCumulativeScores() { + final rounds = widget.gameSession.roundList; + final playerCount = widget.gameSession.players.length; + final playerNames = widget.gameSession.players; + + List> cumulativeScores = List.generate(playerCount, (_) => []); + List runningTotals = List.filled(playerCount, 0); + + for (var round in rounds) { + for (int i = 0; i < playerCount; i++) { + runningTotals[i] += round.scoreUpdates[i]; + cumulativeScores[i].add(runningTotals[i]); + } + } + + const double jitterStep = 0.03; + + /// Create a list of LineSeries for each player + /// Each series contains data points for each round + return List.generate(playerCount, (i) { + final data = List.generate( + cumulativeScores[i].length + 1, + (j) => ( + j, + j == 0 || cumulativeScores[i][j - 1] == 0 + ? 0 // 0 points at the start of the game or when the value is 0 (don't subtract jitter step) + + // Adds a small jitter to the cumulative scores to prevent overlapping data points in the graph. + // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. + : cumulativeScores[i][j - 1] + (i - playerCount ~/ 2) * jitterStep + ), + ); + + /// Create a LineSeries for the player + /// The xValueMapper maps the round number, and the yValueMapper maps the cumulative score. + return LineSeries<(int, num), int>( + name: playerNames[i], + dataSource: data, + xValueMapper: (record, _) => record.$1, + yValueMapper: (record, _) => record.$2, + markerSettings: const MarkerSettings(isVisible: true), + color: lineColors[i], + ); + }); + } +} diff --git a/lib/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart similarity index 57% rename from lib/views/main_menu_view.dart rename to lib/presentation/views/main_menu_view.dart index e087cfc..86ff208 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -1,13 +1,19 @@ +import 'package:cabo_counter/core/constants.dart'; +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/active_game_view.dart'; +import 'package:cabo_counter/presentation/views/create_game_view.dart'; +import 'package:cabo_counter/presentation/views/settings_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/active_game_view.dart'; -import 'package:cabo_counter/views/create_game_view.dart'; -import 'package:cabo_counter/views/settings_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +enum PreRatingDialogDecision { yes, no, cancel } + +enum BadRatingDialogDecision { email, cancel } class MainMenuView extends StatefulWidget { const MainMenuView({super.key}); @@ -29,6 +35,17 @@ class _MainMenuViewState extends State { }); }); gameManager.addListener(_updateView); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + await Constants.rateMyApp.init(); + + if (Constants.rateMyApp.shouldOpenDialog && + Constants.appDevPhase != 'Beta') { + await Future.delayed(const Duration(milliseconds: 600)); + if (!mounted) return; + _handleFeedbackDialog(context); + } + }); } void _updateView() { @@ -57,14 +74,12 @@ class _MainMenuViewState extends State { icon: const Icon(CupertinoIcons.settings, size: 30)), middle: const Text('Cabo Counter'), trailing: IconButton( - onPressed: () => { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const CreateGameView(), - ), - ) - }, + onPressed: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const CreateGameView(), + ), + ), icon: const Icon(CupertinoIcons.add)), ), child: CupertinoPageScaffold( @@ -73,10 +88,9 @@ class _MainMenuViewState extends State { ? const Center(child: CupertinoActivityIndicator()) : gameManager.gameList.isEmpty ? Column( - mainAxisAlignment: - MainAxisAlignment.center, // Oben ausrichten + mainAxisAlignment: MainAxisAlignment.center, children: [ - const SizedBox(height: 30), // Abstand von oben + const SizedBox(height: 30), Center( child: GestureDetector( onTap: () => Navigator.push( @@ -92,7 +106,7 @@ class _MainMenuViewState extends State { color: CustomTheme.primaryColor, ), )), - const SizedBox(height: 10), // Abstand von oben + const SizedBox(height: 10), Padding( padding: const EdgeInsets.symmetric(horizontal: 70), @@ -128,7 +142,7 @@ class _MainMenuViewState extends State { final String gameTitle = gameManager .gameList[index].gameTitle; return await _showDeleteGamePopup( - gameTitle); + context, gameTitle); }, onDismissed: (direction) { gameManager @@ -204,40 +218,144 @@ class _MainMenuViewState extends State { return AppLocalizations.of(context).unlimited; } + /// Handles the feedback dialog when the conditions for rating are met. + /// It shows a dialog asking the user if they like the app, + /// and based on their response, it either opens the rating dialog or an email client for feedback. + Future _handleFeedbackDialog(BuildContext context) async { + final String emailSubject = AppLocalizations.of(context).email_subject; + final String emailBody = AppLocalizations.of(context).email_body; + + final Uri emailUri = Uri( + scheme: 'mailto', + path: Constants.kEmail, + query: 'subject=$emailSubject' + '&body=$emailBody', + ); + + PreRatingDialogDecision preRatingDecision = + await _showPreRatingDialog(context); + BadRatingDialogDecision badRatingDecision = BadRatingDialogDecision.cancel; + + // so that the bad rating dialog is not shown immediately + await Future.delayed(const Duration(milliseconds: 300)); + + switch (preRatingDecision) { + case PreRatingDialogDecision.yes: + if (context.mounted) Constants.rateMyApp.showStarRateDialog(context); + break; + case PreRatingDialogDecision.no: + if (context.mounted) { + badRatingDecision = await _showBadRatingDialog(context); + } + if (badRatingDecision == BadRatingDialogDecision.email) { + if (context.mounted) { + launchUrl(emailUri); + } + } + break; + case PreRatingDialogDecision.cancel: + break; + } + } + /// Shows a confirmation dialog to delete all game sessions. /// Returns true if the user confirms the deletion, false otherwise. /// [gameTitle] is the title of the game session to be deleted. - Future _showDeleteGamePopup(String gameTitle) async { - bool? shouldDelete = await showCupertinoDialog( + Future _showDeleteGamePopup( + BuildContext context, String gameTitle) async { + return await showCupertinoDialog( context: context, - builder: (context) { + builder: (BuildContext context) { return CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).delete_game_title), - content: Text( - AppLocalizations.of(context).delete_game_message(gameTitle)), - actions: [ - CupertinoDialogAction( - onPressed: () { - Navigator.pop(context, false); - }, - child: Text(AppLocalizations.of(context).cancel), + title: Text( + AppLocalizations.of(context).delete_game_title, ), - CupertinoDialogAction( - onPressed: () { - Navigator.pop(context, true); - }, - child: Text( - AppLocalizations.of(context).delete, - style: const TextStyle( - fontWeight: FontWeight.bold, color: Colors.red), + content: Text(AppLocalizations.of(context) + .delete_game_message(gameTitle)), + actions: [ + CupertinoDialogAction( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(AppLocalizations.of(context).cancel), ), - ), - ], - ); + CupertinoDialogAction( + isDestructiveAction: true, + isDefaultAction: true, + onPressed: () { + Navigator.of(context).pop(true); + }, + child: Text( + AppLocalizations.of(context).delete, + ), + ) + ]); }, ) ?? false; - return shouldDelete; + } + + /// Shows a dialog asking the user if they like the app. + /// Returns the user's decision as an integer. + /// - PRE_RATING_DIALOG_YES: User likes the app and wants to rate it. + /// - PRE_RATING_DIALOG_NO: User does not like the app and wants to provide feedback. + /// - PRE_RATING_DIALOG_CANCEL: User cancels the dialog. + Future _showPreRatingDialog( + BuildContext context) async { + return await showCupertinoDialog( + context: context, + builder: (BuildContext context) => CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).pre_rating_title), + content: + Text(AppLocalizations.of(context).pre_rating_message), + actions: [ + CupertinoDialogAction( + onPressed: () => Navigator.of(context) + .pop(PreRatingDialogDecision.yes), + isDefaultAction: true, + child: Text(AppLocalizations.of(context).yes), + ), + CupertinoDialogAction( + onPressed: () => + Navigator.of(context).pop(PreRatingDialogDecision.no), + child: Text(AppLocalizations.of(context).no), + ), + CupertinoDialogAction( + onPressed: () => Navigator.of(context).pop(), + isDestructiveAction: true, + child: Text(AppLocalizations.of(context).cancel), + ) + ], + )) ?? + PreRatingDialogDecision.cancel; + } + + /// Shows a dialog asking the user for feedback if they do not like the app. + /// Returns the user's decision as an integer. + /// - BAD_RATING_DIALOG_EMAIL: User wants to send an email with feedback. + /// - BAD_RATING_DIALOG_CANCEL: User cancels the dialog. + Future _showBadRatingDialog( + BuildContext context) async { + return await showCupertinoDialog( + context: context, + builder: (BuildContext context) => CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).bad_rating_title), + content: + Text(AppLocalizations.of(context).bad_rating_message), + actions: [ + CupertinoDialogAction( + isDefaultAction: true, + onPressed: () => Navigator.of(context) + .pop(BadRatingDialogDecision.email), + child: Text(AppLocalizations.of(context).contact_email), + ), + CupertinoDialogAction( + isDestructiveAction: true, + onPressed: () => Navigator.of(context).pop(), + child: Text(AppLocalizations.of(context).cancel)) + ], + )) ?? + BadRatingDialogDecision.cancel; } @override diff --git a/lib/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart similarity index 92% rename from lib/views/mode_selection_view.dart rename to lib/presentation/views/mode_selection_view.dart index 93cdc7a..a7d3ce7 100644 --- a/lib/views/mode_selection_view.dart +++ b/lib/presentation/views/mode_selection_view.dart @@ -1,5 +1,5 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; class ModeSelectionMenu extends StatelessWidget { diff --git a/lib/views/round_view.dart b/lib/presentation/views/round_view.dart similarity index 89% rename from lib/views/round_view.dart rename to lib/presentation/views/round_view.dart index 4e114fe..39e5cc8 100644 --- a/lib/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -1,7 +1,7 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; @@ -67,19 +67,24 @@ class _RoundViewState extends State { @override Widget build(BuildContext context) { final bottomInset = MediaQuery.of(context).viewInsets.bottom; - final maxLength = widget.gameSession.getMaxLengthOfPlayerNames(); return CupertinoPageScaffold( resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( transitionBetweenRoutes: true, - middle: Text(AppLocalizations.of(context).results), leading: CupertinoButton( padding: EdgeInsets.zero, onPressed: () => {LocalStorageService.saveGameSessions(), Navigator.pop(context)}, child: Text(AppLocalizations.of(context).cancel), ), + middle: Text(AppLocalizations.of(context).results), + trailing: widget.gameSession.isGameFinished + ? const Icon( + CupertinoIcons.lock, + size: 25, + ) + : null, ), child: Stack( children: [ @@ -120,9 +125,8 @@ class _RoundViewState extends State { return MapEntry( index, Padding( - padding: EdgeInsets.symmetric( - horizontal: 4 + - _getSegmentedControlPadding(maxLength), + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 6, ), child: FittedBox( @@ -131,10 +135,8 @@ class _RoundViewState extends State { name, textAlign: TextAlign.center, maxLines: 1, - style: TextStyle( + style: const TextStyle( fontWeight: FontWeight.bold, - fontSize: _getSegmentedControlFontSize( - maxLength), ), ), ), @@ -293,21 +295,22 @@ class _RoundViewState extends State { : null, child: Text(AppLocalizations.of(context).done), ), - CupertinoButton( - onPressed: _areRoundInputsValid() - ? () { - _finishRound(); - LocalStorageService.saveGameSessions(); - if (widget.gameSession.isGameFinished == true) { - Navigator.pop(context); - } else { - Navigator.pop( - context, widget.roundNumber + 1); + if (!widget.gameSession.isGameFinished) + CupertinoButton( + onPressed: _areRoundInputsValid() + ? () { + _finishRound(); + LocalStorageService.saveGameSessions(); + if (widget.gameSession.isGameFinished) { + Navigator.pop(context); + } else { + Navigator.pop( + context, widget.roundNumber + 1); + } } - } - : null, - child: Text(AppLocalizations.of(context).next_round), - ), + : null, + child: Text(AppLocalizations.of(context).next_round), + ), ], ), ); @@ -386,32 +389,6 @@ class _RoundViewState extends State { } } - double _getSegmentedControlFontSize(int maxLength) { - if (maxLength > 8) { - // 9 - 12 characters - return 9.0; - } else if (maxLength > 4) { - // 5 - 8 characters - return 15.0; - } else { - // 0 - 4 characters - return 18.0; - } - } - - double _getSegmentedControlPadding(int maxLength) { - if (maxLength > 8) { - // 9 - 12 characters - return 0.0; - } else if (maxLength > 4) { - // 5 - 8 characters - return 5.0; - } else { - // 0 - 4 characters - return 8.0; - } - } - @override void dispose() { for (final controller in _scoreControllerList) { diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart new file mode 100644 index 0000000..d6f0833 --- /dev/null +++ b/lib/presentation/views/settings_view.dart @@ -0,0 +1,269 @@ +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/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 createState() => _SettingsViewState(); +} + +class _SettingsViewState extends State { + UniqueKey _stepperKey1 = UniqueKey(); + UniqueKey _stepperKey2 = UniqueKey(); + @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.caboPenalty, + minValue: 0, + maxValue: 50, + step: 1, + onChanged: (newCaboPenalty) { + setState(() { + ConfigService.setCaboPenalty(newCaboPenalty); + ConfigService.caboPenalty = newCaboPenalty; + }); + }, + ), + ), + CustomFormRow( + prefixText: AppLocalizations.of(context).point_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(() { + _stepperKey1 = UniqueKey(); + _stepperKey2 = UniqueKey(); + }); + }, + ) + ])), + 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 ('', ''); + } + } +} diff --git a/lib/views/tab_view.dart b/lib/presentation/views/tab_view.dart similarity index 80% rename from lib/views/tab_view.dart rename to lib/presentation/views/tab_view.dart index 4abd411..0c98cc7 100644 --- a/lib/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -1,7 +1,7 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/views/information_view.dart'; -import 'package:cabo_counter/views/main_menu_view.dart'; +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/about_view.dart'; +import 'package:cabo_counter/presentation/views/main_menu_view.dart'; import 'package:flutter/cupertino.dart'; class TabView extends StatefulWidget { @@ -39,7 +39,7 @@ class _TabViewState extends State { if (index == 0) { return const MainMenuView(); } else { - return const InformationView(); + return const AboutView(); } }); }, diff --git a/lib/presentation/widgets/custom_form_row.dart b/lib/presentation/widgets/custom_form_row.dart new file mode 100644 index 0000000..7a2526b --- /dev/null +++ b/lib/presentation/widgets/custom_form_row.dart @@ -0,0 +1,53 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/presentation/widgets/custom_stepper.dart'; +import 'package:flutter/cupertino.dart'; + +class CustomFormRow extends StatefulWidget { + final String prefixText; + final IconData prefixIcon; + final Widget? suffixWidget; + final void Function()? onPressed; + const CustomFormRow({ + super.key, + required this.prefixText, + required this.prefixIcon, + this.onPressed, + this.suffixWidget, + }); + + @override + State createState() => _CustomFormRowState(); +} + +class _CustomFormRowState extends State { + late Widget suffixWidget; + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + suffixWidget = widget.suffixWidget ?? const SizedBox.shrink(); + return CupertinoButton( + padding: EdgeInsets.zero, + onPressed: widget.onPressed, + child: CupertinoFormRow( + prefix: Row( + children: [ + Icon( + widget.prefixIcon, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 10), + Text(widget.prefixText), + ], + ), + padding: suffixWidget is CustomStepper + ? const EdgeInsets.fromLTRB(15, 0, 0, 0) + : const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + child: suffixWidget, + ), + ); + } +} diff --git a/lib/widgets/stepper.dart b/lib/presentation/widgets/custom_stepper.dart similarity index 75% rename from lib/widgets/stepper.dart rename to lib/presentation/widgets/custom_stepper.dart index 879235e..a05a4cb 100644 --- a/lib/widgets/stepper.dart +++ b/lib/presentation/widgets/custom_stepper.dart @@ -1,12 +1,13 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:flutter/cupertino.dart'; // Für iOS-Style -class Stepper extends StatefulWidget { +class CustomStepper extends StatefulWidget { final int minValue; final int maxValue; final int? initialValue; final int step; final ValueChanged onChanged; - const Stepper({ + const CustomStepper({ super.key, required this.minValue, required this.maxValue, @@ -17,10 +18,10 @@ class Stepper extends StatefulWidget { @override // ignore: library_private_types_in_public_api - _StepperState createState() => _StepperState(); + _CustomStepperState createState() => _CustomStepperState(); } -class _StepperState extends State { +class _CustomStepperState extends State { late int _value; @override @@ -34,18 +35,20 @@ class _StepperState extends State { Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, children: [ CupertinoButton( - padding: const EdgeInsets.all(8), + padding: EdgeInsets.zero, onPressed: _decrement, child: const Icon(CupertinoIcons.minus), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Text('$_value', style: const TextStyle(fontSize: 18)), + child: Text('$_value', + style: TextStyle(fontSize: 18, color: CustomTheme.white)), ), CupertinoButton( - padding: const EdgeInsets.all(8), + padding: EdgeInsets.zero, onPressed: _increment, child: const Icon(CupertinoIcons.add), ), diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 12130a1..29ac58b 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -21,7 +21,7 @@ class LocalStorageService { static const String _fileName = 'game_data.json'; /// Writes the game session list to a JSON file and returns it as string. - static String getGameDataAsJsonFile() { + static String _getGameDataAsJsonFile() { final jsonFile = gameManager.gameList.map((session) => session.toJson()).toList(); return json.encode(jsonFile); @@ -39,7 +39,7 @@ class LocalStorageService { print('[local_storage_service.dart] Versuche, Daten zu speichern...'); try { final file = await _getFilePath(); - final jsonFile = getGameDataAsJsonFile(); + final jsonFile = _getGameDataAsJsonFile(); await file.writeAsString(jsonFile); print( '[local_storage_service.dart] Die Spieldaten wurden zwischengespeichert.'); @@ -70,7 +70,7 @@ class LocalStorageService { return false; } - if (!await validateJsonSchema(jsonString, true)) { + if (!await _validateJsonSchema(jsonString, true)) { print( '[local_storage_service.dart] Die Datei konnte nicht validiert werden'); gameManager.gameList = []; @@ -105,7 +105,7 @@ class LocalStorageService { /// Opens the file picker to export game data as a JSON file. /// This method will export the given [jsonString] as a JSON file. It opens /// the file picker with the choosen [fileName]. - static Future exportJsonData( + static Future _exportJsonData( String jsonString, String fileName, ) async { @@ -133,16 +133,16 @@ class LocalStorageService { /// Opens the file picker to export all game sessions as a JSON file. static Future exportGameData() async { - String jsonString = getGameDataAsJsonFile(); + String jsonString = _getGameDataAsJsonFile(); String fileName = 'cabo_counter-game_data'; - return exportJsonData(jsonString, fileName); + return _exportJsonData(jsonString, fileName); } /// Opens the file picker to save a single game session as a JSON file. static Future exportSingleGameSession(GameSession session) async { String jsonString = json.encode(session.toJson()); String fileName = 'cabo_counter-game_${session.id.substring(0, 7)}'; - return exportJsonData(jsonString, fileName); + return _exportJsonData(jsonString, fileName); } /// Opens the file picker to import a JSON file and loads the game data from it. @@ -162,7 +162,7 @@ class LocalStorageService { try { final jsonString = await _readFileContent(path.files.single); - if (await validateJsonSchema(jsonString, true)) { + if (await _validateJsonSchema(jsonString, true)) { // Checks if the JSON String is in the gameList format final jsonData = json.decode(jsonString) as List; @@ -172,12 +172,12 @@ class LocalStorageService { .toList(); for (GameSession s in importedList) { - importSession(s); + _importSession(s); } - } else if (await validateJsonSchema(jsonString, false)) { + } else if (await _validateJsonSchema(jsonString, false)) { // Checks if the JSON String is in the single game format final jsonData = json.decode(jsonString) as Map; - importSession(GameSession.fromJson(jsonData)); + _importSession(GameSession.fromJson(jsonData)); } else { return ImportStatus.validationError; } @@ -198,7 +198,7 @@ class LocalStorageService { } /// Imports a single game session into the gameList. - static Future importSession(GameSession session) async { + static Future _importSession(GameSession session) async { if (gameManager.gameExistsInGameList(session.id)) { print( '[local_storage_service.dart] Die Session mit der ID ${session.id} existiert bereits. Sie wird überschrieben.'); @@ -221,7 +221,7 @@ class LocalStorageService { /// This method checks if the provided [jsonString] is valid against the /// JSON schema. It takes a boolean [isGameList] to determine /// which schema to use (game list or single game). - static Future validateJsonSchema( + static Future _validateJsonSchema( String jsonString, bool isGameList) async { final String schemaString; diff --git a/lib/services/version_service.dart b/lib/services/version_service.dart new file mode 100644 index 0000000..6511c69 --- /dev/null +++ b/lib/services/version_service.dart @@ -0,0 +1,32 @@ +import 'package:cabo_counter/core/constants.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +class VersionService { + static String _version = '-.-.-'; + static String _buildNumber = '-'; + + static Future init() async { + var packageInfo = await PackageInfo.fromPlatform(); + _version = packageInfo.version; + _buildNumber = packageInfo.buildNumber; + } + + static String getVersionNumber() { + return _version; + } + + static String getVersion() { + if (_version == '-.-.-') { + return getVersionNumber(); + } + return '${Constants.appDevPhase} $_version'; + } + + static String getBuildNumber() { + return _buildNumber; + } + + static String getVersionWithBuild() { + return '$_version ($_buildNumber)'; + } +} diff --git a/lib/utility/globals.dart b/lib/utility/globals.dart deleted file mode 100644 index e11a118..0000000 --- a/lib/utility/globals.dart +++ /dev/null @@ -1,3 +0,0 @@ -class Globals { - static String appDevPhase = 'Beta'; -} diff --git a/lib/views/graph_view.dart b/lib/views/graph_view.dart deleted file mode 100644 index 345c670..0000000 --- a/lib/views/graph_view.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/app_localizations.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:syncfusion_flutter_charts/charts.dart'; - -class GraphView extends StatefulWidget { - final GameSession gameSession; - - const GraphView({super.key, required this.gameSession}); - - @override - State createState() => _GraphViewState(); -} - -class _GraphViewState extends State { - /// List of colors for the graph lines. - List lineColors = [ - Colors.red, - Colors.blue, - Colors.orange.shade400, - Colors.purple, - Colors.green, - ]; - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).game_process), - previousPageTitle: AppLocalizations.of(context).back, - ), - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), - child: SfCartesianChart( - legend: - const Legend(isVisible: true, position: LegendPosition.bottom), - primaryXAxis: const NumericAxis(), - primaryYAxis: const NumericAxis(), - series: getCumulativeScores(), - ), - ), - ); - } - - /// Returns a list of LineSeries representing the cumulative scores of each player. - /// Each series contains data points for each round, showing the cumulative score up to that round. - /// The x-axis represents the round number, and the y-axis represents the cumulative score. - List> getCumulativeScores() { - final rounds = widget.gameSession.roundList; - final playerCount = widget.gameSession.players.length; - final playerNames = widget.gameSession.players; - - List> cumulativeScores = List.generate(playerCount, (_) => []); - List runningTotals = List.filled(playerCount, 0); - - for (var round in rounds) { - for (int i = 0; i < playerCount; i++) { - runningTotals[i] += round.scores[i]; - cumulativeScores[i].add(runningTotals[i]); - } - } - - /// Create a list of LineSeries for each player - /// Each series contains data points for each round - return List.generate(playerCount, (i) { - final data = List.generate( - cumulativeScores[i].length, - (j) => (j + 1, cumulativeScores[i][j]), // (round, score) - ); - - /// Create a LineSeries for the player - /// The xValueMapper maps the round number, and the yValueMapper maps the cumulative score. - return LineSeries<(int, int), int>( - name: playerNames[i], - dataSource: data, - xValueMapper: (record, _) => record.$1, // Runde - yValueMapper: (record, _) => record.$2, // Punktestand - markerSettings: const MarkerSettings(isVisible: true), - color: lineColors[i], - ); - }); - } -} diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart deleted file mode 100644 index 2e86122..0000000 --- a/lib/views/settings_view.dart +++ /dev/null @@ -1,267 +0,0 @@ -import 'package:cabo_counter/l10n/app_localizations.dart'; -import 'package:cabo_counter/services/config_service.dart'; -import 'package:cabo_counter/services/local_storage_service.dart'; -import 'package:cabo_counter/utility/custom_theme.dart'; -import 'package:cabo_counter/utility/globals.dart'; -import 'package:cabo_counter/widgets/stepper.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class SettingsView extends StatefulWidget { - const SettingsView({super.key}); - - @override - State createState() => _SettingsViewState(); -} - -class _SettingsViewState extends State { - UniqueKey _stepperKey1 = UniqueKey(); - UniqueKey _stepperKey2 = UniqueKey(); - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).settings), - ), - child: SafeArea( - child: Stack( - children: [ - 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(15, 10, 10, 0), - child: CupertinoListTile( - padding: EdgeInsets.zero, - title: Text(AppLocalizations.of(context).cabo_penalty), - subtitle: Text( - AppLocalizations.of(context).cabo_penalty_subtitle), - trailing: Stepper( - key: _stepperKey1, - initialValue: ConfigService.caboPenalty, - minValue: 0, - maxValue: 50, - step: 1, - onChanged: (newCaboPenalty) { - setState(() { - ConfigService.setCaboPenalty(newCaboPenalty); - ConfigService.caboPenalty = newCaboPenalty; - }); - }, - ), - )), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoListTile( - padding: EdgeInsets.zero, - title: Text(AppLocalizations.of(context).point_limit), - subtitle: - Text(AppLocalizations.of(context).point_limit_subtitle), - trailing: Stepper( - key: _stepperKey2, - initialValue: ConfigService.pointLimit, - minValue: 30, - maxValue: 1000, - step: 10, - onChanged: (newPointLimit) { - setState(() { - ConfigService.setPointLimit(newPointLimit); - ConfigService.pointLimit = newPointLimit; - }); - }, - ), - )), - Padding( - padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), - child: Center( - heightFactor: 0.9, - child: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: () => setState(() { - ConfigService.resetConfig(); - _stepperKey1 = UniqueKey(); - _stepperKey2 = UniqueKey(); - }), - child: - Text(AppLocalizations.of(context).reset_to_default), - ), - )), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).game_data, - style: CustomTheme.rowTitle, - ), - ), - Padding( - padding: const EdgeInsets.only(top: 30), - child: Center( - heightFactor: 1, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CupertinoButton( - color: CustomTheme.primaryColor, - sizeStyle: CupertinoButtonSize.medium, - child: Text( - AppLocalizations.of(context).import_data, - style: - TextStyle(color: CustomTheme.backgroundColor), - ), - onPressed: () async { - final success = - await LocalStorageService.importJsonFile(); - showFeedbackDialog(success); - }), - const SizedBox( - width: 20, - ), - CupertinoButton( - color: CustomTheme.primaryColor, - sizeStyle: CupertinoButtonSize.medium, - child: Text( - AppLocalizations.of(context).export_data, - style: - TextStyle(color: CustomTheme.backgroundColor), - ), - onPressed: () async { - final success = - await LocalStorageService.exportGameData(); - if (!success && context.mounted) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context) - .export_error_title), - content: Text(AppLocalizations.of(context) - .export_error_message), - actions: [ - CupertinoDialogAction( - child: - Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - } - }, - ), - ], - )), - ) - ], - ), - Positioned( - bottom: 30, - left: 0, - right: 0, - child: Column( - children: [ - Center( - child: Text(AppLocalizations.of(context).error_found), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 30), - child: Center( - child: CupertinoButton( - onPressed: () => launchUrl(Uri.parse( - 'https://github.com/flixcoo/Cabo-Counter/issues')), - child: Text(AppLocalizations.of(context).create_issue), - ), - ), - ), - FutureBuilder( - future: _getPackageInfo(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text( - '${Globals.appDevPhase} ${snapshot.data!.version} ' - '(${AppLocalizations.of(context).build} ${snapshot.data!.buildNumber})', - textAlign: TextAlign.center, - ); - } else if (snapshot.hasError) { - return Text( - '${AppLocalizations.of(context).app_version} -.-.- (${AppLocalizations.of(context).build} -)', - textAlign: TextAlign.center, - ); - } - return Text( - AppLocalizations.of(context).load_version, - textAlign: TextAlign.center, - ); - }, - ) - ], - )), - ], - )), - ); - } - - Future _getPackageInfo() async { - return await PackageInfo.fromPlatform(); - } - - 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 ('', ''); - } - } -} diff --git a/pubspec.yaml b/pubspec.yaml index 562b189..da2c087 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.3.9+331 +version: 0.4.4+485 environment: sdk: ^3.5.4 @@ -27,6 +27,7 @@ dependencies: intl: any syncfusion_flutter_charts: ^30.1.37 uuid: ^4.5.1 + rate_my_app: ^2.3.2 dev_dependencies: flutter_test: From d296465b0422581620cabf0b34b41b8a2933d38d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 19:56:31 +0200 Subject: [PATCH 149/353] Updated point reduction --- lib/data/game_session.dart | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 36c4c4e..d40e105 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -282,8 +282,8 @@ class GameSession extends ChangeNotifier { for (int i = 0; i < players.length; i++) { if (playerScores[i] == pointLimit) { print('${players[i]} hat genau 100 Punkte erreicht und bekommt ' - 'deswegen 50 Punkte abgezogen'); - roundList[roundNumber - 1].scoreUpdates[i] -= 50; + 'deswegen ${(pointLimit / 2).round()} Punkte abgezogen'); + roundList[roundNumber - 1].scoreUpdates[i] -= (pointLimit / 2).round(); } } _sumPoints(); diff --git a/pubspec.yaml b/pubspec.yaml index da2c087..7946bbb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.4+485 +version: 0.4.4+486 environment: sdk: ^3.5.4 From 68477158e5768519f59a58788c7e2e54f1931b2f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 13 Jul 2025 23:57:15 +0200 Subject: [PATCH 150/353] Implemented bonus popup --- lib/data/game_session.dart | 11 +++-- lib/presentation/views/round_view.dart | 65 +++++++++++++++++++++++--- pubspec.yaml | 2 +- test/data/game_session_test.dart | 12 ++--- 4 files changed, 74 insertions(+), 16 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index d40e105..54c095b 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -243,10 +243,11 @@ class GameSession extends ChangeNotifier { /// It then checks if any player has exceeded 100 points. If so, it sets /// isGameFinished to true and calls the _setWinner() method to determine /// the winner. - Future updatePoints() async { + List updatePoints() { + List bonusPlayers = []; _sumPoints(); if (isPointsLimitEnabled) { - _checkHundredPointsReached(); + bonusPlayers = _checkHundredPointsReached(); for (int i = 0; i < playerScores.length; i++) { if (playerScores[i] > pointLimit) { @@ -258,6 +259,7 @@ class GameSession extends ChangeNotifier { } } notifyListeners(); + return bonusPlayers; } @visibleForTesting @@ -278,15 +280,18 @@ class GameSession extends ChangeNotifier { /// Checks if a player has reached 100 points in the current round. /// If so, it updates the [scoreUpdate] List by subtracting 50 points from /// the corresponding round update. - void _checkHundredPointsReached() { + List _checkHundredPointsReached() { + List bonusPlayers = []; for (int i = 0; i < players.length; i++) { if (playerScores[i] == pointLimit) { + bonusPlayers.add(i); print('${players[i]} hat genau 100 Punkte erreicht und bekommt ' 'deswegen ${(pointLimit / 2).round()} Punkte abgezogen'); roundList[roundNumber - 1].scoreUpdates[i] -= (pointLimit / 2).round(); } } _sumPoints(); + return bonusPlayers; } /// Determines the winner of the game session. diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 39e5cc8..602c702 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -287,8 +287,11 @@ class _RoundViewState extends State { children: [ CupertinoButton( onPressed: _areRoundInputsValid() - ? () { - _finishRound(); + ? () async { + List boni = _finishRound(); + if (boni.isNotEmpty) { + await _showBonusPopup(context, boni); + } LocalStorageService.saveGameSessions(); Navigator.pop(context); } @@ -298,8 +301,11 @@ class _RoundViewState extends State { if (!widget.gameSession.isGameFinished) CupertinoButton( onPressed: _areRoundInputsValid() - ? () { - _finishRound(); + ? () async { + List boni = _finishRound(); + if (boni.isNotEmpty) { + await _showBonusPopup(context, boni); + } LocalStorageService.saveGameSessions(); if (widget.gameSession.isGameFinished) { Navigator.pop(context); @@ -359,7 +365,7 @@ class _RoundViewState extends State { /// every player. If the round is the highest round played in this game, /// it expands the player score lists. At the end it updates the score /// array for the game. - void _finishRound() { + List _finishRound() { print('===================================='); print('Runde ${widget.roundNumber} beendet'); // The shown round is smaller than the newest round @@ -381,12 +387,59 @@ class _RoundViewState extends State { widget.gameSession.calculateScoredPoints( widget.roundNumber, roundScores, _caboPlayerIndex); } - widget.gameSession.updatePoints(); + List bonusPlayers = widget.gameSession.updatePoints(); if (widget.gameSession.isGameFinished == true) { print('Das Spiel ist beendet'); } else if (widget.roundNumber == widget.gameSession.roundNumber) { widget.gameSession.increaseRound(); } + return bonusPlayers; + } + + /// Shows a popup dialog with the bonus information. + Future _showBonusPopup( + BuildContext context, List bonusPlayers) async { + print('Bonus Popup wird angezeigt'); + int pointLimit = widget.gameSession.pointLimit; + int bonusPoints = (pointLimit / 2).round(); + + String resultText = _getPopupString(pointLimit, bonusPoints, bonusPlayers); + + await showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: const Text('Bonus!'), + content: Text(resultText), + actions: [ + CupertinoDialogAction( + child: const Text('OK'), + onPressed: () => Navigator.of(context).pop(true), + ), + ], + ), + ); + return true; + } + + /// Generates the string for the bonus popup. + /// It takes the [pointLimit], [bonusPoints] and the list of [bonusPlayers] + /// and returns a formatted string. + String _getPopupString( + int pointLimit, int bonusPoints, List bonusPlayers) { + List nameList = + bonusPlayers.map((i) => widget.gameSession.players[i]).toList(); + String resultText = ''; + if (nameList.length == 1) { + resultText = + '${nameList.first} hat exakt das Punktelimit von $pointLimit Punkten erreicht und bekommt deshalb $bonusPoints Punkte abgezogen!'; + } else { + resultText = nameList.length == 2 + ? '${nameList[0]} & ${nameList[1]}' + : '${nameList.sublist(0, nameList.length - 1).join(', ')} & ${nameList.last}'; + resultText += + ' haben exakt das Punktelimit von $pointLimit Punkten erreicht und bekommen deshalb $bonusPoints Punkte abgezogen!'; + } + return resultText; } @override diff --git a/pubspec.yaml b/pubspec.yaml index 7946bbb..f2b4949 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.4+486 +version: 0.4.4+488 environment: sdk: ^3.5.4 diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index de4e284..4ca2158 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -114,15 +114,15 @@ void main() { expect(session.roundList[0].caboPlayerIndex, 0); }); - test('updatePoints - game not finished', () async { + test('updatePoints - game not finished', () { session.addRoundScoresToList(1, [10, 20, 30], [10, 20, 30], 0); - await session.updatePoints(); + session.updatePoints(); expect(session.isGameFinished, isFalse); }); - test('updatePoints - game finished', () async { + test('updatePoints - game finished', () { session.addRoundScoresToList(1, [101, 20, 30], [101, 20, 30], 0); - await session.updatePoints(); + session.updatePoints(); expect(session.isGameFinished, isTrue); }); @@ -154,9 +154,9 @@ void main() { expect(session.playerScores, equals([50, 0, 30])); }); - test('_setWinner via updatePoints', () async { + test('_setWinner via updatePoints', () { session.addRoundScoresToList(1, [101, 20, 30], [101, 0, 30], 1); - await session.updatePoints(); + session.updatePoints(); expect(session.winner, 'Bob'); // Bob has lowest score (20) }); }); From 0a0da96a3f68b939177c403825077e8e4b06052c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 10:01:11 +0200 Subject: [PATCH 151/353] Created Strings for popup --- lib/l10n/arb/app_de.arb | 16 +++++++++++++++ lib/l10n/arb/app_en.arb | 16 +++++++++++++++ lib/l10n/generated/app_localizations.dart | 13 ++++++++++++ lib/l10n/generated/app_localizations_de.dart | 17 ++++++++++++++++ lib/l10n/generated/app_localizations_en.dart | 17 ++++++++++++++++ lib/presentation/views/round_view.dart | 21 ++++++++++---------- pubspec.yaml | 2 +- 7 files changed, 91 insertions(+), 11 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index b072d63..355ab43 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -73,6 +73,22 @@ "kamikaze": "Kamikaze", "done": "Fertig", "next_round": "Nächste Runde", + "bonus_points_title": "Bonus-Punkte!", + "bonus_points_message": "{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}", + "@bonus_points_message": { + "placeholders": { + "names": { + "type": "String" + }, + "pointLimit": { + "type": "int" + }, + "bonusPoints": { + "type": "int" + } + } + }, + "end_game": "Spiel beenden", "delete_game": "Spiel löschen", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index a649362..08072f1 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -73,6 +73,22 @@ "kamikaze": "Kamikaze", "done": "Done", "next_round": "Next Round", + "bonus_points_title": "Bonus-Points!", + "bonus_points_message": "{playerCount, plural, =1{{names} has reached exactly the point limit of {pointLimit} points and therefore gets {bonusPoints} points deducted!} other{{names} have reached exactly the point limit of {pointLimit} points and therefore get {bonusPoints} points deducted!}}", + "@bonus_points_message": { + "placeholders": { + "names": { + "type": "String" + }, + "pointLimit": { + "type": "int" + }, + "bonusPoints": { + "type": "int" + } + } + }, + "end_game": "End Game", "delete_game": "Delete Game", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 2059f1b..5c91414 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -416,6 +416,19 @@ abstract class AppLocalizations { /// **'Nächste Runde'** String get next_round; + /// No description provided for @bonus_points_title. + /// + /// In de, this message translates to: + /// **'Bonus-Punkte!'** + String get bonus_points_title; + + /// No description provided for @bonus_points_message. + /// + /// In de, this message translates to: + /// **'{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}'** + String bonus_points_message( + String names, int pointLimit, int bonusPoints, num playerCount); + /// No description provided for @end_game. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 068711f..2007e48 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -178,6 +178,23 @@ class AppLocalizationsDe extends AppLocalizations { @override String get next_round => 'Nächste Runde'; + @override + String get bonus_points_title => 'Bonus-Punkte!'; + + @override + String bonus_points_message( + String names, int pointLimit, int bonusPoints, num playerCount) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names haben exakt das Punktelimit von $pointLimit Punkten erreicht und bekommen deshalb jeweils $bonusPoints Punkte abgezogen!', + one: + '$names hat exakt das Punktelimit von $pointLimit Punkten erreicht und bekommt deshalb $bonusPoints Punkte abgezogen!', + ); + return '$_temp0'; + } + @override String get end_game => 'Spiel beenden'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 06b5c03..0830f23 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -175,6 +175,23 @@ class AppLocalizationsEn extends AppLocalizations { @override String get next_round => 'Next Round'; + @override + String get bonus_points_title => 'Bonus-Points!'; + + @override + String bonus_points_message( + String names, int pointLimit, int bonusPoints, num playerCount) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names have reached exactly the point limit of $pointLimit points and therefore get $bonusPoints points deducted!', + one: + '$names has reached exactly the point limit of $pointLimit points and therefore gets $bonusPoints points deducted!', + ); + return '$_temp0'; + } + @override String get end_game => 'End Game'; diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 602c702..fdf2b13 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -403,17 +403,18 @@ class _RoundViewState extends State { int pointLimit = widget.gameSession.pointLimit; int bonusPoints = (pointLimit / 2).round(); - String resultText = _getPopupString(pointLimit, bonusPoints, bonusPlayers); + String resultText = + _getBonusPopupMessageString(pointLimit, bonusPoints, bonusPlayers); await showCupertinoDialog( context: context, builder: (context) => CupertinoAlertDialog( - title: const Text('Bonus!'), + title: Text(AppLocalizations.of(context).bonus_points_title), content: Text(resultText), actions: [ CupertinoDialogAction( - child: const Text('OK'), - onPressed: () => Navigator.of(context).pop(true), + child: Text(AppLocalizations.of(context).ok), + onPressed: () => Navigator.of(context).pop(), ), ], ), @@ -421,23 +422,23 @@ class _RoundViewState extends State { return true; } - /// Generates the string for the bonus popup. + /// Generates the message string for the bonus popup. /// It takes the [pointLimit], [bonusPoints] and the list of [bonusPlayers] /// and returns a formatted string. - String _getPopupString( + String _getBonusPopupMessageString( int pointLimit, int bonusPoints, List bonusPlayers) { List nameList = bonusPlayers.map((i) => widget.gameSession.players[i]).toList(); String resultText = ''; if (nameList.length == 1) { - resultText = - '${nameList.first} hat exakt das Punktelimit von $pointLimit Punkten erreicht und bekommt deshalb $bonusPoints Punkte abgezogen!'; + resultText = AppLocalizations.of(context).bonus_points_message( + nameList.first, pointLimit, bonusPoints, nameList.length); } else { resultText = nameList.length == 2 ? '${nameList[0]} & ${nameList[1]}' : '${nameList.sublist(0, nameList.length - 1).join(', ')} & ${nameList.last}'; - resultText += - ' haben exakt das Punktelimit von $pointLimit Punkten erreicht und bekommen deshalb $bonusPoints Punkte abgezogen!'; + resultText = AppLocalizations.of(context).bonus_points_message( + resultText, pointLimit, bonusPoints, nameList.length); } return resultText; } diff --git a/pubspec.yaml b/pubspec.yaml index f2b4949..4444d73 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.4+488 +version: 0.4.5+492 environment: sdk: ^3.5.4 From db6d4690cba5f863d8c0b0f3f1fa0b978407d53c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 10:09:12 +0200 Subject: [PATCH 152/353] Implemented mounted checks & changed return type --- lib/presentation/views/round_view.dart | 9 +++++---- pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index fdf2b13..2d1f785 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -293,6 +293,7 @@ class _RoundViewState extends State { await _showBonusPopup(context, boni); } LocalStorageService.saveGameSessions(); + if (!context.mounted) return; Navigator.pop(context); } : null, @@ -307,9 +308,10 @@ class _RoundViewState extends State { await _showBonusPopup(context, boni); } LocalStorageService.saveGameSessions(); - if (widget.gameSession.isGameFinished) { + if (widget.gameSession.isGameFinished && + context.mounted) { Navigator.pop(context); - } else { + } else if (context.mounted) { Navigator.pop( context, widget.roundNumber + 1); } @@ -397,7 +399,7 @@ class _RoundViewState extends State { } /// Shows a popup dialog with the bonus information. - Future _showBonusPopup( + Future _showBonusPopup( BuildContext context, List bonusPlayers) async { print('Bonus Popup wird angezeigt'); int pointLimit = widget.gameSession.pointLimit; @@ -419,7 +421,6 @@ class _RoundViewState extends State { ], ), ); - return true; } /// Generates the message string for the bonus popup. diff --git a/pubspec.yaml b/pubspec.yaml index 4444d73..4d0b0f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.5+492 +version: 0.4.5+493 environment: sdk: ^3.5.4 From c24c271c8220b5fccb47daee2786d07a43c8c2a9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 10:14:53 +0200 Subject: [PATCH 153/353] Updated comment --- lib/data/game_session.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 54c095b..d1402e5 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -235,7 +235,7 @@ class GameSession extends ChangeNotifier { /// This method updates the points of each player after a round. /// It first uses the _sumPoints() method to calculate the total points of each player. - /// Then, it checks if any player has reached 100 points. If so, it marks + /// Then, it checks if any player has reached 100 points. If so, saves their indices and marks /// that player as having reached 100 points in that corresponding [Round] object. /// If the game has the point limit activated, it first applies the /// _subtractPointsForReachingHundred() method to subtract 50 points @@ -243,6 +243,8 @@ class GameSession extends ChangeNotifier { /// It then checks if any player has exceeded 100 points. If so, it sets /// isGameFinished to true and calls the _setWinner() method to determine /// the winner. + /// It returns a list of players indices who reached 100 points in the current + /// round for the [RoundView] to show a popup List updatePoints() { List bonusPlayers = []; _sumPoints(); From a8298dfa21d3d6df8f06f7812d0bce340971a536 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 10:16:42 +0200 Subject: [PATCH 154/353] Updated variable name --- lib/presentation/views/round_view.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 2d1f785..45ce0ef 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -288,9 +288,10 @@ class _RoundViewState extends State { CupertinoButton( onPressed: _areRoundInputsValid() ? () async { - List boni = _finishRound(); - if (boni.isNotEmpty) { - await _showBonusPopup(context, boni); + List bonusPlayersIndices = _finishRound(); + if (bonusPlayersIndices.isNotEmpty) { + await _showBonusPopup( + context, bonusPlayersIndices); } LocalStorageService.saveGameSessions(); if (!context.mounted) return; @@ -303,9 +304,11 @@ class _RoundViewState extends State { CupertinoButton( onPressed: _areRoundInputsValid() ? () async { - List boni = _finishRound(); - if (boni.isNotEmpty) { - await _showBonusPopup(context, boni); + List bonusPlayersIndices = + _finishRound(); + if (bonusPlayersIndices.isNotEmpty) { + await _showBonusPopup( + context, bonusPlayersIndices); } LocalStorageService.saveGameSessions(); if (widget.gameSession.isGameFinished && From 047acfecd8df9123676bc73053cb42f51e3fea6a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 10:17:51 +0200 Subject: [PATCH 155/353] Updated string placeholders --- lib/l10n/arb/app_de.arb | 3 +++ lib/l10n/arb/app_en.arb | 3 +++ lib/presentation/views/round_view.dart | 8 ++++++-- pubspec.yaml | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 355ab43..93215ed 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -77,6 +77,9 @@ "bonus_points_message": "{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}", "@bonus_points_message": { "placeholders": { + "playerCount": { + "type": "int" + }, "names": { "type": "String" }, diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 08072f1..19695a5 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -77,6 +77,9 @@ "bonus_points_message": "{playerCount, plural, =1{{names} has reached exactly the point limit of {pointLimit} points and therefore gets {bonusPoints} points deducted!} other{{names} have reached exactly the point limit of {pointLimit} points and therefore get {bonusPoints} points deducted!}}", "@bonus_points_message": { "placeholders": { + "playerCount": { + "type": "int" + }, "names": { "type": "String" }, diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 45ce0ef..a821fb5 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -436,13 +436,17 @@ class _RoundViewState extends State { String resultText = ''; if (nameList.length == 1) { resultText = AppLocalizations.of(context).bonus_points_message( - nameList.first, pointLimit, bonusPoints, nameList.length); + nameList.length, nameList.first, pointLimit, bonusPoints); } else { resultText = nameList.length == 2 ? '${nameList[0]} & ${nameList[1]}' : '${nameList.sublist(0, nameList.length - 1).join(', ')} & ${nameList.last}'; resultText = AppLocalizations.of(context).bonus_points_message( - resultText, pointLimit, bonusPoints, nameList.length); + nameList.length, + resultText, + pointLimit, + bonusPoints, + ); } return resultText; } diff --git a/pubspec.yaml b/pubspec.yaml index 4d0b0f6..9db5d4b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.5+493 +version: 0.4.5+494 environment: sdk: ^3.5.4 From 79d0bdd19b7341a3a33dc7552f1f4d5e102a19cb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 10:19:51 +0200 Subject: [PATCH 156/353] Generated files update --- lib/l10n/generated/app_localizations.dart | 2 +- lib/l10n/generated/app_localizations_de.dart | 2 +- lib/l10n/generated/app_localizations_en.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 5c91414..0a902f6 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -427,7 +427,7 @@ abstract class AppLocalizations { /// In de, this message translates to: /// **'{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}'** String bonus_points_message( - String names, int pointLimit, int bonusPoints, num playerCount); + int playerCount, String names, int pointLimit, int bonusPoints); /// No description provided for @end_game. /// diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 2007e48..7a71d00 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -183,7 +183,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String bonus_points_message( - String names, int pointLimit, int bonusPoints, num playerCount) { + int playerCount, String names, int pointLimit, int bonusPoints) { String _temp0 = intl.Intl.pluralLogic( playerCount, locale: localeName, diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 0830f23..4d4d663 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -180,7 +180,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String bonus_points_message( - String names, int pointLimit, int bonusPoints, num playerCount) { + int playerCount, String names, int pointLimit, int bonusPoints) { String _temp0 = intl.Intl.pluralLogic( playerCount, locale: localeName, From 16d1c017afbf2df8b3cc0a2f0e64fc8ee4bacc81 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:06:02 +0200 Subject: [PATCH 157/353] Updated _getPlacementPrefix method for dense ranks --- lib/presentation/views/active_game_view.dart | 65 ++++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 704952a..c280e59 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -58,7 +58,8 @@ class _ActiveGameViewState extends State { return CupertinoListTile( title: Row( children: [ - _getPlacementPrefix(index), + _getPlacementPrefix( + index, gameSession.playerScores), const SizedBox(width: 5), Text( gameSession.players[playerIndex], @@ -266,36 +267,52 @@ class _ActiveGameViewState extends State { playerIndices.sort((a, b) { int scoreA = gameSession.playerScores[a]; int scoreB = gameSession.playerScores[b]; - return scoreA.compareTo(scoreB); + if (scoreA != scoreB) { + return scoreA.compareTo(scoreB); + } + return a.compareTo(b); }); return playerIndices; } - /// Returns a widget that displays the placement prefix based on the index. - /// First three places are represented by medals, and the rest are numbered. - /// [index] is the index of the player in the descending sorted list. - Widget _getPlacementPrefix(int index) { - switch (index) { - case 0: - return const Text( - '\u{1F947}', - style: TextStyle(fontSize: 22), - ); + /// Returns a widget representing the placement prefix for a player based on their index. + /// [index] is the index of the player in [players] list, + /// [playerScores] is a list of the players scores. + Widget _getPlacementPrefix(int index, playerScores) { + int placement = _calculateDenseRank(index, playerScores); + return _getPlacementTextWidget(placement); + } + + /// Calculates the dense rank for a player based on their index in the sorted list of players. + int _calculateDenseRank(int index, List playerScores) { + List sortedIndices = _getSortedPlayerIndices(); + List denseRanks = []; + int rank = 1; + for (int i = 0; i < sortedIndices.length; i++) { + if (i > 0) { + int prevScore = playerScores[sortedIndices[i - 1]]; + int currScore = playerScores[sortedIndices[i]]; + if (currScore != prevScore) { + rank++; + } + } + denseRanks.add(rank); + } + return denseRanks[index]; + } + + /// Returns a text widget representing the placement text based on the given placement number. + Text _getPlacementTextWidget(int placement) { + switch (placement) { case 1: - return const Text( - '\u{1F948}', - style: TextStyle(fontSize: 22), - ); + return const Text('\u{1F947}', style: TextStyle(fontSize: 22)); // 🥇 case 2: - return const Text( - '\u{1F949}', - style: TextStyle(fontSize: 22), - ); + return const Text('\u{1F948}', style: TextStyle(fontSize: 22)); // 🥈 + case 3: + return const Text('\u{1F949}', style: TextStyle(fontSize: 22)); // 🥉 default: - return Text( - ' ${index + 1}.', - style: const TextStyle(fontWeight: FontWeight.bold), - ); + return Text('$placement.', + style: const TextStyle(fontWeight: FontWeight.bold)); } } diff --git a/pubspec.yaml b/pubspec.yaml index 9db5d4b..d50b43a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.5+494 +version: 0.4.6+497 environment: sdk: ^3.5.4 From 48784fd29048c4b8bd246c95aa1b56600e1673fe Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:07:14 +0200 Subject: [PATCH 158/353] Updated comments --- lib/presentation/views/active_game_view.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index c280e59..427fdc8 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -316,6 +316,7 @@ class _ActiveGameViewState extends State { } } + /// Shows a dialog to confirm deleting the game session. Future _showDeleteGameDialog() async { return await showCupertinoDialog( context: context, @@ -348,6 +349,8 @@ class _ActiveGameViewState extends State { false; } + /// Removes the game session in the game manager and navigates back to the previous screen. + /// If the game session does not exist in the game list, it shows an error dialog. Future _removeGameSession(GameSession gameSession) async { if (gameManager.gameExistsInGameList(gameSession.id)) { Navigator.pop(context); From f8bbbb04f3af4f08e571612bd1e8ca2061464e3a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:12:32 +0200 Subject: [PATCH 159/353] Added type annotation --- lib/presentation/views/active_game_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 427fdc8..8698c62 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -278,7 +278,7 @@ class _ActiveGameViewState extends State { /// Returns a widget representing the placement prefix for a player based on their index. /// [index] is the index of the player in [players] list, /// [playerScores] is a list of the players scores. - Widget _getPlacementPrefix(int index, playerScores) { + Widget _getPlacementPrefix(int index, List playerScores) { int placement = _calculateDenseRank(index, playerScores); return _getPlacementTextWidget(placement); } From 4a0ce067b5f3a91056baf9cf61fe0ffe2a554b67 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:14:22 +0200 Subject: [PATCH 160/353] Updated function _getSortedPlayerIndices() --- lib/presentation/views/active_game_view.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 8698c62..6eaee45 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -32,7 +32,10 @@ class _ActiveGameViewState extends State { return ListenableBuilder( listenable: gameSession, builder: (context, _) { - List sortedPlayerIndices = _getSortedPlayerIndices(); + List playerIndices = + List.generate(gameSession.players.length, (index) => index); + List sortedPlayerIndices = + _getSortedPlayerIndices(playerIndices); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(gameSession.gameTitle), @@ -260,9 +263,7 @@ class _ActiveGameViewState extends State { /// Returns a list of player indices sorted by their scores in /// ascending order. - List _getSortedPlayerIndices() { - List playerIndices = - List.generate(gameSession.players.length, (index) => index); + List _getSortedPlayerIndices(List playerIndices) { // Sort the indices based on the summed points playerIndices.sort((a, b) { int scoreA = gameSession.playerScores[a]; @@ -285,7 +286,7 @@ class _ActiveGameViewState extends State { /// Calculates the dense rank for a player based on their index in the sorted list of players. int _calculateDenseRank(int index, List playerScores) { - List sortedIndices = _getSortedPlayerIndices(); + List sortedIndices = _getSortedPlayerIndices(playerScores); List denseRanks = []; int rank = 1; for (int i = 0; i < sortedIndices.length; i++) { From 84e6f3f28653e95bbd7486f27c89d0f867b4454e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:14:44 +0200 Subject: [PATCH 161/353] Updated build method --- lib/presentation/views/active_game_view.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 6eaee45..2153d1d 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -29,13 +29,13 @@ class _ActiveGameViewState extends State { @override Widget build(BuildContext context) { + List playerIndices = + List.generate(gameSession.players.length, (index) => index); + List sortedPlayerIndices = _getSortedPlayerIndices(playerIndices); + return ListenableBuilder( listenable: gameSession, builder: (context, _) { - List playerIndices = - List.generate(gameSession.players.length, (index) => index); - List sortedPlayerIndices = - _getSortedPlayerIndices(playerIndices); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(gameSession.gameTitle), From 8b4a8bb86be4523807cff3ce428fbf30258e0926 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:30:55 +0200 Subject: [PATCH 162/353] Refactored and simplified --- lib/presentation/views/active_game_view.dart | 33 +++++++++----------- pubspec.yaml | 2 +- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 2153d1d..a4c52ee 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -20,6 +20,8 @@ class ActiveGameView extends StatefulWidget { class _ActiveGameViewState extends State { late final GameSession gameSession; + late final List denseRanks; + late List sortedPlayerIndices; @override void initState() { @@ -29,13 +31,11 @@ class _ActiveGameViewState extends State { @override Widget build(BuildContext context) { - List playerIndices = - List.generate(gameSession.players.length, (index) => index); - List sortedPlayerIndices = _getSortedPlayerIndices(playerIndices); - return ListenableBuilder( listenable: gameSession, builder: (context, _) { + sortedPlayerIndices = _getSortedPlayerIndices(); + denseRanks = _calculateDenseRank(gameSession.playerScores); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(gameSession.gameTitle), @@ -61,8 +61,7 @@ class _ActiveGameViewState extends State { return CupertinoListTile( title: Row( children: [ - _getPlacementPrefix( - index, gameSession.playerScores), + _getPlacementTextWidget(index), const SizedBox(width: 5), Text( gameSession.players[playerIndex], @@ -263,7 +262,9 @@ class _ActiveGameViewState extends State { /// Returns a list of player indices sorted by their scores in /// ascending order. - List _getSortedPlayerIndices(List playerIndices) { + List _getSortedPlayerIndices() { + List playerIndices = + List.generate(gameSession.players.length, (index) => index); // Sort the indices based on the summed points playerIndices.sort((a, b) { int scoreA = gameSession.playerScores[a]; @@ -276,17 +277,9 @@ class _ActiveGameViewState extends State { return playerIndices; } - /// Returns a widget representing the placement prefix for a player based on their index. - /// [index] is the index of the player in [players] list, - /// [playerScores] is a list of the players scores. - Widget _getPlacementPrefix(int index, List playerScores) { - int placement = _calculateDenseRank(index, playerScores); - return _getPlacementTextWidget(placement); - } - /// Calculates the dense rank for a player based on their index in the sorted list of players. - int _calculateDenseRank(int index, List playerScores) { - List sortedIndices = _getSortedPlayerIndices(playerScores); + List _calculateDenseRank(List playerScores) { + List sortedIndices = _getSortedPlayerIndices(); List denseRanks = []; int rank = 1; for (int i = 0; i < sortedIndices.length; i++) { @@ -299,11 +292,13 @@ class _ActiveGameViewState extends State { } denseRanks.add(rank); } - return denseRanks[index]; + return denseRanks; } /// Returns a text widget representing the placement text based on the given placement number. - Text _getPlacementTextWidget(int placement) { + /// [index] is the index of the player in [players] list, + Text _getPlacementTextWidget(int index) { + int placement = denseRanks[index]; switch (placement) { case 1: return const Text('\u{1F947}', style: TextStyle(fontSize: 22)); // 🥇 diff --git a/pubspec.yaml b/pubspec.yaml index d50b43a..95fea1d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.6+497 +version: 0.4.6+504 environment: sdk: ^3.5.4 From f4120d28a9948c20214d167fc367ef763bd5d5b1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:38:28 +0200 Subject: [PATCH 163/353] Removed late --- lib/presentation/views/active_game_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index a4c52ee..1ea0a0d 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -20,7 +20,7 @@ class ActiveGameView extends StatefulWidget { class _ActiveGameViewState extends State { late final GameSession gameSession; - late final List denseRanks; + late List denseRanks; late List sortedPlayerIndices; @override From 5a939f4447e7bfb3d8ef651a5c04b372a7c8bf4e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:39:32 +0200 Subject: [PATCH 164/353] Unnessecary code --- lib/presentation/views/active_game_view.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 1ea0a0d..9715f77 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -35,7 +35,8 @@ class _ActiveGameViewState extends State { listenable: gameSession, builder: (context, _) { sortedPlayerIndices = _getSortedPlayerIndices(); - denseRanks = _calculateDenseRank(gameSession.playerScores); + denseRanks = _calculateDenseRank( + gameSession.playerScores, sortedPlayerIndices); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(gameSession.gameTitle), @@ -278,8 +279,8 @@ class _ActiveGameViewState extends State { } /// Calculates the dense rank for a player based on their index in the sorted list of players. - List _calculateDenseRank(List playerScores) { - List sortedIndices = _getSortedPlayerIndices(); + List _calculateDenseRank( + List playerScores, List sortedIndices) { List denseRanks = []; int rank = 1; for (int i = 0; i < sortedIndices.length; i++) { From f7676da88d15f0d49d559645c488aff7e3deab0c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 11:40:03 +0200 Subject: [PATCH 165/353] Added white space --- lib/presentation/views/active_game_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 9715f77..ab07804 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -308,7 +308,7 @@ class _ActiveGameViewState extends State { case 3: return const Text('\u{1F949}', style: TextStyle(fontSize: 22)); // 🥉 default: - return Text('$placement.', + return Text(' $placement.', style: const TextStyle(fontWeight: FontWeight.bold)); } } From 4cfbaa00c0280f95dc93e804dcb419fd0cdd9a3b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 12:20:47 +0200 Subject: [PATCH 166/353] Implemented reordering --- lib/presentation/views/round_view.dart | 96 +++++++++++++++++++++----- pubspec.yaml | 2 +- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index a821fb5..0c5b0e4 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -5,6 +5,7 @@ import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class RoundView extends StatefulWidget { final GameSession gameSession; @@ -67,6 +68,8 @@ class _RoundViewState extends State { @override Widget build(BuildContext context) { final bottomInset = MediaQuery.of(context).viewInsets.bottom; + final rotatedPlayers = _getRotatedPlayers(); + final originalIndices = _getOriginalIndices(); return CupertinoPageScaffold( resizeToAvoidBottomInset: false, @@ -175,9 +178,10 @@ class _RoundViewState extends State { ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemCount: widget.gameSession.players.length, + itemCount: rotatedPlayers.length, itemBuilder: (context, index) { - final name = widget.gameSession.players[index]; + final originalIndex = originalIndices[index]; + final name = rotatedPlayers[index]; return Padding( padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 20), @@ -187,13 +191,23 @@ class _RoundViewState extends State { backgroundColor: CupertinoColors.secondaryLabel, title: Row(children: [ Expanded( - child: Text( - name, - overflow: TextOverflow.ellipsis, - )) + child: Row(children: [ + Text( + name, + overflow: TextOverflow.ellipsis, + ), + Visibility( + visible: index == 0, + child: const SizedBox(width: 10), + ), + Visibility( + visible: index == 0, + child: const Icon(FontAwesomeIcons.medal, + size: 15)) + ])) ]), subtitle: Text( - '${widget.gameSession.playerScores[index]}' + '${widget.gameSession.playerScores[originalIndex]}' ' ${AppLocalizations.of(context).points}'), trailing: Row( children: [ @@ -201,7 +215,7 @@ class _RoundViewState extends State { width: 100, child: CupertinoTextField( maxLength: 3, - focusNode: _focusNodeList[index], + focusNode: _focusNodeList[originalIndex], keyboardType: const TextInputType.numberWithOptions( signed: true, @@ -216,12 +230,13 @@ class _RoundViewState extends State { 1 ? TextInputAction.done : TextInputAction.next, - controller: _scoreControllerList[index], + controller: + _scoreControllerList[originalIndex], placeholder: AppLocalizations.of(context).points, textAlign: TextAlign.center, onSubmitted: (_) => - _focusNextTextfield(index), + _focusNextTextfield(originalIndex), onChanged: (_) => setState(() {}), ), ), @@ -230,7 +245,8 @@ class _RoundViewState extends State { onTap: () { setState(() { _kamikazePlayerIndex = - (_kamikazePlayerIndex == index) + (_kamikazePlayerIndex == + originalIndex) ? null : index; }); @@ -240,17 +256,20 @@ class _RoundViewState extends State { height: 24, decoration: BoxDecoration( shape: BoxShape.circle, - color: _kamikazePlayerIndex == index + color: _kamikazePlayerIndex == + originalIndex ? CupertinoColors.systemRed : CupertinoColors .tertiarySystemFill, border: Border.all( - color: _kamikazePlayerIndex == index + color: _kamikazePlayerIndex == + originalIndex ? CupertinoColors.systemRed : CupertinoColors.systemGrey, ), ), - child: _kamikazePlayerIndex == index + child: _kamikazePlayerIndex == + originalIndex ? const Icon( CupertinoIcons.exclamationmark, size: 16, @@ -338,8 +357,12 @@ class _RoundViewState extends State { /// Focuses the next text field in the list of text fields. /// [index] is the index of the current text field. void _focusNextTextfield(int index) { - if (index < widget.gameSession.players.length - 1) { - FocusScope.of(context).requestFocus(_focusNodeList[index + 1]); + final originalIndices = _getOriginalIndices(); + final currentPos = originalIndices.indexOf(index); + + if (currentPos < originalIndices.length - 1) { + FocusScope.of(context) + .requestFocus(_focusNodeList[originalIndices[currentPos + 1]]); } else { _focusNodeList[index].unfocus(); } @@ -451,6 +474,47 @@ class _RoundViewState extends State { return resultText; } + List _getRotatedPlayers() { + final winnerIndex = _getPreviousRoundWinnerIndex(); + return [ + widget.gameSession.players[winnerIndex], + ...widget.gameSession.players.sublist(winnerIndex + 1), + ...widget.gameSession.players.sublist(0, winnerIndex) + ]; + } + + List _getOriginalIndices() { + final winnerIndex = _getPreviousRoundWinnerIndex(); + return [ + winnerIndex, + ...List.generate(widget.gameSession.players.length - winnerIndex - 1, + (i) => winnerIndex + i + 1), + ...List.generate(winnerIndex, (i) => i) + ]; + } + + int _getPreviousRoundWinnerIndex() { + if (widget.roundNumber == 1) { + return 0; // In der ersten Runde einfach den ersten Spieler nehmen + } + + final previousRound = widget.gameSession.roundList[widget.roundNumber - 2]; + final scores = previousRound.scores; + + // Finde den niedrigsten Score (Gewinner) + int minScore = scores[0]; + int winnerIndex = 0; + + for (int i = 1; i < scores.length; i++) { + if (scores[i] < minScore) { + minScore = scores[i]; + winnerIndex = i; + } + } + + return winnerIndex; + } + @override void dispose() { for (final controller in _scoreControllerList) { diff --git a/pubspec.yaml b/pubspec.yaml index 95fea1d..ba369cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.6+504 +version: 0.4.6+505 environment: sdk: ^3.5.4 From 37338dca766f2ef9efa467c1529b5c7f38ab58b6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 12:34:57 +0200 Subject: [PATCH 167/353] Refactoring --- lib/presentation/views/round_view.dart | 86 ++++++++++++++------------ 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 0c5b0e4..113791c 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -354,6 +354,51 @@ class _RoundViewState extends State { ); } + /// Gets the index of the player who won the previous round. + int _getPreviousRoundWinnerIndex() { + if (widget.roundNumber == 1) { + return 0; // If it's the first round, there's no previous round, so return 0. + } + + final previousRound = widget.gameSession.roundList[widget.roundNumber - 2]; + final scores = previousRound.scoreUpdates; + + // Find the index of the player with the minimum score + int minScore = scores[0]; + int winnerIndex = 0; + + // Iterate through the scores to find the player with the minimum score + for (int i = 1; i < scores.length; i++) { + if (scores[i] < minScore) { + minScore = scores[i]; + winnerIndex = i; + } + } + + return winnerIndex; + } + + /// Rotates the players list based on the previous round's winner. + List _getRotatedPlayers() { + final winnerIndex = _getPreviousRoundWinnerIndex(); + return [ + widget.gameSession.players[winnerIndex], + ...widget.gameSession.players.sublist(winnerIndex + 1), + ...widget.gameSession.players.sublist(0, winnerIndex) + ]; + } + + /// Gets the original indices of the players by recalculating it from the rotated list. + List _getOriginalIndices() { + final winnerIndex = _getPreviousRoundWinnerIndex(); + return [ + winnerIndex, + ...List.generate(widget.gameSession.players.length - winnerIndex - 1, + (i) => winnerIndex + i + 1), + ...List.generate(winnerIndex, (i) => i) + ]; + } + /// Focuses the next text field in the list of text fields. /// [index] is the index of the current text field. void _focusNextTextfield(int index) { @@ -474,47 +519,6 @@ class _RoundViewState extends State { return resultText; } - List _getRotatedPlayers() { - final winnerIndex = _getPreviousRoundWinnerIndex(); - return [ - widget.gameSession.players[winnerIndex], - ...widget.gameSession.players.sublist(winnerIndex + 1), - ...widget.gameSession.players.sublist(0, winnerIndex) - ]; - } - - List _getOriginalIndices() { - final winnerIndex = _getPreviousRoundWinnerIndex(); - return [ - winnerIndex, - ...List.generate(widget.gameSession.players.length - winnerIndex - 1, - (i) => winnerIndex + i + 1), - ...List.generate(winnerIndex, (i) => i) - ]; - } - - int _getPreviousRoundWinnerIndex() { - if (widget.roundNumber == 1) { - return 0; // In der ersten Runde einfach den ersten Spieler nehmen - } - - final previousRound = widget.gameSession.roundList[widget.roundNumber - 2]; - final scores = previousRound.scores; - - // Finde den niedrigsten Score (Gewinner) - int minScore = scores[0]; - int winnerIndex = 0; - - for (int i = 1; i < scores.length; i++) { - if (scores[i] < minScore) { - minScore = scores[i]; - winnerIndex = i; - } - } - - return winnerIndex; - } - @override void dispose() { for (final controller in _scoreControllerList) { From b225b28e32bb815f4c47babe4184a6d38bb214cc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 12:35:13 +0200 Subject: [PATCH 168/353] Updated version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index ba369cf..5a10eca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.6+505 +version: 0.4.7+505 environment: sdk: ^3.5.4 From 4478c00b9d770fb5810d4de97665f56fd8d1e29f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 12:42:30 +0200 Subject: [PATCH 169/353] Corrected kamikaze index --- lib/presentation/views/round_view.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 113791c..7c62120 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -248,7 +248,7 @@ class _RoundViewState extends State { (_kamikazePlayerIndex == originalIndex) ? null - : index; + : originalIndex; }); }, child: Container( diff --git a/pubspec.yaml b/pubspec.yaml index 5a10eca..6773a53 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+505 +version: 0.4.7+506 environment: sdk: ^3.5.4 From 287d57d973d04825412549525961a0a693f3a5a6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 14 Jul 2025 14:19:25 +0200 Subject: [PATCH 170/353] Update Version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 23ec7d3..66eab9f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.4.4-orange) +![Version](https://img.shields.io/badge/Version-0.4.7-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) From cc6a7fee2543d3c4b6382816984c2e5866478dec Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 16 Jul 2025 14:27:38 +0200 Subject: [PATCH 171/353] Fixed bug with wrong medal icon --- lib/presentation/views/round_view.dart | 6 ++++-- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 7c62120..2506cde 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -197,11 +197,13 @@ class _RoundViewState extends State { overflow: TextOverflow.ellipsis, ), Visibility( - visible: index == 0, + visible: + index == 0 && widget.roundNumber != 1, child: const SizedBox(width: 10), ), Visibility( - visible: index == 0, + visible: + index == 0 && widget.roundNumber != 1, child: const Icon(FontAwesomeIcons.medal, size: 15)) ])) diff --git a/pubspec.yaml b/pubspec.yaml index 6773a53..6b71a0f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+506 +version: 0.4.7+507 environment: sdk: ^3.5.4 From 77b551715fe6abca3b1bdc2481a0f215a87f206a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 16 Jul 2025 14:28:49 +0200 Subject: [PATCH 172/353] change not equal to greater than --- lib/presentation/views/round_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 2506cde..a7ddde1 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -198,12 +198,12 @@ class _RoundViewState extends State { ), Visibility( visible: - index == 0 && widget.roundNumber != 1, + index == 0 && widget.roundNumber > 1, child: const SizedBox(width: 10), ), Visibility( visible: - index == 0 && widget.roundNumber != 1, + index == 0 && widget.roundNumber > 1, child: const Icon(FontAwesomeIcons.medal, size: 15)) ])) From 2033f43843450ae1aa4fa7e96d1b1fd8c976afe5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 16 Jul 2025 14:32:40 +0200 Subject: [PATCH 173/353] Updated bool var --- lib/presentation/views/round_view.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index a7ddde1..9e2b40f 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -182,6 +182,8 @@ class _RoundViewState extends State { itemBuilder: (context, index) { final originalIndex = originalIndices[index]; final name = rotatedPlayers[index]; + bool shouldShowMedal = + index == 0 && widget.roundNumber > 1; return Padding( padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 20), @@ -197,13 +199,11 @@ class _RoundViewState extends State { overflow: TextOverflow.ellipsis, ), Visibility( - visible: - index == 0 && widget.roundNumber > 1, + visible: shouldShowMedal, child: const SizedBox(width: 10), ), Visibility( - visible: - index == 0 && widget.roundNumber > 1, + visible: shouldShowMedal, child: const Icon(FontAwesomeIcons.medal, size: 15)) ])) From 1b4c377a13fa67ecfdb1b4ad46b611f2d4824741 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 18 Jul 2025 22:36:59 +0200 Subject: [PATCH 174/353] Fixed deletion error --- lib/presentation/views/main_menu_view.dart | 8 +++----- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 86ff208..6715ba6 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -126,7 +126,7 @@ class _MainMenuViewState extends State { listenable: session, builder: (context, _) { return Dismissible( - key: Key(session.gameTitle), + key: Key(session.id), background: Container( color: CupertinoColors.destructiveRed, alignment: Alignment.centerRight, @@ -139,14 +139,12 @@ class _MainMenuViewState extends State { ), direction: DismissDirection.endToStart, confirmDismiss: (direction) async { - final String gameTitle = gameManager - .gameList[index].gameTitle; return await _showDeleteGamePopup( - context, gameTitle); + context, session.gameTitle); }, onDismissed: (direction) { gameManager - .removeGameSessionByIndex(index); + .removeGameSessionById(session.id); }, dismissThresholds: const { DismissDirection.startToEnd: 0.6 diff --git a/pubspec.yaml b/pubspec.yaml index 6b71a0f..08e9ac7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+507 +version: 0.4.7+509 environment: sdk: ^3.5.4 From 25552d7037d6df4e8d817e8d623447481db546bb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 18 Jul 2025 22:51:59 +0200 Subject: [PATCH 175/353] Small translation improvements --- lib/l10n/arb/app_en.arb | 32 ++++++++++---------- lib/l10n/generated/app_localizations_en.dart | 32 +++++++++++--------- lib/presentation/views/main_menu_view.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 19695a5..8a327a5 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -14,13 +14,13 @@ "player": "Player", "players": "Players", "name": "Name", - "back": "Back", + "back": "Back", "home": "Home", "about": "About", "empty_text_1": "Pretty empty here...", - "empty_text_2": "Add a new round using the button in the top right corner.", + "empty_text_2": "Create a new game using the button in the top right.", "delete_game_title": "Delete game?", "delete_game_message": "Are you sure you want to delete the game \"{gameTitle}\"? This action cannot be undone.", "@delete_game_message": { @@ -46,19 +46,19 @@ "select_mode": "Select a mode", "add_player": "Add Player", "create_game": "Create Game", - "max_players_title": "Maximum reached", - "max_players_message": "A maximum of 5 players can be added.", - "no_gameTitle_title": "No Title", - "no_gameTitle_message": "You must enter a title for the game.", - "no_mode_title": "No Mode", - "no_mode_message": "You must select a game mode.", - "min_players_title": "Too few players", - "min_players_message": "At least 2 players must be added.", - "no_name_title": "No Name", + "max_players_title": "Player Limit Reached", + "max_players_message": "You can add a maximum of 5 players.", + "no_gameTitle_title": "Missing Game Title", + "no_gameTitle_message": "Please enter a title for your game.", + "no_mode_title": "Game Mode Required", + "no_mode_message": "Please select a game mode to continue", + "min_players_title": "Too Few Players", + "min_players_message": "At least 2 players are required to start the game.", + "no_name_title": "Missing Player Names", "no_name_message": "Each player must have a name.", "select_game_mode": "Select game mode", - "point_limit_description": "The game ends when a player reaches more than {pointLimit} points.", + "point_limit_description": "The game ends when a player scores more than {pointLimit} points.", "@point_limit_description": { "placeholders": { "pointLimit": { @@ -66,10 +66,10 @@ } } }, - "unlimited_description": "There is no limit. The game continues until you decide to stop.", + "unlimited_description": "The game continues until you decide to stop playing", "results": "Results", - "who_said_cabo": "Who said CABO?", + "who_said_cabo": "Who called Cabo?", "kamikaze": "Kamikaze", "done": "Done", "next_round": "Next Round", @@ -107,9 +107,9 @@ "settings": "Settings", "cabo_penalty": "Cabo Penalty", - "cabo_penalty_subtitle": "... for falsely calling Cabo.", + "cabo_penalty_subtitle": "A point penalty for incorrectly calling Cabo.", "point_limit": "Point Limit", - "point_limit_subtitle": "... the game ends here.", + "point_limit_subtitle": "The required score to win the game.", "reset_to_default": "Reset to Default", "game_data": "Game Data", "import_data": "Import Data", diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 4d4d663..440d9cd 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -61,7 +61,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get empty_text_2 => - 'Add a new round using the button in the top right corner.'; + 'Create a new game using the button in the top right.'; @override String get delete_game_title => 'Delete game?'; @@ -119,31 +119,32 @@ class AppLocalizationsEn extends AppLocalizations { String get create_game => 'Create Game'; @override - String get max_players_title => 'Maximum reached'; + String get max_players_title => 'Player Limit Reached'; @override - String get max_players_message => 'A maximum of 5 players can be added.'; + String get max_players_message => 'You can add a maximum of 5 players.'; @override - String get no_gameTitle_title => 'No Title'; + String get no_gameTitle_title => 'Missing Game Title'; @override - String get no_gameTitle_message => 'You must enter a title for the game.'; + String get no_gameTitle_message => 'Please enter a title for your game.'; @override - String get no_mode_title => 'No Mode'; + String get no_mode_title => 'Game Mode Required'; @override - String get no_mode_message => 'You must select a game mode.'; + String get no_mode_message => 'Please select a game mode to continue'; @override - String get min_players_title => 'Too few players'; + String get min_players_title => 'Too Few Players'; @override - String get min_players_message => 'At least 2 players must be added.'; + String get min_players_message => + 'At least 2 players are required to start the game.'; @override - String get no_name_title => 'No Name'; + String get no_name_title => 'Missing Player Names'; @override String get no_name_message => 'Each player must have a name.'; @@ -153,18 +154,18 @@ class AppLocalizationsEn extends AppLocalizations { @override String point_limit_description(int pointLimit) { - return 'The game ends when a player reaches more than $pointLimit points.'; + return 'The game ends when a player scores more than $pointLimit points.'; } @override String get unlimited_description => - 'There is no limit. The game continues until you decide to stop.'; + 'The game continues until you decide to stop playing'; @override String get results => 'Results'; @override - String get who_said_cabo => 'Who said CABO?'; + String get who_said_cabo => 'Who called Cabo?'; @override String get kamikaze => 'Kamikaze'; @@ -232,13 +233,14 @@ class AppLocalizationsEn extends AppLocalizations { String get cabo_penalty => 'Cabo Penalty'; @override - String get cabo_penalty_subtitle => '... for falsely calling Cabo.'; + String get cabo_penalty_subtitle => + 'A point penalty for incorrectly calling Cabo.'; @override String get point_limit => 'Point Limit'; @override - String get point_limit_subtitle => '... the game ends here.'; + String get point_limit_subtitle => 'The required score to win the game.'; @override String get reset_to_default => 'Reset to Default'; diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 6715ba6..1a818b6 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -72,7 +72,7 @@ class _MainMenuViewState extends State { }); }, icon: const Icon(CupertinoIcons.settings, size: 30)), - middle: const Text('Cabo Counter'), + middle: Text(AppLocalizations.of(context).app_name), trailing: IconButton( onPressed: () => Navigator.push( context, diff --git a/pubspec.yaml b/pubspec.yaml index 08e9ac7..a29cba1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+509 +version: 0.4.7+512 environment: sdk: ^3.5.4 From c8de78ee77759bae62dbb23011f9d3b3f795d8f4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 18 Jul 2025 23:25:20 +0200 Subject: [PATCH 176/353] Implemented first version of point overview --- lib/presentation/views/active_game_view.dart | 13 +++ .../views/point_overview_view.dart | 93 +++++++++++++++++++ pubspec.yaml | 2 +- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 lib/presentation/views/point_overview_view.dart diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index ab07804..eeae49d 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -4,6 +4,7 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/graph_view.dart'; +import 'package:cabo_counter/presentation/views/point_overview_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; @@ -135,6 +136,18 @@ class _ActiveGameViewState extends State { builder: (_) => GraphView( gameSession: gameSession, )))), + CupertinoListTile( + title: Text( + 'Übersicht', + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (_) => PointOverviewView( + gameSession: gameSession, + )))), Visibility( visible: !gameSession.isPointsLimitEnabled, child: CupertinoListTile( diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/point_overview_view.dart new file mode 100644 index 0000000..f8e15ea --- /dev/null +++ b/lib/presentation/views/point_overview_view.dart @@ -0,0 +1,93 @@ +import 'package:cabo_counter/data/game_session.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class PointOverviewView extends StatefulWidget { + final GameSession gameSession; + + const PointOverviewView({super.key, required this.gameSession}); + + @override + State createState() => _PointOverviewViewState(); +} + +class _PointOverviewViewState extends State { + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + resizeToAvoidBottomInset: true, + navigationBar: CupertinoNavigationBar( + middle: const Text('Punkte-Übersicht'), + previousPageTitle: AppLocalizations.of(context).back, + ), + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 5.0), + child: DataTable( + dataRowMinHeight: 60, + dataRowMaxHeight: 60, + dividerThickness: 0.5, + columnSpacing: 20, + columns: [ + const DataColumn(label: Text('#')), + ...widget.gameSession.players.map( + (player) => DataColumn(label: Text(player)), + ), + ], + rows: List.generate( + widget.gameSession.roundList.length, + (roundIndex) { + final round = widget.gameSession.roundList[roundIndex]; + return DataRow( + cells: [ + DataCell(Align( + alignment: Alignment.center, + child: Text( + '$roundIndex', + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 20), + ), + )), + ...List.generate(widget.gameSession.players.length, + (playerIndex) { + final score = round.scores[playerIndex]; + final update = round.scoreUpdates[playerIndex]; + return DataCell( + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: update <= 0 + ? Colors.green[200] + : Colors.red[200], + borderRadius: BorderRadius.circular(8), + ), + child: Text( + '${update >= 0 ? '+' : '-'}$update', + style: TextStyle( + color: update <= 0 + ? Colors.green[900] + : Colors.red[900], + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 4), + Text('$score'), + ], + ), + ); + }), + ], + ); + }, + ), + ), + ))); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index a29cba1..07b2551 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+512 +version: 0.4.7+513 environment: sdk: ^3.5.4 From 5b418817b20c9078fc95c501bded0c38f9d66f25 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 18 Jul 2025 23:41:09 +0200 Subject: [PATCH 177/353] Visual improvements on table --- .../views/point_overview_view.dart | 78 ++++++++++++------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/point_overview_view.dart index f8e15ea..38d74c6 100644 --- a/lib/presentation/views/point_overview_view.dart +++ b/lib/presentation/views/point_overview_view.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; @@ -24,16 +25,32 @@ class _PointOverviewViewState extends State { child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 5.0), + padding: const EdgeInsets.symmetric(horizontal: 8.0), child: DataTable( dataRowMinHeight: 60, dataRowMaxHeight: 60, dividerThickness: 0.5, columnSpacing: 20, columns: [ - const DataColumn(label: Text('#')), + const DataColumn( + numeric: true, + headingRowAlignment: MainAxisAlignment.center, + label: Text( + '#', + style: TextStyle(fontWeight: FontWeight.bold), + ), + columnWidth: IntrinsicColumnWidth(flex: 0.5)), ...widget.gameSession.players.map( - (player) => DataColumn(label: Text(player)), + (player) => DataColumn( + label: FittedBox( + fit: BoxFit.fill, + child: Text( + player, + style: + const TextStyle(fontWeight: FontWeight.bold), + )), + headingRowAlignment: MainAxisAlignment.center, + columnWidth: const IntrinsicColumnWidth(flex: 1)), ), ], rows: List.generate( @@ -46,40 +63,47 @@ class _PointOverviewViewState extends State { alignment: Alignment.center, child: Text( '$roundIndex', - style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 20), + style: const TextStyle(fontSize: 20), ), )), ...List.generate(widget.gameSession.players.length, (playerIndex) { final score = round.scores[playerIndex]; final update = round.scoreUpdates[playerIndex]; + final saidCabo = round.caboPlayerIndex == playerIndex + ? true + : false; return DataCell( - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: update <= 0 - ? Colors.green[200] - : Colors.red[200], - borderRadius: BorderRadius.circular(8), - ), - child: Text( - '${update >= 0 ? '+' : '-'}$update', - style: TextStyle( + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( color: update <= 0 - ? Colors.green[900] - : Colors.red[900], - fontWeight: FontWeight.bold, + ? CustomTheme.primaryColor + : CupertinoColors.destructiveRed, + borderRadius: BorderRadius.circular(8), + ), + child: Text( + '${update >= 0 ? '+' : '-'}$update', + style: const TextStyle( + color: CupertinoColors.white, + fontWeight: FontWeight.bold, + ), ), ), - ), - const SizedBox(height: 4), - Text('$score'), - ], + const SizedBox(height: 4), + Text('$score', + style: TextStyle( + fontWeight: saidCabo + ? FontWeight.bold + : FontWeight.normal, + )), + ], + ), ), ); }), From 0d9c8a99cd3647931b059afd37d210258dfafeb0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 00:05:44 +0200 Subject: [PATCH 178/353] Added details and sum row --- .../views/point_overview_view.dart | 205 ++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 116 insertions(+), 91 deletions(-) diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/point_overview_view.dart index 38d74c6..fe6373a 100644 --- a/lib/presentation/views/point_overview_view.dart +++ b/lib/presentation/views/point_overview_view.dart @@ -17,101 +17,126 @@ class _PointOverviewViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( - resizeToAvoidBottomInset: true, - navigationBar: CupertinoNavigationBar( - middle: const Text('Punkte-Übersicht'), - previousPageTitle: AppLocalizations.of(context).back, - ), - child: SingleChildScrollView( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: DataTable( - dataRowMinHeight: 60, - dataRowMaxHeight: 60, - dividerThickness: 0.5, - columnSpacing: 20, - columns: [ - const DataColumn( - numeric: true, - headingRowAlignment: MainAxisAlignment.center, - label: Text( - '#', - style: TextStyle(fontWeight: FontWeight.bold), - ), - columnWidth: IntrinsicColumnWidth(flex: 0.5)), - ...widget.gameSession.players.map( - (player) => DataColumn( - label: FittedBox( - fit: BoxFit.fill, - child: Text( - player, - style: - const TextStyle(fontWeight: FontWeight.bold), - )), - headingRowAlignment: MainAxisAlignment.center, - columnWidth: const IntrinsicColumnWidth(flex: 1)), + resizeToAvoidBottomInset: true, + navigationBar: CupertinoNavigationBar( + middle: const Text('Punkte-Übersicht'), + previousPageTitle: AppLocalizations.of(context).back, + ), + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: DataTable( + dataRowMinHeight: 60, + dataRowMaxHeight: 60, + dividerThickness: 0.5, + columnSpacing: 20, + columns: [ + const DataColumn( + numeric: true, + headingRowAlignment: MainAxisAlignment.center, + label: Text( + '#', + style: TextStyle(fontWeight: FontWeight.bold), ), - ], - rows: List.generate( - widget.gameSession.roundList.length, - (roundIndex) { - final round = widget.gameSession.roundList[roundIndex]; - return DataRow( - cells: [ - DataCell(Align( - alignment: Alignment.center, - child: Text( - '$roundIndex', - style: const TextStyle(fontSize: 20), - ), + columnWidth: IntrinsicColumnWidth(flex: 0.5)), + ...widget.gameSession.players.map( + (player) => DataColumn( + label: FittedBox( + fit: BoxFit.fill, + child: Text( + player, + style: const TextStyle(fontWeight: FontWeight.bold), )), - ...List.generate(widget.gameSession.players.length, - (playerIndex) { - final score = round.scores[playerIndex]; - final update = round.scoreUpdates[playerIndex]; - final saidCabo = round.caboPlayerIndex == playerIndex - ? true - : false; - return DataCell( - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: update <= 0 - ? CustomTheme.primaryColor - : CupertinoColors.destructiveRed, - borderRadius: BorderRadius.circular(8), - ), - child: Text( - '${update >= 0 ? '+' : '-'}$update', - style: const TextStyle( - color: CupertinoColors.white, - fontWeight: FontWeight.bold, - ), + headingRowAlignment: MainAxisAlignment.center, + columnWidth: const IntrinsicColumnWidth(flex: 1)), + ), + ], + rows: [ + ...List.generate( + widget.gameSession.roundList.length, + (roundIndex) { + final round = widget.gameSession.roundList[roundIndex]; + return DataRow( + cells: [ + DataCell(Align( + alignment: Alignment.center, + child: Text( + '$roundIndex', + style: const TextStyle(fontSize: 20), + ), + )), + ...List.generate(widget.gameSession.players.length, + (playerIndex) { + final score = round.scores[playerIndex]; + final update = round.scoreUpdates[playerIndex]; + final saidCabo = + round.caboPlayerIndex == playerIndex ? true : false; + return DataCell( + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: update <= 0 + ? CustomTheme.primaryColor + : CupertinoColors.destructiveRed, + borderRadius: BorderRadius.circular(8), + ), + child: Text( + '${update >= 0 ? '+' : '-'}$update', + style: const TextStyle( + color: CupertinoColors.white, + fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 4), - Text('$score', - style: TextStyle( - fontWeight: saidCabo - ? FontWeight.bold - : FontWeight.normal, - )), - ], - ), + ), + const SizedBox(height: 4), + Text('$score', + style: TextStyle( + fontWeight: saidCabo + ? FontWeight.bold + : FontWeight.normal, + )), + ], ), - ); - }), - ], - ); - }, - ), + ), + ); + }), + ], + ); + }, ), - ))); + DataRow( + cells: [ + const DataCell(Align( + alignment: Alignment.center, + child: Text( + 'Σ', + style: + TextStyle(fontSize: 25, fontWeight: FontWeight.bold), + ), + )), + ...widget.gameSession.playerScores.map( + (score) => DataCell( + Center( + child: Text( + '$score', + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 07b2551..817731d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+513 +version: 0.4.7+515 environment: sdk: ^3.5.4 From c461cd0b2a33f90cdbbcca7312162ab5a09671b1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:06:02 +0200 Subject: [PATCH 179/353] Updated strings --- lib/l10n/arb/app_de.arb | 2 +- lib/l10n/arb/app_en.arb | 1 + lib/l10n/generated/app_localizations.dart | 6 ++++++ lib/l10n/generated/app_localizations_de.dart | 3 +++ lib/l10n/generated/app_localizations_en.dart | 3 +++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 93215ed..534a35c 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -92,7 +92,6 @@ } }, - "end_game": "Spiel beenden", "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", @@ -102,6 +101,7 @@ "end_game_title": "Spiel beenden?", "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", + "table": "Punkteübersicht", "game_process": "Spielverlauf", "empty_graph_text": "Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 8a327a5..d0a19c5 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -102,6 +102,7 @@ "end_game_title": "End the game?", "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", + "table": "Point Overview", "game_process": "Scoring History", "empty_graph_text": "You must play at least one round for the game progress graph to be displayed.", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 0a902f6..ab51d4f 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -477,6 +477,12 @@ abstract class AppLocalizations { /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'** String get end_game_message; + /// No description provided for @table. + /// + /// In de, this message translates to: + /// **'Punkteübersicht'** + String get table; + /// No description provided for @game_process. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 7a71d00..9e25d98 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -221,6 +221,9 @@ class AppLocalizationsDe extends AppLocalizations { String get end_game_message => 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'; + @override + String get table => 'Punkteübersicht'; + @override String get game_process => 'Spielverlauf'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 440d9cd..eb29acb 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -219,6 +219,9 @@ class AppLocalizationsEn extends AppLocalizations { String get end_game_message => 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; + @override + String get table => 'Point Overview'; + @override String get game_process => 'Scoring History'; From 4bc3f65c712f2eb4f17fb3a5669556c2bb63605a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:06:15 +0200 Subject: [PATCH 180/353] Implemented new strings --- lib/presentation/views/active_game_view.dart | 2 +- lib/presentation/views/point_overview_view.dart | 3 +-- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index eeae49d..6bbf6bc 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -138,7 +138,7 @@ class _ActiveGameViewState extends State { )))), CupertinoListTile( title: Text( - 'Übersicht', + AppLocalizations.of(context).table, ), backgroundColorActivated: CustomTheme.backgroundColor, diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/point_overview_view.dart index fe6373a..31ea295 100644 --- a/lib/presentation/views/point_overview_view.dart +++ b/lib/presentation/views/point_overview_view.dart @@ -17,9 +17,8 @@ class _PointOverviewViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( - resizeToAvoidBottomInset: true, navigationBar: CupertinoNavigationBar( - middle: const Text('Punkte-Übersicht'), + middle: Text(AppLocalizations.of(context).table), previousPageTitle: AppLocalizations.of(context).back, ), child: SingleChildScrollView( diff --git a/pubspec.yaml b/pubspec.yaml index 817731d..e800775 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+515 +version: 0.4.7+519 environment: sdk: ^3.5.4 From 61d10d7164f2cb56180e07c379f88493dbc79947 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:07:09 +0200 Subject: [PATCH 181/353] Refactoring --- lib/l10n/arb/app_de.arb | 4 ++-- lib/l10n/arb/app_en.arb | 4 ++-- lib/l10n/generated/app_localizations.dart | 8 ++++---- lib/l10n/generated/app_localizations_de.dart | 4 ++-- lib/l10n/generated/app_localizations_en.dart | 4 ++-- lib/presentation/views/active_game_view.dart | 4 ++-- lib/presentation/views/graph_view.dart | 2 +- lib/presentation/views/point_overview_view.dart | 2 +- pubspec.yaml | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 534a35c..037050a 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -101,8 +101,8 @@ "end_game_title": "Spiel beenden?", "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", - "table": "Punkteübersicht", - "game_process": "Spielverlauf", + "point_overview": "Punkteübersicht", + "scoring_history": "Spielverlauf", "empty_graph_text": "Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", "settings": "Einstellungen", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index d0a19c5..d35978c 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -102,8 +102,8 @@ "end_game_title": "End the game?", "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", - "table": "Point Overview", - "game_process": "Scoring History", + "point_overview": "Point Overview", + "scoring_history": "Scoring History", "empty_graph_text": "You must play at least one round for the game progress graph to be displayed.", "settings": "Settings", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index ab51d4f..97f8ebb 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -477,17 +477,17 @@ abstract class AppLocalizations { /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'** String get end_game_message; - /// No description provided for @table. + /// No description provided for @point_overview. /// /// In de, this message translates to: /// **'Punkteübersicht'** - String get table; + String get point_overview; - /// No description provided for @game_process. + /// No description provided for @scoring_history. /// /// In de, this message translates to: /// **'Spielverlauf'** - String get game_process; + String get scoring_history; /// No description provided for @empty_graph_text. /// diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 9e25d98..6f45f13 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -222,10 +222,10 @@ class AppLocalizationsDe extends AppLocalizations { 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'; @override - String get table => 'Punkteübersicht'; + String get point_overview => 'Punkteübersicht'; @override - String get game_process => 'Spielverlauf'; + String get scoring_history => 'Spielverlauf'; @override String get empty_graph_text => diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index eb29acb..5bdc175 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -220,10 +220,10 @@ class AppLocalizationsEn extends AppLocalizations { 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; @override - String get table => 'Point Overview'; + String get point_overview => 'Point Overview'; @override - String get game_process => 'Scoring History'; + String get scoring_history => 'Scoring History'; @override String get empty_graph_text => diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 6bbf6bc..280ae2c 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -126,7 +126,7 @@ class _ActiveGameViewState extends State { children: [ CupertinoListTile( title: Text( - AppLocalizations.of(context).game_process, + AppLocalizations.of(context).scoring_history, ), backgroundColorActivated: CustomTheme.backgroundColor, @@ -138,7 +138,7 @@ class _ActiveGameViewState extends State { )))), CupertinoListTile( title: Text( - AppLocalizations.of(context).table, + AppLocalizations.of(context).point_overview, ), backgroundColorActivated: CustomTheme.backgroundColor, diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index d322bd0..043eaa3 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -27,7 +27,7 @@ class _GraphViewState extends State { Widget build(BuildContext context) { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).game_process), + middle: Text(AppLocalizations.of(context).scoring_history), previousPageTitle: AppLocalizations.of(context).back, ), child: widget.gameSession.roundNumber > 1 diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/point_overview_view.dart index 31ea295..3f1f5d0 100644 --- a/lib/presentation/views/point_overview_view.dart +++ b/lib/presentation/views/point_overview_view.dart @@ -18,7 +18,7 @@ class _PointOverviewViewState extends State { Widget build(BuildContext context) { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).table), + middle: Text(AppLocalizations.of(context).point_overview), previousPageTitle: AppLocalizations.of(context).back, ), child: SingleChildScrollView( diff --git a/pubspec.yaml b/pubspec.yaml index e800775..a00e5a1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+519 +version: 0.4.7+520 environment: sdk: ^3.5.4 From d3374b8b8cf9daa44de800060c546ba5389f668b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:15:53 +0200 Subject: [PATCH 182/353] Updated graph displayment --- lib/presentation/views/graph_view.dart | 14 +++++++++++++- pubspec.yaml | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 043eaa3..23137cd 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -34,17 +34,29 @@ class _GraphViewState extends State { ? Padding( padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), child: SfCartesianChart( + enableAxisAnimation: true, legend: const Legend( overflowMode: LegendItemOverflowMode.wrap, isVisible: true, position: LegendPosition.bottom), primaryXAxis: const NumericAxis( + labelStyle: TextStyle(fontWeight: FontWeight.bold), interval: 1, decimalPlaces: 0, ), - primaryYAxis: const NumericAxis( + primaryYAxis: NumericAxis( + labelStyle: const TextStyle(fontWeight: FontWeight.bold), + labelAlignment: LabelAlignment.center, + labelPosition: ChartDataLabelPosition.inside, interval: 1, decimalPlaces: 0, + axisLabelFormatter: (AxisLabelRenderDetails details) { + if (details.value == 0) { + return ChartAxisLabel('', const TextStyle()); + } + return ChartAxisLabel( + '${details.value.toInt()}', const TextStyle()); + }, ), series: getCumulativeScores(), ), diff --git a/pubspec.yaml b/pubspec.yaml index a00e5a1..e00e46a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+520 +version: 0.4.7+521 environment: sdk: ^3.5.4 From 3b29014d290a4f5e1dd776075d8c1fa7abd87719 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:33:17 +0200 Subject: [PATCH 183/353] Moved new views to statistics section --- lib/l10n/arb/app_de.arb | 1 + lib/l10n/arb/app_en.arb | 1 + lib/l10n/generated/app_localizations.dart | 6 ++++++ lib/l10n/generated/app_localizations_de.dart | 3 +++ lib/l10n/generated/app_localizations_en.dart | 3 +++ lib/presentation/views/active_game_view.dart | 13 ++++++++++++- 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 037050a..399aefd 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -101,6 +101,7 @@ "end_game_title": "Spiel beenden?", "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", + "statistics": "Statistiken", "point_overview": "Punkteübersicht", "scoring_history": "Spielverlauf", "empty_graph_text": "Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index d35978c..4d067ad 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -102,6 +102,7 @@ "end_game_title": "End the game?", "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", + "statistics": "Statistics", "point_overview": "Point Overview", "scoring_history": "Scoring History", "empty_graph_text": "You must play at least one round for the game progress graph to be displayed.", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 97f8ebb..7ce3c52 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -477,6 +477,12 @@ abstract class AppLocalizations { /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'** String get end_game_message; + /// No description provided for @statistics. + /// + /// In de, this message translates to: + /// **'Statistiken'** + String get statistics; + /// No description provided for @point_overview. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 6f45f13..6539c20 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -221,6 +221,9 @@ class AppLocalizationsDe extends AppLocalizations { String get end_game_message => 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'; + @override + String get statistics => 'Statistiken'; + @override String get point_overview => 'Punkteübersicht'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 5bdc175..7e026f6 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -219,6 +219,9 @@ class AppLocalizationsEn extends AppLocalizations { String get end_game_message => 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; + @override + String get statistics => 'Statistics'; + @override String get point_overview => 'Point Overview'; diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 280ae2c..7b88608 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -118,7 +118,7 @@ class _ActiveGameViewState extends State { Padding( padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), child: Text( - AppLocalizations.of(context).game, + AppLocalizations.of(context).statistics, style: CustomTheme.rowTitle, ), ), @@ -148,6 +148,17 @@ class _ActiveGameViewState extends State { builder: (_) => PointOverviewView( gameSession: gameSession, )))), + ], + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).game, + style: CustomTheme.rowTitle, + ), + ), + Column( + children: [ Visibility( visible: !gameSession.isPointsLimitEnabled, child: CupertinoListTile( From 039dfffb5449c00414bbc5a4172a939849204661 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:33:31 +0200 Subject: [PATCH 184/353] Added seperator in main menu --- lib/presentation/views/main_menu_view.dart | 9 ++++++++- pubspec.yaml | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 1a818b6..a80664d 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -118,8 +118,15 @@ class _MainMenuViewState extends State { ), ], ) - : ListView.builder( + : ListView.separated( itemCount: gameManager.gameList.length, + separatorBuilder: (context, index) => Divider( + height: 1, + thickness: 0.5, + color: CustomTheme.white.withAlpha(50), + indent: 50, + endIndent: 50, + ), itemBuilder: (context, index) { final session = gameManager.gameList[index]; return ListenableBuilder( diff --git a/pubspec.yaml b/pubspec.yaml index e00e46a..9f58ea5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+521 +version: 0.4.8+522 environment: sdk: ^3.5.4 From 1cf7fdbac39867424107cc3cbe0c44fea8e8ef31 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:44:54 +0200 Subject: [PATCH 185/353] Renaming --- lib/presentation/views/point_overview_view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/point_overview_view.dart index 3f1f5d0..f80b9b7 100644 --- a/lib/presentation/views/point_overview_view.dart +++ b/lib/presentation/views/point_overview_view.dart @@ -54,14 +54,14 @@ class _PointOverviewViewState extends State { rows: [ ...List.generate( widget.gameSession.roundList.length, - (roundIndex) { - final round = widget.gameSession.roundList[roundIndex]; + (roundNumber) { + final round = widget.gameSession.roundList[roundNumber]; return DataRow( cells: [ DataCell(Align( alignment: Alignment.center, child: Text( - '$roundIndex', + '$roundNumber', style: const TextStyle(fontSize: 20), ), )), From d9c0d40ff2286e88a446765996004e49e4d742aa Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:46:25 +0200 Subject: [PATCH 186/353] Updated sign --- lib/presentation/views/point_overview_view.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/point_overview_view.dart index f80b9b7..0abdaac 100644 --- a/lib/presentation/views/point_overview_view.dart +++ b/lib/presentation/views/point_overview_view.dart @@ -86,7 +86,7 @@ class _PointOverviewViewState extends State { borderRadius: BorderRadius.circular(8), ), child: Text( - '${update >= 0 ? '+' : '-'}$update', + '${update >= 0 ? '+' : ''}$update', style: const TextStyle( color: CupertinoColors.white, fontWeight: FontWeight.bold, diff --git a/pubspec.yaml b/pubspec.yaml index 9f58ea5..63ab04c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.8+522 +version: 0.4.8+523 environment: sdk: ^3.5.4 From 5a775dafd946b1d001515f4e24f704e22c0e35d5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:51:28 +0200 Subject: [PATCH 187/353] Updated colors & class name --- lib/core/custom_theme.dart | 4 ++++ lib/presentation/views/active_game_view.dart | 4 ++-- .../{point_overview_view.dart => points_view.dart} | 12 ++++++------ pubspec.yaml | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) rename lib/presentation/views/{point_overview_view.dart => points_view.dart} (93%) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index a00340b..fa78cb6 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -13,6 +13,10 @@ class CustomTheme { static const Color graphColor4 = Color(0xFF9C27B0); static final Color graphColor5 = primaryColor; + // Colors for PointsView + static Color pointLossColor = primaryColor; + static const Color pointGainColor = Color(0xFFF44336); + static TextStyle modeTitle = TextStyle( color: primaryColor, fontSize: 20, diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 7b88608..defe5fc 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -4,7 +4,7 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/graph_view.dart'; -import 'package:cabo_counter/presentation/views/point_overview_view.dart'; +import 'package:cabo_counter/presentation/views/points_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; @@ -145,7 +145,7 @@ class _ActiveGameViewState extends State { onTap: () => Navigator.push( context, CupertinoPageRoute( - builder: (_) => PointOverviewView( + builder: (_) => PointsView( gameSession: gameSession, )))), ], diff --git a/lib/presentation/views/point_overview_view.dart b/lib/presentation/views/points_view.dart similarity index 93% rename from lib/presentation/views/point_overview_view.dart rename to lib/presentation/views/points_view.dart index 0abdaac..555d5bd 100644 --- a/lib/presentation/views/point_overview_view.dart +++ b/lib/presentation/views/points_view.dart @@ -4,16 +4,16 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -class PointOverviewView extends StatefulWidget { +class PointsView extends StatefulWidget { final GameSession gameSession; - const PointOverviewView({super.key, required this.gameSession}); + const PointsView({super.key, required this.gameSession}); @override - State createState() => _PointOverviewViewState(); + State createState() => _PointsViewState(); } -class _PointOverviewViewState extends State { +class _PointsViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( @@ -81,8 +81,8 @@ class _PointOverviewViewState extends State { horizontal: 6, vertical: 2), decoration: BoxDecoration( color: update <= 0 - ? CustomTheme.primaryColor - : CupertinoColors.destructiveRed, + ? CustomTheme.pointLossColor + : CustomTheme.pointGainColor, borderRadius: BorderRadius.circular(8), ), child: Text( diff --git a/pubspec.yaml b/pubspec.yaml index 63ab04c..7f8483c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.8+523 +version: 0.4.8+525 environment: sdk: ^3.5.4 From 12b4d3d74102f01497af0e1c1ebeb428924848b9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:52:09 +0200 Subject: [PATCH 188/353] Removed empty line --- lib/l10n/arb/app_en.arb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 4d067ad..3b6150a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -92,7 +92,6 @@ } }, - "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", From 65d44ac7b13f3149ff7a504544e908abd5b303d1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:56:48 +0200 Subject: [PATCH 189/353] Updated round index --- lib/presentation/views/points_view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 555d5bd..4e0cded 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -54,14 +54,14 @@ class _PointsViewState extends State { rows: [ ...List.generate( widget.gameSession.roundList.length, - (roundNumber) { - final round = widget.gameSession.roundList[roundNumber]; + (roundIndex) { + final round = widget.gameSession.roundList[roundIndex]; return DataRow( cells: [ DataCell(Align( alignment: Alignment.center, child: Text( - '$roundNumber', + '${roundIndex + 1}', style: const TextStyle(fontSize: 20), ), )), From 91ba666521dcd07e2bb7115687a41864f8b951c2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 15:57:32 +0200 Subject: [PATCH 190/353] Updated types --- lib/presentation/views/points_view.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 4e0cded..1379785 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -67,10 +67,10 @@ class _PointsViewState extends State { )), ...List.generate(widget.gameSession.players.length, (playerIndex) { - final score = round.scores[playerIndex]; - final update = round.scoreUpdates[playerIndex]; - final saidCabo = - round.caboPlayerIndex == playerIndex ? true : false; + final int score = round.scores[playerIndex]; + final int update = round.scoreUpdates[playerIndex]; + final bool saidCabo = + round.caboPlayerIndex == playerIndex; return DataCell( Center( child: Column( From 0ac446b0329265bdf0cc6c3a701ddd9f3c1dc77c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 16:46:20 +0200 Subject: [PATCH 191/353] Added new kamikaze button and bundles navigation functionality --- lib/l10n/arb/app_de.arb | 1 + lib/l10n/arb/app_en.arb | 1 + lib/l10n/generated/app_localizations.dart | 6 ++ lib/l10n/generated/app_localizations_de.dart | 3 + lib/l10n/generated/app_localizations_en.dart | 3 + lib/presentation/views/round_view.dart | 93 +++++++++++++++----- pubspec.yaml | 2 +- 7 files changed, 84 insertions(+), 25 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 399aefd..dceb8fc 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -71,6 +71,7 @@ "results": "Ergebnisse", "who_said_cabo": "Wer hat CABO gesagt?", "kamikaze": "Kamikaze", + "who_has_kamikaze": "Wer hat Kamikaze?", "done": "Fertig", "next_round": "Nächste Runde", "bonus_points_title": "Bonus-Punkte!", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 3b6150a..3009d6e 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -71,6 +71,7 @@ "results": "Results", "who_said_cabo": "Who called Cabo?", "kamikaze": "Kamikaze", + "who_has_kamikaze": "Who has Kamikaze?", "done": "Done", "next_round": "Next Round", "bonus_points_title": "Bonus-Points!", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 7ce3c52..695fb57 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -404,6 +404,12 @@ abstract class AppLocalizations { /// **'Kamikaze'** String get kamikaze; + /// No description provided for @who_has_kamikaze. + /// + /// In de, this message translates to: + /// **'Wer hat Kamikaze?'** + String get who_has_kamikaze; + /// No description provided for @done. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 6539c20..3ef54b8 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -172,6 +172,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get kamikaze => 'Kamikaze'; + @override + String get who_has_kamikaze => 'Wer hat Kamikaze?'; + @override String get done => 'Fertig'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 7e026f6..8a86b95 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -170,6 +170,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get kamikaze => 'Kamikaze'; + @override + String get who_has_kamikaze => 'Who has Kamikaze?'; + @override String get done => 'Done'; diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 9e2b40f..45834e4 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -154,6 +154,17 @@ class _RoundViewState extends State { ), ), ), + Center( + child: CupertinoButton( + onPressed: () async { + if (await _showKamikazeSheet(context)) { + if (!context.mounted) return; + _endOfRoundNavigation(context, true); + } + }, + child: Text(AppLocalizations.of(context).kamikaze), + ), + ), Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: CupertinoListTile( @@ -308,15 +319,8 @@ class _RoundViewState extends State { children: [ CupertinoButton( onPressed: _areRoundInputsValid() - ? () async { - List bonusPlayersIndices = _finishRound(); - if (bonusPlayersIndices.isNotEmpty) { - await _showBonusPopup( - context, bonusPlayersIndices); - } - LocalStorageService.saveGameSessions(); - if (!context.mounted) return; - Navigator.pop(context); + ? () { + _endOfRoundNavigation(context, false); } : null, child: Text(AppLocalizations.of(context).done), @@ -324,21 +328,8 @@ class _RoundViewState extends State { if (!widget.gameSession.isGameFinished) CupertinoButton( onPressed: _areRoundInputsValid() - ? () async { - List bonusPlayersIndices = - _finishRound(); - if (bonusPlayersIndices.isNotEmpty) { - await _showBonusPopup( - context, bonusPlayersIndices); - } - LocalStorageService.saveGameSessions(); - if (widget.gameSession.isGameFinished && - context.mounted) { - Navigator.pop(context); - } else if (context.mounted) { - Navigator.pop( - context, widget.roundNumber + 1); - } + ? () { + _endOfRoundNavigation(context, true); } : null, child: Text(AppLocalizations.of(context).next_round), @@ -401,6 +392,36 @@ class _RoundViewState extends State { ]; } + Future _showKamikazeSheet(BuildContext context) async { + return await showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return CupertinoActionSheet( + title: Text(AppLocalizations.of(context).kamikaze), + message: Text(AppLocalizations.of(context).who_has_kamikaze), + actions: widget.gameSession.players.asMap().entries.map((entry) { + final index = entry.key; + final name = entry.value; + return CupertinoActionSheetAction( + onPressed: () { + _kamikazePlayerIndex = + _kamikazePlayerIndex == index ? null : index; + Navigator.pop(context, true); + }, + child: Text(name), + ); + }).toList(), + cancelButton: CupertinoActionSheetAction( + onPressed: () => Navigator.pop(context, false), + isDestructiveAction: true, + child: Text(AppLocalizations.of(context).cancel), + ), + ); + }, + ) ?? + false; + } + /// Focuses the next text field in the list of text fields. /// [index] is the index of the current text field. void _focusNextTextfield(int index) { @@ -521,6 +542,30 @@ class _RoundViewState extends State { return resultText; } + /// Handles the navigation for the end of the round. + /// It checks for bonus players and shows a popup, saves the game session, + /// and navigates to the next round or back to the previous screen. + /// It takes the BuildContext [context] and a boolean [navigateToNextRound] to determine + /// if it should navigate to the next round or not. + Future _endOfRoundNavigation( + BuildContext context, bool navigateToNextRound) async { + List bonusPlayersIndices = _finishRound(); + if (bonusPlayersIndices.isNotEmpty) { + await _showBonusPopup(context, bonusPlayersIndices); + } + + LocalStorageService.saveGameSessions(); + + if (context.mounted) { + if (!navigateToNextRound || widget.gameSession.isGameFinished) { + Navigator.pop(context); + return; + } else { + Navigator.pop(context, widget.roundNumber + 1); + } + } + } + @override void dispose() { for (final controller in _scoreControllerList) { diff --git a/pubspec.yaml b/pubspec.yaml index 7f8483c..4a2e99d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.8+525 +version: 0.4.8+526 environment: sdk: ^3.5.4 From 29a042ff16fc7c5a156b48cf6a26d244a51b0904 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:06:07 +0200 Subject: [PATCH 192/353] Updated lock icon --- lib/presentation/views/round_view.dart | 40 +++++++++++++++++--------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 45834e4..2e0edd9 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -74,21 +74,22 @@ class _RoundViewState extends State { return CupertinoPageScaffold( resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( - transitionBetweenRoutes: true, - leading: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: () => - {LocalStorageService.saveGameSessions(), Navigator.pop(context)}, - child: Text(AppLocalizations.of(context).cancel), - ), - middle: Text(AppLocalizations.of(context).results), - trailing: widget.gameSession.isGameFinished - ? const Icon( + transitionBetweenRoutes: true, + leading: CupertinoButton( + padding: EdgeInsets.zero, + onPressed: () => { + LocalStorageService.saveGameSessions(), + Navigator.pop(context) + }, + child: Text(AppLocalizations.of(context).cancel), + ), + middle: Text(AppLocalizations.of(context).results), + trailing: Visibility( + visible: widget.gameSession.isGameFinished, + child: const Icon( CupertinoIcons.lock, size: 25, - ) - : null, - ), + ))), child: Stack( children: [ Positioned.fill( @@ -155,14 +156,25 @@ class _RoundViewState extends State { ), ), Center( + heightFactor: 1, child: CupertinoButton( + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 0), + borderRadius: BorderRadius.circular(12), + color: CupertinoColors.systemRed, onPressed: () async { if (await _showKamikazeSheet(context)) { if (!context.mounted) return; _endOfRoundNavigation(context, true); } }, - child: Text(AppLocalizations.of(context).kamikaze), + child: Text( + AppLocalizations.of(context).kamikaze, + style: const TextStyle( + color: CupertinoColors.white, + fontWeight: FontWeight.bold, + ), + ), ), ), Padding( From 81ada1c8103f9cb72fdcfd185ab3c1de9994a9da Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:18:52 +0200 Subject: [PATCH 193/353] Updated button position and design --- lib/presentation/views/round_view.dart | 45 +++++++++++++------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 2e0edd9..b0c24c8 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -155,28 +155,6 @@ class _RoundViewState extends State { ), ), ), - Center( - heightFactor: 1, - child: CupertinoButton( - padding: const EdgeInsets.symmetric( - horizontal: 15, vertical: 0), - borderRadius: BorderRadius.circular(12), - color: CupertinoColors.systemRed, - onPressed: () async { - if (await _showKamikazeSheet(context)) { - if (!context.mounted) return; - _endOfRoundNavigation(context, true); - } - }, - child: Text( - AppLocalizations.of(context).kamikaze, - style: const TextStyle( - color: CupertinoColors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - ), Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: CupertinoListTile( @@ -311,6 +289,29 @@ class _RoundViewState extends State { ); }, ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Center( + heightFactor: 1, + child: CupertinoButton( + sizeStyle: CupertinoButtonSize.medium, + borderRadius: BorderRadius.circular(15), + color: const Color(0xFF202020), + onPressed: () async { + if (await _showKamikazeSheet(context)) { + if (!context.mounted) return; + _endOfRoundNavigation(context, true); + } + }, + child: Text( + AppLocalizations.of(context).kamikaze, + style: const TextStyle( + color: CupertinoColors.destructiveRed, + ), + ), + ), + ), + ), ], ), ), From 5b704d39376e228671ba3aee0a2b39723cd82606 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:28:19 +0200 Subject: [PATCH 194/353] Removed title row and changed segmendetControl Padding --- lib/presentation/views/round_view.dart | 120 ++++++------------------- pubspec.yaml | 2 +- 2 files changed, 28 insertions(+), 94 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index b0c24c8..7d5739a 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -115,7 +115,7 @@ class _RoundViewState extends State { vertical: 10, ), child: SizedBox( - height: 40, + height: 60, child: CupertinoSegmentedControl( unselectedColor: CustomTheme.backgroundTintColor, selectedColor: CustomTheme.primaryColor, @@ -131,7 +131,7 @@ class _RoundViewState extends State { Padding( padding: const EdgeInsets.symmetric( horizontal: 6, - vertical: 6, + vertical: 8, ), child: FittedBox( fit: BoxFit.scaleDown, @@ -155,27 +155,6 @@ class _RoundViewState extends State { ), ), ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: CupertinoListTile( - title: Text(AppLocalizations.of(context).player), - trailing: Row( - children: [ - SizedBox( - width: 100, - child: Center( - child: Text( - AppLocalizations.of(context).points))), - const SizedBox(width: 20), - SizedBox( - width: 80, - child: Center( - child: Text(AppLocalizations.of(context) - .kamikaze))), - ], - ), - ), - ), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -212,77 +191,32 @@ class _RoundViewState extends State { subtitle: Text( '${widget.gameSession.playerScores[originalIndex]}' ' ${AppLocalizations.of(context).points}'), - trailing: Row( - children: [ - SizedBox( - width: 100, - child: CupertinoTextField( - maxLength: 3, - focusNode: _focusNodeList[originalIndex], - keyboardType: - const TextInputType.numberWithOptions( - signed: true, - decimal: false, - ), - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - ], - textInputAction: index == - widget.gameSession.players - .length - - 1 - ? TextInputAction.done - : TextInputAction.next, - controller: - _scoreControllerList[originalIndex], - placeholder: - AppLocalizations.of(context).points, - textAlign: TextAlign.center, - onSubmitted: (_) => - _focusNextTextfield(originalIndex), - onChanged: (_) => setState(() {}), - ), + trailing: SizedBox( + width: 100, + child: CupertinoTextField( + maxLength: 3, + focusNode: _focusNodeList[originalIndex], + keyboardType: + const TextInputType.numberWithOptions( + signed: true, + decimal: false, ), - const SizedBox(width: 50), - GestureDetector( - onTap: () { - setState(() { - _kamikazePlayerIndex = - (_kamikazePlayerIndex == - originalIndex) - ? null - : originalIndex; - }); - }, - child: Container( - width: 24, - height: 24, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: _kamikazePlayerIndex == - originalIndex - ? CupertinoColors.systemRed - : CupertinoColors - .tertiarySystemFill, - border: Border.all( - color: _kamikazePlayerIndex == - originalIndex - ? CupertinoColors.systemRed - : CupertinoColors.systemGrey, - ), - ), - child: _kamikazePlayerIndex == - originalIndex - ? const Icon( - CupertinoIcons.exclamationmark, - size: 16, - color: CupertinoColors.white, - ) - : null, - ), - ), - const SizedBox(width: 22), - ], + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + textInputAction: index == + widget.gameSession.players.length - 1 + ? TextInputAction.done + : TextInputAction.next, + controller: + _scoreControllerList[originalIndex], + placeholder: + AppLocalizations.of(context).points, + textAlign: TextAlign.center, + onSubmitted: (_) => + _focusNextTextfield(originalIndex), + onChanged: (_) => setState(() {}), + ), ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 4a2e99d..f1bf78c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.8+526 +version: 0.4.8+529 environment: sdk: ^3.5.4 From f0cfafd5e3678d71c1125a970742d1ff4e42bc3e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:40:34 +0200 Subject: [PATCH 195/353] Refactored logic and added comments --- lib/presentation/views/round_view.dart | 16 +++++++++++----- pubspec.yaml | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 7d5739a..3d65d17 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -351,8 +351,7 @@ class _RoundViewState extends State { final name = entry.value; return CupertinoActionSheetAction( onPressed: () { - _kamikazePlayerIndex = - _kamikazePlayerIndex == index ? null : index; + _kamikazePlayerIndex = index; Navigator.pop(context, true); }, child: Text(name), @@ -504,12 +503,19 @@ class _RoundViewState extends State { LocalStorageService.saveGameSessions(); if (context.mounted) { - if (!navigateToNextRound || widget.gameSession.isGameFinished) { + // If the game is finished, pop the context and return to the previous screen. + if (widget.gameSession.isGameFinished) { Navigator.pop(context); return; - } else { - Navigator.pop(context, widget.roundNumber + 1); } + // If navigateToNextRound is false, pop the context and return to the previous screen. + if (!navigateToNextRound) { + Navigator.pop(context); + return; + } + // If navigateToNextRound is true and the game isn't finished yet, + // pop the context and navigate to the next round. + Navigator.pop(context, widget.roundNumber + 1); } } diff --git a/pubspec.yaml b/pubspec.yaml index f1bf78c..d9cb654 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.8+529 +version: 0.4.9+529 environment: sdk: ^3.5.4 From cdcdd0b78ada780d6ef6255fd1e8435aaef88b7a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:41:37 +0200 Subject: [PATCH 196/353] Updated comment --- lib/presentation/views/round_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 3d65d17..45c6376 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -438,7 +438,7 @@ class _RoundViewState extends State { return bonusPlayers; } - /// Shows a popup dialog with the bonus information. + /// Shows a popup dialog with the information which player received the bonus points. Future _showBonusPopup( BuildContext context, List bonusPlayers) async { print('Bonus Popup wird angezeigt'); From d10fabb85a117cd4c04f96914f0c2a60133902b7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:47:51 +0200 Subject: [PATCH 197/353] Chaned icon --- lib/presentation/views/round_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 45c6376..050c2f2 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -184,7 +184,7 @@ class _RoundViewState extends State { ), Visibility( visible: shouldShowMedal, - child: const Icon(FontAwesomeIcons.medal, + child: const Icon(FontAwesomeIcons.crown, size: 15)) ])) ]), From 610cdc10e4bc2751a60c4cc2473146f376575303 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:51:08 +0200 Subject: [PATCH 198/353] Added comment --- lib/presentation/views/round_view.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 050c2f2..f9ef0ee 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -339,6 +339,8 @@ class _RoundViewState extends State { ]; } + /// Shows a Cupertino action sheet to select the player who has Kamikaze. + /// It returns true if a player was selected, false if the action was cancelled. Future _showKamikazeSheet(BuildContext context) async { return await showCupertinoModalPopup( context: context, From b7f6bf93484adfabd336312450b0ef3ec4e537ed Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 17:54:25 +0200 Subject: [PATCH 199/353] Removed print --- lib/presentation/views/round_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index f9ef0ee..690e256 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -443,7 +443,6 @@ class _RoundViewState extends State { /// Shows a popup dialog with the information which player received the bonus points. Future _showBonusPopup( BuildContext context, List bonusPlayers) async { - print('Bonus Popup wird angezeigt'); int pointLimit = widget.gameSession.pointLimit; int bonusPoints = (pointLimit / 2).round(); From a7521a3168859820091f8b4e51f2c3da297b0218 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 18:01:39 +0200 Subject: [PATCH 200/353] Updated colors --- lib/core/custom_theme.dart | 4 +++- lib/presentation/views/round_view.dart | 11 ++++++----- lib/presentation/views/tab_view.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index fa78cb6..e123779 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -4,7 +4,9 @@ class CustomTheme { static Color white = CupertinoColors.white; static Color primaryColor = CupertinoColors.systemGreen; static Color backgroundColor = const Color(0xFF101010); - static Color backgroundTintColor = CupertinoColors.darkBackgroundGray; + static Color mainElementbackgroundColor = CupertinoColors.darkBackgroundGray; + static Color playerTileColor = CupertinoColors.secondaryLabel; + static Color buttonBackgroundColor = const Color(0xFF202020); // Line Colors for GraphView static const Color graphColor1 = Color(0xFFF44336); diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 690e256..82af6dc 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -117,7 +117,8 @@ class _RoundViewState extends State { child: SizedBox( height: 60, child: CupertinoSegmentedControl( - unselectedColor: CustomTheme.backgroundTintColor, + unselectedColor: + CustomTheme.mainElementbackgroundColor, selectedColor: CustomTheme.primaryColor, groupValue: _caboPlayerIndex, children: Map.fromEntries(widget.gameSession.players @@ -170,7 +171,7 @@ class _RoundViewState extends State { child: ClipRRect( borderRadius: BorderRadius.circular(12), child: CupertinoListTile( - backgroundColor: CupertinoColors.secondaryLabel, + backgroundColor: CustomTheme.playerTileColor, title: Row(children: [ Expanded( child: Row(children: [ @@ -229,8 +230,8 @@ class _RoundViewState extends State { heightFactor: 1, child: CupertinoButton( sizeStyle: CupertinoButtonSize.medium, - borderRadius: BorderRadius.circular(15), - color: const Color(0xFF202020), + borderRadius: BorderRadius.circular(12), + color: CustomTheme.buttonBackgroundColor, onPressed: () async { if (await _showKamikazeSheet(context)) { if (!context.mounted) return; @@ -260,7 +261,7 @@ class _RoundViewState extends State { return Container( height: 80, padding: const EdgeInsets.only(bottom: 20), - color: CustomTheme.backgroundTintColor, + color: CustomTheme.mainElementbackgroundColor, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 0c98cc7..360737c 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -17,7 +17,7 @@ class _TabViewState extends State { Widget build(BuildContext context) { return CupertinoTabScaffold( tabBar: CupertinoTabBar( - backgroundColor: CustomTheme.backgroundTintColor, + backgroundColor: CustomTheme.mainElementbackgroundColor, iconSize: 27, height: 55, items: [ diff --git a/pubspec.yaml b/pubspec.yaml index d9cb654..37af518 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.9+529 +version: 0.4.9+533 environment: sdk: ^3.5.4 From f17eac14b9bcd47caa2daf2323ea949e3121bea2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 18:06:38 +0200 Subject: [PATCH 201/353] Changed var name --- lib/core/custom_theme.dart | 2 +- lib/presentation/views/round_view.dart | 4 ++-- lib/presentation/views/tab_view.dart | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index e123779..bfc4f3c 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -4,7 +4,7 @@ class CustomTheme { static Color white = CupertinoColors.white; static Color primaryColor = CupertinoColors.systemGreen; static Color backgroundColor = const Color(0xFF101010); - static Color mainElementbackgroundColor = CupertinoColors.darkBackgroundGray; + static Color mainElementBackgroundColor = CupertinoColors.darkBackgroundGray; static Color playerTileColor = CupertinoColors.secondaryLabel; static Color buttonBackgroundColor = const Color(0xFF202020); diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 82af6dc..f99380e 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -118,7 +118,7 @@ class _RoundViewState extends State { height: 60, child: CupertinoSegmentedControl( unselectedColor: - CustomTheme.mainElementbackgroundColor, + CustomTheme.mainElementBackgroundColor, selectedColor: CustomTheme.primaryColor, groupValue: _caboPlayerIndex, children: Map.fromEntries(widget.gameSession.players @@ -261,7 +261,7 @@ class _RoundViewState extends State { return Container( height: 80, padding: const EdgeInsets.only(bottom: 20), - color: CustomTheme.mainElementbackgroundColor, + color: CustomTheme.mainElementBackgroundColor, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 360737c..4b757fa 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -17,7 +17,7 @@ class _TabViewState extends State { Widget build(BuildContext context) { return CupertinoTabScaffold( tabBar: CupertinoTabBar( - backgroundColor: CustomTheme.mainElementbackgroundColor, + backgroundColor: CustomTheme.mainElementBackgroundColor, iconSize: 27, height: 55, items: [ From 21437e6b0ea345278d88a31f9341c603cc0c969c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 21:52:29 +0200 Subject: [PATCH 202/353] Removed unused strings --- lib/l10n/arb/app_de.arb | 3 +-- lib/l10n/arb/app_en.arb | 3 +-- lib/l10n/generated/app_localizations.dart | 12 +++--------- lib/l10n/generated/app_localizations_de.dart | 5 +---- lib/l10n/generated/app_localizations_en.dart | 6 +----- 5 files changed, 7 insertions(+), 22 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index dceb8fc..8fb9c31 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -109,9 +109,8 @@ "settings": "Einstellungen", "cabo_penalty": "Cabo-Strafe", - "cabo_penalty_subtitle": "... für falsches Cabo sagen", "point_limit": "Punkte-Limit", - "point_limit_subtitle": "... hier ist Schluss", + "standard_mode": "Standard-Modus", "reset_to_default": "Auf Standard zurücksetzen", "game_data": "Spieldaten", "import_data": "Spieldaten importieren", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 3009d6e..47893bc 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -109,9 +109,8 @@ "settings": "Settings", "cabo_penalty": "Cabo Penalty", - "cabo_penalty_subtitle": "A point penalty for incorrectly calling Cabo.", "point_limit": "Point Limit", - "point_limit_subtitle": "The required score to win the game.", + "standard_mode": "Default Mode", "reset_to_default": "Reset to Default", "game_data": "Game Data", "import_data": "Import Data", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 695fb57..2e1b880 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -519,23 +519,17 @@ abstract class AppLocalizations { /// **'Cabo-Strafe'** String get cabo_penalty; - /// No description provided for @cabo_penalty_subtitle. - /// - /// In de, this message translates to: - /// **'... für falsches Cabo sagen'** - String get cabo_penalty_subtitle; - /// No description provided for @point_limit. /// /// In de, this message translates to: /// **'Punkte-Limit'** String get point_limit; - /// No description provided for @point_limit_subtitle. + /// No description provided for @standard_mode. /// /// In de, this message translates to: - /// **'... hier ist Schluss'** - String get point_limit_subtitle; + /// **'Standard-Modus'** + String get standard_mode; /// No description provided for @reset_to_default. /// diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 3ef54b8..43b68a7 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -243,14 +243,11 @@ class AppLocalizationsDe extends AppLocalizations { @override String get cabo_penalty => 'Cabo-Strafe'; - @override - String get cabo_penalty_subtitle => '... für falsches Cabo sagen'; - @override String get point_limit => 'Punkte-Limit'; @override - String get point_limit_subtitle => '... hier ist Schluss'; + String get standard_mode => 'Standard-Modus'; @override String get reset_to_default => 'Auf Standard zurücksetzen'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 8a86b95..b54cf3d 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -241,15 +241,11 @@ class AppLocalizationsEn extends AppLocalizations { @override String get cabo_penalty => 'Cabo Penalty'; - @override - String get cabo_penalty_subtitle => - 'A point penalty for incorrectly calling Cabo.'; - @override String get point_limit => 'Point Limit'; @override - String get point_limit_subtitle => 'The required score to win the game.'; + String get standard_mode => 'Default Mode'; @override String get reset_to_default => 'Reset to Default'; From 97b32b5173ff03b2407887966400bbcdfaff4f8f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 21:52:37 +0200 Subject: [PATCH 203/353] Added gameMode --- lib/services/config_service.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 70f6133..02edc7d 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -6,12 +6,15 @@ import 'package:shared_preferences/shared_preferences.dart'; class ConfigService { static const String _keyPointLimit = 'pointLimit'; static const String _keyCaboPenalty = 'caboPenalty'; + static const String _keyGameMode = 'gameMode'; // Actual values used in the app static int pointLimit = 100; static int caboPenalty = 5; + static int gameMode = -1; // Default values static const int _defaultPointLimit = 100; static const int _defaultCaboPenalty = 5; + static const int _defaultGameMode = -1; static Future initConfig() async { final prefs = await SharedPreferences.getInstance(); @@ -21,6 +24,13 @@ class ConfigService { _keyPointLimit, prefs.getInt(_keyPointLimit) ?? _defaultPointLimit); prefs.setInt( _keyCaboPenalty, prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty); + prefs.setInt(_keyGameMode, prefs.getInt(_keyGameMode) ?? _defaultGameMode); + } + + static Future setGameMode(int newGameMode) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt(_keyGameMode, newGameMode); + gameMode = newGameMode; } /// Getter for the point limit. @@ -34,6 +44,7 @@ class ConfigService { static Future setPointLimit(int newPointLimit) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyPointLimit, newPointLimit); + pointLimit = newPointLimit; } /// Getter for the cabo penalty. @@ -47,6 +58,7 @@ class ConfigService { static Future setCaboPenalty(int newCaboPenalty) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyCaboPenalty, newCaboPenalty); + caboPenalty = newCaboPenalty; } /// Resets the configuration to default values. From 2690eac3eb2eca6493b850ba272e46cf0753f451 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 21:52:47 +0200 Subject: [PATCH 204/353] Changed creation variable --- lib/presentation/views/create_game_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 0d23494..fe3173d 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -117,6 +117,7 @@ class _CreateGameViewState extends State { CupertinoPageRoute( builder: (context) => ModeSelectionMenu( pointLimit: ConfigService.pointLimit, + showDeselection: false, ), ), ); From 482180d88e9d3a814987a7f503d56e3a40a3843e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 21:52:56 +0200 Subject: [PATCH 205/353] Updated mode selection --- .../views/mode_selection_view.dart | 21 ++++++++++++++++++- pubspec.yaml | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart index a7d3ce7..8ce0119 100644 --- a/lib/presentation/views/mode_selection_view.dart +++ b/lib/presentation/views/mode_selection_view.dart @@ -4,7 +4,9 @@ import 'package:flutter/cupertino.dart'; class ModeSelectionMenu extends StatelessWidget { final int pointLimit; - const ModeSelectionMenu({super.key, required this.pointLimit}); + final bool showDeselection; + const ModeSelectionMenu( + {super.key, required this.pointLimit, required this.showDeselection}); @override Widget build(BuildContext context) { @@ -14,6 +16,23 @@ class ModeSelectionMenu extends StatelessWidget { ), child: ListView( children: [ + Visibility( + visible: showDeselection, + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), + child: CupertinoListTile( + title: + Text('Kein Standardmodus', style: CustomTheme.modeTitle), + subtitle: const Text( + 'Dein Standardmodus wird zurückgesetzt.', + style: CustomTheme.modeDescription, + maxLines: 3, + ), + onTap: () { + Navigator.pop(context); + }, + ), + )), Padding( padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: CupertinoListTile( diff --git a/pubspec.yaml b/pubspec.yaml index 37af518..623b5b9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.9+533 +version: 0.4.9+537 environment: sdk: ^3.5.4 From 499c0c6dfd542b350af9b94b98320fee958e6ee7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:17:11 +0200 Subject: [PATCH 206/353] Updated strings --- lib/l10n/arb/app_de.arb | 3 +++ lib/l10n/arb/app_en.arb | 3 +++ lib/l10n/generated/app_localizations.dart | 18 ++++++++++++++++++ lib/l10n/generated/app_localizations_de.dart | 9 +++++++++ lib/l10n/generated/app_localizations_en.dart | 9 +++++++++ 5 files changed, 42 insertions(+) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 8fb9c31..c68424c 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -58,6 +58,9 @@ "no_name_message": "Jeder Spieler muss einen Namen haben.", "select_game_mode": "Spielmodus auswählen", + "no_mode_selected": "Kein Modus ausgewählt", + "no_default_mode": "Kein Standard-Modus", + "no_default_description" : "Der Standard-Modus wird zurückgesetzt.", "point_limit_description": "Es wird so lange gespielt, bis ein:e Spieler:in mehr als {pointLimit} Punkte erreicht", "@point_limit_description": { "placeholders": { diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 47893bc..946ac74 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -58,6 +58,9 @@ "no_name_message": "Each player must have a name.", "select_game_mode": "Select game mode", + "no_mode_selected": "No mode selected", + "no_default_mode": "No default mode", + "no_default_description" : "The default mode gets resetted.", "point_limit_description": "The game ends when a player scores more than {pointLimit} points.", "@point_limit_description": { "placeholders": { diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 2e1b880..cc4eb12 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -374,6 +374,24 @@ abstract class AppLocalizations { /// **'Spielmodus auswählen'** String get select_game_mode; + /// No description provided for @no_mode_selected. + /// + /// In de, this message translates to: + /// **'Kein Modus ausgewählt'** + String get no_mode_selected; + + /// No description provided for @no_default_mode. + /// + /// In de, this message translates to: + /// **'Kein Standard-Modus'** + String get no_default_mode; + + /// No description provided for @no_default_description. + /// + /// In de, this message translates to: + /// **'Der Standard-Modus wird zurückgesetzt.'** + String get no_default_description; + /// No description provided for @point_limit_description. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 43b68a7..3820070 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -154,6 +154,15 @@ class AppLocalizationsDe extends AppLocalizations { @override String get select_game_mode => 'Spielmodus auswählen'; + @override + String get no_mode_selected => 'Kein Modus ausgewählt'; + + @override + String get no_default_mode => 'Kein Standard-Modus'; + + @override + String get no_default_description => 'Der Standard-Modus wird zurückgesetzt.'; + @override String point_limit_description(int pointLimit) { return 'Es wird so lange gespielt, bis ein:e Spieler:in mehr als $pointLimit Punkte erreicht'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index b54cf3d..1344f96 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -152,6 +152,15 @@ class AppLocalizationsEn extends AppLocalizations { @override String get select_game_mode => 'Select game mode'; + @override + String get no_mode_selected => 'No mode selected'; + + @override + String get no_default_mode => 'No default mode'; + + @override + String get no_default_description => 'The default mode gets resetted.'; + @override String point_limit_description(int pointLimit) { return 'The game ends when a player scores more than $pointLimit points.'; From 98912d516427f8b2ad7d9ee9046068af06cb450a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:17:28 +0200 Subject: [PATCH 207/353] Changed mode order --- .../views/mode_selection_view.dart | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/presentation/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart index 8ce0119..0424dab 100644 --- a/lib/presentation/views/mode_selection_view.dart +++ b/lib/presentation/views/mode_selection_view.dart @@ -2,6 +2,12 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; +enum GameMode { + none, + pointLimit, + unlimited, +} + class ModeSelectionMenu extends StatelessWidget { final int pointLimit; final bool showDeselection; @@ -16,23 +22,6 @@ class ModeSelectionMenu extends StatelessWidget { ), child: ListView( children: [ - Visibility( - visible: showDeselection, - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), - child: CupertinoListTile( - title: - Text('Kein Standardmodus', style: CustomTheme.modeTitle), - subtitle: const Text( - 'Dein Standardmodus wird zurückgesetzt.', - style: CustomTheme.modeDescription, - maxLines: 3, - ), - onTap: () { - Navigator.pop(context); - }, - ), - )), Padding( padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: CupertinoListTile( @@ -45,12 +34,12 @@ class ModeSelectionMenu extends StatelessWidget { maxLines: 3, ), onTap: () { - Navigator.pop(context, true); + Navigator.pop(context, GameMode.pointLimit); }, ), ), Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: CupertinoListTile( title: Text(AppLocalizations.of(context).unlimited, style: CustomTheme.modeTitle), @@ -60,10 +49,27 @@ class ModeSelectionMenu extends StatelessWidget { maxLines: 3, ), onTap: () { - Navigator.pop(context, false); + Navigator.pop(context, GameMode.unlimited); }, ), ), + Visibility( + visible: showDeselection, + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), + child: CupertinoListTile( + title: Text(AppLocalizations.of(context).no_default_mode, + style: CustomTheme.modeTitle), + subtitle: Text( + AppLocalizations.of(context).no_default_description, + style: CustomTheme.modeDescription, + maxLines: 3, + ), + onTap: () { + Navigator.pop(context, GameMode.none); + }, + ), + )), ], ), ); From 2e1c5392a09845a66ea72b484697a5281a10ac27 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:17:41 +0200 Subject: [PATCH 208/353] Implemented default mode selection --- lib/presentation/views/settings_view.dart | 52 +++++++++++++++++++++++ pubspec.yaml | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index d6f0833..7247073 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,6 +1,7 @@ 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'; @@ -20,6 +21,7 @@ class SettingsView extends StatefulWidget { class _SettingsViewState extends State { UniqueKey _stepperKey1 = UniqueKey(); UniqueKey _stepperKey2 = UniqueKey(); + int defaultMode = ConfigService.gameMode; @override void initState() { super.initState(); @@ -84,6 +86,56 @@ class _SettingsViewState extends State { }, ), ), + CustomFormRow( + prefixText: AppLocalizations.of(context).standard_mode, + prefixIcon: CupertinoIcons.airplane, + suffixWidget: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + defaultMode == -1 + ? AppLocalizations.of(context) + .no_mode_selected + : (defaultMode == 1 + ? '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}' + : AppLocalizations.of(context).unlimited), + ), + const SizedBox(width: 10), + const CupertinoListTileChevron() + ], + ), + onPressed: () async { + final selectedMode = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ModeSelectionMenu( + pointLimit: ConfigService.pointLimit, + showDeselection: true, + ), + ), + ); + print('Selected mode: $selectedMode'); + + switch (selectedMode) { + case GameMode.pointLimit: + setState(() { + defaultMode = 1; + }); + break; + case GameMode.unlimited: + setState(() { + defaultMode = 0; + }); + break; + case GameMode.none: + default: + setState(() { + defaultMode = -1; + }); + } + ConfigService.setGameMode(defaultMode); + }, + ), CustomFormRow( prefixText: AppLocalizations.of(context).reset_to_default, diff --git a/pubspec.yaml b/pubspec.yaml index 623b5b9..13a8959 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.9+537 +version: 0.4.9+539 environment: sdk: ^3.5.4 From 193b66b175490f91ed798c7902a047139d10d22b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:17:48 +0200 Subject: [PATCH 209/353] Updated initState --- lib/presentation/views/create_game_view.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index fe3173d..ab9aabb 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -48,8 +48,15 @@ class _CreateGameViewState extends State { @override void initState() { super.initState(); + print('pointLimit: $_isPointsLimitEnabled'); + + if (widget.isPointsLimitEnabled == null) { + _isPointsLimitEnabled = + ConfigService.gameMode == -1 ? null : ConfigService.gameMode == 1; + } else { + _isPointsLimitEnabled = widget.isPointsLimitEnabled; + } - _isPointsLimitEnabled = widget.isPointsLimitEnabled; _gameTitleTextController.text = widget.gameTitle ?? ''; if (widget.players != null) { @@ -91,7 +98,6 @@ class _CreateGameViewState extends State { controller: _gameTitleTextController, ), ), - // Spielmodus-Auswahl mit Chevron Padding( padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), child: CupertinoTextField( From 1a2a9b5df1a345a0ebb83ba5686db356efde16f8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:20:59 +0200 Subject: [PATCH 210/353] Removed print --- lib/presentation/views/create_game_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index ab9aabb..7928c4d 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -48,7 +48,6 @@ class _CreateGameViewState extends State { @override void initState() { super.initState(); - print('pointLimit: $_isPointsLimitEnabled'); if (widget.isPointsLimitEnabled == null) { _isPointsLimitEnabled = From a6ab7f76b0443b0487efba27a9476573670eb057 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:21:20 +0200 Subject: [PATCH 211/353] Removed print --- lib/presentation/views/settings_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 7247073..b08abf6 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -114,7 +114,6 @@ class _SettingsViewState extends State { ), ), ); - print('Selected mode: $selectedMode'); switch (selectedMode) { case GameMode.pointLimit: From 1935dc488cc49103570d53eb8f589f60cc2dcc5b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:25:30 +0200 Subject: [PATCH 212/353] Removed comments --- lib/presentation/views/create_game_view.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 7928c4d..563eb45 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -144,11 +144,9 @@ class _CreateGameViewState extends State { ), Expanded( child: ListView.builder( - itemCount: _playerNameTextControllers.length + - 1, // +1 für den + Button + itemCount: _playerNameTextControllers.length + 1, itemBuilder: (context, index) { if (index == _playerNameTextControllers.length) { - // + Button als letztes Element return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: CupertinoButton( From e9fe7262ab0c4a01f0cf3db72a03775eddb18292 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:30:16 +0200 Subject: [PATCH 213/353] Updated config service --- lib/services/config_service.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 02edc7d..2b463f5 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -25,6 +25,10 @@ class ConfigService { prefs.setInt( _keyCaboPenalty, prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty); prefs.setInt(_keyGameMode, prefs.getInt(_keyGameMode) ?? _defaultGameMode); + + pointLimit = prefs.getInt(_keyPointLimit) ?? _defaultPointLimit; + caboPenalty = prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty; + gameMode = prefs.getInt(_keyGameMode) ?? _defaultGameMode; } static Future setGameMode(int newGameMode) async { From cfa93b6917501625a2fbd532f531f450ffe2fa06 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:30:29 +0200 Subject: [PATCH 214/353] Changed create game view --- lib/presentation/views/create_game_view.dart | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 563eb45..cdda7f9 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -127,10 +127,22 @@ class _CreateGameViewState extends State { ), ); - if (selectedMode != null) { - setState(() { - _isPointsLimitEnabled = selectedMode; - }); + switch (selectedMode) { + case GameMode.pointLimit: + setState(() { + _isPointsLimitEnabled = null; + }); + break; + case GameMode.unlimited: + setState(() { + _isPointsLimitEnabled = false; + }); + break; + case GameMode.none: + default: + setState(() { + _isPointsLimitEnabled = true; + }); } }, ), From aec3905c551cca62219f888d75b84ee0915b3973 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:34:43 +0200 Subject: [PATCH 215/353] Changed icon --- lib/presentation/views/settings_view.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index b08abf6..67b2fa0 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -64,7 +64,6 @@ class _SettingsViewState extends State { onChanged: (newCaboPenalty) { setState(() { ConfigService.setCaboPenalty(newCaboPenalty); - ConfigService.caboPenalty = newCaboPenalty; }); }, ), @@ -81,14 +80,13 @@ class _SettingsViewState extends State { onChanged: (newPointLimit) { setState(() { ConfigService.setPointLimit(newPointLimit); - ConfigService.pointLimit = newPointLimit; }); }, ), ), CustomFormRow( prefixText: AppLocalizations.of(context).standard_mode, - prefixIcon: CupertinoIcons.airplane, + prefixIcon: CupertinoIcons.square_stack, suffixWidget: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ From 7b8f49c1a486e2256a69831982eaad79fa0b8534 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:36:14 +0200 Subject: [PATCH 216/353] Updated strings --- lib/l10n/arb/app_de.arb | 2 +- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/generated/app_localizations_en.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index c68424c..3c157ad 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -60,7 +60,7 @@ "select_game_mode": "Spielmodus auswählen", "no_mode_selected": "Kein Modus ausgewählt", "no_default_mode": "Kein Standard-Modus", - "no_default_description" : "Der Standard-Modus wird zurückgesetzt.", + "no_default_description": "Der Standard-Modus wird zurückgesetzt.", "point_limit_description": "Es wird so lange gespielt, bis ein:e Spieler:in mehr als {pointLimit} Punkte erreicht", "@point_limit_description": { "placeholders": { diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 946ac74..ea169e9 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -60,7 +60,7 @@ "select_game_mode": "Select game mode", "no_mode_selected": "No mode selected", "no_default_mode": "No default mode", - "no_default_description" : "The default mode gets resetted.", + "no_default_description": "The default mode gets reset.", "point_limit_description": "The game ends when a player scores more than {pointLimit} points.", "@point_limit_description": { "placeholders": { diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 1344f96..6b2689e 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -159,7 +159,7 @@ class AppLocalizationsEn extends AppLocalizations { String get no_default_mode => 'No default mode'; @override - String get no_default_description => 'The default mode gets resetted.'; + String get no_default_description => 'The default mode gets reset.'; @override String point_limit_description(int pointLimit) { diff --git a/pubspec.yaml b/pubspec.yaml index 13a8959..dca4d3a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.9+539 +version: 0.4.9+540 environment: sdk: ^3.5.4 From 38213921afcc87129f97ac4353fa62f223f41db5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:44:47 +0200 Subject: [PATCH 217/353] Updated config --- lib/services/config_service.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 2b463f5..108b210 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -19,16 +19,16 @@ class ConfigService { static Future initConfig() async { final prefs = await SharedPreferences.getInstance(); - // Default values only set if they are not already set - prefs.setInt( - _keyPointLimit, prefs.getInt(_keyPointLimit) ?? _defaultPointLimit); - prefs.setInt( - _keyCaboPenalty, prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty); - prefs.setInt(_keyGameMode, prefs.getInt(_keyGameMode) ?? _defaultGameMode); - + // Initialize pointLimit, caboPenalty, and gameMode from SharedPreferences + // If they are not set, use the default values pointLimit = prefs.getInt(_keyPointLimit) ?? _defaultPointLimit; caboPenalty = prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty; gameMode = prefs.getInt(_keyGameMode) ?? _defaultGameMode; + + // Save the initial values to SharedPreferences + prefs.setInt(_keyPointLimit, pointLimit); + prefs.setInt(_keyCaboPenalty, caboPenalty); + prefs.setInt(_keyGameMode, gameMode); } static Future setGameMode(int newGameMode) async { From c31a3200e9905ec5a2edbbf80d10b262514194c8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:45:52 +0200 Subject: [PATCH 218/353] Updated mode selection logic --- lib/presentation/views/create_game_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index cdda7f9..2634788 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -130,7 +130,7 @@ class _CreateGameViewState extends State { switch (selectedMode) { case GameMode.pointLimit: setState(() { - _isPointsLimitEnabled = null; + _isPointsLimitEnabled = true; }); break; case GameMode.unlimited: @@ -141,7 +141,7 @@ class _CreateGameViewState extends State { case GameMode.none: default: setState(() { - _isPointsLimitEnabled = true; + _isPointsLimitEnabled = null; }); } }, From ac1851d501666dc2317e4894e21b49639c332836 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:53:13 +0200 Subject: [PATCH 219/353] Deleted getter --- lib/services/config_service.dart | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 108b210..a360fe4 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -37,12 +37,6 @@ class ConfigService { gameMode = newGameMode; } - /// Getter for the point limit. - static Future getPointLimit() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getInt(_keyPointLimit) ?? _defaultPointLimit; - } - /// Setter for the point limit. /// [newPointLimit] is the new point limit to be set. static Future setPointLimit(int newPointLimit) async { @@ -51,12 +45,6 @@ class ConfigService { pointLimit = newPointLimit; } - /// Getter for the cabo penalty. - static Future getCaboPenalty() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty; - } - /// Setter for the cabo penalty. /// [newCaboPenalty] is the new cabo penalty to be set. static Future setCaboPenalty(int newCaboPenalty) async { @@ -69,6 +57,7 @@ class ConfigService { static Future resetConfig() async { ConfigService.pointLimit = _defaultPointLimit; ConfigService.caboPenalty = _defaultCaboPenalty; + ConfigService.gameMode = _defaultGameMode; final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyPointLimit, _defaultPointLimit); await prefs.setInt(_keyCaboPenalty, _defaultCaboPenalty); From 7789c05174e5030eda05f35f9c41dd9864053717 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:53:22 +0200 Subject: [PATCH 220/353] Removed not used code --- lib/main.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 9279426..8b45434 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,8 +12,6 @@ Future main() async { await SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); await ConfigService.initConfig(); - ConfigService.pointLimit = await ConfigService.getPointLimit(); - ConfigService.caboPenalty = await ConfigService.getCaboPenalty(); await VersionService.init(); runApp(const App()); } From 9c797e1e5eba42e1135a1f99e460341b5464211d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 22:53:32 +0200 Subject: [PATCH 221/353] Implemented reset logic for default game mode --- lib/presentation/views/settings_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 67b2fa0..c649a20 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -142,6 +142,7 @@ class _SettingsViewState extends State { setState(() { _stepperKey1 = UniqueKey(); _stepperKey2 = UniqueKey(); + defaultMode = ConfigService.gameMode; }); }, ) From d660fb06276f98d6bab960e8c4251183dee235a1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 23:00:02 +0200 Subject: [PATCH 222/353] Updated to 0.5.0 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index dca4d3a..600700e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.9+540 +version: 0.5.0+540 environment: sdk: ^3.5.4 From 96471a5764b773d33d639f1ea9c33b952f45ee89 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 19 Jul 2025 23:06:38 +0200 Subject: [PATCH 223/353] Hotfix: Pixel Overflow --- lib/l10n/arb/app_de.arb | 2 +- lib/l10n/generated/app_localizations.dart | 2 +- lib/l10n/generated/app_localizations_de.dart | 2 +- lib/presentation/views/settings_view.dart | 2 +- pubspec.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 3c157ad..5032baf 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -58,7 +58,7 @@ "no_name_message": "Jeder Spieler muss einen Namen haben.", "select_game_mode": "Spielmodus auswählen", - "no_mode_selected": "Kein Modus ausgewählt", + "no_mode_selected": "Kein Modus", "no_default_mode": "Kein Standard-Modus", "no_default_description": "Der Standard-Modus wird zurückgesetzt.", "point_limit_description": "Es wird so lange gespielt, bis ein:e Spieler:in mehr als {pointLimit} Punkte erreicht", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index cc4eb12..40d8c65 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -377,7 +377,7 @@ abstract class AppLocalizations { /// No description provided for @no_mode_selected. /// /// In de, this message translates to: - /// **'Kein Modus ausgewählt'** + /// **'Kein Modus'** String get no_mode_selected; /// No description provided for @no_default_mode. diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 3820070..b73ccba 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -155,7 +155,7 @@ class AppLocalizationsDe extends AppLocalizations { String get select_game_mode => 'Spielmodus auswählen'; @override - String get no_mode_selected => 'Kein Modus ausgewählt'; + String get no_mode_selected => 'Kein Modus'; @override String get no_default_mode => 'Kein Standard-Modus'; diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index c649a20..596866d 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -98,7 +98,7 @@ class _SettingsViewState extends State { ? '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}' : AppLocalizations.of(context).unlimited), ), - const SizedBox(width: 10), + const SizedBox(width: 5), const CupertinoListTileChevron() ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 600700e..3861d64 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.0+540 +version: 0.5.0+542 environment: sdk: ^3.5.4 From 261e8f80c11c582301ee0fe7ed88a53c4f54bca8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 16:34:00 +0200 Subject: [PATCH 224/353] Changed the overall return type for gamemodes --- lib/l10n/arb/app_de.arb | 6 +- lib/l10n/generated/app_localizations.dart | 6 +- lib/l10n/generated/app_localizations_de.dart | 7 ++- lib/presentation/views/active_game_view.dart | 9 ++- lib/presentation/views/create_game_view.dart | 57 +++++++---------- lib/presentation/views/main_menu_view.dart | 13 ++-- lib/presentation/views/settings_view.dart | 39 ++++-------- lib/services/config_service.dart | 64 ++++++++++++++------ pubspec.yaml | 2 +- 9 files changed, 103 insertions(+), 100 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 5032baf..c5fae28 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -58,9 +58,9 @@ "no_name_message": "Jeder Spieler muss einen Namen haben.", "select_game_mode": "Spielmodus auswählen", - "no_mode_selected": "Kein Modus", - "no_default_mode": "Kein Standard-Modus", - "no_default_description": "Der Standard-Modus wird zurückgesetzt.", + "no_mode_selected": "Wähle einen Spielmodus", + "no_default_mode": "Kein Modus", + "no_default_description": "Entscheide bei jedem Spiel selber, welchen Modus du spielen möchtest.", "point_limit_description": "Es wird so lange gespielt, bis ein:e Spieler:in mehr als {pointLimit} Punkte erreicht", "@point_limit_description": { "placeholders": { diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 40d8c65..d821b28 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -377,19 +377,19 @@ abstract class AppLocalizations { /// No description provided for @no_mode_selected. /// /// In de, this message translates to: - /// **'Kein Modus'** + /// **'Wähle einen Spielmodus'** String get no_mode_selected; /// No description provided for @no_default_mode. /// /// In de, this message translates to: - /// **'Kein Standard-Modus'** + /// **'Kein Modus'** String get no_default_mode; /// No description provided for @no_default_description. /// /// In de, this message translates to: - /// **'Der Standard-Modus wird zurückgesetzt.'** + /// **'Entscheide bei jedem Spiel selber, welchen Modus du spielen möchtest.'** String get no_default_description; /// No description provided for @point_limit_description. diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index b73ccba..13dcf2a 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -155,13 +155,14 @@ class AppLocalizationsDe extends AppLocalizations { String get select_game_mode => 'Spielmodus auswählen'; @override - String get no_mode_selected => 'Kein Modus'; + String get no_mode_selected => 'Wähle einen Spielmodus'; @override - String get no_default_mode => 'Kein Standard-Modus'; + String get no_default_mode => 'Kein Modus'; @override - String get no_default_description => 'Der Standard-Modus wird zurückgesetzt.'; + String get no_default_description => + 'Entscheide bei jedem Spiel selber, welchen Modus du spielen möchtest.'; @override String point_limit_description(int pointLimit) { diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index defe5fc..dece0a6 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -4,6 +4,7 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/graph_view.dart'; +import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:cabo_counter/presentation/views/points_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; @@ -205,9 +206,11 @@ class _ActiveGameViewState extends State { CupertinoPageRoute( builder: (_) => CreateGameView( gameTitle: gameSession.gameTitle, - isPointsLimitEnabled: widget - .gameSession - .isPointsLimitEnabled, + gameMode: widget.gameSession + .isPointsLimitEnabled == + true + ? GameMode.pointLimit + : GameMode.unlimited, players: gameSession.players, ))); }, diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 2634788..bf6d1fb 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -16,15 +16,15 @@ enum CreateStatus { } class CreateGameView extends StatefulWidget { + final GameMode gameMode; final String? gameTitle; - final bool? isPointsLimitEnabled; final List? players; const CreateGameView({ super.key, this.gameTitle, - this.isPointsLimitEnabled, this.players, + required this.gameMode, }); @override @@ -42,19 +42,15 @@ class _CreateGameViewState extends State { /// Maximum number of players allowed in the game. final int maxPlayers = 5; - /// Variable to store whether the points limit feature is enabled. - bool? _isPointsLimitEnabled; + /// Variable to hold the selected game mode. + late GameMode gameMode; @override void initState() { super.initState(); - if (widget.isPointsLimitEnabled == null) { - _isPointsLimitEnabled = - ConfigService.gameMode == -1 ? null : ConfigService.gameMode == 1; - } else { - _isPointsLimitEnabled = widget.isPointsLimitEnabled; - } + gameMode = widget.gameMode; + print('Game mode: $gameMode'); _gameTitleTextController.text = widget.gameTitle ?? ''; @@ -106,10 +102,10 @@ class _CreateGameViewState extends State { suffix: Row( children: [ Text( - _isPointsLimitEnabled == null - ? AppLocalizations.of(context).select_mode - : (_isPointsLimitEnabled! - ? '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}' + gameMode == GameMode.none + ? AppLocalizations.of(context).no_mode_selected + : (gameMode == GameMode.pointLimit + ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' : AppLocalizations.of(context).unlimited), ), const SizedBox(width: 3), @@ -121,29 +117,15 @@ class _CreateGameViewState extends State { context, CupertinoPageRoute( builder: (context) => ModeSelectionMenu( - pointLimit: ConfigService.pointLimit, + pointLimit: ConfigService.getPointLimit(), showDeselection: false, ), ), ); - switch (selectedMode) { - case GameMode.pointLimit: - setState(() { - _isPointsLimitEnabled = true; - }); - break; - case GameMode.unlimited: - setState(() { - _isPointsLimitEnabled = false; - }); - break; - case GameMode.none: - default: - setState(() { - _isPointsLimitEnabled = null; - }); - } + setState(() { + gameMode = selectedMode ?? gameMode; + }); }, ), ), @@ -249,7 +231,7 @@ class _CreateGameViewState extends State { showFeedbackDialog(CreateStatus.noGameTitle); return; } - if (_isPointsLimitEnabled == null) { + if (gameMode == GameMode.none) { showFeedbackDialog(CreateStatus.noModeSelected); return; } @@ -266,13 +248,16 @@ class _CreateGameViewState extends State { for (var controller in _playerNameTextControllers) { players.add(controller.text); } + + bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + GameSession gameSession = GameSession( createdAt: DateTime.now(), gameTitle: _gameTitleTextController.text, players: players, - pointLimit: ConfigService.pointLimit, - caboPenalty: ConfigService.caboPenalty, - isPointsLimitEnabled: _isPointsLimitEnabled!, + pointLimit: ConfigService.getPointLimit(), + caboPenalty: ConfigService.getCaboPenalty(), + isPointsLimitEnabled: isPointsLimitEnabled, ); final index = await gameManager.addGameSession(gameSession); final session = gameManager.gameList[index]; diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index a80664d..f8817a0 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -77,7 +77,8 @@ class _MainMenuViewState extends State { onPressed: () => Navigator.push( context, CupertinoPageRoute( - builder: (context) => const CreateGameView(), + builder: (context) => CreateGameView( + gameMode: ConfigService.getGameMode()), ), ), icon: const Icon(CupertinoIcons.add)), @@ -96,8 +97,8 @@ class _MainMenuViewState extends State { onTap: () => Navigator.push( context, CupertinoPageRoute( - builder: (context) => - const CreateGameView(), + builder: (context) => CreateGameView( + gameMode: ConfigService.getGameMode()), ), ), child: Icon( @@ -216,9 +217,9 @@ class _MainMenuViewState extends State { /// Translates the game mode boolean into the corresponding String. /// If [pointLimit] is true, it returns '101 Punkte', otherwise it returns 'Unbegrenzt'. - String _translateGameMode(bool pointLimit) { - if (pointLimit) { - return '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}'; + String _translateGameMode(bool isPointLimitEnabled) { + if (isPointLimitEnabled) { + return '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}'; } return AppLocalizations.of(context).unlimited; } diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index 596866d..aa49872 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -21,7 +21,7 @@ class SettingsView extends StatefulWidget { class _SettingsViewState extends State { UniqueKey _stepperKey1 = UniqueKey(); UniqueKey _stepperKey2 = UniqueKey(); - int defaultMode = ConfigService.gameMode; + GameMode defaultMode = ConfigService.getGameMode(); @override void initState() { super.initState(); @@ -57,7 +57,7 @@ class _SettingsViewState extends State { prefixIcon: CupertinoIcons.bolt_fill, suffixWidget: CustomStepper( key: _stepperKey1, - initialValue: ConfigService.caboPenalty, + initialValue: ConfigService.getCaboPenalty(), minValue: 0, maxValue: 50, step: 1, @@ -73,7 +73,7 @@ class _SettingsViewState extends State { prefixIcon: FontAwesomeIcons.bullseye, suffixWidget: CustomStepper( key: _stepperKey2, - initialValue: ConfigService.pointLimit, + initialValue: ConfigService.getPointLimit(), minValue: 30, maxValue: 1000, step: 10, @@ -91,11 +91,10 @@ class _SettingsViewState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - defaultMode == -1 - ? AppLocalizations.of(context) - .no_mode_selected - : (defaultMode == 1 - ? '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}' + 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), @@ -107,29 +106,15 @@ class _SettingsViewState extends State { context, CupertinoPageRoute( builder: (context) => ModeSelectionMenu( - pointLimit: ConfigService.pointLimit, + pointLimit: ConfigService.getPointLimit(), showDeselection: true, ), ), ); - switch (selectedMode) { - case GameMode.pointLimit: - setState(() { - defaultMode = 1; - }); - break; - case GameMode.unlimited: - setState(() { - defaultMode = 0; - }); - break; - case GameMode.none: - default: - setState(() { - defaultMode = -1; - }); - } + setState(() { + defaultMode = selectedMode ?? GameMode.none; + }); ConfigService.setGameMode(defaultMode); }, ), @@ -142,7 +127,7 @@ class _SettingsViewState extends State { setState(() { _stepperKey1 = UniqueKey(); _stepperKey2 = UniqueKey(); - defaultMode = ConfigService.gameMode; + defaultMode = ConfigService.getGameMode(); }); }, ) diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index a360fe4..d4ac105 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// This class handles the configuration settings for the app. @@ -8,9 +9,9 @@ class ConfigService { static const String _keyCaboPenalty = 'caboPenalty'; static const String _keyGameMode = 'gameMode'; // Actual values used in the app - static int pointLimit = 100; - static int caboPenalty = 5; - static int gameMode = -1; + static int _pointLimit = 100; + static int _caboPenalty = 5; + static int _gameMode = -1; // Default values static const int _defaultPointLimit = 100; static const int _defaultCaboPenalty = 5; @@ -21,43 +22,70 @@ class ConfigService { // Initialize pointLimit, caboPenalty, and gameMode from SharedPreferences // If they are not set, use the default values - pointLimit = prefs.getInt(_keyPointLimit) ?? _defaultPointLimit; - caboPenalty = prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty; - gameMode = prefs.getInt(_keyGameMode) ?? _defaultGameMode; + _pointLimit = prefs.getInt(_keyPointLimit) ?? _defaultPointLimit; + _caboPenalty = prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty; + _gameMode = prefs.getInt(_keyGameMode) ?? _defaultGameMode; // Save the initial values to SharedPreferences - prefs.setInt(_keyPointLimit, pointLimit); - prefs.setInt(_keyCaboPenalty, caboPenalty); - prefs.setInt(_keyGameMode, gameMode); + prefs.setInt(_keyPointLimit, _pointLimit); + prefs.setInt(_keyCaboPenalty, _caboPenalty); + prefs.setInt(_keyGameMode, _gameMode); } - static Future setGameMode(int newGameMode) async { - final prefs = await SharedPreferences.getInstance(); - await prefs.setInt(_keyGameMode, newGameMode); - gameMode = newGameMode; + static GameMode getGameMode() { + switch (_gameMode) { + case 0: + return GameMode.pointLimit; + case 1: + return GameMode.unlimited; + default: + return GameMode.none; + } } + static Future setGameMode(GameMode newGameMode) async { + int gameMode; + switch (newGameMode) { + case GameMode.pointLimit: + gameMode = 0; + break; + case GameMode.unlimited: + gameMode = 1; + break; + default: + gameMode = -1; + } + + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt(_keyGameMode, gameMode); + _gameMode = gameMode; + } + + static int getPointLimit() => _pointLimit; + /// Setter for the point limit. /// [newPointLimit] is the new point limit to be set. static Future setPointLimit(int newPointLimit) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyPointLimit, newPointLimit); - pointLimit = newPointLimit; + _pointLimit = newPointLimit; } + static int getCaboPenalty() => _caboPenalty; + /// Setter for the cabo penalty. /// [newCaboPenalty] is the new cabo penalty to be set. static Future setCaboPenalty(int newCaboPenalty) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyCaboPenalty, newCaboPenalty); - caboPenalty = newCaboPenalty; + _caboPenalty = newCaboPenalty; } /// Resets the configuration to default values. static Future resetConfig() async { - ConfigService.pointLimit = _defaultPointLimit; - ConfigService.caboPenalty = _defaultCaboPenalty; - ConfigService.gameMode = _defaultGameMode; + ConfigService._pointLimit = _defaultPointLimit; + ConfigService._caboPenalty = _defaultCaboPenalty; + ConfigService._gameMode = _defaultGameMode; final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyPointLimit, _defaultPointLimit); await prefs.setInt(_keyCaboPenalty, _defaultCaboPenalty); diff --git a/pubspec.yaml b/pubspec.yaml index 3861d64..e445bd6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.0+542 +version: 0.5.0+544 environment: sdk: ^3.5.4 From 5d362a77cffb96fa2e864c0aee69a8c33c234be6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 16:41:36 +0200 Subject: [PATCH 225/353] Updated documentation --- lib/presentation/views/create_game_view.dart | 1 - lib/services/config_service.dart | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index bf6d1fb..e0b4198 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -50,7 +50,6 @@ class _CreateGameViewState extends State { super.initState(); gameMode = widget.gameMode; - print('Game mode: $gameMode'); _gameTitleTextController.text = widget.gameTitle ?? ''; diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index d4ac105..1b20ad5 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -32,6 +32,14 @@ class ConfigService { prefs.setInt(_keyGameMode, _gameMode); } + /// Retrieves the current game mode. + /// + /// The game mode is determined based on the stored integer value: + /// - `0`: [GameMode.pointLimit] + /// - `1`: [GameMode.unlimited] + /// - Any other value: [GameMode.none] (-1 is used as a default for no mode) + /// + /// Returns the corresponding [GameMode] enum value. static GameMode getGameMode() { switch (_gameMode) { case 0: @@ -43,6 +51,14 @@ class ConfigService { } } + /// Sets the game mode for the application. + /// + /// [newGameMode] is the new game mode to be set. It can be one of the following: + /// - `GameMode.pointLimit`: The game ends when a pleayer reaches the point limit. + /// - `GameMode.unlimited`: Every game goes for infinity until you end it. + /// - `GameMode.none`: No default mode set. + /// + /// This method updates the `_gameMode` field and persists the value in `SharedPreferences`. static Future setGameMode(GameMode newGameMode) async { int gameMode; switch (newGameMode) { From 651b3eab0f4716855e7a8be156a34920baebd03a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:07:55 +0200 Subject: [PATCH 226/353] Fixed merge issues --- lib/presentation/views/create_game_view.dart | 301 +++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 184 insertions(+), 119 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 47251af..fcb50bc 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -137,127 +137,127 @@ class _CreateGameViewState extends State { ), ), Expanded( - child: ReorderableListView.builder( - physics: const NeverScrollableScrollPhysics(), - itemCount: _playerNameTextControllers.length + 2, - onReorder: (oldIndex, newIndex) { - if (oldIndex < _playerNameTextControllers.length && - newIndex <= _playerNameTextControllers.length) { - setState(() { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - }); - } - }, - itemBuilder: (context, index) { - // Create game button - if (index == _playerNameTextControllers.length + 1) { - return Container( - key: const ValueKey('create_game_button'), - child: CupertinoButton( - padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: CustomTheme.primaryColor, - ), - padding: const EdgeInsets.symmetric( - horizontal: 15, vertical: 8), - child: Text( - AppLocalizations.of(context).create_game, - style: TextStyle( - color: CustomTheme.backgroundColor, + child: ReorderableListView.builder( + physics: const NeverScrollableScrollPhysics(), + itemCount: _playerNameTextControllers.length + 2, + onReorder: (oldIndex, newIndex) { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + setState(() { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + }); + } + }, + itemBuilder: (context, index) { + // Create game button + if (index == _playerNameTextControllers.length + 1) { + return Container( + key: const ValueKey('create_game_button'), + child: CupertinoButton( + padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: CustomTheme.primaryColor, + ), + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 8), + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.backgroundColor, + ), + ), ), - ), - ), - ], - ), - onPressed: () { - _checkAllGameAttributes(); - }, - ), - ); - } - // Add player button - if (index == _playerNameTextControllers.length) { - return Container( - key: const ValueKey('add_player_button'), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 10), - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - CupertinoIcons.add_circled_solid, - color: CustomTheme.primaryColor, - ), - const SizedBox(width: 6), - Text( - AppLocalizations.of(context).add_player, - style: - TextStyle(color: CustomTheme.primaryColor), - ), - ), - ], - ), - onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - showFeedbackDialog(CreateStatus.maxPlayers); - } - }, - ), - ); - } else { - // Spieler-Einträge - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, horizontal: 5), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, + ], ), onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); + _checkAllGameAttributes(); }, ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), + ); + } + // Add player button + if (index == _playerNameTextControllers.length) { + return Container( + key: const ValueKey('add_player_button'), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 10), + child: CupertinoButton( + padding: EdgeInsets.zero, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 6), + Text( + AppLocalizations.of(context) + .add_player, + style: TextStyle( + color: + CustomTheme.primaryColor), + ), + ]), + onPressed: () { + if (_playerNameTextControllers.length < + maxPlayers) { + setState(() { + _playerNameTextControllers + .add(TextEditingController()); + }); + } else { + showFeedbackDialog( + CreateStatus.maxPlayers); + } + }))); + } else { + // Player entries + return Padding( + key: ValueKey(_playerNameTextControllers[index]), + padding: const EdgeInsets.symmetric( + vertical: 8.0, horizontal: 5), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, + ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), + ), + ], ), - ), - ], - ), - ); - }, - ), - ), + ); + } + })), Center( child: CupertinoButton( padding: EdgeInsets.zero, @@ -319,18 +319,26 @@ class _CreateGameViewState extends State { ), ], )))); + } + Future _createGame() async { + /*var uuid = const Uuid(); + id = uuid.v1();*/ + List players = []; for (var controller in _playerNameTextControllers) { players.add(controller.text); } + + bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + GameSession gameSession = GameSession( createdAt: DateTime.now(), gameTitle: _gameTitleTextController.text, players: players, - pointLimit: Globals.pointLimit, - caboPenalty: Globals.caboPenalty, - isPointsLimitEnabled: _isPointsLimitEnabled!, + pointLimit: ConfigService.getPointLimit(), + caboPenalty: ConfigService.getCaboPenalty(), + isPointsLimitEnabled: isPointsLimitEnabled, ); final index = await gameManager.addGameSession(gameSession); final session = gameManager.gameList[index]; @@ -361,6 +369,63 @@ class _CreateGameViewState extends State { }); } + void _checkAllGameAttributes() { + if (_gameTitleTextController.text == '') { + _showDialog(( + AppLocalizations.of(context).no_gameTitle_title, + AppLocalizations.of(context).no_gameTitle_message + )); + return; + } + + if (gameMode == GameMode.none) { + _showDialog( + ( + AppLocalizations.of(context).no_mode_title, + AppLocalizations.of(context).no_mode_message + ), + ); + return; + } + + if (_playerNameTextControllers.length < 2) { + _showDialog( + ( + AppLocalizations.of(context).min_players_title, + AppLocalizations.of(context).min_players_message + ), + ); + return; + } + + if (!everyPlayerHasAName()) { + _showDialog(( + AppLocalizations.of(context).no_name_title, + AppLocalizations.of(context).no_name_message + )); + return; + } + + _createGame(); + } + + void _showDialog((String, String) content) { + final (title, message) = content; + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: Text(title), + content: Text(message), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () => Navigator.pop(context), + ), + ], + ), + ); + } + /// Returns the title and message for the dialog based on the [CreateStatus]. (String, String) _getDialogContent(CreateStatus status) { switch (status) { diff --git a/pubspec.yaml b/pubspec.yaml index 956c747..9d13ace 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.0+554 +version: 0.5.0+556 environment: sdk: ^3.5.4 From 3c095e0f55e20d4c715d39ce2362754def4f4cdb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:27:13 +0200 Subject: [PATCH 227/353] Added Custom button --- lib/presentation/widgets/custom_button.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 lib/presentation/widgets/custom_button.dart diff --git a/lib/presentation/widgets/custom_button.dart b/lib/presentation/widgets/custom_button.dart new file mode 100644 index 0000000..0feb799 --- /dev/null +++ b/lib/presentation/widgets/custom_button.dart @@ -0,0 +1,19 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:flutter/cupertino.dart'; + +class CustomButton extends StatelessWidget { + final Widget child; + final VoidCallback? onPressed; + const CustomButton({super.key, required this.child, this.onPressed}); + + @override + Widget build(BuildContext context) { + return CupertinoButton( + sizeStyle: CupertinoButtonSize.medium, + borderRadius: BorderRadius.circular(12), + color: CustomTheme.buttonBackgroundColor, + onPressed: onPressed, + child: child, + ); + } +} From 5ebce36c125c17a104c20cae4babd9008db893b4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:27:21 +0200 Subject: [PATCH 228/353] Updated strings --- lib/l10n/arb/app_de.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index c5fae28..effbd96 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -55,7 +55,7 @@ "min_players_title": "Zu wenig Spieler:innen", "min_players_message": "Es müssen mindestens 2 Spieler:innen hinzugefügt werden", "no_name_title": "Kein Name", - "no_name_message": "Jeder Spieler muss einen Namen haben.", + "no_name_message": "Jede:r Spieler:in muss einen Namen haben.", "select_game_mode": "Spielmodus auswählen", "no_mode_selected": "Wähle einen Spielmodus", From a4693ccf399235c273326666771ba4b763f89f48 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:51:30 +0200 Subject: [PATCH 229/353] Updated buttons, implemented animatedOpacity --- lib/l10n/generated/app_localizations.dart | 2 +- lib/l10n/generated/app_localizations_de.dart | 2 +- lib/presentation/views/create_game_view.dart | 283 ++++++++----------- pubspec.yaml | 2 +- 4 files changed, 117 insertions(+), 172 deletions(-) diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index d821b28..9c64cb2 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -365,7 +365,7 @@ abstract class AppLocalizations { /// No description provided for @no_name_message. /// /// In de, this message translates to: - /// **'Jeder Spieler muss einen Namen haben.'** + /// **'Jede:r Spieler:in muss einen Namen haben.'** String get no_name_message; /// No description provided for @select_game_mode. diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 13dcf2a..c4849d8 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -149,7 +149,7 @@ class AppLocalizationsDe extends AppLocalizations { String get no_name_title => 'Kein Name'; @override - String get no_name_message => 'Jeder Spieler muss einen Namen haben.'; + String get no_name_message => 'Jede:r Spieler:in muss einen Namen haben.'; @override String get select_game_mode => 'Spielmodus auswählen'; diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index fcb50bc..ea7476f 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -4,6 +4,7 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; +import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -136,185 +137,129 @@ class _CreateGameViewState extends State { style: CustomTheme.rowTitle, ), ), - Expanded( - child: ReorderableListView.builder( - physics: const NeverScrollableScrollPhysics(), - itemCount: _playerNameTextControllers.length + 2, - onReorder: (oldIndex, newIndex) { + Flexible( + child: ReorderableListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { if (oldIndex < _playerNameTextControllers.length && newIndex <= _playerNameTextControllers.length) { - setState(() { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - }); + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); } - }, - itemBuilder: (context, index) { - // Create game button - if (index == _playerNameTextControllers.length + 1) { - return Container( - key: const ValueKey('create_game_button'), - child: CupertinoButton( - padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: CustomTheme.primaryColor, - ), - padding: const EdgeInsets.symmetric( - horizontal: 15, vertical: 8), - child: Text( - AppLocalizations.of(context).create_game, - style: TextStyle( - color: CustomTheme.backgroundColor, - ), - ), - ), - ], + }); + }, + itemBuilder: (context, index) { + return Padding( + key: ValueKey( + 'player_${_playerNameTextControllers[index].hashCode}'), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, ), onPressed: () { - _checkAllGameAttributes(); + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); }, ), - ); - } - // Add player button - if (index == _playerNameTextControllers.length) { - return Container( - key: const ValueKey('add_player_button'), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 10), - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Icon( - CupertinoIcons.add_circled_solid, - color: CustomTheme.primaryColor, - ), - const SizedBox(width: 6), - Text( - AppLocalizations.of(context) - .add_player, - style: TextStyle( - color: - CustomTheme.primaryColor), - ), - ]), - onPressed: () { - if (_playerNameTextControllers.length < - maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - showFeedbackDialog( - CreateStatus.maxPlayers); - } - }))); - } else { - // Player entries - return Padding( - key: ValueKey(_playerNameTextControllers[index]), - padding: const EdgeInsets.symmetric( - vertical: 8.0, horizontal: 5), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); - }, - ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), - ), - ], + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), ), - ); - } - })), - Center( - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context).create_game, - style: const TextStyle( - color: CupertinoColors.activeGreen, + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration(milliseconds: 300), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, + ), + ), + ), + ) + ], ), - ), - ], + ); + }), + ), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 0, 50), + child: Center( + child: CupertinoButton( + padding: EdgeInsets.zero, + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.plus_circle_fill, + color: CustomTheme.primaryColor, + size: 25, + )), + Stack(children: [ + Expanded( + child: Center( + child: Text( + AppLocalizations.of(context).add_player, + style: TextStyle(color: CustomTheme.primaryColor), + ), + ), + ), + ]), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < maxPlayers) { + setState(() { + _playerNameTextControllers.add(TextEditingController()); + }); + } else { + showFeedbackDialog(CreateStatus.maxPlayers); + } + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), + child: Center( + key: const ValueKey('create_game_button'), + child: CustomButton( + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ), + onPressed: () { + _checkAllGameAttributes(); + }, ), - onPressed: () async { - if (_gameTitleTextController.text == '') { - showFeedbackDialog(CreateStatus.noGameTitle); - return; - } - if (gameMode == GameMode.none) { - showFeedbackDialog(CreateStatus.noModeSelected); - return; - } - if (_playerNameTextControllers.length < 2) { - showFeedbackDialog(CreateStatus.minPlayers); - return; - } - if (!everyPlayerHasAName()) { - showFeedbackDialog(CreateStatus.noPlayerName); - return; - } - - List players = []; - for (var controller in _playerNameTextControllers) { - players.add(controller.text); - } - - bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; - - GameSession gameSession = GameSession( - createdAt: DateTime.now(), - gameTitle: _gameTitleTextController.text, - players: players, - pointLimit: ConfigService.getPointLimit(), - caboPenalty: ConfigService.getCaboPenalty(), - isPointsLimitEnabled: isPointsLimitEnabled, - ); - final index = await gameManager.addGameSession(gameSession); - final session = gameManager.gameList[index]; - if (context.mounted) { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => - ActiveGameView(gameSession: session))); - } - }, ), ), ], diff --git a/pubspec.yaml b/pubspec.yaml index 9d13ace..001d4f2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.0+556 +version: 0.5.0+558 environment: sdk: ^3.5.4 From 68a1a5052eb27f91b92ec6147c36bef783617949 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 18:21:30 +0200 Subject: [PATCH 230/353] Keyboard still doesnt works --- lib/presentation/views/create_game_view.dart | 356 +++++++++---------- pubspec.yaml | 2 +- 2 files changed, 178 insertions(+), 180 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index ea7476f..faffe76 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -72,198 +72,196 @@ class _CreateGameViewState extends State { ), child: SafeArea( child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).game, - style: CustomTheme.rowTitle, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - maxLength: 16, - prefix: Text(AppLocalizations.of(context).name), - textAlign: TextAlign.right, - placeholder: AppLocalizations.of(context).game_title, - controller: _gameTitleTextController, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - readOnly: true, - prefix: Text(AppLocalizations.of(context).mode), - suffix: Row( - children: [ - Text( - gameMode == GameMode.none - ? AppLocalizations.of(context).no_mode_selected - : (gameMode == GameMode.pointLimit - ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' - : AppLocalizations.of(context).unlimited), - ), - const SizedBox(width: 3), - const CupertinoListTileChevron(), - ], + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).game, + style: CustomTheme.rowTitle, ), - onTap: () async { - final selectedMode = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ModeSelectionMenu( - pointLimit: ConfigService.getPointLimit(), - showDeselection: false, - ), - ), - ); - - setState(() { - gameMode = selectedMode ?? gameMode; - }); - }, ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).players, - style: CustomTheme.rowTitle, + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + maxLength: 16, + prefix: Text(AppLocalizations.of(context).name), + textAlign: TextAlign.right, + placeholder: AppLocalizations.of(context).game_title, + controller: _gameTitleTextController, + ), ), - ), - Flexible( - child: ReorderableListView.builder( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.all(8), - itemCount: _playerNameTextControllers.length, - onReorder: (oldIndex, newIndex) { - setState(() { - if (oldIndex < _playerNameTextControllers.length && - newIndex <= _playerNameTextControllers.length) { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - } - }); - }, - itemBuilder: (context, index) { - return Padding( - key: ValueKey( - 'player_${_playerNameTextControllers[index].hashCode}'), - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); - }, - ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), - ), - AnimatedOpacity( - opacity: _playerNameTextControllers.length > 1 - ? 1.0 - : 0.0, - duration: const Duration(milliseconds: 300), - child: Padding( - padding: const EdgeInsets.only(right: 8.0), - child: ReorderableDragStartListener( - index: index, - child: const Icon( - CupertinoIcons.line_horizontal_3, - color: CupertinoColors.systemGrey, - ), - ), - ), - ) - ], - ), - ); - }), - ), - Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 0, 50), - child: Center( - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + readOnly: true, + prefix: Text(AppLocalizations.of(context).mode), + suffix: Row( children: [ - CupertinoButton( - padding: EdgeInsets.zero, - onPressed: null, - child: Icon( - CupertinoIcons.plus_circle_fill, - color: CustomTheme.primaryColor, - size: 25, - )), - Stack(children: [ - Expanded( - child: Center( - child: Text( - AppLocalizations.of(context).add_player, - style: TextStyle(color: CustomTheme.primaryColor), - ), - ), - ), - ]), + Text( + gameMode == GameMode.none + ? AppLocalizations.of(context).no_mode_selected + : (gameMode == GameMode.pointLimit + ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' + : AppLocalizations.of(context).unlimited), + ), + const SizedBox(width: 3), + const CupertinoListTileChevron(), ], ), - onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers.add(TextEditingController()); - }); - } else { - showFeedbackDialog(CreateStatus.maxPlayers); - } + onTap: () async { + final selectedMode = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ModeSelectionMenu( + pointLimit: ConfigService.getPointLimit(), + showDeselection: false, + ), + ), + ); + + setState(() { + gameMode = selectedMode ?? gameMode; + }); }, ), ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), - child: Center( - key: const ValueKey('create_game_button'), - child: CustomButton( - child: Text( - AppLocalizations.of(context).create_game, - style: TextStyle( - color: CustomTheme.primaryColor, + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).players, + style: CustomTheme.rowTitle, + ), + ), + Flexible( + child: ReorderableListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + } + }); + }, + itemBuilder: (context, index) { + return Padding( + key: ValueKey( + 'player_${_playerNameTextControllers[index].hashCode}'), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, + ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), + ), + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration(milliseconds: 300), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, + ), + ), + ), + ) + ], + ), + ); + }), + ), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), + child: Center( + child: SizedBox( + width: double.infinity, + child: CupertinoButton( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context).add_player, + style: TextStyle(color: CustomTheme.primaryColor), + ), + const SizedBox(width: 8), + Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + size: 25, + ), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < maxPlayers) { + setState(() { + _playerNameTextControllers + .add(TextEditingController()); + }); + } else { + showFeedbackDialog(CreateStatus.maxPlayers); + } + }, ), ), - onPressed: () { - _checkAllGameAttributes(); - }, ), ), - ), - ], - )))); + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), + child: Center( + key: const ValueKey('create_game_button'), + child: CustomButton( + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ), + onPressed: () { + _checkAllGameAttributes(); + }, + ), + ), + ), + ], + ), + ))); } Future _createGame() async { diff --git a/pubspec.yaml b/pubspec.yaml index 001d4f2..995d091 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.0+558 +version: 0.5.0+568 environment: sdk: ^3.5.4 From 59ff4df83c5f26656e2d57fbacfade57f7e7ac3d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 19:28:38 +0200 Subject: [PATCH 231/353] Fixed keyboard behaviour --- lib/presentation/views/create_game_view.dart | 162 ++++++++++--------- lib/presentation/views/tab_view.dart | 1 + 2 files changed, 90 insertions(+), 73 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index faffe76..880eb6f 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -8,6 +8,7 @@ import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; enum CreateStatus { noGameTitle, @@ -66,12 +67,13 @@ class _CreateGameViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( + resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( previousPageTitle: AppLocalizations.of(context).overview, middle: Text(AppLocalizations.of(context).new_game), ), child: SafeArea( - child: Center( + child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -102,13 +104,7 @@ class _CreateGameViewState extends State { prefix: Text(AppLocalizations.of(context).mode), suffix: Row( children: [ - Text( - gameMode == GameMode.none - ? AppLocalizations.of(context).no_mode_selected - : (gameMode == GameMode.pointLimit - ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' - : AppLocalizations.of(context).unlimited), - ), + _getDisplayedGameMode(), const SizedBox(width: 3), const CupertinoListTileChevron(), ], @@ -137,75 +133,73 @@ class _CreateGameViewState extends State { style: CustomTheme.rowTitle, ), ), - Flexible( - child: ReorderableListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - padding: const EdgeInsets.all(8), - itemCount: _playerNameTextControllers.length, - onReorder: (oldIndex, newIndex) { - setState(() { - if (oldIndex < _playerNameTextControllers.length && - newIndex <= _playerNameTextControllers.length) { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - } - }); - }, - itemBuilder: (context, index) { - return Padding( - key: ValueKey( - 'player_${_playerNameTextControllers[index].hashCode}'), - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); - }, + ReorderableListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + } + }); + }, + itemBuilder: (context, index) { + return Padding( + key: ValueKey( + 'player_${_playerNameTextControllers[index].hashCode}'), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), ), - AnimatedOpacity( - opacity: _playerNameTextControllers.length > 1 - ? 1.0 - : 0.0, - duration: const Duration(milliseconds: 300), - child: Padding( - padding: const EdgeInsets.only(right: 8.0), - child: ReorderableDragStartListener( - index: index, - child: const Icon( - CupertinoIcons.line_horizontal_3, - color: CupertinoColors.systemGrey, - ), + ), + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration(milliseconds: 300), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, ), ), - ) - ], - ), - ); - }), - ), + ), + ) + ], + ), + ); + }), Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), child: Center( @@ -259,6 +253,15 @@ class _CreateGameViewState extends State { ), ), ), + KeyboardVisibilityBuilder(builder: (context, visible) { + if (visible) { + return const SizedBox( + height: 250, + ); + } else { + return const SizedBox.shrink(); + } + }) ], ), ))); @@ -412,6 +415,19 @@ class _CreateGameViewState extends State { return true; } + Text _getDisplayedGameMode() { + if (gameMode == GameMode.none) { + return Text(AppLocalizations.of(context).no_mode_selected); + } else if (gameMode == GameMode.pointLimit) { + return Text( + '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}', + style: TextStyle(color: CustomTheme.primaryColor)); + } else { + return Text(AppLocalizations.of(context).unlimited, + style: TextStyle(color: CustomTheme.primaryColor)); + } + } + @override void dispose() { _gameTitleTextController.dispose(); diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 4b757fa..08b1790 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -16,6 +16,7 @@ class _TabViewState extends State { @override Widget build(BuildContext context) { return CupertinoTabScaffold( + resizeToAvoidBottomInset: false, tabBar: CupertinoTabBar( backgroundColor: CustomTheme.mainElementBackgroundColor, iconSize: 27, From 03ed2a22d50cb5969bf6a92890050ce2101cdd04 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 19:30:15 +0200 Subject: [PATCH 232/353] Changed keyboard height --- lib/presentation/views/create_game_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 880eb6f..0a679a5 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -255,8 +255,8 @@ class _CreateGameViewState extends State { ), KeyboardVisibilityBuilder(builder: (context, visible) { if (visible) { - return const SizedBox( - height: 250, + return SizedBox( + height: MediaQuery.of(context).viewInsets.bottom * 0.75, ); } else { return const SizedBox.shrink(); From 35cfba457da79c270e77d3b0e62bdd48c3066fe2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:20:21 +0200 Subject: [PATCH 233/353] Added method getGameSessionById() --- lib/data/game_manager.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index b3a1933..3fc5e54 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -21,6 +21,10 @@ class GameManager extends ChangeNotifier { return gameList.indexOf(session); } + GameSession? getGameSessionById(String id) { + return gameList.firstWhere((session) => session.id.toString() == id); + } + /// Removes a game session from the list and sorts it by creation date. /// Takes a [index] as input. It then removes the session at the specified index from the `gameList`, /// sorts the list in descending order based on the creation date, and notifies listeners of the change. From d90b9b1bc206850936187946ed460984994bc5d8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:20:52 +0200 Subject: [PATCH 234/353] Updated gameSession class --- lib/data/game_session.dart | 5 ++--- test/data/game_session_test.dart | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index d1402e5..a9164be 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -13,7 +13,7 @@ import 'package:uuid/uuid.dart'; /// [isGameFinished] is a boolean indicating if the game has ended yet. /// [winner] is the name of the player who won the game. class GameSession extends ChangeNotifier { - late String id; + final String id; final DateTime createdAt; final String gameTitle; final List players; @@ -27,6 +27,7 @@ class GameSession extends ChangeNotifier { List roundList = []; GameSession({ + required this.id, required this.createdAt, required this.gameTitle, required this.players, @@ -35,8 +36,6 @@ class GameSession extends ChangeNotifier { required this.isPointsLimitEnabled, }) { playerScores = List.filled(players.length, 0); - var uuid = const Uuid(); - id = uuid.v1(); } @override diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index 4ca2158..9654bad 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -9,6 +9,7 @@ void main() { setUp(() { session = GameSession( + id: '1', createdAt: testDate, gameTitle: testTitle, players: testPlayers, From 1c70cbeb5ad20f51e2f296a321ade748814c0557 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:21:18 +0200 Subject: [PATCH 235/353] id gets added to gameSession class at creation --- lib/presentation/views/create_game_view.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 0a679a5..3817f0a 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -9,6 +9,7 @@ import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:uuid/uuid.dart'; enum CreateStatus { noGameTitle, @@ -268,8 +269,8 @@ class _CreateGameViewState extends State { } Future _createGame() async { - /*var uuid = const Uuid(); - id = uuid.v1();*/ + var uuid = const Uuid(); + final String id = uuid.v1(); List players = []; for (var controller in _playerNameTextControllers) { @@ -279,6 +280,7 @@ class _CreateGameViewState extends State { bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; GameSession gameSession = GameSession( + id: id, createdAt: DateTime.now(), gameTitle: _gameTitleTextController.text, players: players, @@ -286,8 +288,8 @@ class _CreateGameViewState extends State { caboPenalty: ConfigService.getCaboPenalty(), isPointsLimitEnabled: isPointsLimitEnabled, ); - final index = await gameManager.addGameSession(gameSession); - final session = gameManager.gameList[index]; + gameManager.addGameSession(gameSession); + final session = gameManager.getGameSessionById(id)!; Navigator.pushReplacement( context, From cadaf4ce997c5ce900ce3dbc4678e4ba19ef2ec4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:30:20 +0200 Subject: [PATCH 236/353] Cleaned up file --- lib/presentation/views/create_game_view.dart | 176 ++++++++----------- 1 file changed, 75 insertions(+), 101 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 3817f0a..d80d0fb 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -230,7 +230,7 @@ class _CreateGameViewState extends State { .add(TextEditingController()); }); } else { - showFeedbackDialog(CreateStatus.maxPlayers); + _showFeedbackDialog(CreateStatus.maxPlayers); } }, ), @@ -268,37 +268,60 @@ class _CreateGameViewState extends State { ))); } - Future _createGame() async { - var uuid = const Uuid(); - final String id = uuid.v1(); + /// Returns a widget that displays the currently selected game mode in the View. + Text _getDisplayedGameMode() { + if (gameMode == GameMode.none) { + return Text(AppLocalizations.of(context).no_mode_selected); + } else if (gameMode == GameMode.pointLimit) { + return Text( + '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}', + style: TextStyle(color: CustomTheme.primaryColor)); + } else { + return Text(AppLocalizations.of(context).unlimited, + style: TextStyle(color: CustomTheme.primaryColor)); + } + } - List players = []; - for (var controller in _playerNameTextControllers) { - players.add(controller.text); + /// Checks all game attributes before creating a new game. + /// If any attribute is invalid, it shows a feedback dialog. + /// If all attributes are valid, it calls the `_createGame` method. + void _checkAllGameAttributes() { + if (_gameTitleTextController.text == '') { + _showFeedbackDialog(CreateStatus.noGameTitle); + return; } - bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + if (gameMode == GameMode.none) { + _showFeedbackDialog(CreateStatus.noModeSelected); + return; + } - GameSession gameSession = GameSession( - id: id, - createdAt: DateTime.now(), - gameTitle: _gameTitleTextController.text, - players: players, - pointLimit: ConfigService.getPointLimit(), - caboPenalty: ConfigService.getCaboPenalty(), - isPointsLimitEnabled: isPointsLimitEnabled, - ); - gameManager.addGameSession(gameSession); - final session = gameManager.getGameSessionById(id)!; + if (_playerNameTextControllers.length < 2) { + _showFeedbackDialog(CreateStatus.minPlayers); + return; + } - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => ActiveGameView(gameSession: session))); + if (!_everyPlayerHasAName()) { + _showFeedbackDialog(CreateStatus.noPlayerName); + return; + } + + _createGame(); + } + + /// Checks if every player has a name. + /// Returns true if all players have a name, false otherwise. + bool _everyPlayerHasAName() { + for (var controller in _playerNameTextControllers) { + if (controller.text == '') { + return false; + } + } + return true; } /// Displays a feedback dialog based on the [CreateStatus]. - void showFeedbackDialog(CreateStatus status) { + void _showFeedbackDialog(CreateStatus status) { final (title, message) = _getDialogContent(status); showCupertinoDialog( @@ -317,63 +340,6 @@ class _CreateGameViewState extends State { }); } - void _checkAllGameAttributes() { - if (_gameTitleTextController.text == '') { - _showDialog(( - AppLocalizations.of(context).no_gameTitle_title, - AppLocalizations.of(context).no_gameTitle_message - )); - return; - } - - if (gameMode == GameMode.none) { - _showDialog( - ( - AppLocalizations.of(context).no_mode_title, - AppLocalizations.of(context).no_mode_message - ), - ); - return; - } - - if (_playerNameTextControllers.length < 2) { - _showDialog( - ( - AppLocalizations.of(context).min_players_title, - AppLocalizations.of(context).min_players_message - ), - ); - return; - } - - if (!everyPlayerHasAName()) { - _showDialog(( - AppLocalizations.of(context).no_name_title, - AppLocalizations.of(context).no_name_message - )); - return; - } - - _createGame(); - } - - void _showDialog((String, String) content) { - final (title, message) = content; - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(title), - content: Text(message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - } - /// Returns the title and message for the dialog based on the [CreateStatus]. (String, String) _getDialogContent(CreateStatus status) { switch (status) { @@ -406,28 +372,36 @@ class _CreateGameViewState extends State { } } - /// Checks if every player has a name. - /// Returns true if all players have a name, false otherwise. - bool everyPlayerHasAName() { - for (var controller in _playerNameTextControllers) { - if (controller.text == '') { - return false; - } - } - return true; - } + /// Creates a new gameSession and navigates to the active game view. + /// This method creates a new gameSession object with the provided attributes in the text fields. + /// It then adds the game session to the game manager and navigates to the active game view. + void _createGame() { + var uuid = const Uuid(); + final String id = uuid.v1(); - Text _getDisplayedGameMode() { - if (gameMode == GameMode.none) { - return Text(AppLocalizations.of(context).no_mode_selected); - } else if (gameMode == GameMode.pointLimit) { - return Text( - '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}', - style: TextStyle(color: CustomTheme.primaryColor)); - } else { - return Text(AppLocalizations.of(context).unlimited, - style: TextStyle(color: CustomTheme.primaryColor)); + List players = []; + for (var controller in _playerNameTextControllers) { + players.add(controller.text); } + + bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + + GameSession gameSession = GameSession( + id: id, + createdAt: DateTime.now(), + gameTitle: _gameTitleTextController.text, + players: players, + pointLimit: ConfigService.getPointLimit(), + caboPenalty: ConfigService.getCaboPenalty(), + isPointsLimitEnabled: isPointsLimitEnabled, + ); + gameManager.addGameSession(gameSession); + final session = gameManager.getGameSessionById(id)!; + + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView(gameSession: session))); } @override From fd79698b305b36544c501b56a3e1091d6dc05150 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:36:04 +0200 Subject: [PATCH 237/353] Added docs and dependency --- lib/data/game_manager.dart | 7 ++++++- pubspec.yaml | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 3fc5e54..687b0dd 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -1,5 +1,6 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; class GameManager extends ChangeNotifier { @@ -21,8 +22,12 @@ class GameManager extends ChangeNotifier { return gameList.indexOf(session); } + /// Retrieves a game session by its id. + /// Takes a String [id] as input. It searches the `gameList` for a session + /// with a matching id and returns it if found. + /// If no session is found, it returns null. GameSession? getGameSessionById(String id) { - return gameList.firstWhere((session) => session.id.toString() == id); + return gameList.firstWhereOrNull((session) => session.id.toString() == id); } /// Removes a game session from the list and sorts it by creation date. diff --git a/pubspec.yaml b/pubspec.yaml index 995d091..c9be09f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.0+568 +version: 0.5.1+568 environment: sdk: ^3.5.4 @@ -29,6 +29,7 @@ dependencies: uuid: ^4.5.1 rate_my_app: ^2.3.2 reorderables: ^0.4.2 + collection: ^1.18.0 dev_dependencies: flutter_test: From fcdad2b6d290590ea64299630581b868948287da Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:38:31 +0200 Subject: [PATCH 238/353] Removed toString --- lib/data/game_manager.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 687b0dd..3ab9c09 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -27,7 +27,7 @@ class GameManager extends ChangeNotifier { /// with a matching id and returns it if found. /// If no session is found, it returns null. GameSession? getGameSessionById(String id) { - return gameList.firstWhereOrNull((session) => session.id.toString() == id); + return gameList.firstWhereOrNull((session) => session.id == id); } /// Removes a game session from the list and sorts it by creation date. From e1b42a547a6986e03b91b8e6e856e36a29eae3b9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:42:06 +0200 Subject: [PATCH 239/353] Implemented null safety --- lib/presentation/views/create_game_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index d80d0fb..a1b5894 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -396,7 +396,7 @@ class _CreateGameViewState extends State { isPointsLimitEnabled: isPointsLimitEnabled, ); gameManager.addGameSession(gameSession); - final session = gameManager.getGameSessionById(id)!; + final session = gameManager.getGameSessionById(id) ?? gameSession; Navigator.pushReplacement( context, From 88f17fda6a77b45cf098e50226450911ee6ddc08 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:50:57 +0200 Subject: [PATCH 240/353] Added named parameter --- lib/presentation/views/create_game_view.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index a1b5894..5148537 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -46,6 +46,9 @@ class _CreateGameViewState extends State { /// Maximum number of players allowed in the game. final int maxPlayers = 5; + /// Factor to adjust the view length when the keyboard is visible. + final double keyboardHeightAdjustmentFactor = 0.75; + /// Variable to hold the selected game mode. late GameMode gameMode; @@ -152,8 +155,7 @@ class _CreateGameViewState extends State { }, itemBuilder: (context, index) { return Padding( - key: ValueKey( - 'player_${_playerNameTextControllers[index].hashCode}'), + key: UniqueKey(), padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ @@ -257,7 +259,8 @@ class _CreateGameViewState extends State { KeyboardVisibilityBuilder(builder: (context, visible) { if (visible) { return SizedBox( - height: MediaQuery.of(context).viewInsets.bottom * 0.75, + height: MediaQuery.of(context).viewInsets.bottom * + keyboardHeightAdjustmentFactor, ); } else { return const SizedBox.shrink(); From d93abe35df43f7c8a169636f8952ebdbb3880979 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:53:01 +0200 Subject: [PATCH 241/353] Replaced button with custom button --- lib/presentation/views/round_view.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index f99380e..d2a9da5 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -1,6 +1,7 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; @@ -228,10 +229,7 @@ class _RoundViewState extends State { padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), child: Center( heightFactor: 1, - child: CupertinoButton( - sizeStyle: CupertinoButtonSize.medium, - borderRadius: BorderRadius.circular(12), - color: CustomTheme.buttonBackgroundColor, + child: CustomButton( onPressed: () async { if (await _showKamikazeSheet(context)) { if (!context.mounted) return; From 5a5c279ea4594ae96539c5b83488e62ad96b9716 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:56:50 +0200 Subject: [PATCH 242/353] Updated key --- lib/presentation/views/create_game_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 5148537..870ea29 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -155,7 +155,7 @@ class _CreateGameViewState extends State { }, itemBuilder: (context, index) { return Padding( - key: UniqueKey(), + key: ValueKey(index), padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ From 0611154129e64af78dcda76e3cb36d5d0c9da8db Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:57:40 +0200 Subject: [PATCH 243/353] Updated addGameSessionMethod --- lib/data/game_manager.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 3ab9c09..502feb6 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -11,14 +11,14 @@ class GameManager extends ChangeNotifier { /// sorts the list in descending order based on the creation date, and notifies listeners of the change. /// It also saves the updated game sessions to local storage. /// Returns the index of the newly added session in the sorted list. - Future addGameSession(GameSession session) async { + int addGameSession(GameSession session) { session.addListener(() { notifyListeners(); // Propagate session changes }); gameList.add(session); gameList.sort((a, b) => b.createdAt.compareTo(a.createdAt)); notifyListeners(); - await LocalStorageService.saveGameSessions(); + LocalStorageService.saveGameSessions(); return gameList.indexOf(session); } From 77bbb20ebe369e0094570e5cbb43895a9cd32658 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 21:48:39 +0200 Subject: [PATCH 244/353] Update README.md --- README.md | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 66eab9f..1a87cdb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.4.7-orange) +![Version](https://img.shields.io/badge/Version-0.5.1-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) @@ -12,25 +12,29 @@ A mobile score tracker for the card game Cabo, helping players effortlessly mana ## 📱 Description -Cabo Counter is an intuitive Flutter-based mobile application designed to enhance your CABO card game experience. It eliminates manual scorekeeping by automatically calculating points per round. +Cabo Counter is an intuitive Flutter-based mobile application designed to enhance your CABO card game experience. It eliminates manual scorekeeping by automatically calculating points per round. ## ✨ Features -- 🆕 Create new games with customizable rules - 👥 Support for 2-5 players - ⚖️ Two game modes: - - **100 Points Mode** (Standard) - - **Infinite Mode** (Casual play) + - **Point Limit Mode**: Play until a certain point limit is reached + - **Unlimited Mode**: Play without an limit and end the round at any point - 🔢 Automatic score calculation with: + - Falsly calling Cabo + - Exact 100-point bonus (score halving) - Kamikaze rule handling - - Exact 100-point bonus (score halving) -- 📊 Round history tracking +- 📊 Round history tracking via graph and table +- 🎨 Customizable + - Change the default settings for point limits and cabo penaltys + - Choose a default game mode for every new created game +- 💿 Im- and exporting certain games or the whole app data ## 🚀 Getting Started ### Prerequisites -- Flutter 3.24.5+ -- Dart 3.5.4+ +- Flutter 3.32.1+ +- Dart 3.8.1+ ### Installation @@ -43,18 +47,22 @@ flutter run ## 🎮 Usage -1. **Start New Game** -- Choose game mode (100 Points or Infinite) +1. **Start a new game** +- Click the "+"-Button +- Choose a game title and a game mode - Add 2-5 players 2. **Gameplay** -- Track rounds with automatic scoring -- Handle special rules (Kamikaze, exact 100 points) -- View real-time standings +- Open the first round +- Choose the player who called Cabo +- Enter the points of every player +- If given: Choose a Kamikaze player +- Navigate to the next round or back to the overview +- Let the app calculate all points for you -3. **Round Management** -- Automatic winner detection -- Penalty point calculation +3. **Statistics** +- View the progress graph for the game +- Get a detailed table overview for every points made or lost - Game-over detection (100 Points mode) ## 🃏 Key Rules Overview @@ -67,7 +75,8 @@ flutter run - Exact 100 points: Score halved ### Game End -- First player ≥101 points triggers final scoring +- First player ≥100 points triggers final scoring +- In unlimited mode you can end the game via the End Game Button - Lowest total score wins ## 🤝 Contributing From ddc2d68e9b6c79fcb045e1a4b778728bee8e4b1a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 22:36:48 +0200 Subject: [PATCH 245/353] Added Strings for popup --- lib/l10n/arb/app_de.arb | 15 +++++++++++++++ lib/l10n/arb/app_en.arb | 15 +++++++++++++++ lib/l10n/generated/app_localizations.dart | 12 ++++++++++++ lib/l10n/generated/app_localizations_de.dart | 15 +++++++++++++++ lib/l10n/generated/app_localizations_en.dart | 14 ++++++++++++++ 5 files changed, 71 insertions(+) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index effbd96..c8dad5c 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -96,6 +96,21 @@ } }, + "end_of_game_title": "Spiel beendet", + "end_of_game_message": "{playerCount, plural, =1{{names} hat das Spiel mit {points} Punkten gewonnen. Glückwunsch!} other{{names} haben das Spiel mit {points} Punkten gewonnen. Glückwunsch!}}", + "@end_of_game_message": { + "placeholders": { + "playerCount": { + "type": "int" + }, + "names": { + "type": "String" + }, + "points": { + "type": "int" + } + } + }, "end_game": "Spiel beenden", "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index ea169e9..ea4ab8d 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -96,6 +96,21 @@ } }, + "end_of_game_title": "End of Game", + "end_of_game_message": "{playerCount, plural, =1{{names} won the game with {points} points. Congratulations!} other{{names} won the game with {points} points. Congratulations!}}", + "@game_over_message": { + "placeholders": { + "playerCount": { + "type": "int" + }, + "names": { + "type": "String" + }, + "points": { + "type": "int" + } + } + }, "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 9c64cb2..5749079 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -453,6 +453,18 @@ abstract class AppLocalizations { String bonus_points_message( int playerCount, String names, int pointLimit, int bonusPoints); + /// No description provided for @end_of_game_title. + /// + /// In de, this message translates to: + /// **'Spiel beendet'** + String get end_of_game_title; + + /// No description provided for @end_of_game_message. + /// + /// In de, this message translates to: + /// **'{playerCount, plural, =1{{names} hat das Spiel mit {points} Punkten gewonnen. Glückwunsch!} other{{names} haben das Spiel mit {points} Punkten gewonnen. Glückwunsch!}}'** + String end_of_game_message(int playerCount, String names, int points); + /// No description provided for @end_game. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index c4849d8..87745dd 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -208,6 +208,21 @@ class AppLocalizationsDe extends AppLocalizations { return '$_temp0'; } + @override + String get end_of_game_title => 'Spiel beendet'; + + @override + String end_of_game_message(int playerCount, String names, int points) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names haben das Spiel mit $points Punkten gewonnen. Glückwunsch!', + one: '$names hat das Spiel mit $points Punkten gewonnen. Glückwunsch!', + ); + return '$_temp0'; + } + @override String get end_game => 'Spiel beenden'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 6b2689e..2da405c 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -205,6 +205,20 @@ class AppLocalizationsEn extends AppLocalizations { return '$_temp0'; } + @override + String get end_of_game_title => 'End of Game'; + + @override + String end_of_game_message(int playerCount, String names, int points) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: '$names won the game with $points points. Congratulations!', + one: '$names won the game with $points points. Congratulations!', + ); + return '$_temp0'; + } + @override String get end_game => 'End Game'; From 5099dafbe90ca4ab149bc1e14c29abf5b37dcfec Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 22:36:55 +0200 Subject: [PATCH 246/353] Implemented popup & confetti --- lib/presentation/views/active_game_view.dart | 479 +++++++++++-------- pubspec.yaml | 3 +- 2 files changed, 276 insertions(+), 206 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index dece0a6..a14194b 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -8,6 +8,7 @@ import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:cabo_counter/presentation/views/points_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; +import 'package:confetti/confetti.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -21,6 +22,9 @@ class ActiveGameView extends StatefulWidget { } class _ActiveGameViewState extends State { + final confettiController = ConfettiController( + duration: const Duration(seconds: 10), + ); late final GameSession gameSession; late List denseRanks; late List sortedPlayerIndices; @@ -33,225 +37,258 @@ class _ActiveGameViewState extends State { @override Widget build(BuildContext context) { - return ListenableBuilder( - listenable: gameSession, - builder: (context, _) { - sortedPlayerIndices = _getSortedPlayerIndices(); - denseRanks = _calculateDenseRank( - gameSession.playerScores, sortedPlayerIndices); - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text(gameSession.gameTitle), - ), - child: SafeArea( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).players, - style: CustomTheme.rowTitle, - ), - ), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: gameSession.players.length, - itemBuilder: (BuildContext context, int index) { - int playerIndex = sortedPlayerIndices[index]; - return CupertinoListTile( - title: Row( - children: [ - _getPlacementTextWidget(index), - const SizedBox(width: 5), - Text( - gameSession.players[playerIndex], - style: const TextStyle( - fontWeight: FontWeight.bold), - ), - ], + return Stack( + children: [ + ListenableBuilder( + listenable: gameSession, + builder: (context, _) { + sortedPlayerIndices = _getSortedPlayerIndices(); + denseRanks = _calculateDenseRank( + gameSession.playerScores, sortedPlayerIndices); + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(gameSession.gameTitle), + ), + child: SafeArea( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).players, + style: CustomTheme.rowTitle, ), - trailing: Row( - children: [ - const SizedBox(width: 5), - Text('${gameSession.playerScores[playerIndex]} ' - '${AppLocalizations.of(context).points}') - ], - ), - ); - }, - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).rounds, - style: CustomTheme.rowTitle, - ), - ), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: gameSession.roundNumber, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(1), - child: CupertinoListTile( - backgroundColorActivated: - CustomTheme.backgroundColor, - title: Text( - '${AppLocalizations.of(context).round} ${index + 1}', + ), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: gameSession.players.length, + itemBuilder: (BuildContext context, int index) { + int playerIndex = sortedPlayerIndices[index]; + return CupertinoListTile( + title: Row( + children: [ + _getPlacementTextWidget(index), + const SizedBox(width: 5), + Text( + gameSession.players[playerIndex], + style: const TextStyle( + fontWeight: FontWeight.bold), + ), + ], ), - trailing: - index + 1 != gameSession.roundNumber || + trailing: Row( + children: [ + const SizedBox(width: 5), + Text( + '${gameSession.playerScores[playerIndex]} ' + '${AppLocalizations.of(context).points}') + ], + ), + ); + }, + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).rounds, + style: CustomTheme.rowTitle, + ), + ), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: gameSession.roundNumber, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(1), + child: CupertinoListTile( + backgroundColorActivated: + CustomTheme.backgroundColor, + title: Text( + '${AppLocalizations.of(context).round} ${index + 1}', + ), + trailing: index + 1 != + gameSession.roundNumber || gameSession.isGameFinished == true ? (const Text('\u{2705}', style: TextStyle(fontSize: 22))) : const Text('\u{23F3}', style: TextStyle(fontSize: 22)), - onTap: () async { - _openRoundView(index + 1); - }, - )); - }, - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).statistics, - style: CustomTheme.rowTitle, - ), - ), - Column( - children: [ - CupertinoListTile( - title: Text( - AppLocalizations.of(context).scoring_history, + onTap: () async { + _openRoundView(context, index + 1); + }, + )); + }, + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).statistics, + style: CustomTheme.rowTitle, + ), + ), + Column( + children: [ + CupertinoListTile( + title: Text( + AppLocalizations.of(context) + .scoring_history, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (_) => GraphView( + gameSession: gameSession, + )))), + CupertinoListTile( + title: Text( + AppLocalizations.of(context).point_overview, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (_) => PointsView( + gameSession: gameSession, + )))), + ], + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).game, + style: CustomTheme.rowTitle, + ), + ), + Column( + children: [ + Visibility( + visible: !gameSession.isPointsLimitEnabled, + child: CupertinoListTile( + title: Text( + AppLocalizations.of(context).end_game, + style: gameSession.roundNumber > 1 && + !gameSession.isGameFinished + ? const TextStyle(color: Colors.white) + : const TextStyle( + color: Colors.white30), + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () { + if (gameSession.roundNumber > 1 && + !gameSession.isGameFinished) { + _showEndGameDialog(); + } + }), ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () => Navigator.push( - context, - CupertinoPageRoute( - builder: (_) => GraphView( - gameSession: gameSession, - )))), - CupertinoListTile( - title: Text( - AppLocalizations.of(context).point_overview, - ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () => Navigator.push( - context, - CupertinoPageRoute( - builder: (_) => PointsView( - gameSession: gameSession, - )))), - ], - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).game, - style: CustomTheme.rowTitle, - ), - ), - Column( - children: [ - Visibility( - visible: !gameSession.isPointsLimitEnabled, - child: CupertinoListTile( + CupertinoListTile( title: Text( - AppLocalizations.of(context).end_game, - style: gameSession.roundNumber > 1 && - !gameSession.isGameFinished - ? const TextStyle(color: Colors.white) - : const TextStyle(color: Colors.white30), + AppLocalizations.of(context).delete_game, ), backgroundColorActivated: CustomTheme.backgroundColor, onTap: () { - if (gameSession.roundNumber > 1 && - !gameSession.isGameFinished) { - _showEndGameDialog(); - } - }), - ), - CupertinoListTile( - title: Text( - AppLocalizations.of(context).delete_game, - ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () { - _showDeleteGameDialog().then((value) { - if (value) { - _removeGameSession(gameSession); - } - }); - }, - ), - CupertinoListTile( - title: Text( - AppLocalizations.of(context) - .new_game_same_settings, - ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (_) => CreateGameView( - gameTitle: gameSession.gameTitle, - gameMode: widget.gameSession - .isPointsLimitEnabled == - true - ? GameMode.pointLimit - : GameMode.unlimited, - players: gameSession.players, - ))); - }, - ), - CupertinoListTile( - title: Text( - AppLocalizations.of(context).export_game, + _showDeleteGameDialog().then((value) { + if (value) { + _removeGameSession(gameSession); + } + }); + }, ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () async { - final success = await LocalStorageService - .exportSingleGameSession( - widget.gameSession); - if (!success && context.mounted) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context) - .export_error_title), - content: Text(AppLocalizations.of(context) - .export_error_message), - actions: [ - CupertinoDialogAction( - child: Text( - AppLocalizations.of(context).ok), - onPressed: () => - Navigator.pop(context), + CupertinoListTile( + title: Text( + AppLocalizations.of(context) + .new_game_same_settings, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () { + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (_) => CreateGameView( + gameTitle: + gameSession.gameTitle, + gameMode: widget.gameSession + .isPointsLimitEnabled == + true + ? GameMode.pointLimit + : GameMode.unlimited, + players: gameSession.players, + ))); + }, + ), + CupertinoListTile( + title: Text( + AppLocalizations.of(context).export_game, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () async { + final success = await LocalStorageService + .exportSingleGameSession( + widget.gameSession); + if (!success && context.mounted) { + showCupertinoDialog( + context: context, + builder: (context) => + CupertinoAlertDialog( + title: Text( + AppLocalizations.of(context) + .export_error_title), + content: Text( + AppLocalizations.of(context) + .export_error_message), + actions: [ + CupertinoDialogAction( + child: Text( + AppLocalizations.of(context) + .ok), + onPressed: () => + Navigator.pop(context), + ), + ], ), - ], - ), - ); - } - }), + ); + } + }), + CupertinoListTile( + title: const Text('Konfetti'), + onTap: () => confettiController.play(), + ) + ], + ) ], - ) - ], - ), - ), - )); - }); + ), + ), + )); + }), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: ConfettiWidget( + blastDirectionality: BlastDirectionality.explosive, + particleDrag: 0.07, + emissionFrequency: 0.1, + numberOfParticles: 10, + minBlastForce: 5, + maxBlastForce: 20, + confettiController: confettiController, + ), + ), + ], + ), + ], + ); } /// Shows a dialog to confirm ending the game. @@ -403,7 +440,7 @@ class _ActiveGameViewState extends State { /// Recursively opens the RoundView for the specified round number. /// It starts with the given [roundNumber] and continues to open the next round /// until the user navigates back or the round number is invalid. - void _openRoundView(int roundNumber) async { + void _openRoundView(BuildContext context, int roundNumber) async { final val = await Navigator.of(context, rootNavigator: true).push( CupertinoPageRoute( fullscreenDialog: true, @@ -413,10 +450,42 @@ class _ActiveGameViewState extends State { ), ), ); + if (widget.gameSession.isGameFinished && mounted) { + String winner = widget.gameSession.winner; + int winnerIndex = widget.gameSession.players.indexOf(winner); + int points = widget.gameSession.playerScores[winnerIndex]; + + confettiController.play(); + + await Future.delayed(const Duration(milliseconds: 300)); + + if (context.mounted) { + showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).end_of_game_title), + content: Text(AppLocalizations.of(context) + .end_of_game_message(1, winner, points)), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () { + confettiController.stop(); + Navigator.pop(context); + }, + ), + ], + ); + }); + } + } if (val != null && val >= 0) { WidgetsBinding.instance.addPostFrameCallback((_) async { await Future.delayed(const Duration(milliseconds: 600)); - _openRoundView(val); + if (context.mounted) { + _openRoundView(context, val); + } }); } } diff --git a/pubspec.yaml b/pubspec.yaml index c9be09f..06a051a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.1+568 +version: 0.5.2+579 environment: sdk: ^3.5.4 @@ -30,6 +30,7 @@ dependencies: rate_my_app: ^2.3.2 reorderables: ^0.4.2 collection: ^1.18.0 + confetti: ^0.6.0 dev_dependencies: flutter_test: From 4a8abbbe7276d9f8dbb49a326d118fca6b9869f7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 22:49:20 +0200 Subject: [PATCH 247/353] Extracted code to method _playFinishAnimation() --- lib/presentation/views/active_game_view.dart | 70 +++++++++++--------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index a14194b..71fd949 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -441,7 +441,7 @@ class _ActiveGameViewState extends State { /// It starts with the given [roundNumber] and continues to open the next round /// until the user navigates back or the round number is invalid. void _openRoundView(BuildContext context, int roundNumber) async { - final val = await Navigator.of(context, rootNavigator: true).push( + final round = await Navigator.of(context, rootNavigator: true).push( CupertinoPageRoute( fullscreenDialog: true, builder: (context) => RoundView( @@ -450,43 +450,51 @@ class _ActiveGameViewState extends State { ), ), ); - if (widget.gameSession.isGameFinished && mounted) { - String winner = widget.gameSession.winner; - int winnerIndex = widget.gameSession.players.indexOf(winner); - int points = widget.gameSession.playerScores[winnerIndex]; - confettiController.play(); - - await Future.delayed(const Duration(milliseconds: 300)); - - if (context.mounted) { - showCupertinoDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).end_of_game_title), - content: Text(AppLocalizations.of(context) - .end_of_game_message(1, winner, points)), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () { - confettiController.stop(); - Navigator.pop(context); - }, - ), - ], - ); - }); - } + if (widget.gameSession.isGameFinished && context.mounted) { + _playFinishAnimation(context); } - if (val != null && val >= 0) { + + // If the previous round was not the last one + if (round != null && round >= 0) { WidgetsBinding.instance.addPostFrameCallback((_) async { await Future.delayed(const Duration(milliseconds: 600)); if (context.mounted) { - _openRoundView(context, val); + _openRoundView(context, round); } }); } } + + /// Plays the confetti animation and shows a dialog with the winner's information. + Future _playFinishAnimation(BuildContext context) async { + String winner = widget.gameSession.winner; + int winnerIndex = widget.gameSession.players.indexOf(winner); + int points = widget.gameSession.playerScores[winnerIndex]; + + confettiController.play(); + + await Future.delayed(const Duration(milliseconds: 300)); + + if (context.mounted) { + showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).end_of_game_title), + content: Text(AppLocalizations.of(context) + .end_of_game_message(1, winner, points)), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () { + confettiController.stop(); + Navigator.pop(context); + }, + ), + ], + ); + }); + } + } } From 864c21b77c54ebbc15a97b767f6edd62e04eacbe Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 22:49:35 +0200 Subject: [PATCH 248/353] Replaced tenary operator with Visibility Widget --- lib/presentation/views/graph_view.dart | 100 +++++++++++++------------ 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 23137cd..4147f51 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -25,60 +25,64 @@ class _GraphViewState extends State { @override Widget build(BuildContext context) { + print('roundNumber: ${widget.gameSession.roundNumber}'); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(AppLocalizations.of(context).scoring_history), previousPageTitle: AppLocalizations.of(context).back, ), - child: widget.gameSession.roundNumber > 1 - ? Padding( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), - child: SfCartesianChart( - enableAxisAnimation: true, - legend: const Legend( - overflowMode: LegendItemOverflowMode.wrap, - isVisible: true, - position: LegendPosition.bottom), - primaryXAxis: const NumericAxis( - labelStyle: TextStyle(fontWeight: FontWeight.bold), - interval: 1, - decimalPlaces: 0, - ), - primaryYAxis: NumericAxis( - labelStyle: const TextStyle(fontWeight: FontWeight.bold), - labelAlignment: LabelAlignment.center, - labelPosition: ChartDataLabelPosition.inside, - interval: 1, - decimalPlaces: 0, - axisLabelFormatter: (AxisLabelRenderDetails details) { - if (details.value == 0) { - return ChartAxisLabel('', const TextStyle()); - } - return ChartAxisLabel( - '${details.value.toInt()}', const TextStyle()); - }, - ), - series: getCumulativeScores(), + child: Visibility( + visible: widget.gameSession.roundNumber > 1 || + widget.gameSession.isGameFinished, + replacement: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Center( + child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), + ), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: Text( + AppLocalizations.of(context).empty_graph_text, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), ), - ) - : Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Center( - child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), - ), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 40), - child: Text( - AppLocalizations.of(context).empty_graph_text, - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 16), - ), - ), - ], - )); + ), + ], + ), + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: SfCartesianChart( + enableAxisAnimation: true, + legend: const Legend( + overflowMode: LegendItemOverflowMode.wrap, + isVisible: true, + position: LegendPosition.bottom), + primaryXAxis: const NumericAxis( + labelStyle: TextStyle(fontWeight: FontWeight.bold), + interval: 1, + decimalPlaces: 0, + ), + primaryYAxis: NumericAxis( + labelStyle: const TextStyle(fontWeight: FontWeight.bold), + labelAlignment: LabelAlignment.center, + labelPosition: ChartDataLabelPosition.inside, + interval: 1, + decimalPlaces: 0, + axisLabelFormatter: (AxisLabelRenderDetails details) { + if (details.value == 0) { + return ChartAxisLabel('', const TextStyle()); + } + return ChartAxisLabel( + '${details.value.toInt()}', const TextStyle()); + }, + ), + series: getCumulativeScores(), + ), + ), + )); } /// Returns a list of LineSeries representing the cumulative scores of each player. From 357f74d4aa0ccdf186a0eaf0564ae587727e19fe Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 22:49:48 +0200 Subject: [PATCH 249/353] Replaced tenary operator with Visibility Widget --- lib/presentation/views/main_menu_view.dart | 286 ++++++++++----------- pubspec.yaml | 2 +- 2 files changed, 142 insertions(+), 146 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index f8817a0..dd01e03 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -58,160 +58,156 @@ class _MainMenuViewState extends State { listenable: gameManager, builder: (context, _) { return CupertinoPageScaffold( - resizeToAvoidBottomInset: false, - navigationBar: CupertinoNavigationBar( - leading: IconButton( - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const SettingsView(), - ), - ).then((_) { - setState(() {}); - }); - }, - icon: const Icon(CupertinoIcons.settings, size: 30)), - middle: Text(AppLocalizations.of(context).app_name), - trailing: IconButton( - onPressed: () => Navigator.push( + resizeToAvoidBottomInset: false, + navigationBar: CupertinoNavigationBar( + leading: IconButton( + onPressed: () { + Navigator.push( context, CupertinoPageRoute( - builder: (context) => CreateGameView( - gameMode: ConfigService.getGameMode()), + builder: (context) => const SettingsView(), ), + ).then((_) { + setState(() {}); + }); + }, + icon: const Icon(CupertinoIcons.settings, size: 30)), + middle: Text(AppLocalizations.of(context).app_name), + trailing: IconButton( + onPressed: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => CreateGameView( + gameMode: ConfigService.getGameMode()), + ), + ), + icon: const Icon(CupertinoIcons.add)), + ), + child: CupertinoPageScaffold( + child: SafeArea( + child: Visibility( + replacement: + const Center(child: CupertinoActivityIndicator()), + child: Visibility( + visible: gameManager.gameList.isEmpty, + replacement: ListView.separated( + itemCount: gameManager.gameList.length, + separatorBuilder: (context, index) => Divider( + height: 1, + thickness: 0.5, + color: CustomTheme.white.withAlpha(50), + indent: 50, + endIndent: 50, ), - icon: const Icon(CupertinoIcons.add)), - ), - child: CupertinoPageScaffold( - child: SafeArea( - child: _isLoading - ? const Center(child: CupertinoActivityIndicator()) - : gameManager.gameList.isEmpty - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(height: 30), - Center( - child: GestureDetector( - onTap: () => Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => CreateGameView( - gameMode: ConfigService.getGameMode()), + itemBuilder: (context, index) { + final session = gameManager.gameList[index]; + return ListenableBuilder( + listenable: session, + builder: (context, _) { + return Dismissible( + key: Key(session.id), + background: Container( + color: CupertinoColors.destructiveRed, + alignment: Alignment.centerRight, + padding: const EdgeInsets.only(right: 20.0), + child: const Icon( + CupertinoIcons.delete, + color: CupertinoColors.white, ), ), - child: Icon( - CupertinoIcons.plus, - size: 60, - color: CustomTheme.primaryColor, + direction: DismissDirection.endToStart, + confirmDismiss: (direction) async { + return await _showDeleteGamePopup( + context, session.gameTitle); + }, + onDismissed: (direction) { + gameManager.removeGameSessionById(session.id); + }, + dismissThresholds: const { + DismissDirection.startToEnd: 0.6 + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 10.0), + child: CupertinoListTile( + backgroundColorActivated: + CustomTheme.backgroundColor, + title: Text(session.gameTitle), + subtitle: Visibility( + visible: session.isGameFinished, + replacement: Text( + '${AppLocalizations.of(context).mode}: ${_translateGameMode(session.isPointsLimitEnabled)}', + style: const TextStyle(fontSize: 14), + ), + child: Text( + '\u{1F947} ${session.winner}', + style: const TextStyle(fontSize: 14), + )), + trailing: Row( + children: [ + Text('${session.roundNumber}'), + const SizedBox(width: 3), + const Icon(CupertinoIcons + .arrow_2_circlepath_circle_fill), + const SizedBox(width: 15), + Text('${session.players.length}'), + const SizedBox(width: 3), + const Icon( + CupertinoIcons.person_2_fill), + ], + ), + onTap: () { + final session = + gameManager.gameList[index]; + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView( + gameSession: session), + ), + ).then((_) { + setState(() {}); + }); + }, + ), ), - )), - const SizedBox(height: 10), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 70), - child: Text( - '${AppLocalizations.of(context).empty_text_1}\n${AppLocalizations.of(context).empty_text_2}', - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 16), - ), - ), - ], - ) - : ListView.separated( - itemCount: gameManager.gameList.length, - separatorBuilder: (context, index) => Divider( - height: 1, - thickness: 0.5, - color: CustomTheme.white.withAlpha(50), - indent: 50, - endIndent: 50, + ); + }); + }, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 30), + Center( + child: GestureDetector( + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => CreateGameView( + gameMode: ConfigService.getGameMode()), ), - itemBuilder: (context, index) { - final session = gameManager.gameList[index]; - return ListenableBuilder( - listenable: session, - builder: (context, _) { - return Dismissible( - key: Key(session.id), - background: Container( - color: CupertinoColors.destructiveRed, - alignment: Alignment.centerRight, - padding: - const EdgeInsets.only(right: 20.0), - child: const Icon( - CupertinoIcons.delete, - color: CupertinoColors.white, - ), - ), - direction: DismissDirection.endToStart, - confirmDismiss: (direction) async { - return await _showDeleteGamePopup( - context, session.gameTitle); - }, - onDismissed: (direction) { - gameManager - .removeGameSessionById(session.id); - }, - dismissThresholds: const { - DismissDirection.startToEnd: 0.6 - }, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 10.0), - child: CupertinoListTile( - backgroundColorActivated: - CustomTheme.backgroundColor, - title: Text(session.gameTitle), - subtitle: - session.isGameFinished == true - ? Text( - '\u{1F947} ${session.winner}', - style: const TextStyle( - fontSize: 14), - ) - : Text( - '${AppLocalizations.of(context).mode}: ${_translateGameMode(session.isPointsLimitEnabled)}', - style: const TextStyle( - fontSize: 14), - ), - trailing: Row( - children: [ - Text('${session.roundNumber}'), - const SizedBox(width: 3), - const Icon(CupertinoIcons - .arrow_2_circlepath_circle_fill), - const SizedBox(width: 15), - Text('${session.players.length}'), - const SizedBox(width: 3), - const Icon( - CupertinoIcons.person_2_fill), - ], - ), - onTap: () { - final session = - gameManager.gameList[index]; - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => - ActiveGameView( - gameSession: session), - ), - ).then((_) { - setState(() {}); - }); - }, - ), - ), - ); - }); - }, ), - ), - ), - ); + child: Icon( + CupertinoIcons.plus, + size: 60, + color: CustomTheme.primaryColor, + ), + )), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 70), + child: Text( + '${AppLocalizations.of(context).empty_text_1}\n${AppLocalizations.of(context).empty_text_2}', + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ), + ), + ], + ), + ), + ), + ))); }); } diff --git a/pubspec.yaml b/pubspec.yaml index 06a051a..0bc543c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+579 +version: 0.5.2+580 environment: sdk: ^3.5.4 From 382fab57dd6228fad183d243a78274166231bcd4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 22:51:11 +0200 Subject: [PATCH 250/353] Used variable again --- lib/presentation/views/main_menu_view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index dd01e03..2f2044a 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -86,9 +86,8 @@ class _MainMenuViewState extends State { child: CupertinoPageScaffold( child: SafeArea( child: Visibility( - replacement: - const Center(child: CupertinoActivityIndicator()), - child: Visibility( + visible: _isLoading, + replacement: Visibility( visible: gameManager.gameList.isEmpty, replacement: ListView.separated( itemCount: gameManager.gameList.length, @@ -206,6 +205,7 @@ class _MainMenuViewState extends State { ], ), ), + child: const Center(child: CupertinoActivityIndicator()), ), ))); }); From 2a7b2a9dc0dc48b754d655e20f833b96e66c83e8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 22:56:41 +0200 Subject: [PATCH 251/353] Added delays in constants.dart --- lib/core/constants.dart | 9 +++++++++ lib/presentation/views/active_game_view.dart | 3 ++- lib/presentation/views/create_game_view.dart | 4 +++- lib/presentation/views/main_menu_view.dart | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index e716464..e1c2f8d 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -19,4 +19,13 @@ class Constants { remindDays: 45, minLaunches: 15, remindLaunches: 40); + + /// Delay in milliseconds before a pop-up appears. + static const int popUpDelay = 300; + + /// Delay in milliseconds before the round view appears after the previous one is closed. + static const int roundViewDelay = 600; + + /// Duration in milliseconds for the fade-in animation of texts. + static const int fadeInDuration = 300; } diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 71fd949..58f5765 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; @@ -474,7 +475,7 @@ class _ActiveGameViewState extends State { confettiController.play(); - await Future.delayed(const Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: Constants.popUpDelay)); if (context.mounted) { showCupertinoDialog( diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 870ea29..236baff 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; @@ -187,7 +188,8 @@ class _CreateGameViewState extends State { opacity: _playerNameTextControllers.length > 1 ? 1.0 : 0.0, - duration: const Duration(milliseconds: 300), + duration: const Duration( + milliseconds: Constants.fadeInDuration), child: Padding( padding: const EdgeInsets.only(right: 8.0), child: ReorderableDragStartListener( diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 2f2044a..6d8262b 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -239,7 +239,7 @@ class _MainMenuViewState extends State { BadRatingDialogDecision badRatingDecision = BadRatingDialogDecision.cancel; // so that the bad rating dialog is not shown immediately - await Future.delayed(const Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: Constants.popUpDelay)); switch (preRatingDecision) { case PreRatingDialogDecision.yes: From 43fd53a011ff964dffd6c81686b7407778c2ca6b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:12:19 +0200 Subject: [PATCH 252/353] Removed confetti button --- lib/presentation/views/active_game_view.dart | 4 ---- pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 58f5765..1c10095 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -260,10 +260,6 @@ class _ActiveGameViewState extends State { ); } }), - CupertinoListTile( - title: const Text('Konfetti'), - onTap: () => confettiController.play(), - ) ], ) ], diff --git a/pubspec.yaml b/pubspec.yaml index 0bc543c..01d641d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+580 +version: 0.5.2+581 environment: sdk: ^3.5.4 From b2100412093861d3d5a6e80b6e39186d24cad089 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:16:25 +0200 Subject: [PATCH 253/353] Updated strings --- lib/l10n/arb/app_de.arb | 24 ++++++++++++------------ lib/l10n/arb/app_en.arb | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index c8dad5c..cd1a8c7 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -98,18 +98,18 @@ "end_of_game_title": "Spiel beendet", "end_of_game_message": "{playerCount, plural, =1{{names} hat das Spiel mit {points} Punkten gewonnen. Glückwunsch!} other{{names} haben das Spiel mit {points} Punkten gewonnen. Glückwunsch!}}", - "@end_of_game_message": { - "placeholders": { - "playerCount": { - "type": "int" - }, - "names": { - "type": "String" - }, - "points": { - "type": "int" - } - } + "@end_of_game_message": { + "placeholders": { + "playerCount": { + "type": "int" + }, + "names": { + "type": "String" + }, + "points": { + "type": "int" + } + } }, "end_game": "Spiel beenden", "delete_game": "Spiel löschen", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index ea4ab8d..306768f 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -98,7 +98,7 @@ "end_of_game_title": "End of Game", "end_of_game_message": "{playerCount, plural, =1{{names} won the game with {points} points. Congratulations!} other{{names} won the game with {points} points. Congratulations!}}", - "@game_over_message": { + "@end_of_game_message": { "placeholders": { "playerCount": { "type": "int" From 7988e3764a25de7487d4d727b3ee98448932d919 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:16:30 +0200 Subject: [PATCH 254/353] Removed print --- lib/presentation/views/graph_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 4147f51..da9f8e7 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -25,7 +25,6 @@ class _GraphViewState extends State { @override Widget build(BuildContext context) { - print('roundNumber: ${widget.gameSession.roundNumber}'); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(AppLocalizations.of(context).scoring_history), From dc19bf6f4cd42037f901409e19e930da97e15f53 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:16:58 +0200 Subject: [PATCH 255/353] Added dispose for confettiController --- lib/presentation/views/active_game_view.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 1c10095..c3510a2 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -494,4 +494,10 @@ class _ActiveGameViewState extends State { }); } } + + @override + void dispose() { + confettiController.dispose(); + super.dispose(); + } } From b38a3be28860875443dca44e30df5d37c1e89656 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:20:28 +0200 Subject: [PATCH 256/353] Implemented missing constant in code --- lib/presentation/views/active_game_view.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index c3510a2..58d0885 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -455,7 +455,8 @@ class _ActiveGameViewState extends State { // If the previous round was not the last one if (round != null && round >= 0) { WidgetsBinding.instance.addPostFrameCallback((_) async { - await Future.delayed(const Duration(milliseconds: 600)); + await Future.delayed( + const Duration(milliseconds: Constants.roundViewDelay)); if (context.mounted) { _openRoundView(context, round); } From 36aad89952e4a3fb737cda915d6bb717c77cb03f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:29:25 +0200 Subject: [PATCH 257/353] Updated gameSession logic so more than one player can be winner --- lib/data/game_session.dart | 16 ++++++++++------ lib/presentation/views/active_game_view.dart | 8 ++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index a9164be..3dcf4c2 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -299,15 +299,19 @@ class GameSession extends ChangeNotifier { /// It iterates through the player scores and finds the player /// with the lowest score. void _setWinner() { - int score = playerScores[0]; - String lowestPlayer = players[0]; + int minScore = playerScores.reduce((a, b) => a < b ? a : b); + List lowestPlayers = []; for (int i = 0; i < players.length; i++) { - if (playerScores[i] < score) { - score = playerScores[i]; - lowestPlayer = players[i]; + if (playerScores[i] == minScore) { + lowestPlayers.add(players[i]); } } - winner = lowestPlayer; + if (lowestPlayers.length > 1) { + winner = + '${lowestPlayers.sublist(0, lowestPlayers.length - 1).join(', ')} & ${lowestPlayers.last}'; + } else { + winner = lowestPlayers.first; + } notifyListeners(); } diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 58d0885..e1d1638 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -9,6 +9,7 @@ import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:cabo_counter/presentation/views/points_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; +import 'package:collection/collection.dart'; import 'package:confetti/confetti.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -467,8 +468,7 @@ class _ActiveGameViewState extends State { /// Plays the confetti animation and shows a dialog with the winner's information. Future _playFinishAnimation(BuildContext context) async { String winner = widget.gameSession.winner; - int winnerIndex = widget.gameSession.players.indexOf(winner); - int points = widget.gameSession.playerScores[winnerIndex]; + int winnerPoints = widget.gameSession.playerScores.min; confettiController.play(); @@ -480,8 +480,8 @@ class _ActiveGameViewState extends State { builder: (BuildContext context) { return CupertinoAlertDialog( title: Text(AppLocalizations.of(context).end_of_game_title), - content: Text(AppLocalizations.of(context) - .end_of_game_message(1, winner, points)), + content: Text(AppLocalizations.of(context).end_of_game_message( + winner.contains('&') ? 2 : 1, winner, winnerPoints)), actions: [ CupertinoDialogAction( child: Text(AppLocalizations.of(context).ok), From 2bb9d82bfcdfcb5b37ed452b606373fed3a8757d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:33:55 +0200 Subject: [PATCH 258/353] Updated strings --- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/generated/app_localizations_en.dart | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 306768f..bedf95f 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -97,7 +97,7 @@ }, "end_of_game_title": "End of Game", - "end_of_game_message": "{playerCount, plural, =1{{names} won the game with {points} points. Congratulations!} other{{names} won the game with {points} points. Congratulations!}}", + "end_of_game_message": "{names} won the game with {points} points. Congratulations!", "@end_of_game_message": { "placeholders": { "playerCount": { diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 2da405c..837c83e 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -210,13 +210,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String end_of_game_message(int playerCount, String names, int points) { - String _temp0 = intl.Intl.pluralLogic( - playerCount, - locale: localeName, - other: '$names won the game with $points points. Congratulations!', - one: '$names won the game with $points points. Congratulations!', - ); - return '$_temp0'; + return '$names won the game with $points points. Congratulations!'; } @override From 1c7dd0a6337ee53c3f03f33abe2c0b4c393e3e5a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:34:46 +0200 Subject: [PATCH 259/353] Updated winner popup --- lib/presentation/views/active_game_view.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index e1d1638..25e88a7 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -469,6 +469,7 @@ class _ActiveGameViewState extends State { Future _playFinishAnimation(BuildContext context) async { String winner = widget.gameSession.winner; int winnerPoints = widget.gameSession.playerScores.min; + int winnerAmount = winner.contains('&') ? 2 : 1; confettiController.play(); @@ -480,8 +481,8 @@ class _ActiveGameViewState extends State { builder: (BuildContext context) { return CupertinoAlertDialog( title: Text(AppLocalizations.of(context).end_of_game_title), - content: Text(AppLocalizations.of(context).end_of_game_message( - winner.contains('&') ? 2 : 1, winner, winnerPoints)), + content: Text(AppLocalizations.of(context) + .end_of_game_message(winnerAmount, winner, winnerPoints)), actions: [ CupertinoDialogAction( child: Text(AppLocalizations.of(context).ok), From 1e40b41e2609dfd49a4549c28f5651a403b55843 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:47:18 +0200 Subject: [PATCH 260/353] game names now can have up to 20 chars --- lib/presentation/views/active_game_view.dart | 5 ++++- lib/presentation/views/create_game_view.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 25e88a7..230603c 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -49,7 +49,10 @@ class _ActiveGameViewState extends State { gameSession.playerScores, sortedPlayerIndices); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - middle: Text(gameSession.gameTitle), + middle: Text( + gameSession.gameTitle, + overflow: TextOverflow.ellipsis, + ), ), child: SafeArea( child: SingleChildScrollView( diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 236baff..94f7c3a 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -94,7 +94,7 @@ class _CreateGameViewState extends State { padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), child: CupertinoTextField( decoration: const BoxDecoration(), - maxLength: 16, + maxLength: 20, prefix: Text(AppLocalizations.of(context).name), textAlign: TextAlign.right, placeholder: AppLocalizations.of(context).game_title, diff --git a/pubspec.yaml b/pubspec.yaml index 01d641d..4994cb9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+581 +version: 0.5.2+582 environment: sdk: ^3.5.4 From d7eeec5626ab96d39b4ad86900b1313e5865ce65 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:48:26 +0200 Subject: [PATCH 261/353] Updated strings --- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/generated/app_localizations_en.dart | 9 ++++++++- pubspec.yaml | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index bedf95f..7346343 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -97,7 +97,7 @@ }, "end_of_game_title": "End of Game", - "end_of_game_message": "{names} won the game with {points} points. Congratulations!", + "end_of_game_message": "{playerCount, plural, =1{{names} won the game with {points} points. Congratulations!} other{{names} won the game with {points} points. Congratulations to everyone!}}", "@end_of_game_message": { "placeholders": { "playerCount": { diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 837c83e..eb341af 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -210,7 +210,14 @@ class AppLocalizationsEn extends AppLocalizations { @override String end_of_game_message(int playerCount, String names, int points) { - return '$names won the game with $points points. Congratulations!'; + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names won the game with $points points. Congratulations to everyone!', + one: '$names won the game with $points points. Congratulations!', + ); + return '$_temp0'; } @override diff --git a/pubspec.yaml b/pubspec.yaml index 4994cb9..af2a3bd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+582 +version: 0.5.2+583 environment: sdk: ^3.5.4 From a5bd9367a0c82cc08bf02d2a1122f7830946dec8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:52:43 +0200 Subject: [PATCH 262/353] Added sized box for visual enhancement --- lib/presentation/views/main_menu_view.dart | 3 +++ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 6d8262b..21deb97 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -144,6 +144,9 @@ class _MainMenuViewState extends State { )), trailing: Row( children: [ + const SizedBox( + width: 5, + ), Text('${session.roundNumber}'), const SizedBox(width: 3), const Icon(CupertinoIcons diff --git a/pubspec.yaml b/pubspec.yaml index af2a3bd..4bbcdd3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+583 +version: 0.5.2+584 environment: sdk: ^3.5.4 From 3090af9e5cfcc90909fec4073d21c6460018fc2a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 23:58:09 +0200 Subject: [PATCH 263/353] Centered the add player button and made it wider --- lib/presentation/views/create_game_view.dart | 70 ++++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 94f7c3a..5f9dbf0 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -207,38 +207,52 @@ class _CreateGameViewState extends State { }), Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), - child: Center( - child: SizedBox( - width: double.infinity, - child: CupertinoButton( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context).add_player, - style: TextStyle(color: CustomTheme.primaryColor), - ), - const SizedBox(width: 8), - Icon( - CupertinoIcons.add_circled_solid, + child: Stack( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.plus_circle_fill, color: CustomTheme.primaryColor, size: 25, ), - ], - ), - onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - _showFeedbackDialog(CreateStatus.maxPlayers); - } - }, + ), + ], ), - ), + Center( + child: CupertinoButton( + padding: const EdgeInsets.symmetric(horizontal: 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Center( + child: Text( + AppLocalizations.of(context).add_player, + style: TextStyle( + color: CustomTheme.primaryColor), + ), + ), + ), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < maxPlayers) { + setState(() { + _playerNameTextControllers + .add(TextEditingController()); + }); + } else { + _showFeedbackDialog(CreateStatus.maxPlayers); + } + }, + ), + ), + ], ), ), Padding( From 7830d296c32b7792cc553bf47c78dec3f7a1e746 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 00:01:05 +0200 Subject: [PATCH 264/353] New created player textfields get automatically focused --- lib/presentation/views/create_game_view.dart | 14 ++++++++++++-- pubspec.yaml | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 5f9dbf0..b81437c 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -38,11 +38,16 @@ class CreateGameView extends StatefulWidget { } class _CreateGameViewState extends State { + final TextEditingController _gameTitleTextController = + TextEditingController(); + + /// List of text controllers for player names. final List _playerNameTextControllers = [ TextEditingController() ]; - final TextEditingController _gameTitleTextController = - TextEditingController(); + + /// List of focus nodes for player name text fields. + final List _playerNameFocusNodes = [FocusNode()]; /// Maximum number of players allowed in the game. final int maxPlayers = 5; @@ -177,6 +182,7 @@ class _CreateGameViewState extends State { Expanded( child: CupertinoTextField( controller: _playerNameTextControllers[index], + focusNode: _playerNameFocusNodes[index], maxLength: 12, placeholder: '${AppLocalizations.of(context).player} ${index + 1}', @@ -245,6 +251,10 @@ class _CreateGameViewState extends State { setState(() { _playerNameTextControllers .add(TextEditingController()); + _playerNameFocusNodes.add(FocusNode()); + }); + WidgetsBinding.instance.addPostFrameCallback((_) { + _playerNameFocusNodes.last.requestFocus(); }); } else { _showFeedbackDialog(CreateStatus.maxPlayers); diff --git a/pubspec.yaml b/pubspec.yaml index 4bbcdd3..0c5c712 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+584 +version: 0.5.2+585 environment: sdk: ^3.5.4 From ca9d55c29b417b4652ba26ca1b990526e35f2590 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 00:07:20 +0200 Subject: [PATCH 265/353] Added focus nodes for autofocus and navigation between textfields --- lib/presentation/views/create_game_view.dart | 12 ++++++++++++ pubspec.yaml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index b81437c..201ce9d 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -188,6 +188,18 @@ class _CreateGameViewState extends State { '${AppLocalizations.of(context).player} ${index + 1}', padding: const EdgeInsets.all(12), decoration: const BoxDecoration(), + textInputAction: + index + 1 < _playerNameTextControllers.length + ? TextInputAction.next + : TextInputAction.done, + onSubmitted: (_) { + if (index + 1 < _playerNameFocusNodes.length) { + _playerNameFocusNodes[index + 1] + .requestFocus(); + } else { + FocusScope.of(context).unfocus(); + } + }, ), ), AnimatedOpacity( diff --git a/pubspec.yaml b/pubspec.yaml index 0c5c712..65c736c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+585 +version: 0.5.2+586 environment: sdk: ^3.5.4 From 8aa90215cfc347b3a2963bb1446c99be23f57f28 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 11:52:25 +0200 Subject: [PATCH 266/353] Updated version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 65c736c..04d9ee1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.2+586 +version: 0.5.3+587 environment: sdk: ^3.5.4 From 472e6156ac1aecb91ca25dafb52d4172ff4f2485 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 12:04:46 +0200 Subject: [PATCH 267/353] Updated game title textfield with focus node and textaction --- lib/presentation/views/create_game_view.dart | 8 ++++++++ pubspec.yaml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 201ce9d..a5fe6ef 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -104,6 +104,14 @@ class _CreateGameViewState extends State { textAlign: TextAlign.right, placeholder: AppLocalizations.of(context).game_title, controller: _gameTitleTextController, + onSubmitted: (_) { + _playerNameFocusNodes.isNotEmpty + ? _playerNameFocusNodes[0].requestFocus() + : FocusScope.of(context).unfocus(); + }, + textInputAction: _playerNameFocusNodes.isNotEmpty + ? TextInputAction.next + : TextInputAction.done, ), ), Padding( diff --git a/pubspec.yaml b/pubspec.yaml index 04d9ee1..8964db2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+587 +version: 0.5.3+588 environment: sdk: ^3.5.4 From ef039ff2f2ddfc9116952778c2bcb5504723e287 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 12:16:05 +0200 Subject: [PATCH 268/353] Added focusnodes to dispose --- lib/presentation/views/create_game_view.dart | 3 +++ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index a5fe6ef..dcaa210 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -459,6 +459,9 @@ class _CreateGameViewState extends State { for (var controller in _playerNameTextControllers) { controller.dispose(); } + for (var focusnode in _playerNameFocusNodes) { + focusnode.dispose(); + } super.dispose(); } diff --git a/pubspec.yaml b/pubspec.yaml index 8964db2..1ff6a27 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+588 +version: 0.5.3+589 environment: sdk: ^3.5.4 From 9aaba188585c45cf5eef8e5ada27a79ff31c08e0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 12:22:57 +0200 Subject: [PATCH 269/353] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a87cdb..c1c7a24 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.5.1-orange) +![Version](https://img.shields.io/badge/Version-0.5.3-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) From afa52488b0f5f8494838f5aac1c3cd9fe03201e3 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 13:05:22 +0200 Subject: [PATCH 270/353] Fixed bug with no popup shown --- lib/data/game_manager.dart | 3 ++- lib/data/game_session.dart | 4 ++-- lib/presentation/views/active_game_view.dart | 1 + pubspec.yaml | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 502feb6..41ef640 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -69,7 +69,8 @@ class GameManager extends ChangeNotifier { gameList[index].roundNumber--; gameList[index].isGameFinished = true; - notifyListeners(); + gameList[index].setWinner(); + gameList[index].notifyListeners(); LocalStorageService.saveGameSessions(); } } diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 3dcf4c2..dc100a5 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -255,7 +255,7 @@ class GameSession extends ChangeNotifier { isGameFinished = true; print('${players[i]} hat die 100 Punkte ueberschritten, ' 'deswegen wurde das Spiel beendet'); - _setWinner(); + setWinner(); } } } @@ -298,7 +298,7 @@ class GameSession extends ChangeNotifier { /// Determines the winner of the game session. /// It iterates through the player scores and finds the player /// with the lowest score. - void _setWinner() { + void setWinner() { int minScore = playerScores.reduce((a, b) => a < b ? a : b); List lowestPlayers = []; for (int i = 0; i < players.length; i++) { diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index 230603c..ff9e066 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -312,6 +312,7 @@ class _ActiveGameViewState extends State { onPressed: () { setState(() { gameManager.endGame(gameSession.id); + _playFinishAnimation(context); }); Navigator.pop(context); }, diff --git a/pubspec.yaml b/pubspec.yaml index 1ff6a27..9c26ec2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+589 +version: 0.5.3+593 environment: sdk: ^3.5.4 From 159a4905b3413e59b1e2e14376688c5c42f91de4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 13:07:37 +0200 Subject: [PATCH 271/353] Fixed bug with out of range error --- lib/presentation/views/create_game_view.dart | 1 + pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index dcaa210..193cdff 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -70,6 +70,7 @@ class _CreateGameViewState extends State { _playerNameTextControllers.clear(); for (var player in widget.players!) { _playerNameTextControllers.add(TextEditingController(text: player)); + _playerNameFocusNodes.add(FocusNode()); } } } diff --git a/pubspec.yaml b/pubspec.yaml index 1ff6a27..ab68b9b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+589 +version: 0.5.3+590 environment: sdk: ^3.5.4 From 9cfb3fefb076b19aaebd92c5aef1356fdb5afae2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 13:08:30 +0200 Subject: [PATCH 272/353] Updated listener notification --- lib/data/game_manager.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 41ef640..eca6880 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -70,7 +70,7 @@ class GameManager extends ChangeNotifier { gameList[index].roundNumber--; gameList[index].isGameFinished = true; gameList[index].setWinner(); - gameList[index].notifyListeners(); + notifyListeners(); LocalStorageService.saveGameSessions(); } } From d627f335797cdb8d739a4ba3a8bc458c669ce0c1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 21 Jul 2025 13:29:25 +0200 Subject: [PATCH 273/353] Beta-Version 0.5.3 (#136) * 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 --- README.md | 45 +- lib/core/constants.dart | 9 + lib/core/custom_theme.dart | 8 +- lib/data/game_manager.dart | 14 +- lib/data/game_session.dart | 25 +- lib/l10n/arb/app_de.arb | 29 +- lib/l10n/arb/app_en.arb | 55 +- lib/l10n/generated/app_localizations.dart | 66 ++- lib/l10n/generated/app_localizations_de.dart | 43 +- lib/l10n/generated/app_localizations_en.dart | 67 ++- lib/main.dart | 2 - lib/presentation/views/active_game_view.dart | 479 +++++++++++------- lib/presentation/views/create_game_view.dart | 474 ++++++++++------- lib/presentation/views/graph_view.dart | 89 ++-- lib/presentation/views/main_menu_view.dart | 291 +++++------ .../views/mode_selection_view.dart | 33 +- lib/presentation/views/points_view.dart | 141 ++++++ lib/presentation/views/round_view.dart | 276 +++++----- lib/presentation/views/settings_view.dart | 43 +- lib/presentation/views/tab_view.dart | 3 +- lib/presentation/widgets/custom_button.dart | 19 + lib/services/config_service.dart | 85 +++- pubspec.yaml | 5 +- test/data/game_session_test.dart | 1 + 24 files changed, 1503 insertions(+), 799 deletions(-) create mode 100644 lib/presentation/views/points_view.dart create mode 100644 lib/presentation/widgets/custom_button.dart diff --git a/README.md b/README.md index 66eab9f..c1c7a24 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.4.7-orange) +![Version](https://img.shields.io/badge/Version-0.5.3-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) @@ -12,25 +12,29 @@ A mobile score tracker for the card game Cabo, helping players effortlessly mana ## 📱 Description -Cabo Counter is an intuitive Flutter-based mobile application designed to enhance your CABO card game experience. It eliminates manual scorekeeping by automatically calculating points per round. +Cabo Counter is an intuitive Flutter-based mobile application designed to enhance your CABO card game experience. It eliminates manual scorekeeping by automatically calculating points per round. ## ✨ Features -- 🆕 Create new games with customizable rules - 👥 Support for 2-5 players - ⚖️ Two game modes: - - **100 Points Mode** (Standard) - - **Infinite Mode** (Casual play) + - **Point Limit Mode**: Play until a certain point limit is reached + - **Unlimited Mode**: Play without an limit and end the round at any point - 🔢 Automatic score calculation with: + - Falsly calling Cabo + - Exact 100-point bonus (score halving) - Kamikaze rule handling - - Exact 100-point bonus (score halving) -- 📊 Round history tracking +- 📊 Round history tracking via graph and table +- 🎨 Customizable + - Change the default settings for point limits and cabo penaltys + - Choose a default game mode for every new created game +- 💿 Im- and exporting certain games or the whole app data ## 🚀 Getting Started ### Prerequisites -- Flutter 3.24.5+ -- Dart 3.5.4+ +- Flutter 3.32.1+ +- Dart 3.8.1+ ### Installation @@ -43,18 +47,22 @@ flutter run ## 🎮 Usage -1. **Start New Game** -- Choose game mode (100 Points or Infinite) +1. **Start a new game** +- Click the "+"-Button +- Choose a game title and a game mode - Add 2-5 players 2. **Gameplay** -- Track rounds with automatic scoring -- Handle special rules (Kamikaze, exact 100 points) -- View real-time standings +- Open the first round +- Choose the player who called Cabo +- Enter the points of every player +- If given: Choose a Kamikaze player +- Navigate to the next round or back to the overview +- Let the app calculate all points for you -3. **Round Management** -- Automatic winner detection -- Penalty point calculation +3. **Statistics** +- View the progress graph for the game +- Get a detailed table overview for every points made or lost - Game-over detection (100 Points mode) ## 🃏 Key Rules Overview @@ -67,7 +75,8 @@ flutter run - Exact 100 points: Score halved ### Game End -- First player ≥101 points triggers final scoring +- First player ≥100 points triggers final scoring +- In unlimited mode you can end the game via the End Game Button - Lowest total score wins ## 🤝 Contributing diff --git a/lib/core/constants.dart b/lib/core/constants.dart index e716464..e1c2f8d 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -19,4 +19,13 @@ class Constants { remindDays: 45, minLaunches: 15, remindLaunches: 40); + + /// Delay in milliseconds before a pop-up appears. + static const int popUpDelay = 300; + + /// Delay in milliseconds before the round view appears after the previous one is closed. + static const int roundViewDelay = 600; + + /// Duration in milliseconds for the fade-in animation of texts. + static const int fadeInDuration = 300; } diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index a00340b..bfc4f3c 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -4,7 +4,9 @@ class CustomTheme { static Color white = CupertinoColors.white; static Color primaryColor = CupertinoColors.systemGreen; static Color backgroundColor = const Color(0xFF101010); - static Color backgroundTintColor = CupertinoColors.darkBackgroundGray; + static Color mainElementBackgroundColor = CupertinoColors.darkBackgroundGray; + static Color playerTileColor = CupertinoColors.secondaryLabel; + static Color buttonBackgroundColor = const Color(0xFF202020); // Line Colors for GraphView static const Color graphColor1 = Color(0xFFF44336); @@ -13,6 +15,10 @@ class CustomTheme { static const Color graphColor4 = Color(0xFF9C27B0); static final Color graphColor5 = primaryColor; + // Colors for PointsView + static Color pointLossColor = primaryColor; + static const Color pointGainColor = Color(0xFFF44336); + static TextStyle modeTitle = TextStyle( color: primaryColor, fontSize: 20, diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index b3a1933..eca6880 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -1,5 +1,6 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; class GameManager extends ChangeNotifier { @@ -10,17 +11,25 @@ class GameManager extends ChangeNotifier { /// sorts the list in descending order based on the creation date, and notifies listeners of the change. /// It also saves the updated game sessions to local storage. /// Returns the index of the newly added session in the sorted list. - Future addGameSession(GameSession session) async { + int addGameSession(GameSession session) { session.addListener(() { notifyListeners(); // Propagate session changes }); gameList.add(session); gameList.sort((a, b) => b.createdAt.compareTo(a.createdAt)); notifyListeners(); - await LocalStorageService.saveGameSessions(); + LocalStorageService.saveGameSessions(); return gameList.indexOf(session); } + /// Retrieves a game session by its id. + /// Takes a String [id] as input. It searches the `gameList` for a session + /// with a matching id and returns it if found. + /// If no session is found, it returns null. + GameSession? getGameSessionById(String id) { + return gameList.firstWhereOrNull((session) => session.id == id); + } + /// Removes a game session from the list and sorts it by creation date. /// Takes a [index] as input. It then removes the session at the specified index from the `gameList`, /// sorts the list in descending order based on the creation date, and notifies listeners of the change. @@ -60,6 +69,7 @@ class GameManager extends ChangeNotifier { gameList[index].roundNumber--; gameList[index].isGameFinished = true; + gameList[index].setWinner(); notifyListeners(); LocalStorageService.saveGameSessions(); } diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index d1402e5..dc100a5 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -13,7 +13,7 @@ import 'package:uuid/uuid.dart'; /// [isGameFinished] is a boolean indicating if the game has ended yet. /// [winner] is the name of the player who won the game. class GameSession extends ChangeNotifier { - late String id; + final String id; final DateTime createdAt; final String gameTitle; final List players; @@ -27,6 +27,7 @@ class GameSession extends ChangeNotifier { List roundList = []; GameSession({ + required this.id, required this.createdAt, required this.gameTitle, required this.players, @@ -35,8 +36,6 @@ class GameSession extends ChangeNotifier { required this.isPointsLimitEnabled, }) { playerScores = List.filled(players.length, 0); - var uuid = const Uuid(); - id = uuid.v1(); } @override @@ -256,7 +255,7 @@ class GameSession extends ChangeNotifier { isGameFinished = true; print('${players[i]} hat die 100 Punkte ueberschritten, ' 'deswegen wurde das Spiel beendet'); - _setWinner(); + setWinner(); } } } @@ -299,16 +298,20 @@ class GameSession extends ChangeNotifier { /// Determines the winner of the game session. /// It iterates through the player scores and finds the player /// with the lowest score. - void _setWinner() { - int score = playerScores[0]; - String lowestPlayer = players[0]; + void setWinner() { + int minScore = playerScores.reduce((a, b) => a < b ? a : b); + List lowestPlayers = []; for (int i = 0; i < players.length; i++) { - if (playerScores[i] < score) { - score = playerScores[i]; - lowestPlayer = players[i]; + if (playerScores[i] == minScore) { + lowestPlayers.add(players[i]); } } - winner = lowestPlayer; + if (lowestPlayers.length > 1) { + winner = + '${lowestPlayers.sublist(0, lowestPlayers.length - 1).join(', ')} & ${lowestPlayers.last}'; + } else { + winner = lowestPlayers.first; + } notifyListeners(); } diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 93215ed..cd1a8c7 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -55,9 +55,12 @@ "min_players_title": "Zu wenig Spieler:innen", "min_players_message": "Es müssen mindestens 2 Spieler:innen hinzugefügt werden", "no_name_title": "Kein Name", - "no_name_message": "Jeder Spieler muss einen Namen haben.", + "no_name_message": "Jede:r Spieler:in muss einen Namen haben.", "select_game_mode": "Spielmodus auswählen", + "no_mode_selected": "Wähle einen Spielmodus", + "no_default_mode": "Kein Modus", + "no_default_description": "Entscheide bei jedem Spiel selber, welchen Modus du spielen möchtest.", "point_limit_description": "Es wird so lange gespielt, bis ein:e Spieler:in mehr als {pointLimit} Punkte erreicht", "@point_limit_description": { "placeholders": { @@ -71,6 +74,7 @@ "results": "Ergebnisse", "who_said_cabo": "Wer hat CABO gesagt?", "kamikaze": "Kamikaze", + "who_has_kamikaze": "Wer hat Kamikaze?", "done": "Fertig", "next_round": "Nächste Runde", "bonus_points_title": "Bonus-Punkte!", @@ -92,7 +96,21 @@ } }, - + "end_of_game_title": "Spiel beendet", + "end_of_game_message": "{playerCount, plural, =1{{names} hat das Spiel mit {points} Punkten gewonnen. Glückwunsch!} other{{names} haben das Spiel mit {points} Punkten gewonnen. Glückwunsch!}}", + "@end_of_game_message": { + "placeholders": { + "playerCount": { + "type": "int" + }, + "names": { + "type": "String" + }, + "points": { + "type": "int" + } + } + }, "end_game": "Spiel beenden", "delete_game": "Spiel löschen", "new_game_same_settings": "Neues Spiel mit gleichen Einstellungen", @@ -102,14 +120,15 @@ "end_game_title": "Spiel beenden?", "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", - "game_process": "Spielverlauf", + "statistics": "Statistiken", + "point_overview": "Punkteübersicht", + "scoring_history": "Spielverlauf", "empty_graph_text": "Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", "settings": "Einstellungen", "cabo_penalty": "Cabo-Strafe", - "cabo_penalty_subtitle": "... für falsches Cabo sagen", "point_limit": "Punkte-Limit", - "point_limit_subtitle": "... hier ist Schluss", + "standard_mode": "Standard-Modus", "reset_to_default": "Auf Standard zurücksetzen", "game_data": "Spieldaten", "import_data": "Spieldaten importieren", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 19695a5..7346343 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -14,13 +14,13 @@ "player": "Player", "players": "Players", "name": "Name", - "back": "Back", + "back": "Back", "home": "Home", "about": "About", "empty_text_1": "Pretty empty here...", - "empty_text_2": "Add a new round using the button in the top right corner.", + "empty_text_2": "Create a new game using the button in the top right.", "delete_game_title": "Delete game?", "delete_game_message": "Are you sure you want to delete the game \"{gameTitle}\"? This action cannot be undone.", "@delete_game_message": { @@ -46,19 +46,22 @@ "select_mode": "Select a mode", "add_player": "Add Player", "create_game": "Create Game", - "max_players_title": "Maximum reached", - "max_players_message": "A maximum of 5 players can be added.", - "no_gameTitle_title": "No Title", - "no_gameTitle_message": "You must enter a title for the game.", - "no_mode_title": "No Mode", - "no_mode_message": "You must select a game mode.", - "min_players_title": "Too few players", - "min_players_message": "At least 2 players must be added.", - "no_name_title": "No Name", + "max_players_title": "Player Limit Reached", + "max_players_message": "You can add a maximum of 5 players.", + "no_gameTitle_title": "Missing Game Title", + "no_gameTitle_message": "Please enter a title for your game.", + "no_mode_title": "Game Mode Required", + "no_mode_message": "Please select a game mode to continue", + "min_players_title": "Too Few Players", + "min_players_message": "At least 2 players are required to start the game.", + "no_name_title": "Missing Player Names", "no_name_message": "Each player must have a name.", "select_game_mode": "Select game mode", - "point_limit_description": "The game ends when a player reaches more than {pointLimit} points.", + "no_mode_selected": "No mode selected", + "no_default_mode": "No default mode", + "no_default_description": "The default mode gets reset.", + "point_limit_description": "The game ends when a player scores more than {pointLimit} points.", "@point_limit_description": { "placeholders": { "pointLimit": { @@ -66,11 +69,12 @@ } } }, - "unlimited_description": "There is no limit. The game continues until you decide to stop.", + "unlimited_description": "The game continues until you decide to stop playing", "results": "Results", - "who_said_cabo": "Who said CABO?", + "who_said_cabo": "Who called Cabo?", "kamikaze": "Kamikaze", + "who_has_kamikaze": "Who has Kamikaze?", "done": "Done", "next_round": "Next Round", "bonus_points_title": "Bonus-Points!", @@ -92,7 +96,21 @@ } }, - + "end_of_game_title": "End of Game", + "end_of_game_message": "{playerCount, plural, =1{{names} won the game with {points} points. Congratulations!} other{{names} won the game with {points} points. Congratulations to everyone!}}", + "@end_of_game_message": { + "placeholders": { + "playerCount": { + "type": "int" + }, + "names": { + "type": "String" + }, + "points": { + "type": "int" + } + } + }, "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", @@ -102,14 +120,15 @@ "end_game_title": "End the game?", "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", - "game_process": "Scoring History", + "statistics": "Statistics", + "point_overview": "Point Overview", + "scoring_history": "Scoring History", "empty_graph_text": "You must play at least one round for the game progress graph to be displayed.", "settings": "Settings", "cabo_penalty": "Cabo Penalty", - "cabo_penalty_subtitle": "... for falsely calling Cabo.", "point_limit": "Point Limit", - "point_limit_subtitle": "... the game ends here.", + "standard_mode": "Default Mode", "reset_to_default": "Reset to Default", "game_data": "Game Data", "import_data": "Import Data", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 0a902f6..5749079 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -365,7 +365,7 @@ abstract class AppLocalizations { /// No description provided for @no_name_message. /// /// In de, this message translates to: - /// **'Jeder Spieler muss einen Namen haben.'** + /// **'Jede:r Spieler:in muss einen Namen haben.'** String get no_name_message; /// No description provided for @select_game_mode. @@ -374,6 +374,24 @@ abstract class AppLocalizations { /// **'Spielmodus auswählen'** String get select_game_mode; + /// No description provided for @no_mode_selected. + /// + /// In de, this message translates to: + /// **'Wähle einen Spielmodus'** + String get no_mode_selected; + + /// No description provided for @no_default_mode. + /// + /// In de, this message translates to: + /// **'Kein Modus'** + String get no_default_mode; + + /// No description provided for @no_default_description. + /// + /// In de, this message translates to: + /// **'Entscheide bei jedem Spiel selber, welchen Modus du spielen möchtest.'** + String get no_default_description; + /// No description provided for @point_limit_description. /// /// In de, this message translates to: @@ -404,6 +422,12 @@ abstract class AppLocalizations { /// **'Kamikaze'** String get kamikaze; + /// No description provided for @who_has_kamikaze. + /// + /// In de, this message translates to: + /// **'Wer hat Kamikaze?'** + String get who_has_kamikaze; + /// No description provided for @done. /// /// In de, this message translates to: @@ -429,6 +453,18 @@ abstract class AppLocalizations { String bonus_points_message( int playerCount, String names, int pointLimit, int bonusPoints); + /// No description provided for @end_of_game_title. + /// + /// In de, this message translates to: + /// **'Spiel beendet'** + String get end_of_game_title; + + /// No description provided for @end_of_game_message. + /// + /// In de, this message translates to: + /// **'{playerCount, plural, =1{{names} hat das Spiel mit {points} Punkten gewonnen. Glückwunsch!} other{{names} haben das Spiel mit {points} Punkten gewonnen. Glückwunsch!}}'** + String end_of_game_message(int playerCount, String names, int points); + /// No description provided for @end_game. /// /// In de, this message translates to: @@ -477,11 +513,23 @@ abstract class AppLocalizations { /// **'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'** String get end_game_message; - /// No description provided for @game_process. + /// No description provided for @statistics. + /// + /// In de, this message translates to: + /// **'Statistiken'** + String get statistics; + + /// No description provided for @point_overview. + /// + /// In de, this message translates to: + /// **'Punkteübersicht'** + String get point_overview; + + /// No description provided for @scoring_history. /// /// In de, this message translates to: /// **'Spielverlauf'** - String get game_process; + String get scoring_history; /// No description provided for @empty_graph_text. /// @@ -501,23 +549,17 @@ abstract class AppLocalizations { /// **'Cabo-Strafe'** String get cabo_penalty; - /// No description provided for @cabo_penalty_subtitle. - /// - /// In de, this message translates to: - /// **'... für falsches Cabo sagen'** - String get cabo_penalty_subtitle; - /// No description provided for @point_limit. /// /// In de, this message translates to: /// **'Punkte-Limit'** String get point_limit; - /// No description provided for @point_limit_subtitle. + /// No description provided for @standard_mode. /// /// In de, this message translates to: - /// **'... hier ist Schluss'** - String get point_limit_subtitle; + /// **'Standard-Modus'** + String get standard_mode; /// No description provided for @reset_to_default. /// diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 7a71d00..87745dd 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -149,11 +149,21 @@ class AppLocalizationsDe extends AppLocalizations { String get no_name_title => 'Kein Name'; @override - String get no_name_message => 'Jeder Spieler muss einen Namen haben.'; + String get no_name_message => 'Jede:r Spieler:in muss einen Namen haben.'; @override String get select_game_mode => 'Spielmodus auswählen'; + @override + String get no_mode_selected => 'Wähle einen Spielmodus'; + + @override + String get no_default_mode => 'Kein Modus'; + + @override + String get no_default_description => + 'Entscheide bei jedem Spiel selber, welchen Modus du spielen möchtest.'; + @override String point_limit_description(int pointLimit) { return 'Es wird so lange gespielt, bis ein:e Spieler:in mehr als $pointLimit Punkte erreicht'; @@ -172,6 +182,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get kamikaze => 'Kamikaze'; + @override + String get who_has_kamikaze => 'Wer hat Kamikaze?'; + @override String get done => 'Fertig'; @@ -195,6 +208,21 @@ class AppLocalizationsDe extends AppLocalizations { return '$_temp0'; } + @override + String get end_of_game_title => 'Spiel beendet'; + + @override + String end_of_game_message(int playerCount, String names, int points) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names haben das Spiel mit $points Punkten gewonnen. Glückwunsch!', + one: '$names hat das Spiel mit $points Punkten gewonnen. Glückwunsch!', + ); + return '$_temp0'; + } + @override String get end_game => 'Spiel beenden'; @@ -222,7 +250,13 @@ class AppLocalizationsDe extends AppLocalizations { 'Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.'; @override - String get game_process => 'Spielverlauf'; + String get statistics => 'Statistiken'; + + @override + String get point_overview => 'Punkteübersicht'; + + @override + String get scoring_history => 'Spielverlauf'; @override String get empty_graph_text => @@ -234,14 +268,11 @@ class AppLocalizationsDe extends AppLocalizations { @override String get cabo_penalty => 'Cabo-Strafe'; - @override - String get cabo_penalty_subtitle => '... für falsches Cabo sagen'; - @override String get point_limit => 'Punkte-Limit'; @override - String get point_limit_subtitle => '... hier ist Schluss'; + String get standard_mode => 'Standard-Modus'; @override String get reset_to_default => 'Auf Standard zurücksetzen'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 4d4d663..eb341af 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -61,7 +61,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get empty_text_2 => - 'Add a new round using the button in the top right corner.'; + 'Create a new game using the button in the top right.'; @override String get delete_game_title => 'Delete game?'; @@ -119,31 +119,32 @@ class AppLocalizationsEn extends AppLocalizations { String get create_game => 'Create Game'; @override - String get max_players_title => 'Maximum reached'; + String get max_players_title => 'Player Limit Reached'; @override - String get max_players_message => 'A maximum of 5 players can be added.'; + String get max_players_message => 'You can add a maximum of 5 players.'; @override - String get no_gameTitle_title => 'No Title'; + String get no_gameTitle_title => 'Missing Game Title'; @override - String get no_gameTitle_message => 'You must enter a title for the game.'; + String get no_gameTitle_message => 'Please enter a title for your game.'; @override - String get no_mode_title => 'No Mode'; + String get no_mode_title => 'Game Mode Required'; @override - String get no_mode_message => 'You must select a game mode.'; + String get no_mode_message => 'Please select a game mode to continue'; @override - String get min_players_title => 'Too few players'; + String get min_players_title => 'Too Few Players'; @override - String get min_players_message => 'At least 2 players must be added.'; + String get min_players_message => + 'At least 2 players are required to start the game.'; @override - String get no_name_title => 'No Name'; + String get no_name_title => 'Missing Player Names'; @override String get no_name_message => 'Each player must have a name.'; @@ -151,24 +152,36 @@ class AppLocalizationsEn extends AppLocalizations { @override String get select_game_mode => 'Select game mode'; + @override + String get no_mode_selected => 'No mode selected'; + + @override + String get no_default_mode => 'No default mode'; + + @override + String get no_default_description => 'The default mode gets reset.'; + @override String point_limit_description(int pointLimit) { - return 'The game ends when a player reaches more than $pointLimit points.'; + return 'The game ends when a player scores more than $pointLimit points.'; } @override String get unlimited_description => - 'There is no limit. The game continues until you decide to stop.'; + 'The game continues until you decide to stop playing'; @override String get results => 'Results'; @override - String get who_said_cabo => 'Who said CABO?'; + String get who_said_cabo => 'Who called Cabo?'; @override String get kamikaze => 'Kamikaze'; + @override + String get who_has_kamikaze => 'Who has Kamikaze?'; + @override String get done => 'Done'; @@ -192,6 +205,21 @@ class AppLocalizationsEn extends AppLocalizations { return '$_temp0'; } + @override + String get end_of_game_title => 'End of Game'; + + @override + String end_of_game_message(int playerCount, String names, int points) { + String _temp0 = intl.Intl.pluralLogic( + playerCount, + locale: localeName, + other: + '$names won the game with $points points. Congratulations to everyone!', + one: '$names won the game with $points points. Congratulations!', + ); + return '$_temp0'; + } + @override String get end_game => 'End Game'; @@ -219,7 +247,13 @@ class AppLocalizationsEn extends AppLocalizations { 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; @override - String get game_process => 'Scoring History'; + String get statistics => 'Statistics'; + + @override + String get point_overview => 'Point Overview'; + + @override + String get scoring_history => 'Scoring History'; @override String get empty_graph_text => @@ -231,14 +265,11 @@ class AppLocalizationsEn extends AppLocalizations { @override String get cabo_penalty => 'Cabo Penalty'; - @override - String get cabo_penalty_subtitle => '... for falsely calling Cabo.'; - @override String get point_limit => 'Point Limit'; @override - String get point_limit_subtitle => '... the game ends here.'; + String get standard_mode => 'Default Mode'; @override String get reset_to_default => 'Reset to Default'; diff --git a/lib/main.dart b/lib/main.dart index 9279426..8b45434 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,8 +12,6 @@ Future main() async { await SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); await ConfigService.initConfig(); - ConfigService.pointLimit = await ConfigService.getPointLimit(); - ConfigService.caboPenalty = await ConfigService.getCaboPenalty(); await VersionService.init(); runApp(const App()); } diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index ab07804..ff9e066 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -1,11 +1,16 @@ +import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/create_game_view.dart'; import 'package:cabo_counter/presentation/views/graph_view.dart'; +import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; +import 'package:cabo_counter/presentation/views/points_view.dart'; import 'package:cabo_counter/presentation/views/round_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; +import 'package:collection/collection.dart'; +import 'package:confetti/confetti.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -19,6 +24,9 @@ class ActiveGameView extends StatefulWidget { } class _ActiveGameViewState extends State { + final confettiController = ConfettiController( + duration: const Duration(seconds: 10), + ); late final GameSession gameSession; late List denseRanks; late List sortedPlayerIndices; @@ -31,200 +39,257 @@ class _ActiveGameViewState extends State { @override Widget build(BuildContext context) { - return ListenableBuilder( - listenable: gameSession, - builder: (context, _) { - sortedPlayerIndices = _getSortedPlayerIndices(); - denseRanks = _calculateDenseRank( - gameSession.playerScores, sortedPlayerIndices); - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text(gameSession.gameTitle), - ), - child: SafeArea( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).players, - style: CustomTheme.rowTitle, - ), - ), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: gameSession.players.length, - itemBuilder: (BuildContext context, int index) { - int playerIndex = sortedPlayerIndices[index]; - return CupertinoListTile( - title: Row( - children: [ - _getPlacementTextWidget(index), - const SizedBox(width: 5), - Text( - gameSession.players[playerIndex], - style: const TextStyle( - fontWeight: FontWeight.bold), - ), - ], + return Stack( + children: [ + ListenableBuilder( + listenable: gameSession, + builder: (context, _) { + sortedPlayerIndices = _getSortedPlayerIndices(); + denseRanks = _calculateDenseRank( + gameSession.playerScores, sortedPlayerIndices); + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text( + gameSession.gameTitle, + overflow: TextOverflow.ellipsis, + ), + ), + child: SafeArea( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).players, + style: CustomTheme.rowTitle, ), - trailing: Row( - children: [ - const SizedBox(width: 5), - Text('${gameSession.playerScores[playerIndex]} ' - '${AppLocalizations.of(context).points}') - ], - ), - ); - }, - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).rounds, - style: CustomTheme.rowTitle, - ), - ), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: gameSession.roundNumber, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(1), - child: CupertinoListTile( - backgroundColorActivated: - CustomTheme.backgroundColor, - title: Text( - '${AppLocalizations.of(context).round} ${index + 1}', + ), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: gameSession.players.length, + itemBuilder: (BuildContext context, int index) { + int playerIndex = sortedPlayerIndices[index]; + return CupertinoListTile( + title: Row( + children: [ + _getPlacementTextWidget(index), + const SizedBox(width: 5), + Text( + gameSession.players[playerIndex], + style: const TextStyle( + fontWeight: FontWeight.bold), + ), + ], ), - trailing: - index + 1 != gameSession.roundNumber || + trailing: Row( + children: [ + const SizedBox(width: 5), + Text( + '${gameSession.playerScores[playerIndex]} ' + '${AppLocalizations.of(context).points}') + ], + ), + ); + }, + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).rounds, + style: CustomTheme.rowTitle, + ), + ), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: gameSession.roundNumber, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(1), + child: CupertinoListTile( + backgroundColorActivated: + CustomTheme.backgroundColor, + title: Text( + '${AppLocalizations.of(context).round} ${index + 1}', + ), + trailing: index + 1 != + gameSession.roundNumber || gameSession.isGameFinished == true ? (const Text('\u{2705}', style: TextStyle(fontSize: 22))) : const Text('\u{23F3}', style: TextStyle(fontSize: 22)), - onTap: () async { - _openRoundView(index + 1); - }, - )); - }, - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).game, - style: CustomTheme.rowTitle, - ), - ), - Column( - children: [ - CupertinoListTile( - title: Text( - AppLocalizations.of(context).game_process, + onTap: () async { + _openRoundView(context, index + 1); + }, + )); + }, + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).statistics, + style: CustomTheme.rowTitle, + ), + ), + Column( + children: [ + CupertinoListTile( + title: Text( + AppLocalizations.of(context) + .scoring_history, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (_) => GraphView( + gameSession: gameSession, + )))), + CupertinoListTile( + title: Text( + AppLocalizations.of(context).point_overview, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (_) => PointsView( + gameSession: gameSession, + )))), + ], + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).game, + style: CustomTheme.rowTitle, + ), + ), + Column( + children: [ + Visibility( + visible: !gameSession.isPointsLimitEnabled, + child: CupertinoListTile( + title: Text( + AppLocalizations.of(context).end_game, + style: gameSession.roundNumber > 1 && + !gameSession.isGameFinished + ? const TextStyle(color: Colors.white) + : const TextStyle( + color: Colors.white30), + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () { + if (gameSession.roundNumber > 1 && + !gameSession.isGameFinished) { + _showEndGameDialog(); + } + }), ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () => Navigator.push( - context, - CupertinoPageRoute( - builder: (_) => GraphView( - gameSession: gameSession, - )))), - Visibility( - visible: !gameSession.isPointsLimitEnabled, - child: CupertinoListTile( + CupertinoListTile( title: Text( - AppLocalizations.of(context).end_game, - style: gameSession.roundNumber > 1 && - !gameSession.isGameFinished - ? const TextStyle(color: Colors.white) - : const TextStyle(color: Colors.white30), + AppLocalizations.of(context).delete_game, ), backgroundColorActivated: CustomTheme.backgroundColor, onTap: () { - if (gameSession.roundNumber > 1 && - !gameSession.isGameFinished) { - _showEndGameDialog(); - } - }), - ), - CupertinoListTile( - title: Text( - AppLocalizations.of(context).delete_game, - ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () { - _showDeleteGameDialog().then((value) { - if (value) { - _removeGameSession(gameSession); - } - }); - }, - ), - CupertinoListTile( - title: Text( - AppLocalizations.of(context) - .new_game_same_settings, - ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (_) => CreateGameView( - gameTitle: gameSession.gameTitle, - isPointsLimitEnabled: widget - .gameSession - .isPointsLimitEnabled, - players: gameSession.players, - ))); - }, - ), - CupertinoListTile( - title: Text( - AppLocalizations.of(context).export_game, + _showDeleteGameDialog().then((value) { + if (value) { + _removeGameSession(gameSession); + } + }); + }, ), - backgroundColorActivated: - CustomTheme.backgroundColor, - onTap: () async { - final success = await LocalStorageService - .exportSingleGameSession( - widget.gameSession); - if (!success && context.mounted) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context) - .export_error_title), - content: Text(AppLocalizations.of(context) - .export_error_message), - actions: [ - CupertinoDialogAction( - child: Text( - AppLocalizations.of(context).ok), - onPressed: () => - Navigator.pop(context), + CupertinoListTile( + title: Text( + AppLocalizations.of(context) + .new_game_same_settings, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () { + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (_) => CreateGameView( + gameTitle: + gameSession.gameTitle, + gameMode: widget.gameSession + .isPointsLimitEnabled == + true + ? GameMode.pointLimit + : GameMode.unlimited, + players: gameSession.players, + ))); + }, + ), + CupertinoListTile( + title: Text( + AppLocalizations.of(context).export_game, + ), + backgroundColorActivated: + CustomTheme.backgroundColor, + onTap: () async { + final success = await LocalStorageService + .exportSingleGameSession( + widget.gameSession); + if (!success && context.mounted) { + showCupertinoDialog( + context: context, + builder: (context) => + CupertinoAlertDialog( + title: Text( + AppLocalizations.of(context) + .export_error_title), + content: Text( + AppLocalizations.of(context) + .export_error_message), + actions: [ + CupertinoDialogAction( + child: Text( + AppLocalizations.of(context) + .ok), + onPressed: () => + Navigator.pop(context), + ), + ], ), - ], - ), - ); - } - }), + ); + } + }), + ], + ) ], - ) - ], - ), - ), - )); - }); + ), + ), + )); + }), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: ConfettiWidget( + blastDirectionality: BlastDirectionality.explosive, + particleDrag: 0.07, + emissionFrequency: 0.1, + numberOfParticles: 10, + minBlastForce: 5, + maxBlastForce: 20, + confettiController: confettiController, + ), + ), + ], + ), + ], + ); } /// Shows a dialog to confirm ending the game. @@ -247,6 +312,7 @@ class _ActiveGameViewState extends State { onPressed: () { setState(() { gameManager.endGame(gameSession.id); + _playFinishAnimation(context); }); Navigator.pop(context); }, @@ -376,8 +442,8 @@ class _ActiveGameViewState extends State { /// Recursively opens the RoundView for the specified round number. /// It starts with the given [roundNumber] and continues to open the next round /// until the user navigates back or the round number is invalid. - void _openRoundView(int roundNumber) async { - final val = await Navigator.of(context, rootNavigator: true).push( + void _openRoundView(BuildContext context, int roundNumber) async { + final round = await Navigator.of(context, rootNavigator: true).push( CupertinoPageRoute( fullscreenDialog: true, builder: (context) => RoundView( @@ -386,11 +452,58 @@ class _ActiveGameViewState extends State { ), ), ); - if (val != null && val >= 0) { + + if (widget.gameSession.isGameFinished && context.mounted) { + _playFinishAnimation(context); + } + + // If the previous round was not the last one + if (round != null && round >= 0) { WidgetsBinding.instance.addPostFrameCallback((_) async { - await Future.delayed(const Duration(milliseconds: 600)); - _openRoundView(val); + await Future.delayed( + const Duration(milliseconds: Constants.roundViewDelay)); + if (context.mounted) { + _openRoundView(context, round); + } }); } } + + /// Plays the confetti animation and shows a dialog with the winner's information. + Future _playFinishAnimation(BuildContext context) async { + String winner = widget.gameSession.winner; + int winnerPoints = widget.gameSession.playerScores.min; + int winnerAmount = winner.contains('&') ? 2 : 1; + + confettiController.play(); + + await Future.delayed(const Duration(milliseconds: Constants.popUpDelay)); + + if (context.mounted) { + showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(AppLocalizations.of(context).end_of_game_title), + content: Text(AppLocalizations.of(context) + .end_of_game_message(winnerAmount, winner, winnerPoints)), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () { + confettiController.stop(); + Navigator.pop(context); + }, + ), + ], + ); + }); + } + } + + @override + void dispose() { + confettiController.dispose(); + super.dispose(); + } } diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 0d23494..193cdff 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -1,11 +1,16 @@ +import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; +import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:uuid/uuid.dart'; enum CreateStatus { noGameTitle, @@ -16,15 +21,15 @@ enum CreateStatus { } class CreateGameView extends StatefulWidget { + final GameMode gameMode; final String? gameTitle; - final bool? isPointsLimitEnabled; final List? players; const CreateGameView({ super.key, this.gameTitle, - this.isPointsLimitEnabled, this.players, + required this.gameMode, }); @override @@ -33,29 +38,39 @@ class CreateGameView extends StatefulWidget { } class _CreateGameViewState extends State { + final TextEditingController _gameTitleTextController = + TextEditingController(); + + /// List of text controllers for player names. final List _playerNameTextControllers = [ TextEditingController() ]; - final TextEditingController _gameTitleTextController = - TextEditingController(); + + /// List of focus nodes for player name text fields. + final List _playerNameFocusNodes = [FocusNode()]; /// Maximum number of players allowed in the game. final int maxPlayers = 5; - /// Variable to store whether the points limit feature is enabled. - bool? _isPointsLimitEnabled; + /// Factor to adjust the view length when the keyboard is visible. + final double keyboardHeightAdjustmentFactor = 0.75; + + /// Variable to hold the selected game mode. + late GameMode gameMode; @override void initState() { super.initState(); - _isPointsLimitEnabled = widget.isPointsLimitEnabled; + gameMode = widget.gameMode; + _gameTitleTextController.text = widget.gameTitle ?? ''; if (widget.players != null) { _playerNameTextControllers.clear(); for (var player in widget.players!) { _playerNameTextControllers.add(TextEditingController(text: player)); + _playerNameFocusNodes.add(FocusNode()); } } } @@ -63,124 +78,100 @@ class _CreateGameViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( + resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( previousPageTitle: AppLocalizations.of(context).overview, middle: Text(AppLocalizations.of(context).new_game), ), child: SafeArea( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).game, - style: CustomTheme.rowTitle, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - maxLength: 16, - prefix: Text(AppLocalizations.of(context).name), - textAlign: TextAlign.right, - placeholder: AppLocalizations.of(context).game_title, - controller: _gameTitleTextController, - ), - ), - // Spielmodus-Auswahl mit Chevron - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - readOnly: true, - prefix: Text(AppLocalizations.of(context).mode), - suffix: Row( - children: [ - Text( - _isPointsLimitEnabled == null - ? AppLocalizations.of(context).select_mode - : (_isPointsLimitEnabled! - ? '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}' - : AppLocalizations.of(context).unlimited), - ), - const SizedBox(width: 3), - const CupertinoListTileChevron(), - ], + 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).game, + style: CustomTheme.rowTitle, ), - onTap: () async { - final selectedMode = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ModeSelectionMenu( - pointLimit: ConfigService.pointLimit, - ), - ), - ); - - if (selectedMode != null) { - setState(() { - _isPointsLimitEnabled = selectedMode; - }); - } - }, ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).players, - style: CustomTheme.rowTitle, + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + maxLength: 20, + prefix: Text(AppLocalizations.of(context).name), + textAlign: TextAlign.right, + placeholder: AppLocalizations.of(context).game_title, + controller: _gameTitleTextController, + onSubmitted: (_) { + _playerNameFocusNodes.isNotEmpty + ? _playerNameFocusNodes[0].requestFocus() + : FocusScope.of(context).unfocus(); + }, + textInputAction: _playerNameFocusNodes.isNotEmpty + ? TextInputAction.next + : TextInputAction.done, + ), ), - ), - Expanded( - child: ListView.builder( - itemCount: _playerNameTextControllers.length + - 1, // +1 für den + Button - itemBuilder: (context, index) { - if (index == _playerNameTextControllers.length) { - // + Button als letztes Element - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - CupertinoIcons.add_circled, - color: CupertinoColors.activeGreen, - size: 25, - ), - const SizedBox(width: 8), - Text( - AppLocalizations.of(context).add_player, - style: const TextStyle( - color: CupertinoColors.activeGreen, - ), - ), - ], + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + readOnly: true, + prefix: Text(AppLocalizations.of(context).mode), + suffix: Row( + children: [ + _getDisplayedGameMode(), + const SizedBox(width: 3), + const CupertinoListTileChevron(), + ], + ), + onTap: () async { + final selectedMode = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ModeSelectionMenu( + pointLimit: ConfigService.getPointLimit(), + showDeselection: false, ), - onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - showFeedbackDialog(CreateStatus.maxPlayers); - } - }, ), ); - } else { - // Spieler-Einträge + + setState(() { + gameMode = selectedMode ?? gameMode; + }); + }, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).players, + style: CustomTheme.rowTitle, + ), + ), + ReorderableListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + } + }); + }, + itemBuilder: (context, index) { return Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, horizontal: 5), + key: ValueKey(index), + padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ CupertinoButton( @@ -200,82 +191,187 @@ class _CreateGameViewState extends State { Expanded( child: CupertinoTextField( controller: _playerNameTextControllers[index], + focusNode: _playerNameFocusNodes[index], maxLength: 12, placeholder: '${AppLocalizations.of(context).player} ${index + 1}', padding: const EdgeInsets.all(12), decoration: const BoxDecoration(), + textInputAction: + index + 1 < _playerNameTextControllers.length + ? TextInputAction.next + : TextInputAction.done, + onSubmitted: (_) { + if (index + 1 < _playerNameFocusNodes.length) { + _playerNameFocusNodes[index + 1] + .requestFocus(); + } else { + FocusScope.of(context).unfocus(); + } + }, ), ), + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration( + milliseconds: Constants.fadeInDuration), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, + ), + ), + ), + ) ], ), ); - } - }, - ), - ), - Center( - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + }), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), + child: Stack( children: [ - Text( - AppLocalizations.of(context).create_game, - style: const TextStyle( - color: CupertinoColors.activeGreen, + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.plus_circle_fill, + color: CustomTheme.primaryColor, + size: 25, + ), + ), + ], + ), + Center( + child: CupertinoButton( + padding: const EdgeInsets.symmetric(horizontal: 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Center( + child: Text( + AppLocalizations.of(context).add_player, + style: TextStyle( + color: CustomTheme.primaryColor), + ), + ), + ), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < maxPlayers) { + setState(() { + _playerNameTextControllers + .add(TextEditingController()); + _playerNameFocusNodes.add(FocusNode()); + }); + WidgetsBinding.instance.addPostFrameCallback((_) { + _playerNameFocusNodes.last.requestFocus(); + }); + } else { + _showFeedbackDialog(CreateStatus.maxPlayers); + } + }, ), ), ], ), - onPressed: () async { - if (_gameTitleTextController.text == '') { - showFeedbackDialog(CreateStatus.noGameTitle); - return; - } - if (_isPointsLimitEnabled == null) { - showFeedbackDialog(CreateStatus.noModeSelected); - return; - } - if (_playerNameTextControllers.length < 2) { - showFeedbackDialog(CreateStatus.minPlayers); - return; - } - if (!everyPlayerHasAName()) { - showFeedbackDialog(CreateStatus.noPlayerName); - return; - } - - List players = []; - for (var controller in _playerNameTextControllers) { - players.add(controller.text); - } - GameSession gameSession = GameSession( - createdAt: DateTime.now(), - gameTitle: _gameTitleTextController.text, - players: players, - pointLimit: ConfigService.pointLimit, - caboPenalty: ConfigService.caboPenalty, - isPointsLimitEnabled: _isPointsLimitEnabled!, - ); - final index = await gameManager.addGameSession(gameSession); - final session = gameManager.gameList[index]; - if (context.mounted) { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => - ActiveGameView(gameSession: session))); - } - }, ), - ), - ], - )))); + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), + child: Center( + key: const ValueKey('create_game_button'), + child: CustomButton( + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ), + onPressed: () { + _checkAllGameAttributes(); + }, + ), + ), + ), + KeyboardVisibilityBuilder(builder: (context, visible) { + if (visible) { + return SizedBox( + height: MediaQuery.of(context).viewInsets.bottom * + keyboardHeightAdjustmentFactor, + ); + } else { + return const SizedBox.shrink(); + } + }) + ], + ), + ))); + } + + /// Returns a widget that displays the currently selected game mode in the View. + Text _getDisplayedGameMode() { + if (gameMode == GameMode.none) { + return Text(AppLocalizations.of(context).no_mode_selected); + } else if (gameMode == GameMode.pointLimit) { + return Text( + '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}', + style: TextStyle(color: CustomTheme.primaryColor)); + } else { + return Text(AppLocalizations.of(context).unlimited, + style: TextStyle(color: CustomTheme.primaryColor)); + } + } + + /// Checks all game attributes before creating a new game. + /// If any attribute is invalid, it shows a feedback dialog. + /// If all attributes are valid, it calls the `_createGame` method. + void _checkAllGameAttributes() { + if (_gameTitleTextController.text == '') { + _showFeedbackDialog(CreateStatus.noGameTitle); + return; + } + + if (gameMode == GameMode.none) { + _showFeedbackDialog(CreateStatus.noModeSelected); + return; + } + + if (_playerNameTextControllers.length < 2) { + _showFeedbackDialog(CreateStatus.minPlayers); + return; + } + + if (!_everyPlayerHasAName()) { + _showFeedbackDialog(CreateStatus.noPlayerName); + return; + } + + _createGame(); + } + + /// Checks if every player has a name. + /// Returns true if all players have a name, false otherwise. + bool _everyPlayerHasAName() { + for (var controller in _playerNameTextControllers) { + if (controller.text == '') { + return false; + } + } + return true; } /// Displays a feedback dialog based on the [CreateStatus]. - void showFeedbackDialog(CreateStatus status) { + void _showFeedbackDialog(CreateStatus status) { final (title, message) = _getDialogContent(status); showCupertinoDialog( @@ -326,15 +422,36 @@ class _CreateGameViewState extends State { } } - /// Checks if every player has a name. - /// Returns true if all players have a name, false otherwise. - bool everyPlayerHasAName() { + /// Creates a new gameSession and navigates to the active game view. + /// This method creates a new gameSession object with the provided attributes in the text fields. + /// It then adds the game session to the game manager and navigates to the active game view. + void _createGame() { + var uuid = const Uuid(); + final String id = uuid.v1(); + + List players = []; for (var controller in _playerNameTextControllers) { - if (controller.text == '') { - return false; - } + players.add(controller.text); } - return true; + + bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + + GameSession gameSession = GameSession( + id: id, + createdAt: DateTime.now(), + gameTitle: _gameTitleTextController.text, + players: players, + pointLimit: ConfigService.getPointLimit(), + caboPenalty: ConfigService.getCaboPenalty(), + isPointsLimitEnabled: isPointsLimitEnabled, + ); + gameManager.addGameSession(gameSession); + final session = gameManager.getGameSessionById(id) ?? gameSession; + + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView(gameSession: session))); } @override @@ -343,6 +460,9 @@ class _CreateGameViewState extends State { for (var controller in _playerNameTextControllers) { controller.dispose(); } + for (var focusnode in _playerNameFocusNodes) { + focusnode.dispose(); + } super.dispose(); } diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index d322bd0..da9f8e7 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -27,46 +27,61 @@ class _GraphViewState extends State { Widget build(BuildContext context) { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).game_process), + middle: Text(AppLocalizations.of(context).scoring_history), previousPageTitle: AppLocalizations.of(context).back, ), - child: widget.gameSession.roundNumber > 1 - ? Padding( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), - child: SfCartesianChart( - legend: const Legend( - overflowMode: LegendItemOverflowMode.wrap, - isVisible: true, - position: LegendPosition.bottom), - primaryXAxis: const NumericAxis( - interval: 1, - decimalPlaces: 0, - ), - primaryYAxis: const NumericAxis( - interval: 1, - decimalPlaces: 0, - ), - series: getCumulativeScores(), + child: Visibility( + visible: widget.gameSession.roundNumber > 1 || + widget.gameSession.isGameFinished, + replacement: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Center( + child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), + ), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: Text( + AppLocalizations.of(context).empty_graph_text, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), ), - ) - : Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Center( - child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), - ), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 40), - child: Text( - AppLocalizations.of(context).empty_graph_text, - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 16), - ), - ), - ], - )); + ), + ], + ), + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: SfCartesianChart( + enableAxisAnimation: true, + legend: const Legend( + overflowMode: LegendItemOverflowMode.wrap, + isVisible: true, + position: LegendPosition.bottom), + primaryXAxis: const NumericAxis( + labelStyle: TextStyle(fontWeight: FontWeight.bold), + interval: 1, + decimalPlaces: 0, + ), + primaryYAxis: NumericAxis( + labelStyle: const TextStyle(fontWeight: FontWeight.bold), + labelAlignment: LabelAlignment.center, + labelPosition: ChartDataLabelPosition.inside, + interval: 1, + decimalPlaces: 0, + axisLabelFormatter: (AxisLabelRenderDetails details) { + if (details.value == 0) { + return ChartAxisLabel('', const TextStyle()); + } + return ChartAxisLabel( + '${details.value.toInt()}', const TextStyle()); + }, + ), + series: getCumulativeScores(), + ), + ), + )); } /// Returns a list of LineSeries representing the cumulative scores of each player. diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 86ff208..21deb97 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -58,162 +58,167 @@ class _MainMenuViewState extends State { listenable: gameManager, builder: (context, _) { return CupertinoPageScaffold( - resizeToAvoidBottomInset: false, - navigationBar: CupertinoNavigationBar( - leading: IconButton( - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const SettingsView(), - ), - ).then((_) { - setState(() {}); - }); - }, - icon: const Icon(CupertinoIcons.settings, size: 30)), - middle: const Text('Cabo Counter'), - trailing: IconButton( - onPressed: () => Navigator.push( + resizeToAvoidBottomInset: false, + navigationBar: CupertinoNavigationBar( + leading: IconButton( + onPressed: () { + Navigator.push( context, CupertinoPageRoute( - builder: (context) => const CreateGameView(), + builder: (context) => const SettingsView(), ), + ).then((_) { + setState(() {}); + }); + }, + icon: const Icon(CupertinoIcons.settings, size: 30)), + middle: Text(AppLocalizations.of(context).app_name), + trailing: IconButton( + onPressed: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => CreateGameView( + gameMode: ConfigService.getGameMode()), + ), + ), + icon: const Icon(CupertinoIcons.add)), + ), + child: CupertinoPageScaffold( + child: SafeArea( + child: Visibility( + visible: _isLoading, + replacement: Visibility( + visible: gameManager.gameList.isEmpty, + replacement: ListView.separated( + itemCount: gameManager.gameList.length, + separatorBuilder: (context, index) => Divider( + height: 1, + thickness: 0.5, + color: CustomTheme.white.withAlpha(50), + indent: 50, + endIndent: 50, ), - icon: const Icon(CupertinoIcons.add)), - ), - child: CupertinoPageScaffold( - child: SafeArea( - child: _isLoading - ? const Center(child: CupertinoActivityIndicator()) - : gameManager.gameList.isEmpty - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(height: 30), - Center( - child: GestureDetector( - onTap: () => Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => - const CreateGameView(), + itemBuilder: (context, index) { + final session = gameManager.gameList[index]; + return ListenableBuilder( + listenable: session, + builder: (context, _) { + return Dismissible( + key: Key(session.id), + background: Container( + color: CupertinoColors.destructiveRed, + alignment: Alignment.centerRight, + padding: const EdgeInsets.only(right: 20.0), + child: const Icon( + CupertinoIcons.delete, + color: CupertinoColors.white, ), ), - child: Icon( - CupertinoIcons.plus, - size: 60, - color: CustomTheme.primaryColor, - ), - )), - const SizedBox(height: 10), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 70), - child: Text( - '${AppLocalizations.of(context).empty_text_1}\n${AppLocalizations.of(context).empty_text_2}', - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 16), - ), - ), - ], - ) - : ListView.builder( - itemCount: gameManager.gameList.length, - itemBuilder: (context, index) { - final session = gameManager.gameList[index]; - return ListenableBuilder( - listenable: session, - builder: (context, _) { - return Dismissible( - key: Key(session.gameTitle), - background: Container( - color: CupertinoColors.destructiveRed, - alignment: Alignment.centerRight, - padding: - const EdgeInsets.only(right: 20.0), - child: const Icon( - CupertinoIcons.delete, - color: CupertinoColors.white, + direction: DismissDirection.endToStart, + confirmDismiss: (direction) async { + return await _showDeleteGamePopup( + context, session.gameTitle); + }, + onDismissed: (direction) { + gameManager.removeGameSessionById(session.id); + }, + dismissThresholds: const { + DismissDirection.startToEnd: 0.6 + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 10.0), + child: CupertinoListTile( + backgroundColorActivated: + CustomTheme.backgroundColor, + title: Text(session.gameTitle), + subtitle: Visibility( + visible: session.isGameFinished, + replacement: Text( + '${AppLocalizations.of(context).mode}: ${_translateGameMode(session.isPointsLimitEnabled)}', + style: const TextStyle(fontSize: 14), ), - ), - direction: DismissDirection.endToStart, - confirmDismiss: (direction) async { - final String gameTitle = gameManager - .gameList[index].gameTitle; - return await _showDeleteGamePopup( - context, gameTitle); - }, - onDismissed: (direction) { - gameManager - .removeGameSessionByIndex(index); - }, - dismissThresholds: const { - DismissDirection.startToEnd: 0.6 - }, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 10.0), - child: CupertinoListTile( - backgroundColorActivated: - CustomTheme.backgroundColor, - title: Text(session.gameTitle), - subtitle: - session.isGameFinished == true - ? Text( - '\u{1F947} ${session.winner}', - style: const TextStyle( - fontSize: 14), - ) - : Text( - '${AppLocalizations.of(context).mode}: ${_translateGameMode(session.isPointsLimitEnabled)}', - style: const TextStyle( - fontSize: 14), - ), - trailing: Row( - children: [ - Text('${session.roundNumber}'), - const SizedBox(width: 3), - const Icon(CupertinoIcons - .arrow_2_circlepath_circle_fill), - const SizedBox(width: 15), - Text('${session.players.length}'), - const SizedBox(width: 3), - const Icon( - CupertinoIcons.person_2_fill), - ], - ), - onTap: () { - final session = - gameManager.gameList[index]; - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => - ActiveGameView( - gameSession: session), - ), - ).then((_) { - setState(() {}); - }); - }, + child: Text( + '\u{1F947} ${session.winner}', + style: const TextStyle(fontSize: 14), + )), + trailing: Row( + children: [ + const SizedBox( + width: 5, ), - ), - ); - }); - }, + Text('${session.roundNumber}'), + const SizedBox(width: 3), + const Icon(CupertinoIcons + .arrow_2_circlepath_circle_fill), + const SizedBox(width: 15), + Text('${session.players.length}'), + const SizedBox(width: 3), + const Icon( + CupertinoIcons.person_2_fill), + ], + ), + onTap: () { + final session = + gameManager.gameList[index]; + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView( + gameSession: session), + ), + ).then((_) { + setState(() {}); + }); + }, + ), + ), + ); + }); + }, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 30), + Center( + child: GestureDetector( + onTap: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => CreateGameView( + gameMode: ConfigService.getGameMode()), + ), ), - ), - ), - ); + child: Icon( + CupertinoIcons.plus, + size: 60, + color: CustomTheme.primaryColor, + ), + )), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 70), + child: Text( + '${AppLocalizations.of(context).empty_text_1}\n${AppLocalizations.of(context).empty_text_2}', + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ), + ), + ], + ), + ), + child: const Center(child: CupertinoActivityIndicator()), + ), + ))); }); } /// Translates the game mode boolean into the corresponding String. /// If [pointLimit] is true, it returns '101 Punkte', otherwise it returns 'Unbegrenzt'. - String _translateGameMode(bool pointLimit) { - if (pointLimit) { - return '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}'; + String _translateGameMode(bool isPointLimitEnabled) { + if (isPointLimitEnabled) { + return '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}'; } return AppLocalizations.of(context).unlimited; } @@ -237,7 +242,7 @@ class _MainMenuViewState extends State { BadRatingDialogDecision badRatingDecision = BadRatingDialogDecision.cancel; // so that the bad rating dialog is not shown immediately - await Future.delayed(const Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: Constants.popUpDelay)); switch (preRatingDecision) { case PreRatingDialogDecision.yes: diff --git a/lib/presentation/views/mode_selection_view.dart b/lib/presentation/views/mode_selection_view.dart index a7d3ce7..0424dab 100644 --- a/lib/presentation/views/mode_selection_view.dart +++ b/lib/presentation/views/mode_selection_view.dart @@ -2,9 +2,17 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; +enum GameMode { + none, + pointLimit, + unlimited, +} + class ModeSelectionMenu extends StatelessWidget { final int pointLimit; - const ModeSelectionMenu({super.key, required this.pointLimit}); + final bool showDeselection; + const ModeSelectionMenu( + {super.key, required this.pointLimit, required this.showDeselection}); @override Widget build(BuildContext context) { @@ -26,12 +34,12 @@ class ModeSelectionMenu extends StatelessWidget { maxLines: 3, ), onTap: () { - Navigator.pop(context, true); + Navigator.pop(context, GameMode.pointLimit); }, ), ), Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: CupertinoListTile( title: Text(AppLocalizations.of(context).unlimited, style: CustomTheme.modeTitle), @@ -41,10 +49,27 @@ class ModeSelectionMenu extends StatelessWidget { maxLines: 3, ), onTap: () { - Navigator.pop(context, false); + Navigator.pop(context, GameMode.unlimited); }, ), ), + Visibility( + visible: showDeselection, + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), + child: CupertinoListTile( + title: Text(AppLocalizations.of(context).no_default_mode, + style: CustomTheme.modeTitle), + subtitle: Text( + AppLocalizations.of(context).no_default_description, + style: CustomTheme.modeDescription, + maxLines: 3, + ), + onTap: () { + Navigator.pop(context, GameMode.none); + }, + ), + )), ], ), ); diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart new file mode 100644 index 0000000..1379785 --- /dev/null +++ b/lib/presentation/views/points_view.dart @@ -0,0 +1,141 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/data/game_session.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class PointsView extends StatefulWidget { + final GameSession gameSession; + + const PointsView({super.key, required this.gameSession}); + + @override + State createState() => _PointsViewState(); +} + +class _PointsViewState extends State { + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(AppLocalizations.of(context).point_overview), + previousPageTitle: AppLocalizations.of(context).back, + ), + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: DataTable( + dataRowMinHeight: 60, + dataRowMaxHeight: 60, + dividerThickness: 0.5, + columnSpacing: 20, + columns: [ + const DataColumn( + numeric: true, + headingRowAlignment: MainAxisAlignment.center, + label: Text( + '#', + style: TextStyle(fontWeight: FontWeight.bold), + ), + columnWidth: IntrinsicColumnWidth(flex: 0.5)), + ...widget.gameSession.players.map( + (player) => DataColumn( + label: FittedBox( + fit: BoxFit.fill, + child: Text( + player, + style: const TextStyle(fontWeight: FontWeight.bold), + )), + headingRowAlignment: MainAxisAlignment.center, + columnWidth: const IntrinsicColumnWidth(flex: 1)), + ), + ], + rows: [ + ...List.generate( + widget.gameSession.roundList.length, + (roundIndex) { + final round = widget.gameSession.roundList[roundIndex]; + return DataRow( + cells: [ + DataCell(Align( + alignment: Alignment.center, + child: Text( + '${roundIndex + 1}', + style: const TextStyle(fontSize: 20), + ), + )), + ...List.generate(widget.gameSession.players.length, + (playerIndex) { + final int score = round.scores[playerIndex]; + final int update = round.scoreUpdates[playerIndex]; + final bool saidCabo = + round.caboPlayerIndex == playerIndex; + return DataCell( + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: update <= 0 + ? CustomTheme.pointLossColor + : CustomTheme.pointGainColor, + borderRadius: BorderRadius.circular(8), + ), + child: Text( + '${update >= 0 ? '+' : ''}$update', + style: const TextStyle( + color: CupertinoColors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 4), + Text('$score', + style: TextStyle( + fontWeight: saidCabo + ? FontWeight.bold + : FontWeight.normal, + )), + ], + ), + ), + ); + }), + ], + ); + }, + ), + DataRow( + cells: [ + const DataCell(Align( + alignment: Alignment.center, + child: Text( + 'Σ', + style: + TextStyle(fontSize: 25, fontWeight: FontWeight.bold), + ), + )), + ...widget.gameSession.playerScores.map( + (score) => DataCell( + Center( + child: Text( + '$score', + style: const TextStyle( + fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 7c62120..d2a9da5 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -1,6 +1,7 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; @@ -74,21 +75,22 @@ class _RoundViewState extends State { return CupertinoPageScaffold( resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( - transitionBetweenRoutes: true, - leading: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: () => - {LocalStorageService.saveGameSessions(), Navigator.pop(context)}, - child: Text(AppLocalizations.of(context).cancel), - ), - middle: Text(AppLocalizations.of(context).results), - trailing: widget.gameSession.isGameFinished - ? const Icon( + transitionBetweenRoutes: true, + leading: CupertinoButton( + padding: EdgeInsets.zero, + onPressed: () => { + LocalStorageService.saveGameSessions(), + Navigator.pop(context) + }, + child: Text(AppLocalizations.of(context).cancel), + ), + middle: Text(AppLocalizations.of(context).results), + trailing: Visibility( + visible: widget.gameSession.isGameFinished, + child: const Icon( CupertinoIcons.lock, size: 25, - ) - : null, - ), + ))), child: Stack( children: [ Positioned.fill( @@ -114,9 +116,10 @@ class _RoundViewState extends State { vertical: 10, ), child: SizedBox( - height: 40, + height: 60, child: CupertinoSegmentedControl( - unselectedColor: CustomTheme.backgroundTintColor, + unselectedColor: + CustomTheme.mainElementBackgroundColor, selectedColor: CustomTheme.primaryColor, groupValue: _caboPlayerIndex, children: Map.fromEntries(widget.gameSession.players @@ -130,7 +133,7 @@ class _RoundViewState extends State { Padding( padding: const EdgeInsets.symmetric( horizontal: 6, - vertical: 6, + vertical: 8, ), child: FittedBox( fit: BoxFit.scaleDown, @@ -154,27 +157,6 @@ class _RoundViewState extends State { ), ), ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: CupertinoListTile( - title: Text(AppLocalizations.of(context).player), - trailing: Row( - children: [ - SizedBox( - width: 100, - child: Center( - child: Text( - AppLocalizations.of(context).points))), - const SizedBox(width: 20), - SizedBox( - width: 80, - child: Center( - child: Text(AppLocalizations.of(context) - .kamikaze))), - ], - ), - ), - ), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -182,13 +164,15 @@ class _RoundViewState extends State { itemBuilder: (context, index) { final originalIndex = originalIndices[index]; final name = rotatedPlayers[index]; + bool shouldShowMedal = + index == 0 && widget.roundNumber > 1; return Padding( padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 20), child: ClipRRect( borderRadius: BorderRadius.circular(12), child: CupertinoListTile( - backgroundColor: CupertinoColors.secondaryLabel, + backgroundColor: CustomTheme.playerTileColor, title: Row(children: [ Expanded( child: Row(children: [ @@ -197,95 +181,70 @@ class _RoundViewState extends State { overflow: TextOverflow.ellipsis, ), Visibility( - visible: index == 0, + visible: shouldShowMedal, child: const SizedBox(width: 10), ), Visibility( - visible: index == 0, - child: const Icon(FontAwesomeIcons.medal, + visible: shouldShowMedal, + child: const Icon(FontAwesomeIcons.crown, size: 15)) ])) ]), subtitle: Text( '${widget.gameSession.playerScores[originalIndex]}' ' ${AppLocalizations.of(context).points}'), - trailing: Row( - children: [ - SizedBox( - width: 100, - child: CupertinoTextField( - maxLength: 3, - focusNode: _focusNodeList[originalIndex], - keyboardType: - const TextInputType.numberWithOptions( - signed: true, - decimal: false, - ), - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - ], - textInputAction: index == - widget.gameSession.players - .length - - 1 - ? TextInputAction.done - : TextInputAction.next, - controller: - _scoreControllerList[originalIndex], - placeholder: - AppLocalizations.of(context).points, - textAlign: TextAlign.center, - onSubmitted: (_) => - _focusNextTextfield(originalIndex), - onChanged: (_) => setState(() {}), - ), + trailing: SizedBox( + width: 100, + child: CupertinoTextField( + maxLength: 3, + focusNode: _focusNodeList[originalIndex], + keyboardType: + const TextInputType.numberWithOptions( + signed: true, + decimal: false, ), - const SizedBox(width: 50), - GestureDetector( - onTap: () { - setState(() { - _kamikazePlayerIndex = - (_kamikazePlayerIndex == - originalIndex) - ? null - : originalIndex; - }); - }, - child: Container( - width: 24, - height: 24, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: _kamikazePlayerIndex == - originalIndex - ? CupertinoColors.systemRed - : CupertinoColors - .tertiarySystemFill, - border: Border.all( - color: _kamikazePlayerIndex == - originalIndex - ? CupertinoColors.systemRed - : CupertinoColors.systemGrey, - ), - ), - child: _kamikazePlayerIndex == - originalIndex - ? const Icon( - CupertinoIcons.exclamationmark, - size: 16, - color: CupertinoColors.white, - ) - : null, - ), - ), - const SizedBox(width: 22), - ], + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + textInputAction: index == + widget.gameSession.players.length - 1 + ? TextInputAction.done + : TextInputAction.next, + controller: + _scoreControllerList[originalIndex], + placeholder: + AppLocalizations.of(context).points, + textAlign: TextAlign.center, + onSubmitted: (_) => + _focusNextTextfield(originalIndex), + onChanged: (_) => setState(() {}), + ), ), ), ), ); }, ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Center( + heightFactor: 1, + child: CustomButton( + onPressed: () async { + if (await _showKamikazeSheet(context)) { + if (!context.mounted) return; + _endOfRoundNavigation(context, true); + } + }, + child: Text( + AppLocalizations.of(context).kamikaze, + style: const TextStyle( + color: CupertinoColors.destructiveRed, + ), + ), + ), + ), + ), ], ), ), @@ -300,21 +259,14 @@ class _RoundViewState extends State { return Container( height: 80, padding: const EdgeInsets.only(bottom: 20), - color: CustomTheme.backgroundTintColor, + color: CustomTheme.mainElementBackgroundColor, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ CupertinoButton( onPressed: _areRoundInputsValid() - ? () async { - List bonusPlayersIndices = _finishRound(); - if (bonusPlayersIndices.isNotEmpty) { - await _showBonusPopup( - context, bonusPlayersIndices); - } - LocalStorageService.saveGameSessions(); - if (!context.mounted) return; - Navigator.pop(context); + ? () { + _endOfRoundNavigation(context, false); } : null, child: Text(AppLocalizations.of(context).done), @@ -322,21 +274,8 @@ class _RoundViewState extends State { if (!widget.gameSession.isGameFinished) CupertinoButton( onPressed: _areRoundInputsValid() - ? () async { - List bonusPlayersIndices = - _finishRound(); - if (bonusPlayersIndices.isNotEmpty) { - await _showBonusPopup( - context, bonusPlayersIndices); - } - LocalStorageService.saveGameSessions(); - if (widget.gameSession.isGameFinished && - context.mounted) { - Navigator.pop(context); - } else if (context.mounted) { - Navigator.pop( - context, widget.roundNumber + 1); - } + ? () { + _endOfRoundNavigation(context, true); } : null, child: Text(AppLocalizations.of(context).next_round), @@ -399,6 +338,37 @@ class _RoundViewState extends State { ]; } + /// Shows a Cupertino action sheet to select the player who has Kamikaze. + /// It returns true if a player was selected, false if the action was cancelled. + Future _showKamikazeSheet(BuildContext context) async { + return await showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return CupertinoActionSheet( + title: Text(AppLocalizations.of(context).kamikaze), + message: Text(AppLocalizations.of(context).who_has_kamikaze), + actions: widget.gameSession.players.asMap().entries.map((entry) { + final index = entry.key; + final name = entry.value; + return CupertinoActionSheetAction( + onPressed: () { + _kamikazePlayerIndex = index; + Navigator.pop(context, true); + }, + child: Text(name), + ); + }).toList(), + cancelButton: CupertinoActionSheetAction( + onPressed: () => Navigator.pop(context, false), + isDestructiveAction: true, + child: Text(AppLocalizations.of(context).cancel), + ), + ); + }, + ) ?? + false; + } + /// Focuses the next text field in the list of text fields. /// [index] is the index of the current text field. void _focusNextTextfield(int index) { @@ -469,10 +439,9 @@ class _RoundViewState extends State { return bonusPlayers; } - /// Shows a popup dialog with the bonus information. + /// Shows a popup dialog with the information which player received the bonus points. Future _showBonusPopup( BuildContext context, List bonusPlayers) async { - print('Bonus Popup wird angezeigt'); int pointLimit = widget.gameSession.pointLimit; int bonusPoints = (pointLimit / 2).round(); @@ -519,6 +488,37 @@ class _RoundViewState extends State { return resultText; } + /// Handles the navigation for the end of the round. + /// It checks for bonus players and shows a popup, saves the game session, + /// and navigates to the next round or back to the previous screen. + /// It takes the BuildContext [context] and a boolean [navigateToNextRound] to determine + /// if it should navigate to the next round or not. + Future _endOfRoundNavigation( + BuildContext context, bool navigateToNextRound) async { + List bonusPlayersIndices = _finishRound(); + if (bonusPlayersIndices.isNotEmpty) { + await _showBonusPopup(context, bonusPlayersIndices); + } + + LocalStorageService.saveGameSessions(); + + if (context.mounted) { + // If the game is finished, pop the context and return to the previous screen. + if (widget.gameSession.isGameFinished) { + Navigator.pop(context); + return; + } + // If navigateToNextRound is false, pop the context and return to the previous screen. + if (!navigateToNextRound) { + Navigator.pop(context); + return; + } + // If navigateToNextRound is true and the game isn't finished yet, + // pop the context and navigate to the next round. + Navigator.pop(context, widget.roundNumber + 1); + } + } + @override void dispose() { for (final controller in _scoreControllerList) { diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index d6f0833..aa49872 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,6 +1,7 @@ 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'; @@ -20,6 +21,7 @@ class SettingsView extends StatefulWidget { class _SettingsViewState extends State { UniqueKey _stepperKey1 = UniqueKey(); UniqueKey _stepperKey2 = UniqueKey(); + GameMode defaultMode = ConfigService.getGameMode(); @override void initState() { super.initState(); @@ -55,14 +57,13 @@ class _SettingsViewState extends State { prefixIcon: CupertinoIcons.bolt_fill, suffixWidget: CustomStepper( key: _stepperKey1, - initialValue: ConfigService.caboPenalty, + initialValue: ConfigService.getCaboPenalty(), minValue: 0, maxValue: 50, step: 1, onChanged: (newCaboPenalty) { setState(() { ConfigService.setCaboPenalty(newCaboPenalty); - ConfigService.caboPenalty = newCaboPenalty; }); }, ), @@ -72,18 +73,51 @@ class _SettingsViewState extends State { prefixIcon: FontAwesomeIcons.bullseye, suffixWidget: CustomStepper( key: _stepperKey2, - initialValue: ConfigService.pointLimit, + initialValue: ConfigService.getPointLimit(), minValue: 30, maxValue: 1000, step: 10, onChanged: (newPointLimit) { setState(() { ConfigService.setPointLimit(newPointLimit); - ConfigService.pointLimit = 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, @@ -93,6 +127,7 @@ class _SettingsViewState extends State { setState(() { _stepperKey1 = UniqueKey(); _stepperKey2 = UniqueKey(); + defaultMode = ConfigService.getGameMode(); }); }, ) diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 0c98cc7..08b1790 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -16,8 +16,9 @@ class _TabViewState extends State { @override Widget build(BuildContext context) { return CupertinoTabScaffold( + resizeToAvoidBottomInset: false, tabBar: CupertinoTabBar( - backgroundColor: CustomTheme.backgroundTintColor, + backgroundColor: CustomTheme.mainElementBackgroundColor, iconSize: 27, height: 55, items: [ diff --git a/lib/presentation/widgets/custom_button.dart b/lib/presentation/widgets/custom_button.dart new file mode 100644 index 0000000..0feb799 --- /dev/null +++ b/lib/presentation/widgets/custom_button.dart @@ -0,0 +1,19 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:flutter/cupertino.dart'; + +class CustomButton extends StatelessWidget { + final Widget child; + final VoidCallback? onPressed; + const CustomButton({super.key, required this.child, this.onPressed}); + + @override + Widget build(BuildContext context) { + return CupertinoButton( + sizeStyle: CupertinoButtonSize.medium, + borderRadius: BorderRadius.circular(12), + color: CustomTheme.buttonBackgroundColor, + onPressed: onPressed, + child: child, + ); + } +} diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 70f6133..1b20ad5 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -1,3 +1,4 @@ +import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// This class handles the configuration settings for the app. @@ -6,53 +7,101 @@ import 'package:shared_preferences/shared_preferences.dart'; class ConfigService { static const String _keyPointLimit = 'pointLimit'; static const String _keyCaboPenalty = 'caboPenalty'; + static const String _keyGameMode = 'gameMode'; // Actual values used in the app - static int pointLimit = 100; - static int caboPenalty = 5; + static int _pointLimit = 100; + static int _caboPenalty = 5; + static int _gameMode = -1; // Default values static const int _defaultPointLimit = 100; static const int _defaultCaboPenalty = 5; + static const int _defaultGameMode = -1; static Future initConfig() async { final prefs = await SharedPreferences.getInstance(); - // Default values only set if they are not already set - prefs.setInt( - _keyPointLimit, prefs.getInt(_keyPointLimit) ?? _defaultPointLimit); - prefs.setInt( - _keyCaboPenalty, prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty); + // Initialize pointLimit, caboPenalty, and gameMode from SharedPreferences + // If they are not set, use the default values + _pointLimit = prefs.getInt(_keyPointLimit) ?? _defaultPointLimit; + _caboPenalty = prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty; + _gameMode = prefs.getInt(_keyGameMode) ?? _defaultGameMode; + + // Save the initial values to SharedPreferences + prefs.setInt(_keyPointLimit, _pointLimit); + prefs.setInt(_keyCaboPenalty, _caboPenalty); + prefs.setInt(_keyGameMode, _gameMode); } - /// Getter for the point limit. - static Future getPointLimit() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getInt(_keyPointLimit) ?? _defaultPointLimit; + /// Retrieves the current game mode. + /// + /// The game mode is determined based on the stored integer value: + /// - `0`: [GameMode.pointLimit] + /// - `1`: [GameMode.unlimited] + /// - Any other value: [GameMode.none] (-1 is used as a default for no mode) + /// + /// Returns the corresponding [GameMode] enum value. + static GameMode getGameMode() { + switch (_gameMode) { + case 0: + return GameMode.pointLimit; + case 1: + return GameMode.unlimited; + default: + return GameMode.none; + } } + /// Sets the game mode for the application. + /// + /// [newGameMode] is the new game mode to be set. It can be one of the following: + /// - `GameMode.pointLimit`: The game ends when a pleayer reaches the point limit. + /// - `GameMode.unlimited`: Every game goes for infinity until you end it. + /// - `GameMode.none`: No default mode set. + /// + /// This method updates the `_gameMode` field and persists the value in `SharedPreferences`. + static Future setGameMode(GameMode newGameMode) async { + int gameMode; + switch (newGameMode) { + case GameMode.pointLimit: + gameMode = 0; + break; + case GameMode.unlimited: + gameMode = 1; + break; + default: + gameMode = -1; + } + + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt(_keyGameMode, gameMode); + _gameMode = gameMode; + } + + static int getPointLimit() => _pointLimit; + /// Setter for the point limit. /// [newPointLimit] is the new point limit to be set. static Future setPointLimit(int newPointLimit) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyPointLimit, newPointLimit); + _pointLimit = newPointLimit; } - /// Getter for the cabo penalty. - static Future getCaboPenalty() async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getInt(_keyCaboPenalty) ?? _defaultCaboPenalty; - } + static int getCaboPenalty() => _caboPenalty; /// Setter for the cabo penalty. /// [newCaboPenalty] is the new cabo penalty to be set. static Future setCaboPenalty(int newCaboPenalty) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyCaboPenalty, newCaboPenalty); + _caboPenalty = newCaboPenalty; } /// Resets the configuration to default values. static Future resetConfig() async { - ConfigService.pointLimit = _defaultPointLimit; - ConfigService.caboPenalty = _defaultCaboPenalty; + ConfigService._pointLimit = _defaultPointLimit; + ConfigService._caboPenalty = _defaultCaboPenalty; + ConfigService._gameMode = _defaultGameMode; final prefs = await SharedPreferences.getInstance(); await prefs.setInt(_keyPointLimit, _defaultPointLimit); await prefs.setInt(_keyCaboPenalty, _defaultCaboPenalty); diff --git a/pubspec.yaml b/pubspec.yaml index 6773a53..2ea3c92 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.7+506 +version: 0.5.3+594 environment: sdk: ^3.5.4 @@ -28,6 +28,9 @@ dependencies: syncfusion_flutter_charts: ^30.1.37 uuid: ^4.5.1 rate_my_app: ^2.3.2 + reorderables: ^0.4.2 + collection: ^1.18.0 + confetti: ^0.6.0 dev_dependencies: flutter_test: diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index 4ca2158..9654bad 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -9,6 +9,7 @@ void main() { setUp(() { session = GameSession( + id: '1', createdAt: testDate, gameTitle: testTitle, players: testPlayers, From fadc99564ff6ea2a05c31b863ee224c833ac0853 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 23 Jul 2025 11:26:09 +0200 Subject: [PATCH 274/353] Fixed bug with playing confetti on cancel button --- lib/presentation/views/active_game_view.dart | 2 ++ lib/presentation/views/round_view.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index ff9e066..d428f1c 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -453,6 +453,8 @@ class _ActiveGameViewState extends State { ), ); + if (round == -1) return; + if (widget.gameSession.isGameFinished && context.mounted) { _playFinishAnimation(context); } diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index d2a9da5..45249b4 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -80,7 +80,7 @@ class _RoundViewState extends State { padding: EdgeInsets.zero, onPressed: () => { LocalStorageService.saveGameSessions(), - Navigator.pop(context) + Navigator.pop(context, -1) }, child: Text(AppLocalizations.of(context).cancel), ), diff --git a/pubspec.yaml b/pubspec.yaml index 2ea3c92..367411f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+594 +version: 0.5.3+595 environment: sdk: ^3.5.4 From 237af7e3dc8abeb72e558a5e4cdc1e53749926f2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 23 Jul 2025 11:33:57 +0200 Subject: [PATCH 275/353] Added constant and updated docs --- lib/presentation/views/active_game_view.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index d428f1c..b05daba 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -24,11 +24,19 @@ class ActiveGameView extends StatefulWidget { } class _ActiveGameViewState extends State { + /// Constant value to represent a press on the cancel button in round view. + static const int kRoundCancelled = -1; + final confettiController = ConfettiController( duration: const Duration(seconds: 10), ); + late final GameSession gameSession; + + /// A list of the ranks for each player corresponding to their index in sortedPlayerIndices late List denseRanks; + + /// A list of player indices sorted by their scores in ascending order. late List sortedPlayerIndices; @override @@ -453,7 +461,8 @@ class _ActiveGameViewState extends State { ), ); - if (round == -1) return; + // If the user presses the cancel button + if (round == kRoundCancelled) return; if (widget.gameSession.isGameFinished && context.mounted) { _playFinishAnimation(context); From afed5fd9a3999d4841657f0826899ae648a74053 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 22:13:21 +0200 Subject: [PATCH 276/353] Fixed bug with wrong round winner --- lib/presentation/views/round_view.dart | 5 ++++- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 45249b4..964351d 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -308,7 +308,10 @@ class _RoundViewState extends State { // Iterate through the scores to find the player with the minimum score for (int i = 1; i < scores.length; i++) { - if (scores[i] < minScore) { + + // Check if the current score is less than the minimum score + // and is not negative (to avoid bonus points being considered) + if (scores[i] < minScore && !(scores[i] < 0)) { minScore = scores[i]; winnerIndex = i; } diff --git a/pubspec.yaml b/pubspec.yaml index 367411f..2658056 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+595 +version: 0.5.3+596 environment: sdk: ^3.5.4 From 69a2a7caec4efccdee13f0964901de13ac76a471 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 22:20:18 +0200 Subject: [PATCH 277/353] Updated function logic --- lib/presentation/views/round_view.dart | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 964351d..df60a69 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -294,30 +294,14 @@ class _RoundViewState extends State { } /// Gets the index of the player who won the previous round. + /// Returns 0 in the first round, as there is no previous round. int _getPreviousRoundWinnerIndex() { if (widget.roundNumber == 1) { return 0; // If it's the first round, there's no previous round, so return 0. } - final previousRound = widget.gameSession.roundList[widget.roundNumber - 2]; - final scores = previousRound.scoreUpdates; - - // Find the index of the player with the minimum score - int minScore = scores[0]; - int winnerIndex = 0; - - // Iterate through the scores to find the player with the minimum score - for (int i = 1; i < scores.length; i++) { - - // Check if the current score is less than the minimum score - // and is not negative (to avoid bonus points being considered) - if (scores[i] < minScore && !(scores[i] < 0)) { - minScore = scores[i]; - winnerIndex = i; - } - } - - return winnerIndex; + final scores = widget.gameSession.roundList[widget.roundNumber - 2].scoreUpdates; + return scores.indexOf(0); } /// Rotates the players list based on the previous round's winner. From e18874c094f2618bc6983725d199f2c9a53f67ad Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 22:24:27 +0200 Subject: [PATCH 278/353] Added fallback to _getPreviousRoundWinnerIndex() --- lib/presentation/views/round_view.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index df60a69..62319e9 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -297,11 +297,17 @@ class _RoundViewState extends State { /// Returns 0 in the first round, as there is no previous round. int _getPreviousRoundWinnerIndex() { if (widget.roundNumber == 1) { - return 0; // If it's the first round, there's no previous round, so return 0. + return 0; // If it's the first round, the order should be the same as the players list. } - final scores = widget.gameSession.roundList[widget.roundNumber - 2].scoreUpdates; - return scores.indexOf(0); + final List scores = widget.gameSession.roundList[widget.roundNumber - 2].scoreUpdates; + final int winnerIndex = scores.indexOf(0); + + // Fallback if no player has 0 points, which should not happen in a valid game. + if (winnerIndex == -1) { + return 0; + } + return winnerIndex; } /// Rotates the players list based on the previous round's winner. From 4972aaa1a9dc88102bf7b8e2debc2c74aaf4b42f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 22:28:22 +0200 Subject: [PATCH 279/353] Updated white space --- lib/presentation/views/round_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 62319e9..0c4d454 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -301,7 +301,7 @@ class _RoundViewState extends State { } final List scores = widget.gameSession.roundList[widget.roundNumber - 2].scoreUpdates; - final int winnerIndex = scores.indexOf(0); + final int winnerIndex = scores.indexOf(0); // Fallback if no player has 0 points, which should not happen in a valid game. if (winnerIndex == -1) { From 06204f0d3682b484642daaba3fa6843766f3ac22 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 22:41:24 +0200 Subject: [PATCH 280/353] Implement possibilty to reopen game --- lib/data/game_session.dart | 6 ++++++ pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index dc100a5..dca4f52 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -247,17 +247,23 @@ class GameSession extends ChangeNotifier { List updatePoints() { List bonusPlayers = []; _sumPoints(); + bool limitExceeded = false; + if (isPointsLimitEnabled) { bonusPlayers = _checkHundredPointsReached(); for (int i = 0; i < playerScores.length; i++) { if (playerScores[i] > pointLimit) { isGameFinished = true; + limitExceeded = true; print('${players[i]} hat die 100 Punkte ueberschritten, ' 'deswegen wurde das Spiel beendet'); setWinner(); } } + if (!limitExceeded) { + isGameFinished = false; + } } notifyListeners(); return bonusPlayers; diff --git a/pubspec.yaml b/pubspec.yaml index 2658056..a79e550 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+596 +version: 0.5.3+597 environment: sdk: ^3.5.4 From d4be9bffba79585e3d2f562edfd91b7128bba6a2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 22:46:53 +0200 Subject: [PATCH 281/353] Updated pointLimit shown in main menu --- lib/presentation/views/main_menu_view.dart | 9 +++++---- pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 21deb97..74a7549 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -1,6 +1,7 @@ import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; +import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; import 'package:cabo_counter/presentation/views/create_game_view.dart'; @@ -135,7 +136,7 @@ class _MainMenuViewState extends State { subtitle: Visibility( visible: session.isGameFinished, replacement: Text( - '${AppLocalizations.of(context).mode}: ${_translateGameMode(session.isPointsLimitEnabled)}', + '${AppLocalizations.of(context).mode}: ${_translateGameMode(session)}', style: const TextStyle(fontSize: 14), ), child: Text( @@ -216,9 +217,9 @@ class _MainMenuViewState extends State { /// Translates the game mode boolean into the corresponding String. /// If [pointLimit] is true, it returns '101 Punkte', otherwise it returns 'Unbegrenzt'. - String _translateGameMode(bool isPointLimitEnabled) { - if (isPointLimitEnabled) { - return '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}'; + String _translateGameMode(GameSession gameSession) { + if (gameSession.isPointsLimitEnabled) { + return '${gameSession.pointLimit} ${AppLocalizations.of(context).points}'; } return AppLocalizations.of(context).unlimited; } diff --git a/pubspec.yaml b/pubspec.yaml index a79e550..a67a45f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+597 +version: 0.5.3+598 environment: sdk: ^3.5.4 From 1652fcd946491f0470a306bde7ac960218189418 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 23:04:02 +0200 Subject: [PATCH 282/353] Update var --- lib/data/game_session.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index dca4f52..ddc3104 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -247,10 +247,10 @@ class GameSession extends ChangeNotifier { List updatePoints() { List bonusPlayers = []; _sumPoints(); - bool limitExceeded = false; if (isPointsLimitEnabled) { bonusPlayers = _checkHundredPointsReached(); + bool limitExceeded = false; for (int i = 0; i < playerScores.length; i++) { if (playerScores[i] > pointLimit) { From 1239f7fe08560ec865c297e9f980e8a1b3503204 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 23:14:57 +0200 Subject: [PATCH 283/353] Implement image caching --- lib/presentation/views/main_menu_view.dart | 7 +++++++ pubspec.yaml | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 74a7549..5ba9859 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -49,6 +49,13 @@ class _MainMenuViewState extends State { }); } + @override + void didChangeDependencies() { + precacheImage( + const AssetImage('assets/cabo_counter-logo_rounded.png'), context); + super.didChangeDependencies(); + } + void _updateView() { if (mounted) setState(() {}); } diff --git a/pubspec.yaml b/pubspec.yaml index a67a45f..68b8523 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+598 +version: 0.5.3+604 environment: sdk: ^3.5.4 @@ -31,6 +31,7 @@ dependencies: reorderables: ^0.4.2 collection: ^1.18.0 confetti: ^0.6.0 + flutter_cache_manager: ^3.3.0 dev_dependencies: flutter_test: From cb66159493a11e697148753dc0e9505d865c3a9b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 23:18:27 +0200 Subject: [PATCH 284/353] Updated version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 68b8523..961e6cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.3+604 +version: 0.5.4+604 environment: sdk: ^3.5.4 From f5078a512bc67ceb0ec0494db30c1542992561cb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 24 Jul 2025 23:24:49 +0200 Subject: [PATCH 285/353] Updated caching placement --- lib/presentation/views/main_menu_view.dart | 9 ++------- pubspec.yaml | 3 +-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 5ba9859..0ad5cfa 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -38,6 +38,8 @@ class _MainMenuViewState extends State { gameManager.addListener(_updateView); WidgetsBinding.instance.addPostFrameCallback((_) async { + precacheImage( + const AssetImage('assets/cabo_counter-logo_rounded.png'), context); await Constants.rateMyApp.init(); if (Constants.rateMyApp.shouldOpenDialog && @@ -49,13 +51,6 @@ class _MainMenuViewState extends State { }); } - @override - void didChangeDependencies() { - precacheImage( - const AssetImage('assets/cabo_counter-logo_rounded.png'), context); - super.didChangeDependencies(); - } - void _updateView() { if (mounted) setState(() {}); } diff --git a/pubspec.yaml b/pubspec.yaml index 961e6cb..abca6e8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+604 +version: 0.5.4+605 environment: sdk: ^3.5.4 @@ -31,7 +31,6 @@ dependencies: reorderables: ^0.4.2 collection: ^1.18.0 confetti: ^0.6.0 - flutter_cache_manager: ^3.3.0 dev_dependencies: flutter_test: From 7fd5fab8c08e39db7f737e61ccd5d296a55abacb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 31 Jul 2025 22:45:31 +0200 Subject: [PATCH 286/353] Fixed keyboard bug --- lib/presentation/views/create_game_view.dart | 6 ++++-- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 193cdff..a767991 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -289,7 +289,6 @@ class _CreateGameViewState extends State { Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), child: Center( - key: const ValueKey('create_game_button'), child: CustomButton( child: Text( AppLocalizations.of(context).create_game, @@ -298,7 +297,10 @@ class _CreateGameViewState extends State { ), ), onPressed: () { - _checkAllGameAttributes(); + FocusScope.of(context).unfocus(); + Future.delayed(const Duration(milliseconds: 300), () { + _checkAllGameAttributes(); + }); }, ), ), diff --git a/pubspec.yaml b/pubspec.yaml index abca6e8..216777c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+605 +version: 0.5.4+608 environment: sdk: ^3.5.4 From 5e812717c7769cf76a5820bbeebd50f05916f47c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 31 Jul 2025 22:56:33 +0200 Subject: [PATCH 287/353] Updated colors and changed button color --- lib/core/custom_theme.dart | 2 ++ lib/presentation/views/active_game_view.dart | 5 +++-- lib/presentation/views/create_game_view.dart | 4 ++-- lib/presentation/views/main_menu_view.dart | 2 +- lib/presentation/views/round_view.dart | 18 ++++++++++-------- pubspec.yaml | 2 +- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index bfc4f3c..74b735f 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -2,11 +2,13 @@ import 'package:flutter/cupertino.dart'; class CustomTheme { static Color white = CupertinoColors.white; + static Color red = CupertinoColors.destructiveRed; static Color primaryColor = CupertinoColors.systemGreen; static Color backgroundColor = const Color(0xFF101010); static Color mainElementBackgroundColor = CupertinoColors.darkBackgroundGray; static Color playerTileColor = CupertinoColors.secondaryLabel; static Color buttonBackgroundColor = const Color(0xFF202020); + static Color kamikazeColor = CupertinoColors.systemYellow; // Line Colors for GraphView static const Color graphColor1 = Color(0xFFF44336); diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index b05daba..ab18c76 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -311,11 +311,12 @@ class _ActiveGameViewState extends State { content: Text(AppLocalizations.of(context).end_game_message), actions: [ CupertinoDialogAction( + isDestructiveAction: true, child: Text( AppLocalizations.of(context).end_game, style: const TextStyle( - fontWeight: FontWeight.bold, - color: CupertinoColors.destructiveRed), + fontWeight: FontWeight.bold, + ), ), onPressed: () { setState(() { diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 193cdff..a868998 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -176,9 +176,9 @@ class _CreateGameViewState extends State { children: [ CupertinoButton( padding: EdgeInsets.zero, - child: const Icon( + child: Icon( CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, + color: CustomTheme.red, size: 25, ), onPressed: () { diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 0ad5cfa..0603622 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -109,7 +109,7 @@ class _MainMenuViewState extends State { return Dismissible( key: Key(session.id), background: Container( - color: CupertinoColors.destructiveRed, + color: CustomTheme.red, alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20.0), child: const Icon( diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index 0c4d454..b20255b 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -236,12 +236,10 @@ class _RoundViewState extends State { _endOfRoundNavigation(context, true); } }, - child: Text( - AppLocalizations.of(context).kamikaze, - style: const TextStyle( - color: CupertinoColors.destructiveRed, - ), - ), + child: Text(AppLocalizations.of(context).kamikaze, + style: TextStyle( + color: CustomTheme.kamikazeColor, + )), ), ), ), @@ -300,7 +298,8 @@ class _RoundViewState extends State { return 0; // If it's the first round, the order should be the same as the players list. } - final List scores = widget.gameSession.roundList[widget.roundNumber - 2].scoreUpdates; + final List scores = + widget.gameSession.roundList[widget.roundNumber - 2].scoreUpdates; final int winnerIndex = scores.indexOf(0); // Fallback if no player has 0 points, which should not happen in a valid game. @@ -348,7 +347,10 @@ class _RoundViewState extends State { _kamikazePlayerIndex = index; Navigator.pop(context, true); }, - child: Text(name), + child: Text( + name, + style: TextStyle(color: CustomTheme.kamikazeColor), + ), ); }).toList(), cancelButton: CupertinoActionSheetAction( diff --git a/pubspec.yaml b/pubspec.yaml index abca6e8..6e937cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+605 +version: 0.5.4+606 environment: sdk: ^3.5.4 From 052f7aab8e9826856096caf47adf86059bcd3a6c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 31 Jul 2025 22:57:06 +0200 Subject: [PATCH 288/353] Increased version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 6e937cf..df8ca8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+606 +version: 0.5.5+606 environment: sdk: ^3.5.4 From a4befd5bb8ca771c2d7d04ea7bfba015bfafd18c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 31 Jul 2025 23:02:24 +0200 Subject: [PATCH 289/353] Implemented named constant --- lib/core/constants.dart | 3 +++ lib/presentation/views/create_game_view.dart | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index e1c2f8d..4a215f7 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -28,4 +28,7 @@ class Constants { /// Duration in milliseconds for the fade-in animation of texts. static const int fadeInDuration = 300; + + /// Duration in milliseconds for the keyboard to fully disappear. + static const int kKeyboardDelay = 300; } diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index a767991..6eab929 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -298,7 +298,9 @@ class _CreateGameViewState extends State { ), onPressed: () { FocusScope.of(context).unfocus(); - Future.delayed(const Duration(milliseconds: 300), () { + Future.delayed( + const Duration( + milliseconds: Constants.kKeyboardDelay), () { _checkAllGameAttributes(); }); }, From e201a26b6d59c300eb93abe4584204c67e1c95d7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 31 Jul 2025 23:02:52 +0200 Subject: [PATCH 290/353] Updated constant names --- lib/core/constants.dart | 6 +++--- lib/presentation/views/active_game_view.dart | 4 ++-- lib/presentation/views/create_game_view.dart | 2 +- lib/presentation/views/main_menu_view.dart | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 4a215f7..54c2c62 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -21,13 +21,13 @@ class Constants { remindLaunches: 40); /// Delay in milliseconds before a pop-up appears. - static const int popUpDelay = 300; + static const int kPopUpDelay = 300; /// Delay in milliseconds before the round view appears after the previous one is closed. - static const int roundViewDelay = 600; + static const int kRoundViewDelay = 600; /// Duration in milliseconds for the fade-in animation of texts. - static const int fadeInDuration = 300; + static const int kFadeInDuration = 300; /// Duration in milliseconds for the keyboard to fully disappear. static const int kKeyboardDelay = 300; diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/active_game_view.dart index b05daba..1a944f5 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/active_game_view.dart @@ -472,7 +472,7 @@ class _ActiveGameViewState extends State { if (round != null && round >= 0) { WidgetsBinding.instance.addPostFrameCallback((_) async { await Future.delayed( - const Duration(milliseconds: Constants.roundViewDelay)); + const Duration(milliseconds: Constants.kRoundViewDelay)); if (context.mounted) { _openRoundView(context, round); } @@ -488,7 +488,7 @@ class _ActiveGameViewState extends State { confettiController.play(); - await Future.delayed(const Duration(milliseconds: Constants.popUpDelay)); + await Future.delayed(const Duration(milliseconds: Constants.kPopUpDelay)); if (context.mounted) { showCupertinoDialog( diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 6eab929..a85f14f 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -216,7 +216,7 @@ class _CreateGameViewState extends State { ? 1.0 : 0.0, duration: const Duration( - milliseconds: Constants.fadeInDuration), + milliseconds: Constants.kFadeInDuration), child: Padding( padding: const EdgeInsets.only(right: 8.0), child: ReorderableDragStartListener( diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 0ad5cfa..f2ab020 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -245,7 +245,7 @@ class _MainMenuViewState extends State { BadRatingDialogDecision badRatingDecision = BadRatingDialogDecision.cancel; // so that the bad rating dialog is not shown immediately - await Future.delayed(const Duration(milliseconds: Constants.popUpDelay)); + await Future.delayed(const Duration(milliseconds: Constants.kPopUpDelay)); switch (preRatingDecision) { case PreRatingDialogDecision.yes: From bb43bd2d4b0691f7ead264913a6a21532b0738d8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 1 Aug 2025 13:21:22 +0200 Subject: [PATCH 291/353] Build no --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 0873c95..95e9bab 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+609 +version: 0.5.4+613 environment: sdk: ^3.5.4 From 3346bfe6d972bd272654cf1afe93eb5eac0f31b1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 Aug 2025 16:44:17 +0200 Subject: [PATCH 292/353] Updated graph padding --- lib/presentation/views/graph_view.dart | 43 +++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index da9f8e7..d67507a 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -30,29 +30,28 @@ class _GraphViewState extends State { middle: Text(AppLocalizations.of(context).scoring_history), previousPageTitle: AppLocalizations.of(context).back, ), - child: Visibility( - visible: widget.gameSession.roundNumber > 1 || - widget.gameSession.isGameFinished, - replacement: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Center( - child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), - ), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 40), - child: Text( - AppLocalizations.of(context).empty_graph_text, - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 16), + child: SafeArea( + child: Visibility( + visible: widget.gameSession.roundNumber > 1 || + widget.gameSession.isGameFinished, + replacement: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Center( + child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), ), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: Text( + AppLocalizations.of(context).empty_graph_text, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ), + ), + ], + ), child: SfCartesianChart( enableAxisAnimation: true, legend: const Legend( From 287294526a4d0c1ecef9f57f3d925ad256ceb69f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 Aug 2025 16:44:31 +0200 Subject: [PATCH 293/353] Implemented new point view --- lib/presentation/views/points_view.dart | 259 +++++++++++++----------- pubspec.yaml | 2 +- 2 files changed, 145 insertions(+), 116 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 1379785..64ea452 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -17,125 +17,154 @@ class _PointsViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).point_overview), - previousPageTitle: AppLocalizations.of(context).back, - ), - child: SingleChildScrollView( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: DataTable( - dataRowMinHeight: 60, - dataRowMaxHeight: 60, - dividerThickness: 0.5, - columnSpacing: 20, - columns: [ - const DataColumn( - numeric: true, - headingRowAlignment: MainAxisAlignment.center, - label: Text( - '#', - style: TextStyle(fontWeight: FontWeight.bold), - ), - columnWidth: IntrinsicColumnWidth(flex: 0.5)), - ...widget.gameSession.players.map( - (player) => DataColumn( - label: FittedBox( - fit: BoxFit.fill, - child: Text( - player, - style: const TextStyle(fontWeight: FontWeight.bold), - )), - headingRowAlignment: MainAxisAlignment.center, - columnWidth: const IntrinsicColumnWidth(flex: 1)), - ), - ], - rows: [ - ...List.generate( - widget.gameSession.roundList.length, - (roundIndex) { - final round = widget.gameSession.roundList[roundIndex]; - return DataRow( - cells: [ - DataCell(Align( - alignment: Alignment.center, - child: Text( - '${roundIndex + 1}', - style: const TextStyle(fontSize: 20), - ), - )), - ...List.generate(widget.gameSession.players.length, - (playerIndex) { - final int score = round.scores[playerIndex]; - final int update = round.scoreUpdates[playerIndex]; - final bool saidCabo = - round.caboPlayerIndex == playerIndex; - return DataCell( - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: update <= 0 - ? CustomTheme.pointLossColor - : CustomTheme.pointGainColor, - borderRadius: BorderRadius.circular(8), - ), - child: Text( - '${update >= 0 ? '+' : ''}$update', - style: const TextStyle( - color: CupertinoColors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 4), - Text('$score', - style: TextStyle( - fontWeight: saidCabo - ? FontWeight.bold - : FontWeight.normal, - )), - ], + navigationBar: CupertinoNavigationBar( + middle: Text(AppLocalizations.of(context).point_overview), + previousPageTitle: AppLocalizations.of(context).back, + ), + child: SafeArea(child: LayoutBuilder(builder: (context, constraints) { + final int columnCount = 1 + widget.gameSession.players.length; + final double columnWidth = constraints.maxWidth / columnCount; + + return SingleChildScrollView( + scrollDirection: Axis.vertical, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: constraints.maxWidth), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: DataTable( + dataRowMaxHeight: 60, + dataRowMinHeight: 60, + columnSpacing: 20, + columns: [ + const DataColumn( + label: SizedBox( + width: 18, + child: Text( + '#', + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, ), ), - ); - }), - ], - ); - }, - ), - DataRow( - cells: [ - const DataCell(Align( - alignment: Alignment.center, - child: Text( - 'Σ', - style: - TextStyle(fontSize: 25, fontWeight: FontWeight.bold), - ), - )), - ...widget.gameSession.playerScores.map( - (score) => DataCell( - Center( - child: Text( - '$score', - style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.bold), + numeric: true, ), - ), + ...widget.gameSession.players.map( + (player) => DataColumn( + label: SizedBox( + width: columnWidth, + child: Text( + player, + style: const TextStyle( + fontWeight: FontWeight.bold), + overflow: TextOverflow.ellipsis, + softWrap: true, + maxLines: 2, + textAlign: TextAlign.center, + ), + ), + ), + ), + ], + rows: [ + ...List.generate( + widget.gameSession.roundList.length, + (roundIndex) { + final round = + widget.gameSession.roundList[roundIndex]; + return DataRow( + cells: [ + DataCell(Align( + alignment: Alignment.center, + child: Text( + '${roundIndex + 1}', + style: const TextStyle(fontSize: 20), + ), + )), + ...List.generate( + widget.gameSession.players.length, + (playerIndex) { + final int score = round.scores[playerIndex]; + final int update = + round.scoreUpdates[playerIndex]; + final bool saidCabo = + round.caboPlayerIndex == playerIndex; + return DataCell( + Center( + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + const SizedBox( + height: 5, + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: update <= 0 + ? CustomTheme.pointLossColor + : CustomTheme.pointGainColor, + borderRadius: + BorderRadius.circular(8), + ), + child: Text( + '${update >= 0 ? '+' : ''}$update', + style: const TextStyle( + color: CupertinoColors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 4), + Text('$score', + style: TextStyle( + decorationThickness: 1, + decoration: saidCabo + ? TextDecoration.underline + : TextDecoration.none, + fontWeight: saidCabo + ? FontWeight.bold + : FontWeight.normal, + )), + ], + ), + ), + ); + }), + ], + ); + }, + ), + DataRow( + cells: [ + const DataCell(Align( + alignment: Alignment.center, + child: Text( + 'Σ', + style: TextStyle( + fontSize: 25, fontWeight: FontWeight.bold), + ), + )), + ...widget.gameSession.playerScores.map( + (score) => DataCell( + Center( + child: Text( + '$score', + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold), + ), + ), + ), + ), + ], + ), + ], ), ), - ], - ), - ], - ), - ), - ), - ); + ), + )); + }))); } } diff --git a/pubspec.yaml b/pubspec.yaml index 95e9bab..8d46244 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+613 +version: 0.5.4+616 environment: sdk: ^3.5.4 From bd8d3562354faf43a112ccb5305f5fc256a812ca Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 Aug 2025 17:08:11 +0200 Subject: [PATCH 294/353] Removed horizontal scrollbar and adjusted text width --- lib/presentation/views/points_view.dart | 227 ++++++++++++------------ pubspec.yaml | 2 +- 2 files changed, 115 insertions(+), 114 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 64ea452..b914be6 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -27,32 +27,33 @@ class _PointsViewState extends State { return SingleChildScrollView( scrollDirection: Axis.vertical, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: constraints.maxWidth), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: DataTable( - dataRowMaxHeight: 60, - dataRowMinHeight: 60, - columnSpacing: 20, - columns: [ - const DataColumn( - label: SizedBox( - width: 18, - child: Text( - '#', - style: TextStyle(fontWeight: FontWeight.bold), - textAlign: TextAlign.center, - ), + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: constraints.maxWidth), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: DataTable( + dataRowMaxHeight: 60, + dataRowMinHeight: 60, + columnSpacing: 0, + columns: [ + const DataColumn( + label: SizedBox( + width: 18, + child: Text( + '#', + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, ), - numeric: true, ), - ...widget.gameSession.players.map( - (player) => DataColumn( - label: SizedBox( - width: columnWidth, + numeric: true, + ), + ...widget.gameSession.players.map( + (player) => DataColumn( + label: SizedBox( + width: columnWidth, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 4), child: Text( player, style: const TextStyle( @@ -65,103 +66,103 @@ class _PointsViewState extends State { ), ), ), - ], - rows: [ - ...List.generate( - widget.gameSession.roundList.length, - (roundIndex) { - final round = - widget.gameSession.roundList[roundIndex]; - return DataRow( - cells: [ - DataCell(Align( - alignment: Alignment.center, - child: Text( - '${roundIndex + 1}', - style: const TextStyle(fontSize: 20), - ), - )), - ...List.generate( - widget.gameSession.players.length, - (playerIndex) { - final int score = round.scores[playerIndex]; - final int update = - round.scoreUpdates[playerIndex]; - final bool saidCabo = - round.caboPlayerIndex == playerIndex; - return DataCell( - Center( - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - const SizedBox( - height: 5, + ), + ], + rows: [ + ...List.generate( + widget.gameSession.roundList.length, + (roundIndex) { + final round = + widget.gameSession.roundList[roundIndex]; + return DataRow( + cells: [ + DataCell(Align( + alignment: Alignment.center, + child: Text( + '${roundIndex + 1}', + style: const TextStyle(fontSize: 20), + ), + )), + ...List.generate( + widget.gameSession.players.length, + (playerIndex) { + final int score = round.scores[playerIndex]; + final int update = + round.scoreUpdates[playerIndex]; + final bool saidCabo = + round.caboPlayerIndex == playerIndex; + return DataCell( + Center( + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + const SizedBox( + height: 5, + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: update <= 0 + ? CustomTheme.pointLossColor + : CustomTheme.pointGainColor, + borderRadius: + BorderRadius.circular(8), ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: update <= 0 - ? CustomTheme.pointLossColor - : CustomTheme.pointGainColor, - borderRadius: - BorderRadius.circular(8), - ), - child: Text( - '${update >= 0 ? '+' : ''}$update', - style: const TextStyle( - color: CupertinoColors.white, - fontWeight: FontWeight.bold, - ), + child: Text( + '${update >= 0 ? '+' : ''}$update', + style: const TextStyle( + color: CupertinoColors.white, + fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 4), - Text('$score', - style: TextStyle( - decorationThickness: 1, - decoration: saidCabo - ? TextDecoration.underline - : TextDecoration.none, - fontWeight: saidCabo - ? FontWeight.bold - : FontWeight.normal, - )), - ], - ), + ), + const SizedBox(height: 4), + Text('$score', + style: TextStyle( + decorationThickness: 1, + decoration: saidCabo + ? TextDecoration.underline + : TextDecoration.none, + fontWeight: saidCabo + ? FontWeight.bold + : FontWeight.normal, + )), + ], ), - ); - }), - ], - ); - }, - ), - DataRow( - cells: [ - const DataCell(Align( - alignment: Alignment.center, - child: Text( - 'Σ', - style: TextStyle( - fontSize: 25, fontWeight: FontWeight.bold), - ), - )), - ...widget.gameSession.playerScores.map( - (score) => DataCell( - Center( - child: Text( - '$score', - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold), ), + ); + }), + ], + ); + }, + ), + DataRow( + cells: [ + const DataCell(Align( + alignment: Alignment.center, + child: Text( + 'Σ', + style: TextStyle( + fontSize: 25, fontWeight: FontWeight.bold), + ), + )), + ...widget.gameSession.playerScores.map( + (score) => DataCell( + Center( + child: Text( + '$score', + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold), ), ), ), - ], - ), - ], - ), + ), + ], + ), + ], ), ), )); diff --git a/pubspec.yaml b/pubspec.yaml index 8d46244..2a96a6a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+616 +version: 0.5.4+622 environment: sdk: ^3.5.4 From 1974cff35f5911806d6a2529a3d46476bc31b442 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 Aug 2025 17:57:30 +0200 Subject: [PATCH 295/353] Updated table width calculation and formatting --- lib/presentation/views/points_view.dart | 48 +++++++++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index b914be6..3db61ef 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -22,23 +22,31 @@ class _PointsViewState extends State { previousPageTitle: AppLocalizations.of(context).back, ), child: SafeArea(child: LayoutBuilder(builder: (context, constraints) { - final int columnCount = 1 + widget.gameSession.players.length; - final double columnWidth = constraints.maxWidth / columnCount; + const double roundColWidth = 35; + const double tablePadding = 8; + final int playerCount = widget.gameSession.players.length; + final double playerColWidth = + (constraints.maxWidth - roundColWidth - (tablePadding)) / + playerCount; + print('Column width: $playerColWidth'); + print('Max width: ${constraints.maxWidth}'); + print('Round column width: $roundColWidth'); return SingleChildScrollView( scrollDirection: Axis.vertical, child: ConstrainedBox( - constraints: BoxConstraints(minWidth: constraints.maxWidth), + constraints: BoxConstraints(maxWidth: constraints.maxWidth), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.symmetric(horizontal: tablePadding), child: DataTable( - dataRowMaxHeight: 60, - dataRowMinHeight: 60, + dataRowMaxHeight: 65, + dataRowMinHeight: 65, columnSpacing: 0, + horizontalMargin: 0, columns: [ const DataColumn( label: SizedBox( - width: 18, + width: roundColWidth, child: Text( '#', style: TextStyle(fontWeight: FontWeight.bold), @@ -50,10 +58,10 @@ class _PointsViewState extends State { ...widget.gameSession.players.map( (player) => DataColumn( label: SizedBox( - width: columnWidth, + width: playerColWidth, child: Padding( padding: - const EdgeInsets.symmetric(horizontal: 4), + const EdgeInsets.symmetric(horizontal: 8), child: Text( player, style: const TextStyle( @@ -119,16 +127,26 @@ class _PointsViewState extends State { ), ), const SizedBox(height: 4), - Text('$score', + Container( + padding: const EdgeInsets.symmetric( + horizontal: 4, vertical: 2), + decoration: BoxDecoration( + color: saidCabo + ? const Color(0xFF505050) + : CupertinoColors.transparent, + borderRadius: + BorderRadius.circular(5), + ), + child: Text( + '$score', style: TextStyle( - decorationThickness: 1, - decoration: saidCabo - ? TextDecoration.underline - : TextDecoration.none, + color: CustomTheme.white, fontWeight: saidCabo ? FontWeight.bold : FontWeight.normal, - )), + ), + ), + ), ], ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 2a96a6a..5b3cf65 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.4+622 +version: 0.5.5+633 environment: sdk: ^3.5.4 From 7518d006b8be73cd32c4a306695a120463199d01 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 Aug 2025 18:07:07 +0200 Subject: [PATCH 296/353] Removed prints --- lib/presentation/views/points_view.dart | 3 --- pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 3db61ef..692622d 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -28,9 +28,6 @@ class _PointsViewState extends State { final double playerColWidth = (constraints.maxWidth - roundColWidth - (tablePadding)) / playerCount; - print('Column width: $playerColWidth'); - print('Max width: ${constraints.maxWidth}'); - print('Round column width: $roundColWidth'); return SingleChildScrollView( scrollDirection: Axis.vertical, diff --git a/pubspec.yaml b/pubspec.yaml index 5b3cf65..80cf6ca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.5+633 +version: 0.5.5+634 environment: sdk: ^3.5.4 From 03462808c24b8805a7a5e01ba6c5fd8d3c0a3136 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 Aug 2025 18:20:12 +0200 Subject: [PATCH 297/353] Adjusted cabo player highlighting --- lib/presentation/views/points_view.dart | 84 +++++++++++++------------ pubspec.yaml | 2 +- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 692622d..a850bf2 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -36,8 +36,8 @@ class _PointsViewState extends State { child: Padding( padding: const EdgeInsets.symmetric(horizontal: tablePadding), child: DataTable( - dataRowMaxHeight: 65, - dataRowMinHeight: 65, + dataRowMaxHeight: 75, + dataRowMinHeight: 75, columnSpacing: 0, horizontalMargin: 0, columns: [ @@ -96,45 +96,47 @@ class _PointsViewState extends State { round.scoreUpdates[playerIndex]; final bool saidCabo = round.caboPlayerIndex == playerIndex; - return DataCell( - Center( - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - const SizedBox( - height: 5, - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: update <= 0 - ? CustomTheme.pointLossColor - : CustomTheme.pointGainColor, - borderRadius: - BorderRadius.circular(8), + return DataCell(Center( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 6.0), + child: Container( + width: playerColWidth * + (playerCount * + 0.2), // Adjust width based on amount of players + decoration: BoxDecoration( + color: saidCabo + ? CustomTheme.buttonBackgroundColor + : CupertinoColors.transparent, + borderRadius: BorderRadius.circular(5), + ), + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + const SizedBox( + height: 5, ), - child: Text( - '${update >= 0 ? '+' : ''}$update', - style: const TextStyle( - color: CupertinoColors.white, - fontWeight: FontWeight.bold, + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: update <= 0 + ? CustomTheme.pointLossColor + : CustomTheme.pointGainColor, + borderRadius: + BorderRadius.circular(6), + ), + child: Text( + '${update >= 0 ? '+' : ''}$update', + style: const TextStyle( + color: CupertinoColors.white, + fontWeight: FontWeight.bold, + ), ), ), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, vertical: 2), - decoration: BoxDecoration( - color: saidCabo - ? const Color(0xFF505050) - : CupertinoColors.transparent, - borderRadius: - BorderRadius.circular(5), - ), - child: Text( + const SizedBox(height: 4), + Text( '$score', style: TextStyle( color: CustomTheme.white, @@ -143,11 +145,11 @@ class _PointsViewState extends State { : FontWeight.normal, ), ), - ), - ], + ], + ), ), ), - ); + )); }), ], ); diff --git a/pubspec.yaml b/pubspec.yaml index 80cf6ca..58f0816 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.5+634 +version: 0.5.5+636 environment: sdk: ^3.5.4 From e265a671ffcd9775d6eeaf92852a9c6f2ed0ddab Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 Aug 2025 18:57:18 +0200 Subject: [PATCH 298/353] Added sticky header to table --- lib/presentation/views/points_view.dart | 276 +++++++++++++++--------- pubspec.yaml | 2 +- 2 files changed, 172 insertions(+), 106 deletions(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index a850bf2..2927d94 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -29,15 +29,15 @@ class _PointsViewState extends State { (constraints.maxWidth - roundColWidth - (tablePadding)) / playerCount; - return SingleChildScrollView( - scrollDirection: Axis.vertical, - child: ConstrainedBox( + return Column( + children: [ + ConstrainedBox( constraints: BoxConstraints(maxWidth: constraints.maxWidth), child: Padding( padding: const EdgeInsets.symmetric(horizontal: tablePadding), child: DataTable( - dataRowMaxHeight: 75, - dataRowMinHeight: 75, + dataRowMaxHeight: 0, + dataRowMinHeight: 0, columnSpacing: 0, horizontalMargin: 0, columns: [ @@ -73,116 +73,182 @@ class _PointsViewState extends State { ), ), ], - rows: [ - ...List.generate( - widget.gameSession.roundList.length, - (roundIndex) { - final round = - widget.gameSession.roundList[roundIndex]; - return DataRow( - cells: [ - DataCell(Align( - alignment: Alignment.center, + rows: const [], + ), + ), + ), + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: ConstrainedBox( + constraints: + BoxConstraints(maxWidth: constraints.maxWidth), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: tablePadding), + child: DataTable( + dataRowMaxHeight: 75, + dataRowMinHeight: 75, + columnSpacing: 0, + horizontalMargin: 0, + headingRowHeight: 0, + columns: [ + const DataColumn( + label: SizedBox( + width: roundColWidth, child: Text( - '${roundIndex + 1}', - style: const TextStyle(fontSize: 20), + '#', + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, ), - )), - ...List.generate( - widget.gameSession.players.length, - (playerIndex) { - final int score = round.scores[playerIndex]; - final int update = - round.scoreUpdates[playerIndex]; - final bool saidCabo = - round.caboPlayerIndex == playerIndex; - return DataCell(Center( + ), + numeric: true, + ), + ...widget.gameSession.players.map( + (player) => DataColumn( + label: SizedBox( + width: playerColWidth, child: Padding( padding: const EdgeInsets.symmetric( - vertical: 6.0), - child: Container( - width: playerColWidth * - (playerCount * - 0.2), // Adjust width based on amount of players - decoration: BoxDecoration( - color: saidCabo - ? CustomTheme.buttonBackgroundColor - : CupertinoColors.transparent, - borderRadius: BorderRadius.circular(5), - ), - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - const SizedBox( - height: 5, - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: update <= 0 - ? CustomTheme.pointLossColor - : CustomTheme.pointGainColor, - borderRadius: - BorderRadius.circular(6), - ), - child: Text( - '${update >= 0 ? '+' : ''}$update', - style: const TextStyle( - color: CupertinoColors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 4), - Text( - '$score', - style: TextStyle( - color: CustomTheme.white, - fontWeight: saidCabo - ? FontWeight.bold - : FontWeight.normal, - ), - ), - ], - ), + horizontal: 8), + child: Text( + player, + style: const TextStyle( + fontWeight: FontWeight.bold), + overflow: TextOverflow.ellipsis, + softWrap: true, + maxLines: 2, + textAlign: TextAlign.center, ), ), - )); - }), - ], - ); - }, - ), - DataRow( - cells: [ - const DataCell(Align( - alignment: Alignment.center, - child: Text( - 'Σ', - style: TextStyle( - fontSize: 25, fontWeight: FontWeight.bold), - ), - )), - ...widget.gameSession.playerScores.map( - (score) => DataCell( - Center( - child: Text( - '$score', - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold), ), ), ), - ), - ], + ], + rows: [ + ...List.generate( + widget.gameSession.roundList.length, + (roundIndex) { + final round = + widget.gameSession.roundList[roundIndex]; + return DataRow( + cells: [ + DataCell(Align( + alignment: Alignment.center, + child: Text( + '${roundIndex + 1}', + style: const TextStyle(fontSize: 20), + ), + )), + ...List.generate( + widget.gameSession.players.length, + (playerIndex) { + final int score = + round.scores[playerIndex]; + final int update = + round.scoreUpdates[playerIndex]; + final bool saidCabo = + round.caboPlayerIndex == playerIndex; + return DataCell(Center( + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 6.0), + child: Container( + width: playerColWidth * + (playerCount * + 0.2), // Adjust width based on amount of players + decoration: BoxDecoration( + color: saidCabo + ? CustomTheme + .buttonBackgroundColor + : CupertinoColors.transparent, + borderRadius: + BorderRadius.circular(5), + ), + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + const SizedBox( + height: 5, + ), + Container( + padding: const EdgeInsets + .symmetric( + horizontal: 6, + vertical: 2), + decoration: BoxDecoration( + color: update <= 0 + ? CustomTheme + .pointLossColor + : CustomTheme + .pointGainColor, + borderRadius: + BorderRadius.circular( + 6), + ), + child: Text( + '${update >= 0 ? '+' : ''}$update', + style: const TextStyle( + color: + CupertinoColors.white, + fontWeight: + FontWeight.bold, + ), + ), + ), + const SizedBox(height: 4), + Text( + '$score', + style: TextStyle( + color: CustomTheme.white, + fontWeight: saidCabo + ? FontWeight.bold + : FontWeight.normal, + ), + ), + ], + ), + ), + ), + )); + }), + ], + ); + }, + ), + DataRow( + cells: [ + const DataCell(Align( + alignment: Alignment.center, + child: Text( + 'Σ', + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold), + ), + )), + ...widget.gameSession.playerScores.map( + (score) => DataCell( + Center( + child: Text( + '$score', + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold), + ), + ), + ), + ), + ], + ), + ], + ), ), - ], - ), - ), - )); + )), + ), + ], + ); }))); } } diff --git a/pubspec.yaml b/pubspec.yaml index 58f0816..f59ec44 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.5+636 +version: 0.5.5+639 environment: sdk: ^3.5.4 From 231c0442448412bd4b1d9a7e84eafde198de6779 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 19:36:44 +0200 Subject: [PATCH 299/353] Added named constant --- lib/presentation/views/points_view.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 2927d94..161d72e 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -22,6 +22,7 @@ class _PointsViewState extends State { previousPageTitle: AppLocalizations.of(context).back, ), child: SafeArea(child: LayoutBuilder(builder: (context, constraints) { + const double caboFieldWidthFactor = 0.2; const double roundColWidth = 35; const double tablePadding = 8; final int playerCount = widget.gameSession.players.length; @@ -156,7 +157,7 @@ class _PointsViewState extends State { child: Container( width: playerColWidth * (playerCount * - 0.2), // Adjust width based on amount of players + caboFieldWidthFactor), // Adjust width based on amount of players decoration: BoxDecoration( color: saidCabo ? CustomTheme From 7691d74f37534db94c4153ae0fa9c1524c3e5749 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 21:16:48 +0200 Subject: [PATCH 300/353] Implemented license_detail_view and license_view --- lib/l10n/arb/app_de.arb | 2 + lib/l10n/arb/app_en.arb | 2 + lib/l10n/generated/app_localizations.dart | 12 + lib/l10n/generated/app_localizations_de.dart | 6 + lib/l10n/generated/app_localizations_en.dart | 6 + lib/presentation/views/about_view.dart | 115 +- .../views/licenses/license_detail_view.dart | 58 + .../views/licenses/license_view.dart | 60 + .../views/licenses/oss_licenses.dart | 5464 +++++++++++++++++ pubspec.yaml | 4 +- 10 files changed, 5674 insertions(+), 55 deletions(-) create mode 100644 lib/presentation/views/licenses/license_detail_view.dart create mode 100644 lib/presentation/views/licenses/license_view.dart create mode 100644 lib/presentation/views/licenses/oss_licenses.dart diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index cd1a8c7..56525a8 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -18,6 +18,8 @@ "home": "Home", "about": "Über", + "licenses": "Lizenzen", + "license_details": "Lizenzdetails", "empty_text_1": "Ganz schön leer hier...", "empty_text_2": "Füge über den Button oben rechts eine neue Runde hinzu", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 7346343..d37fcb9 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -18,6 +18,8 @@ "home": "Home", "about": "About", + "licenses": "Licenses", + "license_details": "License Details", "empty_text_1": "Pretty empty here...", "empty_text_2": "Create a new game using the button in the top right.", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 5749079..3960c09 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -194,6 +194,18 @@ abstract class AppLocalizations { /// **'Über'** String get about; + /// No description provided for @licenses. + /// + /// In de, this message translates to: + /// **'Lizenzen'** + String get licenses; + + /// No description provided for @license_details. + /// + /// In de, this message translates to: + /// **'Lizenzdetails'** + String get license_details; + /// No description provided for @empty_text_1. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 87745dd..ddc48ea 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -56,6 +56,12 @@ class AppLocalizationsDe extends AppLocalizations { @override String get about => 'Über'; + @override + String get licenses => 'Lizenzen'; + + @override + String get license_details => 'Lizenzdetails'; + @override String get empty_text_1 => 'Ganz schön leer hier...'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index eb341af..9bd04e8 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -56,6 +56,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get about => 'About'; + @override + String get licenses => 'Licenses'; + + @override + String get license_details => 'License Details'; + @override String get empty_text_1 => 'Pretty empty here...'; diff --git a/lib/presentation/views/about_view.dart b/lib/presentation/views/about_view.dart index 481e294..94b6ad0 100644 --- a/lib/presentation/views/about_view.dart +++ b/lib/presentation/views/about_view.dart @@ -1,5 +1,6 @@ import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/licenses/license_view.dart'; import 'package:cabo_counter/services/version_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -17,62 +18,68 @@ class AboutView extends StatelessWidget { middle: Text(AppLocalizations.of(context).about), ), child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), - child: Text( - AppLocalizations.of(context).app_name, - style: const TextStyle( - fontSize: 30, - fontWeight: FontWeight.bold, + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Text( + AppLocalizations.of(context).app_name, + style: const TextStyle( + fontSize: 30, + fontWeight: FontWeight.bold, + ), ), ), - ), - Text( - '${AppLocalizations.of(context).app_version} ${VersionService.getVersionWithBuild()}', - style: TextStyle(fontSize: 15, color: Colors.grey[300]), - ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 15), - child: SizedBox( - height: 200, - child: Image.asset('assets/cabo_counter-logo_rounded.png'), - )), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Text( - AppLocalizations.of(context).about_text, - textAlign: TextAlign.center, - softWrap: true, - )), - const SizedBox( - height: 30, - ), - const Text( - '\u00A9 Felix Kirchner', - style: TextStyle(fontSize: 16), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - onPressed: () => - launchUrl(Uri.parse(Constants.kInstagramLink)), - icon: const Icon(FontAwesomeIcons.instagram)), - IconButton( - onPressed: () => - launchUrl(Uri.parse('mailto:${Constants.kEmail}')), - icon: const Icon(CupertinoIcons.envelope)), - IconButton( - onPressed: () => - launchUrl(Uri.parse(Constants.kGithubLink)), - icon: const Icon(FontAwesomeIcons.github)), - ], - ), - ], + Text( + '${AppLocalizations.of(context).app_version} ${VersionService.getVersionWithBuild()}', + style: TextStyle(fontSize: 15, color: Colors.grey[300]), + ), + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20, vertical: 15), + child: SizedBox( + height: 200, + child: Image.asset('assets/cabo_counter-logo_rounded.png'), + )), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Text( + AppLocalizations.of(context).about_text, + textAlign: TextAlign.center, + softWrap: true, + )), + const SizedBox( + height: 30, + ), + CupertinoButton( + child: Text(AppLocalizations.of(context).licenses), + onPressed: () => Navigator.push(context, + CupertinoPageRoute(builder: (_) => const LicenseView()))), + const Text( + '\u00A9 Felix Kirchner', + style: TextStyle(fontSize: 16), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + onPressed: () => + launchUrl(Uri.parse(Constants.kInstagramLink)), + icon: const Icon(FontAwesomeIcons.instagram)), + IconButton( + onPressed: () => + launchUrl(Uri.parse('mailto:${Constants.kEmail}')), + icon: const Icon(CupertinoIcons.envelope)), + IconButton( + onPressed: () => + launchUrl(Uri.parse(Constants.kGithubLink)), + icon: const Icon(FontAwesomeIcons.github)), + ], + ), + ], + ), ))); } } diff --git a/lib/presentation/views/licenses/license_detail_view.dart b/lib/presentation/views/licenses/license_detail_view.dart new file mode 100644 index 0000000..0f3a566 --- /dev/null +++ b/lib/presentation/views/licenses/license_detail_view.dart @@ -0,0 +1,58 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart' + show AppLocalizations; +import 'package:flutter/cupertino.dart'; + +class LicenceDetailView extends StatelessWidget { + final String title, licence; + const LicenceDetailView( + {super.key, required this.title, required this.licence}); + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + previousPageTitle: AppLocalizations.of(context).licenses, + middle: Text( + AppLocalizations.of(context).license_details, + ), + ), + child: SafeArea( + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(vertical: 8, horizontal: 12), + child: FittedBox( + fit: BoxFit.fill, + child: Text( + title, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + Container( + margin: const EdgeInsets.all(8), + padding: + const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + decoration: BoxDecoration( + color: CustomTheme.buttonBackgroundColor, + borderRadius: BorderRadius.circular(16)), + child: Text( + licence, + style: const TextStyle(fontSize: 15), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/views/licenses/license_view.dart b/lib/presentation/views/licenses/license_view.dart new file mode 100644 index 0000000..e89d16a --- /dev/null +++ b/lib/presentation/views/licenses/license_view.dart @@ -0,0 +1,60 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/views/licenses/license_detail_view.dart'; +import 'package:cabo_counter/presentation/views/licenses/oss_licenses.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class LicenseView extends StatelessWidget { + const LicenseView({super.key}); + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text(AppLocalizations.of(context).licenses), + previousPageTitle: AppLocalizations.of(context).about, + ), + child: SafeArea( + child: ListView.builder( + physics: const BouncingScrollPhysics(), + itemCount: ossLicenses.length, + itemBuilder: (_, index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 4), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).cardColor, + borderRadius: BorderRadius.circular(8), + ), + child: CupertinoListTile( + backgroundColor: CustomTheme.backgroundColor, + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (_) => LicenceDetailView( + title: ossLicenses[index].name[0].toUpperCase() + + ossLicenses[index].name.substring(1), + licence: ossLicenses[index].license!, + ), + ), + ); + }, + trailing: const CupertinoListTileChevron(), + title: Text( + ossLicenses[index].name[0].toUpperCase() + + ossLicenses[index].name.substring(1), + style: GoogleFonts.roboto(), + ), + subtitle: Text(ossLicenses[index].description), + ), + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/presentation/views/licenses/oss_licenses.dart b/lib/presentation/views/licenses/oss_licenses.dart new file mode 100644 index 0000000..f070f1e --- /dev/null +++ b/lib/presentation/views/licenses/oss_licenses.dart @@ -0,0 +1,5464 @@ +// cSpell:disable + +/// This code was generated by flutter_oss_licenses +/// https://pub.dev/packages/flutter_oss_licenses +const ossLicenses = [ + Package( + name: '_fe_analyzer_shared', + description: + 'Logic that is shared between the front_end and analyzer packages.', + repository: + 'https://github.com/dart-lang/sdk/tree/main/pkg/_fe_analyzer_shared', + authors: [], + version: '85.0.0', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'analyzer', + description: + 'This package provides a library that performs static analysis of Dart code.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/analyzer', + authors: [], + version: '7.5.2', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'args', + description: + 'Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/args', + authors: [], + version: '2.7.0', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'async', + description: + "Utility functions and classes related to the 'dart:async' library.", + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/async', + authors: [], + version: '2.13.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'boolean_selector', + description: + "A flexible syntax for boolean expressions, based on a simplified version of Dart's expression syntax.", + repository: + 'https://github.com/dart-lang/tools/tree/main/pkgs/boolean_selector', + authors: [], + version: '2.1.2', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'characters', + description: + 'String replacement with operations that are Unicode/grapheme cluster aware.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/characters', + authors: [], + version: '1.4.0', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'checked_yaml', + description: + 'Generate more helpful exceptions when decoding YAML documents using package:json_serializable and package:yaml.', + repository: + 'https://github.com/google/json_serializable.dart/tree/master/checked_yaml', + authors: [], + version: '2.0.3', + license: '''Copyright 2019, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'cli_config', + description: + 'A library to take config values from configuration files, CLI arguments, and environment variables.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/cli_config', + authors: [], + version: '0.2.0', + license: '''Copyright 2023, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'clock', + description: 'A fakeable wrapper for dart:core clock APIs.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/clock', + authors: [], + version: '1.1.2', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'collection', + description: + 'Collections and utilities functions and classes related to collections.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/collection', + authors: [], + version: '1.19.1', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'confetti', + description: + 'Blast colorful confetti all over the screen. Celebrate in app achievements with style. Control the velocity, angle, gravity and amount of confetti.', + homepage: 'https://github.com/funwithflutter/flutter_confetti', + authors: [], + version: '0.6.0', + license: '''The MIT License (MIT) +Copyright (c) 2018 Felix Angelov + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'convert', + description: + 'Utilities for converting between data representations. Provides a number of Sink, Codec, Decoder, and Encoder types.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/convert', + authors: [], + version: '3.1.2', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'coverage', + description: 'Coverage data manipulation and formatting', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/coverage', + authors: [], + version: '1.14.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'cross_file', + description: + 'An abstraction to allow working with files across multiple platforms.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/cross_file', + authors: [], + version: '0.3.4+2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'crypto', + description: + 'Implementations of SHA, MD5, and HMAC cryptographic functions.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/crypto', + authors: [], + version: '3.0.6', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'cupertino_icons', + description: + 'Default icons asset for Cupertino widgets based on Apple styled icons', + repository: + 'https://github.com/flutter/packages/tree/main/third_party/packages/cupertino_icons', + authors: [], + version: '1.0.8', + license: '''The MIT License (MIT) + +Copyright (c) 2016 Vladimir Kharlampidi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'dart_pubspec_licenses', + description: + 'A library to make it easy to extract OSS license information from Dart packages using pubspec.yaml', + homepage: + 'https://github.com/espresso3389/flutter_oss_licenses/tree/master/packages/dart_pubspec_licenses', + repository: 'https://github.com/espresso3389/flutter_oss_licenses', + authors: [], + version: '2.0.3', + license: '''MIT License + +Copyright (c) 2019 Takashi Kawasaki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'dio', + description: '''A powerful HTTP networking package, +supports Interceptors, +Aborting and canceling a request, +Custom adapters, Transformers, etc. +''', + homepage: 'https://github.com/cfug/dio', + repository: 'https://github.com/cfug/dio/blob/main/dio', + authors: [], + version: '5.8.0+1', + license: '''MIT License + +Copyright (c) 2018 Wen Du (wendux) +Copyright (c) 2022 The CFUG Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'dio_web_adapter', + description: 'An adapter that supports Dio on Web.', + homepage: 'https://github.com/cfug/dio', + repository: 'https://github.com/cfug/dio/blob/main/plugins/web_adapter', + authors: [], + version: '2.1.1', + license: '''MIT License + +Copyright (c) 2018 Wen Du (wendux) +Copyright (c) 2022 The CFUG Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'fake_async', + description: + 'Fake asynchronous events such as timers and microtasks for deterministic testing.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/fake_async', + authors: [], + version: '1.3.3', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'ffi', + description: + 'Utilities for working with Foreign Function Interface (FFI) code.', + repository: 'https://github.com/dart-lang/native/tree/main/pkgs/ffi', + authors: [], + version: '2.1.4', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'file', + description: + 'A pluggable, mockable file system abstraction for Dart. Supports local file system access, as well as in-memory file systems, record-replay file systems, and chroot file systems.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/file', + authors: [], + version: '7.0.1', + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'file_picker', + description: + 'A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.', + homepage: 'https://github.com/miguelpruivo/plugins_flutter_file_picker', + repository: 'https://github.com/miguelpruivo/flutter_file_picker', + authors: [], + version: '10.1.9', + license: '''MIT License + +Copyright (c) 2018 Miguel Ruivo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'file_saver', + description: + 'This package will help you save file with a single method on any platform including macOS, iOS, Android, Windows, Web, Linux.', + homepage: 'https://hassanansari.dev', + repository: 'https://github.com/incrediblezayed/file_saver', + authors: [], + version: '0.2.14', + license: '''BSD 3-Clause License + +Copyright (c) 2021, Hassan Ansari +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'fixnum', + description: + 'Library for 32- and 64-bit signed fixed-width integers with consistent behavior between native and JS runtimes.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/fixnum', + authors: [], + version: '1.1.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter', + description: 'A framework for writing Flutter applications', + homepage: 'https://flutter.dev', + authors: [], + version: '3.32.1', + license: '''Copyright 2014 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: true, + isDirectDependency: true, + ), + Package( + name: 'flutter_keyboard_visibility', + description: + 'Flutter plugin for discovering the state of the soft-keyboard visibility on Android and iOS.', + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '6.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'flutter_keyboard_visibility_linux', + description: + "An implementation for the linux platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '1.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_macos', + description: + "An implementation for the macOS platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '1.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_platform_interface', + description: + 'A common platform interface for the flutter_keyboard_visibility plugin.', + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '2.0.0', + license: '''The MIT License + +Copyright (c) 2006-2020 +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_web', + description: + "An implementation for the web platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '2.0.0', + license: '''The MIT License + +Copyright (c) 2006-2020 +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_windows', + description: + "An implementation for the Windows platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '1.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_lints', + description: + 'Recommended lints for Flutter apps, packages, and plugins to encourage good coding practices.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/flutter_lints', + authors: [], + version: '5.0.0', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_oss_licenses', + description: + 'A tool to generate detail and better OSS license list using pubspec.yaml/lock files.', + homepage: + 'https://github.com/espresso3389/flutter_oss_licenses/tree/master/packages/flutter_oss_licenses', + repository: 'https://github.com/espresso3389/flutter_oss_licenses', + authors: [], + version: '2.0.3', + license: '''MIT License + +Copyright (c) 2019 Takashi Kawasaki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'flutter_plugin_android_lifecycle', + description: + 'Flutter plugin for accessing an Android Lifecycle within other plugins.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/flutter_plugin_android_lifecycle', + authors: [], + version: '2.0.28', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_rating_bar', + description: + 'A simple yet fully customizable ratingbar for flutter which also include a rating bar indicator, supporting any fraction of rating.', + homepage: 'https://sarbagyastha.com.np', + repository: 'https://github.com/sarbagyastha/flutter_rating_bar', + authors: [], + version: '4.0.1', + license: '''The MIT License (MIT) + +Copyright (c) 2021 Sarbagya Dhaubanjar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'font_awesome_flutter', + description: + 'The Font Awesome Icon pack available as Flutter Icons. Provides 2000 additional icons to use in your apps.', + repository: 'https://github.com/fluttercommunity/font_awesome_flutter', + authors: [], + version: '10.8.0', + license: '''MIT License + +Copyright (c) 2017 Brian Egan +Copyright (c) 2020 Michael Spiss +Font Awesome Icons by @fontawesome - https://fontawesome.com +License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'frontend_server_client', + description: + 'Client code to start and interact with the frontend_server compiler from the Dart SDK.', + repository: + 'https://github.com/dart-lang/webdev/tree/master/frontend_server_client', + authors: [], + version: '4.0.0', + license: '''Copyright 2020, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'glob', + description: 'A library to perform Bash-style file and directory globbing.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/glob', + authors: [], + version: '2.1.3', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'http', + description: + 'A composable, multi-platform, Future-based API for HTTP requests.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http', + authors: [], + version: '1.4.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'http_multi_server', + description: + 'A dart:io HttpServer wrapper that handles requests from multiple servers.', + repository: + 'https://github.com/dart-lang/http/tree/master/pkgs/http_multi_server', + authors: [], + version: '3.2.2', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'http_parser', + description: + 'A platform-independent package for parsing and serializing HTTP formats.', + repository: + 'https://github.com/dart-lang/http/tree/master/pkgs/http_parser', + authors: [], + version: '4.1.2', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'intl', + description: + 'Contains code to deal with internationalized/localized messages, date and number formatting and parsing, bi-directional text, and other internationalization issues.', + repository: 'https://github.com/dart-lang/i18n/tree/main/pkgs/intl', + authors: [], + version: '0.20.2', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'io', + description: + 'Utilities for the Dart VM Runtime including support for ANSI colors, file copying, and standard exit code values.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/io', + authors: [], + version: '1.0.5', + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'js', + description: + 'Annotations to create static Dart interfaces for JavaScript APIs.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/js', + authors: [], + version: '0.7.2', + license: '''Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'json_annotation', + description: + 'Classes and helper functions that support JSON code generation via the `json_serializable` package.', + repository: + 'https://github.com/google/json_serializable.dart/tree/master/json_annotation', + authors: [], + version: '4.9.0', + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'json_schema', + description: 'JSON Schema implementation in Dart', + homepage: 'https://github.com/workiva/json_schema', + authors: [], + version: '5.2.1', + license: '''Copyright 2013-2022 Workiva Inc. + +Licensed under the Boost Software License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.boost.org/LICENSE_1_0.txt + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +This software or document includes material copied from or derived +from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite), +Copyright (c) 2012 Julian Berman, which is licensed under the following terms: + + Copyright (c) 2012 Julian Berman + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'leak_tracker', + description: + 'A framework for memory leak tracking for Dart and Flutter applications.', + repository: + 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker', + authors: [], + version: '10.0.9', + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'leak_tracker_flutter_testing', + description: 'An internal package to test leak tracking with Flutter.', + repository: + 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_flutter_testing', + authors: [], + version: '3.0.9', + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'leak_tracker_testing', + description: 'Leak tracking code intended for usage in tests.', + repository: + 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_testing', + authors: [], + version: '3.0.1', + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'lints', + description: + """Official Dart lint rules. Defines the 'core' and 'recommended' set of lints suggested by the Dart team. +""", + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/lints', + authors: [], + version: '5.1.1', + license: '''Copyright 2021, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'logger', + description: + 'Small, easy to use and extensible logger which prints beautiful logs.', + repository: 'https://github.com/SourceHorizon/logger', + authors: [], + version: '2.5.0', + license: '''MIT License + +Copyright (c) 2019 Simon Leier +Copyright (c) 2019 Harm Aarts +Copyright (c) 2023 Severin Hamader + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'logging', + description: + 'Provides APIs for debugging and error logging, similar to loggers in other languages, such as the Closure JS Logger and java.util.logging.Logger.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/logging', + authors: [], + version: '1.3.0', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'matcher', + description: + 'Support for specifying test expectations via an extensible Matcher class. Also includes a number of built-in Matcher implementations for common cases.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/matcher', + authors: [], + version: '0.12.17', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'material_color_utilities', + description: + 'Algorithms and utilities that power the Material Design 3 color system, including choosing theme colors from images and creating tones of colors; all in a new color space.', + repository: + 'https://github.com/material-foundation/material-color-utilities/tree/main/dart', + authors: [], + version: '0.11.1', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'meta', + description: + "Annotations used to express developer intentions that can't otherwise be deduced by statically analyzing source code.", + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/meta', + authors: [], + version: '1.16.0', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'mime', + description: + 'Utilities for handling media (MIME) types, including determining a type from a file extension and file contents.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/mime', + authors: [], + version: '2.0.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'node_preamble', + description: + 'Better node.js preamble for dart2js, use it in your build system.', + homepage: 'https://github.com/mbullington/node_preamble.dart', + authors: ['Michael Bullington '], + version: '2.0.2', + license: '''The MIT License (MIT) + +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=== + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'package_config', + description: + 'Support for reading and writing Dart Package Configuration files.', + repository: + 'https://github.com/dart-lang/tools/tree/main/pkgs/package_config', + authors: [], + version: '2.2.0', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'package_info_plus', + description: + 'Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android.', + homepage: 'https://github.com/fluttercommunity/plus_plugins', + repository: + 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus/package_info_plus', + authors: [], + version: '8.3.0', + license: '''Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'package_info_plus_platform_interface', + description: + 'A common platform interface for the package_info_plus plugin.', + homepage: 'https://github.com/fluttercommunity/plus_plugins', + repository: + 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/', + authors: [], + version: '3.2.0', + license: '''Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path', + description: + 'A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/path', + authors: [], + version: '1.9.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider', + description: + 'Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider', + authors: [], + version: '2.1.5', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'path_provider_android', + description: 'Android implementation of the path_provider plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android', + authors: [], + version: '2.2.17', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_foundation', + description: 'iOS and macOS implementation of the path_provider plugin', + repository: + 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation', + authors: [], + version: '2.4.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_linux', + description: 'Linux implementation of the path_provider plugin', + repository: + 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_linux', + authors: [], + version: '2.2.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_platform_interface', + description: 'A common platform interface for the path_provider plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_platform_interface', + authors: [], + version: '2.1.2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_windows', + description: 'Windows implementation of the path_provider plugin', + repository: + 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_windows', + authors: [], + version: '2.3.0', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'platform', + description: + 'A pluggable, mockable platform information abstraction for Dart.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/platform', + authors: [], + version: '3.1.6', + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'plugin_platform_interface', + description: + 'Reusable base class for platform interfaces of Flutter federated plugins, to help enforce best practices.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/plugin_platform_interface', + authors: [], + version: '2.1.8', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'pool', + description: + 'Manage a finite pool of resources. Useful for controlling concurrent file system or network requests.', + repository: 'https://github.com/dart-lang/pool', + authors: [], + version: '1.5.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'pub_semver', + description: + "Versions and version constraints implementing pub's versioning policy. This is very similar to vanilla semver, with a few corner cases.", + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/pub_semver', + authors: [], + version: '2.2.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'pubspec_parse', + description: + 'Simple package for parsing pubspec.yaml files with a type-safe API and rich error reporting.', + repository: + 'https://github.com/dart-lang/tools/tree/main/pkgs/pubspec_parse', + authors: [], + version: '1.5.0', + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'quiver', + description: + 'Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.', + repository: 'https://github.com/google/quiver-dart', + authors: [], + version: '3.2.2', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'rate_my_app', + description: + 'Allows to kindly ask users to rate your app if custom conditions are met (eg. install time, number of launches, etc...).', + homepage: 'https://github.com/Skyost/RateMyApp', + authors: [], + version: '2.3.2', + license: '''MIT License + +Copyright (c) 2019 Hugo DELAUNAY "Skyost" + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'reorderables', + description: + 'Reorderable table, row, column, wrap, sliver list that allow drag and drop of their children.', + homepage: 'https://github.com/hanshengchiu/reorderables', + authors: [], + version: '0.4.4', + license: '''MIT License + +Copyright (c) 2019 Hansheng Chiu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'rfc_6901', + description: + 'JSON Pointer (RFC 6901). Reads/writes referred values in JSON documents.', + homepage: 'https://github.com/f3ath/rfc-6901-dart', + authors: [], + version: '0.2.0', + license: '''MIT License + +Copyright (c) 2021 The Конь + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences', + description: + 'Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences', + authors: [], + version: '2.5.3', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'shared_preferences_android', + description: 'Android implementation of the shared_preferences plugin', + repository: + 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android', + authors: [], + version: '2.4.10', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_foundation', + description: + 'iOS and macOS implementation of the shared_preferences plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation', + authors: [], + version: '2.5.4', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_linux', + description: 'Linux implementation of the shared_preferences plugin', + repository: + 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux', + authors: [], + version: '2.4.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_platform_interface', + description: + 'A common platform interface for the shared_preferences plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_platform_interface', + authors: [], + version: '2.4.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_web', + description: 'Web platform implementation of shared_preferences', + repository: + 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_web', + authors: [], + version: '2.4.3', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_windows', + description: 'Windows implementation of shared_preferences', + repository: + 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_windows', + authors: [], + version: '2.4.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf', + description: + '''A model for web server middleware that encourages composition and easy reuse. +''', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf', + authors: [], + version: '1.4.2', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf_packages_handler', + description: 'A shelf handler for serving a `packages/` directory.', + repository: + 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_packages_handler', + authors: [], + version: '3.0.2', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf_static', + description: + 'Static file server support for the shelf package and ecosystem.', + repository: + 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_static', + authors: [], + version: '1.1.3', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf_web_socket', + description: + 'A shelf handler that wires up a listener for every connection.', + repository: + 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_web_socket', + authors: [], + version: '3.0.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'source_map_stack_trace', + description: 'A package for applying source maps to stack traces.', + repository: + 'https://github.com/dart-lang/tools/tree/main/pkgs/source_map_stack_trace', + authors: [], + version: '2.1.2', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'source_maps', + description: 'A library to programmatically manipulate source map files.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_maps', + authors: [], + version: '0.10.13', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'source_span', + description: + 'Provides a standard representation for source code locations and spans.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_span', + authors: [], + version: '1.10.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'sprintf', + description: + 'Dart implementation of sprintf. Provides simple printf like formatting such as sprintf("hello %s", ["world"]);', + homepage: 'https://github.com/Naddiseo/dart-sprintf', + authors: [], + version: '7.0.0', + license: '''Copyright (c) 2012, Richard Eames +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'stack_trace', + description: + 'A package for manipulating stack traces and printing them readably.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/stack_trace', + authors: [], + version: '1.12.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'stream_channel', + description: + 'An abstraction for two-way communication channels based on the Dart Stream class.', + repository: + 'https://github.com/dart-lang/tools/tree/main/pkgs/stream_channel', + authors: [], + version: '2.1.4', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'string_scanner', + description: 'A class for parsing strings using a sequence of patterns.', + repository: + 'https://github.com/dart-lang/tools/tree/main/pkgs/string_scanner', + authors: [], + version: '1.4.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'syncfusion_flutter_charts', + description: + 'A Flutter Charts library which includes data visualization widgets such as cartesian and circular charts, to create real-time, interactive, high-performance, animated charts.', + homepage: + 'https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_charts', + authors: [], + version: '30.1.37', + license: '''Syncfusion® License + +Syncfusion® Flutter Chart package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. + +To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars (\$1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. + +Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. + +Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion® license containing all terms and conditions. + +The Syncfusion® license that contains the terms and conditions can be found at +https://www.syncfusion.com/content/downloads/syncfusion_license.pdf''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'syncfusion_flutter_core', + description: + 'Syncfusion Flutter Core is a dependent package for all the Syncfusion Flutter widgets.', + homepage: + 'https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_core', + authors: [], + version: '30.1.42', + license: '''Syncfusion® License + +Syncfusion® Flutter Core package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. + +To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars (\$1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. + +Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. + +Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion® license containing all terms and conditions. + +The Syncfusion® license that contains the terms and conditions can be found at +https://www.syncfusion.com/content/downloads/syncfusion_license.pdf''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'term_glyph', + description: 'Useful Unicode glyphs and ASCII substitutes.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/term_glyph', + authors: [], + version: '1.2.2', + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'test', + description: + 'A full featured library for writing and running Dart tests across platforms.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test', + authors: [], + version: '1.25.15', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'test_api', + description: + 'The user facing API for structuring Dart tests and checking expectations.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_api', + authors: [], + version: '0.7.4', + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'test_core', + description: + 'A basic library for writing tests and running them on the VM.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_core', + authors: [], + version: '0.6.8', + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'typed_data', + description: + 'Utility functions and classes related to the dart:typed_data library.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/typed_data', + authors: [], + version: '1.4.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'uri', + description: + 'Utilities for building and parsing URIs, including support for parsing URI templates as defined in RFC 6570.', + repository: 'https://github.com/google/uri.dart', + authors: [], + version: '1.0.0', + license: '''Copyright 2013, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher', + description: + 'Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher', + authors: [], + version: '6.3.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'url_launcher_android', + description: 'Android implementation of the url_launcher plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_android', + authors: [], + version: '6.3.16', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_ios', + description: 'iOS implementation of the url_launcher plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_ios', + authors: [], + version: '6.3.3', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_linux', + description: 'Linux implementation of the url_launcher plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_linux', + authors: [], + version: '3.2.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_macos', + description: 'macOS implementation of the url_launcher plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_macos', + authors: [], + version: '3.2.2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_platform_interface', + description: 'A common platform interface for the url_launcher plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_platform_interface', + authors: [], + version: '2.3.2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_web', + description: 'Web platform implementation of url_launcher', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_web', + authors: [], + version: '2.4.1', + license: '''url_launcher_web + +Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +platform_detect + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Workiva Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_windows', + description: 'Windows implementation of the url_launcher plugin.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_windows', + authors: [], + version: '3.1.4', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'uuid', + description: + '''RFC4122 (v1, v4, v5, v6, v7, v8) UUID Generator and Parser for Dart +''', + repository: 'https://github.com/Daegalus/dart-uuid', + authors: [], + version: '4.5.1', + license: '''Copyright (c) 2021 Yulian Kuncheff + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'vector_math', + description: 'A Vector Math library for 2D and 3D applications.', + repository: 'https://github.com/google/vector_math.dart', + authors: [], + version: '2.1.4', + license: '''Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2013 Andrew Magill + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'vm_service', + description: + 'A library to communicate with a service implementing the Dart VM service protocol.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/vm_service', + authors: [], + version: '15.0.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'watcher', + description: + 'A file system watcher. It monitors changes to contents of directories and sends notifications when files have been added, removed, or modified.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/watcher', + authors: [], + version: '1.1.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'web', + description: 'Lightweight browser API bindings built around JS interop.', + repository: 'https://github.com/dart-lang/web', + authors: [], + version: '1.1.1', + license: '''Copyright 2023, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'web_socket', + description: + 'Any easy-to-use library for communicating with WebSockets that has multiple implementations.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket', + authors: [], + version: '1.0.1', + license: '''Copyright 2024, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'web_socket_channel', + description: + 'StreamChannel wrappers for WebSockets. Provides a cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying StreamChannel.', + repository: + 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket_channel', + authors: [], + version: '3.0.3', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'webkit_inspection_protocol', + description: + '''A client for the Chrome DevTools Protocol (previously called the Webkit Inspection Protocol). +''', + repository: 'https://github.com/google/webkit_inspection_protocol.dart', + authors: [], + version: '1.2.1', + license: '''Copyright 2013, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'win32', + description: + '''Access common Win32 APIs directly from Dart using FFI — no C required! +''', + homepage: 'https://win32.pub', + repository: 'https://github.com/halildurmus/win32', + authors: [], + version: '5.13.0', + license: '''BSD 3-Clause License + +Copyright (c) 2024, Halil Durmus + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'xdg_directories', + description: + 'A Dart package for reading XDG directory configuration information on Linux.', + repository: + 'https://github.com/flutter/packages/tree/main/packages/xdg_directories', + authors: [], + version: '1.1.0', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'yaml', + description: + 'A parser for YAML, a human-friendly data serialization standard', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/yaml', + authors: [], + version: '3.1.3', + license: '''Copyright (c) 2014, the Dart project authors. +Copyright (c) 2006, Kirill Simonov. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), +]; + +/// Package license definition. +class Package { + /// Package name + final String name; + + /// Description + final String description; + + /// Website URL + final String? homepage; + + /// Repository URL + final String? repository; + + /// Authors + final List authors; + + /// Version + final String version; + + /// License + final String? license; + + /// Whether the license is in markdown format or not (plain text). + final bool isMarkdown; + + /// Whether the package is included in the SDK or not. + final bool isSdk; + + /// Whether the package is direct dependency or not. + final bool isDirectDependency; + + const Package({ + required this.name, + required this.description, + this.homepage, + this.repository, + required this.authors, + required this.version, + this.license, + required this.isMarkdown, + required this.isSdk, + required this.isDirectDependency, + }); +} diff --git a/pubspec.yaml b/pubspec.yaml index f59ec44..3f9f742 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.5+639 +version: 0.5.6+648 environment: sdk: ^3.5.4 @@ -31,6 +31,8 @@ dependencies: reorderables: ^0.4.2 collection: ^1.18.0 confetti: ^0.6.0 + flutter_oss_licenses: ^2.0.1 + google_fonts: ^6.3.0 dev_dependencies: flutter_test: From 3d2a9bcfff99db4867bfa5403f2ccd11ed928973 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:26:02 +0200 Subject: [PATCH 301/353] Updated about view --- lib/l10n/arb/app_de.arb | 1 + lib/l10n/arb/app_en.arb | 2 ++ lib/presentation/views/about_view.dart | 43 ++++++++++++++++++++------ pubspec.yaml | 2 +- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 56525a8..5a0bfa0 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -20,6 +20,7 @@ "about": "Über", "licenses": "Lizenzen", "license_details": "Lizenzdetails", + "imprint": "Impressum", "empty_text_1": "Ganz schön leer hier...", "empty_text_2": "Füge über den Button oben rechts eine neue Runde hinzu", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index d37fcb9..0715ee2 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -20,6 +20,8 @@ "about": "About", "licenses": "Licenses", "license_details": "License Details", + "imprint": "Imprint", + "empty_text_1": "Pretty empty here...", "empty_text_2": "Create a new game using the button in the top right.", diff --git a/lib/presentation/views/about_view.dart b/lib/presentation/views/about_view.dart index 94b6ad0..03ac569 100644 --- a/lib/presentation/views/about_view.dart +++ b/lib/presentation/views/about_view.dart @@ -43,20 +43,45 @@ class AboutView extends StatelessWidget { height: 200, child: Image.asset('assets/cabo_counter-logo_rounded.png'), )), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Text( - AppLocalizations.of(context).about_text, - textAlign: TextAlign.center, - softWrap: true, - )), - const SizedBox( - height: 30, + Visibility( + visible: Constants.appDevPhase == 'Beta', + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Text( + AppLocalizations.of(context).about_text, + textAlign: TextAlign.center, + softWrap: true, + )), + const SizedBox( + height: 10, + ), + ], + ), ), CupertinoButton( + sizeStyle: CupertinoButtonSize.medium, + padding: EdgeInsets.zero, + child: Text(AppLocalizations.of(context).privacy_policy), + onPressed: () => + launchUrl(Uri.parse(Constants.kPrivacyPolicyLink)), + ), + CupertinoButton( + sizeStyle: CupertinoButtonSize.medium, + padding: EdgeInsets.zero, + child: Text(AppLocalizations.of(context).imprint), + onPressed: () => launchUrl(Uri.parse(Constants.kImprintLink)), + ), + CupertinoButton( + sizeStyle: CupertinoButtonSize.medium, + padding: EdgeInsets.zero, child: Text(AppLocalizations.of(context).licenses), onPressed: () => Navigator.push(context, CupertinoPageRoute(builder: (_) => const LicenseView()))), + const SizedBox( + height: 10, + ), const Text( '\u00A9 Felix Kirchner', style: TextStyle(fontSize: 16), diff --git a/pubspec.yaml b/pubspec.yaml index 3f9f742..6bdb330 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.6+648 +version: 0.5.6+656 environment: sdk: ^3.5.4 From c217493be25e0ad9f83e08104495b8b01cb38f15 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:26:20 +0200 Subject: [PATCH 302/353] Updated strings --- lib/core/constants.dart | 3 ++- lib/l10n/generated/app_localizations.dart | 6 ++++++ lib/l10n/generated/app_localizations_de.dart | 3 +++ lib/l10n/generated/app_localizations_en.dart | 3 +++ lib/presentation/views/settings_view.dart | 10 ++++++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 54c2c62..89176cc 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,7 +1,7 @@ import 'package:rate_my_app/rate_my_app.dart'; class Constants { - static const String appDevPhase = 'Beta'; + static const String appDevPhase = 'Stable'; static const String kInstagramLink = 'https://instagram.felixkirchner.de'; static const String kGithubLink = 'https://github.felixkirchner.de'; @@ -12,6 +12,7 @@ class Constants { static const String kEmail = 'cabocounter@felixkirchner.de'; static const String kPrivacyPolicyLink = 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; + static const String kImprintLink = ''; static RateMyApp rateMyApp = RateMyApp( appStoreIdentifier: '6747105718', diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 3960c09..4ef4c4b 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -206,6 +206,12 @@ abstract class AppLocalizations { /// **'Lizenzdetails'** String get license_details; + /// No description provided for @imprint. + /// + /// In de, this message translates to: + /// **'Impressum'** + String get imprint; + /// No description provided for @empty_text_1. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index ddc48ea..1974c56 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -62,6 +62,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get license_details => 'Lizenzdetails'; + @override + String get imprint => 'Impressum'; + @override String get empty_text_1 => 'Ganz schön leer hier...'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 9bd04e8..d358b72 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -62,6 +62,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get license_details => 'License Details'; + @override + String get imprint => 'Imprint'; + @override String get empty_text_1 => 'Pretty empty here...'; diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index aa49872..f067669 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,6 +1,7 @@ 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/licenses/license_view.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'; @@ -194,6 +195,15 @@ class _SettingsViewState extends State { launchUrl(Uri.parse(Constants.kPrivacyPolicyLink)), suffixWidget: const CupertinoListTileChevron(), ), + CustomFormRow( + prefixText: AppLocalizations.of(context).licenses, + prefixIcon: CupertinoIcons.doc_append, + onPressed: () => Navigator.push( + context, + CupertinoPageRoute( + builder: (_) => const LicenseView())), + suffixWidget: const CupertinoListTileChevron(), + ), CustomFormRow( prefixText: AppLocalizations.of(context).error_found, prefixIcon: FontAwesomeIcons.github, From b9f92bc71fa5241a441cd64ba342d70da81f466e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:26:30 +0200 Subject: [PATCH 303/353] Updated licenses --- lib/presentation/views/licenses/license_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/licenses/license_view.dart b/lib/presentation/views/licenses/license_view.dart index e89d16a..38dc833 100644 --- a/lib/presentation/views/licenses/license_view.dart +++ b/lib/presentation/views/licenses/license_view.dart @@ -14,7 +14,6 @@ class LicenseView extends StatelessWidget { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(AppLocalizations.of(context).licenses), - previousPageTitle: AppLocalizations.of(context).about, ), child: SafeArea( child: ListView.builder( From c5a12755513a466e2caf986193284f17b87bdf3f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:30:31 +0200 Subject: [PATCH 304/353] Removed about text --- lib/core/constants.dart | 2 +- lib/presentation/views/about_view.dart | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 89176cc..90fb36d 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,7 +1,7 @@ import 'package:rate_my_app/rate_my_app.dart'; class Constants { - static const String appDevPhase = 'Stable'; + static const String appDevPhase = 'Beta'; static const String kInstagramLink = 'https://instagram.felixkirchner.de'; static const String kGithubLink = 'https://github.felixkirchner.de'; diff --git a/lib/presentation/views/about_view.dart b/lib/presentation/views/about_view.dart index 03ac569..b4b99ca 100644 --- a/lib/presentation/views/about_view.dart +++ b/lib/presentation/views/about_view.dart @@ -43,23 +43,6 @@ class AboutView extends StatelessWidget { height: 200, child: Image.asset('assets/cabo_counter-logo_rounded.png'), )), - Visibility( - visible: Constants.appDevPhase == 'Beta', - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Text( - AppLocalizations.of(context).about_text, - textAlign: TextAlign.center, - softWrap: true, - )), - const SizedBox( - height: 10, - ), - ], - ), - ), CupertinoButton( sizeStyle: CupertinoButtonSize.medium, padding: EdgeInsets.zero, From 93b753fae598ed464985bb63894821938a036bea Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:31:19 +0200 Subject: [PATCH 305/353] Updated strings --- lib/l10n/arb/app_de.arb | 6 ++---- lib/l10n/arb/app_en.arb | 4 +--- lib/l10n/generated/app_localizations.dart | 6 ------ lib/l10n/generated/app_localizations_de.dart | 4 ---- lib/l10n/generated/app_localizations_en.dart | 4 ---- pubspec.yaml | 2 +- 6 files changed, 4 insertions(+), 22 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 5a0bfa0..148c19b 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -159,7 +159,5 @@ "app_version": "App-Version", "privacy_policy": "Datenschutzerklärung", "build": "Build-Nr.", - "loading": "Lädt...", - - "about_text": "Hey :) Danke, dass du als eine:r der ersten User meiner ersten eigenen App dabei bist! Ich hab sehr viel Arbeit in dieses Projekt gesteckt und auch, wenn ich (hoffentlich) an vieles Gedacht hab, wird auf jeden Fall noch nicht alles 100% funktionieren. Solltest du also irgendwelche Fehler entdecken oder Feedback zum Design oder der Benutzerfreundlichkeit haben, teile Sie mir gern über die Testflight App oder auf den dir bekannten Wegen mit. Danke! " -} \ No newline at end of file + "loading": "Lädt..." +} diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 0715ee2..101a847 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -160,7 +160,5 @@ "app_version": "App Version", "privacy_policy": "Privacy Policy", "loading": "Loading...", - "build": "Build No.", - - "about_text": "Hey :) Thanks for being one of the first users of my app! I’ve put a lot of work into this project, and even though I tried to think of everything, it might not work perfectly just yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the TestFlight app or by sending me a message or email. Thank you very much!" + "build": "Build No." } diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 4ef4c4b..a5054c9 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -728,12 +728,6 @@ abstract class AppLocalizations { /// In de, this message translates to: /// **'Lädt...'** String get loading; - - /// No description provided for @about_text. - /// - /// In de, this message translates to: - /// **'Hey :) Danke, dass du als eine:r der ersten User meiner ersten eigenen App dabei bist! Ich hab sehr viel Arbeit in dieses Projekt gesteckt und auch, wenn ich (hoffentlich) an vieles Gedacht hab, wird auf jeden Fall noch nicht alles 100% funktionieren. Solltest du also irgendwelche Fehler entdecken oder Feedback zum Design oder der Benutzerfreundlichkeit haben, teile Sie mir gern über die Testflight App oder auf den dir bekannten Wegen mit. Danke! '** - String get about_text; } class _AppLocalizationsDelegate diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 1974c56..4406605 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -361,8 +361,4 @@ class AppLocalizationsDe extends AppLocalizations { @override String get loading => 'Lädt...'; - - @override - String get about_text => - 'Hey :) Danke, dass du als eine:r der ersten User meiner ersten eigenen App dabei bist! Ich hab sehr viel Arbeit in dieses Projekt gesteckt und auch, wenn ich (hoffentlich) an vieles Gedacht hab, wird auf jeden Fall noch nicht alles 100% funktionieren. Solltest du also irgendwelche Fehler entdecken oder Feedback zum Design oder der Benutzerfreundlichkeit haben, teile Sie mir gern über die Testflight App oder auf den dir bekannten Wegen mit. Danke! '; } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index d358b72..9056c26 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -358,8 +358,4 @@ class AppLocalizationsEn extends AppLocalizations { @override String get loading => 'Loading...'; - - @override - String get about_text => - 'Hey :) Thanks for being one of the first users of my app! I’ve put a lot of work into this project, and even though I tried to think of everything, it might not work perfectly just yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the TestFlight app or by sending me a message or email. Thank you very much!'; } diff --git a/pubspec.yaml b/pubspec.yaml index 6bdb330..2ebba6d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.6+656 +version: 0.5.6+657 environment: sdk: ^3.5.4 From 48ddc6b98247b26491b6ec8b7124c40b15dbeed9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:32:15 +0200 Subject: [PATCH 306/353] Removed privacy policy and licenses from settings --- lib/presentation/views/settings_view.dart | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/settings_view.dart index f067669..1633b20 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/settings_view.dart @@ -1,7 +1,6 @@ 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/licenses/license_view.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'; @@ -188,22 +187,6 @@ class _SettingsViewState extends State { 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).licenses, - prefixIcon: CupertinoIcons.doc_append, - onPressed: () => Navigator.push( - context, - CupertinoPageRoute( - builder: (_) => const LicenseView())), - suffixWidget: const CupertinoListTileChevron(), - ), CustomFormRow( prefixText: AppLocalizations.of(context).error_found, prefixIcon: FontAwesomeIcons.github, From d8236230e97413ba41d07931b2969f5daaac1659 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:38:20 +0200 Subject: [PATCH 307/353] Removed page title --- lib/presentation/views/licenses/license_detail_view.dart | 1 - pubspec.yaml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/presentation/views/licenses/license_detail_view.dart b/lib/presentation/views/licenses/license_detail_view.dart index 0f3a566..025cbe1 100644 --- a/lib/presentation/views/licenses/license_detail_view.dart +++ b/lib/presentation/views/licenses/license_detail_view.dart @@ -12,7 +12,6 @@ class LicenceDetailView extends StatelessWidget { Widget build(BuildContext context) { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - previousPageTitle: AppLocalizations.of(context).licenses, middle: Text( AppLocalizations.of(context).license_details, ), diff --git a/pubspec.yaml b/pubspec.yaml index 2ebba6d..04f1c1a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.6+657 +version: 0.5.6+660 environment: sdk: ^3.5.4 From 20e2167e874e61853108a40869f760cc626e5db0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 4 Aug 2025 22:53:25 +0200 Subject: [PATCH 308/353] Updated var order --- lib/presentation/views/points_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart index 161d72e..8c08467 100644 --- a/lib/presentation/views/points_view.dart +++ b/lib/presentation/views/points_view.dart @@ -23,9 +23,9 @@ class _PointsViewState extends State { ), child: SafeArea(child: LayoutBuilder(builder: (context, constraints) { const double caboFieldWidthFactor = 0.2; - const double roundColWidth = 35; const double tablePadding = 8; final int playerCount = widget.gameSession.players.length; + const double roundColWidth = 35; final double playerColWidth = (constraints.maxWidth - roundColWidth - (tablePadding)) / playerCount; From bd0c2e79440e194091013b928b4d448d2f13db81 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:02:16 +0200 Subject: [PATCH 309/353] Added imprint link --- lib/core/constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 90fb36d..d91b4bd 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -12,7 +12,7 @@ class Constants { static const String kEmail = 'cabocounter@felixkirchner.de'; static const String kPrivacyPolicyLink = 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; - static const String kImprintLink = ''; + static const String kImprintLink = 'https://imprint.felixkirchner.de'; static RateMyApp rateMyApp = RateMyApp( appStoreIdentifier: '6747105718', From 344aa970cd05693ea7c5b4376002c6f39f3166ce Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:04:13 +0200 Subject: [PATCH 310/353] Corrected typo --- .../views/licenses/license_detail_view.dart | 10 +++++----- lib/presentation/views/licenses/license_view.dart | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/presentation/views/licenses/license_detail_view.dart b/lib/presentation/views/licenses/license_detail_view.dart index 025cbe1..6f818ae 100644 --- a/lib/presentation/views/licenses/license_detail_view.dart +++ b/lib/presentation/views/licenses/license_detail_view.dart @@ -3,10 +3,10 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart' show AppLocalizations; import 'package:flutter/cupertino.dart'; -class LicenceDetailView extends StatelessWidget { - final String title, licence; - const LicenceDetailView( - {super.key, required this.title, required this.licence}); +class LicenseDetailView extends StatelessWidget { + final String title, license; + const LicenseDetailView( + {super.key, required this.title, required this.license}); @override Widget build(BuildContext context) { @@ -44,7 +44,7 @@ class LicenceDetailView extends StatelessWidget { color: CustomTheme.buttonBackgroundColor, borderRadius: BorderRadius.circular(16)), child: Text( - licence, + license, style: const TextStyle(fontSize: 15), ), ) diff --git a/lib/presentation/views/licenses/license_view.dart b/lib/presentation/views/licenses/license_view.dart index 38dc833..ca799d8 100644 --- a/lib/presentation/views/licenses/license_view.dart +++ b/lib/presentation/views/licenses/license_view.dart @@ -33,10 +33,10 @@ class LicenseView extends StatelessWidget { Navigator.push( context, CupertinoPageRoute( - builder: (_) => LicenceDetailView( + builder: (_) => LicenseDetailView( title: ossLicenses[index].name[0].toUpperCase() + ossLicenses[index].name.substring(1), - licence: ossLicenses[index].license!, + license: ossLicenses[index].license!, ), ), ); From 07906d61dd593a44b40ca72a487febf1bc38dcc7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:28:18 +0200 Subject: [PATCH 311/353] Reordered views --- lib/presentation/views/{ => about}/about_view.dart | 2 +- .../{ => about}/licenses/license_detail_view.dart | 0 .../views/{ => about}/licenses/license_view.dart | 4 ++-- .../views/{ => about}/licenses/oss_licenses.dart | 0 .../views/{ => home/active_game}/active_game_view.dart | 10 +++++----- .../views/{ => home/active_game}/graph_view.dart | 0 .../{ => home/active_game}/mode_selection_view.dart | 0 .../views/{ => home/active_game}/points_view.dart | 0 .../views/{ => home/active_game}/round_view.dart | 0 .../views/{ => home}/create_game_view.dart | 4 ++-- lib/presentation/views/{ => home}/main_menu_view.dart | 6 +++--- lib/presentation/views/{ => home}/settings_view.dart | 2 +- lib/presentation/views/tab_view.dart | 4 ++-- lib/services/config_service.dart | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) rename lib/presentation/views/{ => about}/about_view.dart (97%) rename lib/presentation/views/{ => about}/licenses/license_detail_view.dart (100%) rename lib/presentation/views/{ => about}/licenses/license_view.dart (92%) rename lib/presentation/views/{ => about}/licenses/oss_licenses.dart (100%) rename lib/presentation/views/{ => home/active_game}/active_game_view.dart (98%) rename lib/presentation/views/{ => home/active_game}/graph_view.dart (100%) rename lib/presentation/views/{ => home/active_game}/mode_selection_view.dart (100%) rename lib/presentation/views/{ => home/active_game}/points_view.dart (100%) rename lib/presentation/views/{ => home/active_game}/round_view.dart (100%) rename lib/presentation/views/{ => home}/create_game_view.dart (98%) rename lib/presentation/views/{ => home}/main_menu_view.dart (98%) rename lib/presentation/views/{ => home}/settings_view.dart (99%) diff --git a/lib/presentation/views/about_view.dart b/lib/presentation/views/about/about_view.dart similarity index 97% rename from lib/presentation/views/about_view.dart rename to lib/presentation/views/about/about_view.dart index b4b99ca..89cfb5f 100644 --- a/lib/presentation/views/about_view.dart +++ b/lib/presentation/views/about/about_view.dart @@ -1,6 +1,6 @@ import 'package:cabo_counter/core/constants.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/presentation/views/licenses/license_view.dart'; +import 'package:cabo_counter/presentation/views/about/licenses/license_view.dart'; import 'package:cabo_counter/services/version_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/presentation/views/licenses/license_detail_view.dart b/lib/presentation/views/about/licenses/license_detail_view.dart similarity index 100% rename from lib/presentation/views/licenses/license_detail_view.dart rename to lib/presentation/views/about/licenses/license_detail_view.dart diff --git a/lib/presentation/views/licenses/license_view.dart b/lib/presentation/views/about/licenses/license_view.dart similarity index 92% rename from lib/presentation/views/licenses/license_view.dart rename to lib/presentation/views/about/licenses/license_view.dart index ca799d8..3429363 100644 --- a/lib/presentation/views/licenses/license_view.dart +++ b/lib/presentation/views/about/licenses/license_view.dart @@ -1,7 +1,7 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/presentation/views/licenses/license_detail_view.dart'; -import 'package:cabo_counter/presentation/views/licenses/oss_licenses.dart'; +import 'package:cabo_counter/presentation/views/about/licenses/license_detail_view.dart'; +import 'package:cabo_counter/presentation/views/about/licenses/oss_licenses.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; diff --git a/lib/presentation/views/licenses/oss_licenses.dart b/lib/presentation/views/about/licenses/oss_licenses.dart similarity index 100% rename from lib/presentation/views/licenses/oss_licenses.dart rename to lib/presentation/views/about/licenses/oss_licenses.dart diff --git a/lib/presentation/views/active_game_view.dart b/lib/presentation/views/home/active_game/active_game_view.dart similarity index 98% rename from lib/presentation/views/active_game_view.dart rename to lib/presentation/views/home/active_game/active_game_view.dart index 7a957ce..754df18 100644 --- a/lib/presentation/views/active_game_view.dart +++ b/lib/presentation/views/home/active_game/active_game_view.dart @@ -3,11 +3,11 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/presentation/views/create_game_view.dart'; -import 'package:cabo_counter/presentation/views/graph_view.dart'; -import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; -import 'package:cabo_counter/presentation/views/points_view.dart'; -import 'package:cabo_counter/presentation/views/round_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/graph_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/points_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/round_view.dart'; +import 'package:cabo_counter/presentation/views/home/create_game_view.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:collection/collection.dart'; import 'package:confetti/confetti.dart'; diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/home/active_game/graph_view.dart similarity index 100% rename from lib/presentation/views/graph_view.dart rename to lib/presentation/views/home/active_game/graph_view.dart diff --git a/lib/presentation/views/mode_selection_view.dart b/lib/presentation/views/home/active_game/mode_selection_view.dart similarity index 100% rename from lib/presentation/views/mode_selection_view.dart rename to lib/presentation/views/home/active_game/mode_selection_view.dart diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/home/active_game/points_view.dart similarity index 100% rename from lib/presentation/views/points_view.dart rename to lib/presentation/views/home/active_game/points_view.dart diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/home/active_game/round_view.dart similarity index 100% rename from lib/presentation/views/round_view.dart rename to lib/presentation/views/home/active_game/round_view.dart diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/home/create_game_view.dart similarity index 98% rename from lib/presentation/views/create_game_view.dart rename to lib/presentation/views/home/create_game_view.dart index 22a4e2d..3b54a03 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/home/create_game_view.dart @@ -3,8 +3,8 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/presentation/views/active_game_view.dart'; -import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/active_game_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart'; import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/home/main_menu_view.dart similarity index 98% rename from lib/presentation/views/main_menu_view.dart rename to lib/presentation/views/home/main_menu_view.dart index 0765e14..d99d61c 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/home/main_menu_view.dart @@ -3,9 +3,9 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_manager.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/presentation/views/active_game_view.dart'; -import 'package:cabo_counter/presentation/views/create_game_view.dart'; -import 'package:cabo_counter/presentation/views/settings_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/active_game_view.dart'; +import 'package:cabo_counter/presentation/views/home/create_game_view.dart'; +import 'package:cabo_counter/presentation/views/home/settings_view.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/presentation/views/settings_view.dart b/lib/presentation/views/home/settings_view.dart similarity index 99% rename from lib/presentation/views/settings_view.dart rename to lib/presentation/views/home/settings_view.dart index 1633b20..bbc471e 100644 --- a/lib/presentation/views/settings_view.dart +++ b/lib/presentation/views/home/settings_view.dart @@ -1,7 +1,7 @@ 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/views/home/active_game/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'; diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 08b1790..29dd4b8 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -1,7 +1,7 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:cabo_counter/presentation/views/about_view.dart'; -import 'package:cabo_counter/presentation/views/main_menu_view.dart'; +import 'package:cabo_counter/presentation/views/about/about_view.dart'; +import 'package:cabo_counter/presentation/views/home/main_menu_view.dart'; import 'package:flutter/cupertino.dart'; class TabView extends StatefulWidget { diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 1b20ad5..4ff68d9 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -1,4 +1,4 @@ -import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; +import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// This class handles the configuration settings for the app. From 92d8a6f68f2292efc54d70b95fcb7f01cff621e4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:33:16 +0200 Subject: [PATCH 312/353] Added documentation --- lib/presentation/views/about/about_view.dart | 2 ++ lib/presentation/views/about/licenses/license_detail_view.dart | 2 ++ lib/presentation/views/about/licenses/license_view.dart | 2 ++ lib/presentation/views/tab_view.dart | 1 + 4 files changed, 7 insertions(+) diff --git a/lib/presentation/views/about/about_view.dart b/lib/presentation/views/about/about_view.dart index 89cfb5f..25431ec 100644 --- a/lib/presentation/views/about/about_view.dart +++ b/lib/presentation/views/about/about_view.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; +/// A view that displays information about the app, including its name, version, +/// privacy policy, imprint, and licenses. class AboutView extends StatelessWidget { const AboutView({super.key}); diff --git a/lib/presentation/views/about/licenses/license_detail_view.dart b/lib/presentation/views/about/licenses/license_detail_view.dart index 6f818ae..efae60c 100644 --- a/lib/presentation/views/about/licenses/license_detail_view.dart +++ b/lib/presentation/views/about/licenses/license_detail_view.dart @@ -3,6 +3,8 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart' show AppLocalizations; import 'package:flutter/cupertino.dart'; +/// A view that displays the details of a specific open source software license. +/// It shows the title and the full license text in a scrollable view. class LicenseDetailView extends StatelessWidget { final String title, license; const LicenseDetailView( diff --git a/lib/presentation/views/about/licenses/license_view.dart b/lib/presentation/views/about/licenses/license_view.dart index 3429363..a180f21 100644 --- a/lib/presentation/views/about/licenses/license_view.dart +++ b/lib/presentation/views/about/licenses/license_view.dart @@ -6,6 +6,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +/// A view that displays a list of the open source software licenses used in the app. +/// It allows users to tap on a license to view its details in a separate screen. class LicenseView extends StatelessWidget { const LicenseView({super.key}); diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 29dd4b8..e8469f7 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -4,6 +4,7 @@ import 'package:cabo_counter/presentation/views/about/about_view.dart'; import 'package:cabo_counter/presentation/views/home/main_menu_view.dart'; import 'package:flutter/cupertino.dart'; +/// A view that provides a tabbed interface for navigating between the main menu and the about section. class TabView extends StatefulWidget { const TabView({super.key}); From 91a21d14912e3a241257b6e48aa939f073d89761 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:45:55 +0200 Subject: [PATCH 313/353] Removed capitalization --- lib/presentation/views/about/licenses/license_view.dart | 6 ++---- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/about/licenses/license_view.dart b/lib/presentation/views/about/licenses/license_view.dart index a180f21..d2ebbcf 100644 --- a/lib/presentation/views/about/licenses/license_view.dart +++ b/lib/presentation/views/about/licenses/license_view.dart @@ -36,8 +36,7 @@ class LicenseView extends StatelessWidget { context, CupertinoPageRoute( builder: (_) => LicenseDetailView( - title: ossLicenses[index].name[0].toUpperCase() + - ossLicenses[index].name.substring(1), + title: ossLicenses[index].name, license: ossLicenses[index].license!, ), ), @@ -45,8 +44,7 @@ class LicenseView extends StatelessWidget { }, trailing: const CupertinoListTileChevron(), title: Text( - ossLicenses[index].name[0].toUpperCase() + - ossLicenses[index].name.substring(1), + ossLicenses[index].name, style: GoogleFonts.roboto(), ), subtitle: Text(ossLicenses[index].description), diff --git a/pubspec.yaml b/pubspec.yaml index 04f1c1a..dc9eb58 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.6+660 +version: 0.5.6+661 environment: sdk: ^3.5.4 From 68d4841b2d86ccda16165ae44711a64065af7aec Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:47:44 +0200 Subject: [PATCH 314/353] Added null safety --- lib/l10n/arb/app_de.arb | 3 +++ lib/l10n/arb/app_en.arb | 3 +++ lib/l10n/generated/app_localizations.dart | 6 ++++++ lib/l10n/generated/app_localizations_de.dart | 3 +++ lib/l10n/generated/app_localizations_en.dart | 3 +++ lib/presentation/views/about/licenses/license_view.dart | 3 ++- 6 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 148c19b..b6339c0 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -17,11 +17,14 @@ "back": "Zurück", "home": "Home", + "about": "Über", "licenses": "Lizenzen", "license_details": "Lizenzdetails", + "no_license_text": "Keine Lizenz verfügbar", "imprint": "Impressum", + "empty_text_1": "Ganz schön leer hier...", "empty_text_2": "Füge über den Button oben rechts eine neue Runde hinzu", "delete_game_title": "Spiel löschen?", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 101a847..2e6146e 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -17,10 +17,13 @@ "back": "Back", "home": "Home", + "about": "About", "licenses": "Licenses", "license_details": "License Details", "imprint": "Imprint", + "no_license_text": "No license available", + "empty_text_1": "Pretty empty here...", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index a5054c9..2546a04 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -206,6 +206,12 @@ abstract class AppLocalizations { /// **'Lizenzdetails'** String get license_details; + /// No description provided for @no_license_text. + /// + /// In de, this message translates to: + /// **'Keine Lizenz verfügbar'** + String get no_license_text; + /// No description provided for @imprint. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 4406605..317fae1 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -62,6 +62,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get license_details => 'Lizenzdetails'; + @override + String get no_license_text => 'Keine Lizenz verfügbar'; + @override String get imprint => 'Impressum'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 9056c26..d4ace96 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -62,6 +62,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get license_details => 'License Details'; + @override + String get no_license_text => 'No license available'; + @override String get imprint => 'Imprint'; diff --git a/lib/presentation/views/about/licenses/license_view.dart b/lib/presentation/views/about/licenses/license_view.dart index d2ebbcf..d8edaa3 100644 --- a/lib/presentation/views/about/licenses/license_view.dart +++ b/lib/presentation/views/about/licenses/license_view.dart @@ -37,7 +37,8 @@ class LicenseView extends StatelessWidget { CupertinoPageRoute( builder: (_) => LicenseDetailView( title: ossLicenses[index].name, - license: ossLicenses[index].license!, + license: ossLicenses[index].license ?? + AppLocalizations.of(context).no_license_text, ), ), ); From 8d719e11dfd5e95b240c59c55bfa1339ad3fa8e0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:48:42 +0200 Subject: [PATCH 315/353] Altered arb files --- lib/l10n/arb/app_de.arb | 5 ++--- lib/l10n/arb/app_en.arb | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index b6339c0..a1e4c26 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -24,7 +24,6 @@ "no_license_text": "Keine Lizenz verfügbar", "imprint": "Impressum", - "empty_text_1": "Ganz schön leer hier...", "empty_text_2": "Füge über den Button oben rechts eine neue Runde hinzu", "delete_game_title": "Spiel löschen?", @@ -161,6 +160,6 @@ "wiki": "Wiki", "app_version": "App-Version", "privacy_policy": "Datenschutzerklärung", - "build": "Build-Nr.", - "loading": "Lädt..." + "loading": "Lädt...", + "build": "Build-Nr." } diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 2e6146e..9ba17c4 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -24,8 +24,6 @@ "imprint": "Imprint", "no_license_text": "No license available", - - "empty_text_1": "Pretty empty here...", "empty_text_2": "Create a new game using the button in the top right.", "delete_game_title": "Delete game?", From 3b1cc6008c1ce94e50fcd43be580a5dc87a3da8a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 Aug 2025 14:49:03 +0200 Subject: [PATCH 316/353] Altered arb files --- lib/l10n/generated/app_localizations.dart | 12 ++++++------ lib/l10n/generated/app_localizations_de.dart | 4 ++-- lib/l10n/generated/app_localizations_en.dart | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 2546a04..890e1ca 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -723,17 +723,17 @@ abstract class AppLocalizations { /// **'Datenschutzerklärung'** String get privacy_policy; - /// No description provided for @build. - /// - /// In de, this message translates to: - /// **'Build-Nr.'** - String get build; - /// No description provided for @loading. /// /// In de, this message translates to: /// **'Lädt...'** String get loading; + + /// No description provided for @build. + /// + /// In de, this message translates to: + /// **'Build-Nr.'** + String get build; } class _AppLocalizationsDelegate diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 317fae1..bb930f3 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -360,8 +360,8 @@ class AppLocalizationsDe extends AppLocalizations { String get privacy_policy => 'Datenschutzerklärung'; @override - String get build => 'Build-Nr.'; + String get loading => 'Lädt...'; @override - String get loading => 'Lädt...'; + String get build => 'Build-Nr.'; } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index d4ace96..ff9c81a 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -357,8 +357,8 @@ class AppLocalizationsEn extends AppLocalizations { String get privacy_policy => 'Privacy Policy'; @override - String get build => 'Build No.'; + String get loading => 'Loading...'; @override - String get loading => 'Loading...'; + String get build => 'Build No.'; } From e0d7a231c998973d0db4cd42ce359e6e404a61b6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 20:23:41 +0200 Subject: [PATCH 317/353] Updated page titles --- lib/l10n/arb/app_de.arb | 4 +++- lib/l10n/arb/app_en.arb | 4 +++- lib/l10n/generated/app_localizations.dart | 14 +++++++++++++- lib/l10n/generated/app_localizations_de.dart | 8 +++++++- lib/l10n/generated/app_localizations_en.dart | 8 +++++++- .../views/about/licenses/license_detail_view.dart | 1 + .../views/about/licenses/license_view.dart | 1 + .../views/home/active_game/active_game_view.dart | 6 ++---- .../views/home/active_game/graph_view.dart | 2 +- .../home/active_game/mode_selection_view.dart | 4 +++- .../views/home/active_game/points_view.dart | 2 +- lib/presentation/views/home/create_game_view.dart | 2 +- lib/presentation/views/home/main_menu_view.dart | 2 +- lib/presentation/views/home/settings_view.dart | 1 + 14 files changed, 45 insertions(+), 14 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index a1e4c26..63f4a30 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -10,6 +10,8 @@ "delete": "Löschen", "cancel": "Abbrechen", "game": "Spiel", + "games": "Spiele", + "gamemode": "Spielmodus", "ok": "OK", "player": "Spieler:in", "players": "Spieler:innen", @@ -126,7 +128,7 @@ "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", "statistics": "Statistiken", - "point_overview": "Punkteübersicht", + "point_overview": "Punktetabelle", "scoring_history": "Spielverlauf", "empty_graph_text": "Du musst mindestens eine Runde spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 9ba17c4..e1f57fb 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -10,6 +10,8 @@ "delete": "Delete", "cancel": "Cancel", "game": "Game", + "games": "Games", + "gamemode": "Gamemode", "ok": "OK", "player": "Player", "players": "Players", @@ -40,7 +42,7 @@ "yes": "Yes", "no": "No", "bad_rating_title": "Not satisfied?", - "bad_rating_message": "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.", + "bad_rating_message": "Feel free to send me an email directly so we can solve your problem!", "contact_email": "Contact via E-Mail", "email_subject": "Feedback: Cabo Counter App", "email_body": "I have the following feedback...", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 890e1ca..eb3620c 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -152,6 +152,18 @@ abstract class AppLocalizations { /// **'Spiel'** String get game; + /// No description provided for @games. + /// + /// In de, this message translates to: + /// **'Spiele'** + String get games; + + /// No description provided for @gamemode. + /// + /// In de, this message translates to: + /// **'Spielmodus'** + String get gamemode; + /// No description provided for @ok. /// /// In de, this message translates to: @@ -546,7 +558,7 @@ abstract class AppLocalizations { /// No description provided for @point_overview. /// /// In de, this message translates to: - /// **'Punkteübersicht'** + /// **'Punktetabelle'** String get point_overview; /// No description provided for @scoring_history. diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index bb930f3..4611788 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -35,6 +35,12 @@ class AppLocalizationsDe extends AppLocalizations { @override String get game => 'Spiel'; + @override + String get games => 'Spiele'; + + @override + String get gamemode => 'Spielmodus'; + @override String get ok => 'OK'; @@ -265,7 +271,7 @@ class AppLocalizationsDe extends AppLocalizations { String get statistics => 'Statistiken'; @override - String get point_overview => 'Punkteübersicht'; + String get point_overview => 'Punktetabelle'; @override String get scoring_history => 'Spielverlauf'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index ff9c81a..2072fd8 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -35,6 +35,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get game => 'Game'; + @override + String get games => 'Games'; + + @override + String get gamemode => 'Gamemode'; + @override String get ok => 'OK'; @@ -101,7 +107,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get bad_rating_message => - '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.'; + 'Feel free to send me an email directly so we can solve your problem!'; @override String get contact_email => 'Contact via E-Mail'; diff --git a/lib/presentation/views/about/licenses/license_detail_view.dart b/lib/presentation/views/about/licenses/license_detail_view.dart index efae60c..787c686 100644 --- a/lib/presentation/views/about/licenses/license_detail_view.dart +++ b/lib/presentation/views/about/licenses/license_detail_view.dart @@ -17,6 +17,7 @@ class LicenseDetailView extends StatelessWidget { middle: Text( AppLocalizations.of(context).license_details, ), + previousPageTitle: AppLocalizations.of(context).licenses, ), child: SafeArea( child: SingleChildScrollView( diff --git a/lib/presentation/views/about/licenses/license_view.dart b/lib/presentation/views/about/licenses/license_view.dart index d8edaa3..0b54f76 100644 --- a/lib/presentation/views/about/licenses/license_view.dart +++ b/lib/presentation/views/about/licenses/license_view.dart @@ -16,6 +16,7 @@ class LicenseView extends StatelessWidget { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(AppLocalizations.of(context).licenses), + previousPageTitle: AppLocalizations.of(context).about, ), child: SafeArea( child: ListView.builder( diff --git a/lib/presentation/views/home/active_game/active_game_view.dart b/lib/presentation/views/home/active_game/active_game_view.dart index 754df18..4434787 100644 --- a/lib/presentation/views/home/active_game/active_game_view.dart +++ b/lib/presentation/views/home/active_game/active_game_view.dart @@ -57,10 +57,8 @@ class _ActiveGameViewState extends State { gameSession.playerScores, sortedPlayerIndices); return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - middle: Text( - gameSession.gameTitle, - overflow: TextOverflow.ellipsis, - ), + previousPageTitle: AppLocalizations.of(context).games, + middle: Text(AppLocalizations.of(context).overview), ), child: SafeArea( child: SingleChildScrollView( diff --git a/lib/presentation/views/home/active_game/graph_view.dart b/lib/presentation/views/home/active_game/graph_view.dart index d67507a..f23be15 100644 --- a/lib/presentation/views/home/active_game/graph_view.dart +++ b/lib/presentation/views/home/active_game/graph_view.dart @@ -28,7 +28,7 @@ class _GraphViewState extends State { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(AppLocalizations.of(context).scoring_history), - previousPageTitle: AppLocalizations.of(context).back, + previousPageTitle: AppLocalizations.of(context).overview, ), child: SafeArea( child: Visibility( diff --git a/lib/presentation/views/home/active_game/mode_selection_view.dart b/lib/presentation/views/home/active_game/mode_selection_view.dart index 0424dab..86db5ff 100644 --- a/lib/presentation/views/home/active_game/mode_selection_view.dart +++ b/lib/presentation/views/home/active_game/mode_selection_view.dart @@ -18,7 +18,9 @@ class ModeSelectionMenu extends StatelessWidget { Widget build(BuildContext context) { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).select_game_mode), + middle: Text(AppLocalizations.of(context).gamemode), + previousPageTitle: + !showDeselection ? AppLocalizations.of(context).new_game : '', ), child: ListView( children: [ diff --git a/lib/presentation/views/home/active_game/points_view.dart b/lib/presentation/views/home/active_game/points_view.dart index 8c08467..7844872 100644 --- a/lib/presentation/views/home/active_game/points_view.dart +++ b/lib/presentation/views/home/active_game/points_view.dart @@ -19,7 +19,7 @@ class _PointsViewState extends State { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(AppLocalizations.of(context).point_overview), - previousPageTitle: AppLocalizations.of(context).back, + previousPageTitle: AppLocalizations.of(context).overview, ), child: SafeArea(child: LayoutBuilder(builder: (context, constraints) { const double caboFieldWidthFactor = 0.2; diff --git a/lib/presentation/views/home/create_game_view.dart b/lib/presentation/views/home/create_game_view.dart index 3b54a03..d92a375 100644 --- a/lib/presentation/views/home/create_game_view.dart +++ b/lib/presentation/views/home/create_game_view.dart @@ -80,7 +80,7 @@ class _CreateGameViewState extends State { return CupertinoPageScaffold( resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( - previousPageTitle: AppLocalizations.of(context).overview, + previousPageTitle: AppLocalizations.of(context).games, middle: Text(AppLocalizations.of(context).new_game), ), child: SafeArea( diff --git a/lib/presentation/views/home/main_menu_view.dart b/lib/presentation/views/home/main_menu_view.dart index d99d61c..3363511 100644 --- a/lib/presentation/views/home/main_menu_view.dart +++ b/lib/presentation/views/home/main_menu_view.dart @@ -75,7 +75,7 @@ class _MainMenuViewState extends State { }); }, icon: const Icon(CupertinoIcons.settings, size: 30)), - middle: Text(AppLocalizations.of(context).app_name), + middle: Text(AppLocalizations.of(context).games), trailing: IconButton( onPressed: () => Navigator.push( context, diff --git a/lib/presentation/views/home/settings_view.dart b/lib/presentation/views/home/settings_view.dart index bbc471e..d8e8d6c 100644 --- a/lib/presentation/views/home/settings_view.dart +++ b/lib/presentation/views/home/settings_view.dart @@ -32,6 +32,7 @@ class _SettingsViewState extends State { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(AppLocalizations.of(context).settings), + previousPageTitle: AppLocalizations.of(context).games, ), child: SafeArea( child: SingleChildScrollView( From cd3ac1f0f9fc4b290d6b35625097d90facd862d8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 20:27:36 +0200 Subject: [PATCH 318/353] Edited descriptio --- lib/l10n/arb/app_de.arb | 2 +- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/generated/app_localizations.dart | 2 +- lib/l10n/generated/app_localizations_de.dart | 2 +- lib/l10n/generated/app_localizations_en.dart | 2 +- pubspec.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 63f4a30..bd83532 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -76,7 +76,7 @@ } } }, - "unlimited_description": "Dem Spiel sind keine Grenzen gesetzt. Es wird so lange gespielt, bis ihr keine Lust mehr habt.", + "unlimited_description": "Es wird so lange gespielt, bis ihr keine Lust mehr habt. Das Spiel kann jederzeit manuell beendet werden.", "results": "Ergebnisse", "who_said_cabo": "Wer hat CABO gesagt?", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index e1f57fb..8fa17c1 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -76,7 +76,7 @@ } } }, - "unlimited_description": "The game continues until you decide to stop playing", + "unlimited_description": "The game continues until you decide to stop playing. The game can be ended manually at any time.", "results": "Results", "who_said_cabo": "Who called Cabo?", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index eb3620c..ad31f5a 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -437,7 +437,7 @@ abstract class AppLocalizations { /// No description provided for @unlimited_description. /// /// In de, this message translates to: - /// **'Dem Spiel sind keine Grenzen gesetzt. Es wird so lange gespielt, bis ihr keine Lust mehr habt.'** + /// **'Es wird so lange gespielt, bis ihr keine Lust mehr habt. Das Spiel kann jederzeit manuell beendet werden.'** String get unlimited_description; /// No description provided for @results. diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 4611788..069a214 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -189,7 +189,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get unlimited_description => - 'Dem Spiel sind keine Grenzen gesetzt. Es wird so lange gespielt, bis ihr keine Lust mehr habt.'; + 'Es wird so lange gespielt, bis ihr keine Lust mehr habt. Das Spiel kann jederzeit manuell beendet werden.'; @override String get results => 'Ergebnisse'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 2072fd8..777d979 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -186,7 +186,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String get unlimited_description => - 'The game continues until you decide to stop playing'; + 'The game continues until you decide to stop playing. The game can be ended manually at any time.'; @override String get results => 'Results'; diff --git a/pubspec.yaml b/pubspec.yaml index dc9eb58..1dbde3a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.6+661 +version: 0.5.7+661 environment: sdk: ^3.5.4 From 354922b93d1a1716d22784e0e7d8d303a60421f9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 20:33:54 +0200 Subject: [PATCH 319/353] Updated navigation for creating a game --- .../views/home/active_game/active_game_view.dart | 2 +- lib/presentation/views/home/create_game_view.dart | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/home/active_game/active_game_view.dart b/lib/presentation/views/home/active_game/active_game_view.dart index 4434787..60ae16d 100644 --- a/lib/presentation/views/home/active_game/active_game_view.dart +++ b/lib/presentation/views/home/active_game/active_game_view.dart @@ -221,7 +221,7 @@ class _ActiveGameViewState extends State { backgroundColorActivated: CustomTheme.backgroundColor, onTap: () { - Navigator.pushReplacement( + Navigator.push( context, CupertinoPageRoute( builder: (_) => CreateGameView( diff --git a/lib/presentation/views/home/create_game_view.dart b/lib/presentation/views/home/create_game_view.dart index d92a375..8b18bfc 100644 --- a/lib/presentation/views/home/create_game_view.dart +++ b/lib/presentation/views/home/create_game_view.dart @@ -452,10 +452,12 @@ class _CreateGameViewState extends State { gameManager.addGameSession(gameSession); final session = gameManager.getGameSessionById(id) ?? gameSession; - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => ActiveGameView(gameSession: session))); + Navigator.pushAndRemoveUntil( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView(gameSession: session)), + (Route route) => route.isFirst, + ); } @override From 360ee839f8953fcfc0ee561eb06ae6ff20ccb8b5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 20:59:21 +0200 Subject: [PATCH 320/353] Added keyboard checks --- .../views/home/create_game_view.dart | 477 +++++++++--------- 1 file changed, 249 insertions(+), 228 deletions(-) diff --git a/lib/presentation/views/home/create_game_view.dart b/lib/presentation/views/home/create_game_view.dart index 8b18bfc..bbea2cf 100644 --- a/lib/presentation/views/home/create_game_view.dart +++ b/lib/presentation/views/home/create_game_view.dart @@ -77,249 +77,260 @@ class _CreateGameViewState extends State { @override Widget build(BuildContext context) { - return CupertinoPageScaffold( - resizeToAvoidBottomInset: false, - navigationBar: CupertinoNavigationBar( - previousPageTitle: AppLocalizations.of(context).games, - middle: Text(AppLocalizations.of(context).new_game), - ), - 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).game, - style: CustomTheme.rowTitle, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - maxLength: 20, - prefix: Text(AppLocalizations.of(context).name), - textAlign: TextAlign.right, - placeholder: AppLocalizations.of(context).game_title, - controller: _gameTitleTextController, - onSubmitted: (_) { - _playerNameFocusNodes.isNotEmpty - ? _playerNameFocusNodes[0].requestFocus() - : FocusScope.of(context).unfocus(); - }, - textInputAction: _playerNameFocusNodes.isNotEmpty - ? TextInputAction.next - : TextInputAction.done, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - readOnly: true, - prefix: Text(AppLocalizations.of(context).mode), - suffix: Row( - children: [ - _getDisplayedGameMode(), - const SizedBox(width: 3), - const CupertinoListTileChevron(), - ], + return PopScope( + canPop: false, + onPopInvokedWithResult: (bool didPop, dynamic result) async { + if (!didPop) { + await _keyboardDelay(); + if (context.mounted) Navigator.pop(context); + } + }, + child: CupertinoPageScaffold( + resizeToAvoidBottomInset: false, + navigationBar: CupertinoNavigationBar( + previousPageTitle: AppLocalizations.of(context).games, + middle: Text(AppLocalizations.of(context).new_game), + ), + 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).game, + style: CustomTheme.rowTitle, + ), ), - onTap: () async { - final selectedMode = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ModeSelectionMenu( - pointLimit: ConfigService.getPointLimit(), - showDeselection: false, - ), - ), - ); - - setState(() { - gameMode = selectedMode ?? gameMode; - }); - }, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).players, - style: CustomTheme.rowTitle, - ), - ), - ReorderableListView.builder( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.all(8), - itemCount: _playerNameTextControllers.length, - onReorder: (oldIndex, newIndex) { - setState(() { - if (oldIndex < _playerNameTextControllers.length && - newIndex <= _playerNameTextControllers.length) { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - } - }); - }, - itemBuilder: (context, index) { - return Padding( - key: ValueKey(index), - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + maxLength: 20, + prefix: Text(AppLocalizations.of(context).name), + textAlign: TextAlign.right, + placeholder: AppLocalizations.of(context).game_title, + controller: _gameTitleTextController, + onSubmitted: (_) { + _playerNameFocusNodes.isNotEmpty + ? _playerNameFocusNodes[0].requestFocus() + : FocusScope.of(context).unfocus(); + }, + textInputAction: _playerNameFocusNodes.isNotEmpty + ? TextInputAction.next + : TextInputAction.done, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + readOnly: true, + prefix: Text(AppLocalizations.of(context).mode), + suffix: Row( children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: Icon( - CupertinoIcons.minus_circle_fill, - color: CustomTheme.red, - size: 25, - ), - onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); - }, - ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - focusNode: _playerNameFocusNodes[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - textInputAction: - index + 1 < _playerNameTextControllers.length - ? TextInputAction.next - : TextInputAction.done, - onSubmitted: (_) { - if (index + 1 < _playerNameFocusNodes.length) { - _playerNameFocusNodes[index + 1] - .requestFocus(); - } else { - FocusScope.of(context).unfocus(); - } - }, - ), - ), - AnimatedOpacity( - opacity: _playerNameTextControllers.length > 1 - ? 1.0 - : 0.0, - duration: const Duration( - milliseconds: Constants.kFadeInDuration), - child: Padding( - padding: const EdgeInsets.only(right: 8.0), - child: ReorderableDragStartListener( - index: index, - child: const Icon( - CupertinoIcons.line_horizontal_3, - color: CupertinoColors.systemGrey, - ), - ), - ), - ) + _getDisplayedGameMode(), + const SizedBox(width: 3), + const CupertinoListTileChevron(), ], ), - ); - }), - Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), - child: Stack( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - onPressed: null, - child: Icon( - CupertinoIcons.plus_circle_fill, - color: CustomTheme.primaryColor, - size: 25, - ), - ), - ], + onTap: () async { + await _keyboardDelay(); + + if (context.mounted) { + final selectedMode = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ModeSelectionMenu( + pointLimit: ConfigService.getPointLimit(), + showDeselection: false, + ), + ), + ); + + setState(() { + gameMode = selectedMode ?? gameMode; + }); + } + }, ), - Center( - child: CupertinoButton( - padding: const EdgeInsets.symmetric(horizontal: 0), - child: Row( + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).players, + style: CustomTheme.rowTitle, + ), + ), + ReorderableListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + } + }); + }, + itemBuilder: (context, index) { + return Padding( + key: ValueKey(index), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: Icon( + CupertinoIcons.minus_circle_fill, + color: CustomTheme.red, + size: 25, + ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + focusNode: _playerNameFocusNodes[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + textInputAction: index + 1 < + _playerNameTextControllers.length + ? TextInputAction.next + : TextInputAction.done, + onSubmitted: (_) { + if (index + 1 < + _playerNameFocusNodes.length) { + _playerNameFocusNodes[index + 1] + .requestFocus(); + } else { + FocusScope.of(context).unfocus(); + } + }, + ), + ), + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration( + milliseconds: Constants.kFadeInDuration), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, + ), + ), + ), + ) + ], + ), + ); + }), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), + child: Stack( + children: [ + Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - Expanded( - child: Center( - child: Text( - AppLocalizations.of(context).add_player, - style: TextStyle( - color: CustomTheme.primaryColor), - ), + CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.plus_circle_fill, + color: CustomTheme.primaryColor, + size: 25, ), ), ], ), - onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - _playerNameFocusNodes.add(FocusNode()); - }); - WidgetsBinding.instance.addPostFrameCallback((_) { - _playerNameFocusNodes.last.requestFocus(); - }); - } else { - _showFeedbackDialog(CreateStatus.maxPlayers); - } + Center( + child: CupertinoButton( + padding: const EdgeInsets.symmetric(horizontal: 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Center( + child: Text( + AppLocalizations.of(context).add_player, + style: TextStyle( + color: CustomTheme.primaryColor), + ), + ), + ), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < + maxPlayers) { + setState(() { + _playerNameTextControllers + .add(TextEditingController()); + _playerNameFocusNodes.add(FocusNode()); + }); + WidgetsBinding.instance + .addPostFrameCallback((_) { + _playerNameFocusNodes.last.requestFocus(); + }); + } else { + _showFeedbackDialog(CreateStatus.maxPlayers); + } + }, + ), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), + child: Center( + child: CustomButton( + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ), + onPressed: () async { + await _keyboardDelay(); + _checkAllGameAttributes(); }, ), ), - ], - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), - child: Center( - child: CustomButton( - child: Text( - AppLocalizations.of(context).create_game, - style: TextStyle( - color: CustomTheme.primaryColor, - ), - ), - onPressed: () { - FocusScope.of(context).unfocus(); - Future.delayed( - const Duration( - milliseconds: Constants.kKeyboardDelay), () { - _checkAllGameAttributes(); - }); - }, ), - ), + KeyboardVisibilityBuilder(builder: (context, visible) { + if (visible) { + return SizedBox( + height: MediaQuery.of(context).viewInsets.bottom * + keyboardHeightAdjustmentFactor, + ); + } else { + return const SizedBox.shrink(); + } + }) + ], ), - KeyboardVisibilityBuilder(builder: (context, visible) { - if (visible) { - return SizedBox( - height: MediaQuery.of(context).viewInsets.bottom * - keyboardHeightAdjustmentFactor, - ); - } else { - return const SizedBox.shrink(); - } - }) - ], - ), - ))); + )))); } /// Returns a widget that displays the currently selected game mode in the View. @@ -460,8 +471,18 @@ class _CreateGameViewState extends State { ); } + Future _keyboardDelay() async { + if (!KeyboardVisibilityController().isVisible) { + return; + } else { + FocusScope.of(context).unfocus(); + await Future.delayed( + const Duration(milliseconds: Constants.kKeyboardDelay), () {}); + } + } + @override - void dispose() { + Future dispose() async { _gameTitleTextController.dispose(); for (var controller in _playerNameTextControllers) { controller.dispose(); From 3e0743c3dd16a86043e29cd16f5c192732e55e54 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 21:03:54 +0200 Subject: [PATCH 321/353] Added docs --- lib/presentation/views/home/create_game_view.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/presentation/views/home/create_game_view.dart b/lib/presentation/views/home/create_game_view.dart index bbea2cf..bb79df1 100644 --- a/lib/presentation/views/home/create_game_view.dart +++ b/lib/presentation/views/home/create_game_view.dart @@ -471,6 +471,8 @@ class _CreateGameViewState extends State { ); } + /// If the keyboard is visible, this method will unfocus the current text field + /// to prevent the keyboard from interfering with the navigation bar. Future _keyboardDelay() async { if (!KeyboardVisibilityController().isVisible) { return; From e8258efaf52b38018614e9ae1f3c9f92f9103b87 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 21:08:08 +0200 Subject: [PATCH 322/353] Updated function return type --- lib/presentation/views/home/create_game_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/home/create_game_view.dart b/lib/presentation/views/home/create_game_view.dart index bb79df1..2a3f3d8 100644 --- a/lib/presentation/views/home/create_game_view.dart +++ b/lib/presentation/views/home/create_game_view.dart @@ -479,12 +479,12 @@ class _CreateGameViewState extends State { } else { FocusScope.of(context).unfocus(); await Future.delayed( - const Duration(milliseconds: Constants.kKeyboardDelay), () {}); + const Duration(milliseconds: Constants.kKeyboardDelay)); } } @override - Future dispose() async { + void dispose() { _gameTitleTextController.dispose(); for (var controller in _playerNameTextControllers) { controller.dispose(); From 7fc38f87c3dcc7daea4673cf96bcf9643df58a66 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 21:27:00 +0200 Subject: [PATCH 323/353] Updated keyboard behaviour in round view --- .../views/home/active_game/round_view.dart | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/presentation/views/home/active_game/round_view.dart b/lib/presentation/views/home/active_game/round_view.dart index b20255b..614f39e 100644 --- a/lib/presentation/views/home/active_game/round_view.dart +++ b/lib/presentation/views/home/active_game/round_view.dart @@ -42,6 +42,8 @@ class _RoundViewState extends State { (index) => FocusNode(), ); + late List _textFieldKeys; + @override void initState() { print('=== Runde ${widget.roundNumber} geöffnet ==='); @@ -62,6 +64,11 @@ class _RoundViewState extends State { gameSession.roundList[widget.roundNumber - 1].kamikazePlayerIndex; } + _textFieldKeys = List.generate( + widget.gameSession.players.length, + (index) => GlobalKey(), + ); + super.initState(); } @@ -75,7 +82,6 @@ class _RoundViewState extends State { return CupertinoPageScaffold( resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( - transitionBetweenRoutes: true, leading: CupertinoButton( padding: EdgeInsets.zero, onPressed: () => { @@ -91,11 +97,11 @@ class _RoundViewState extends State { CupertinoIcons.lock, size: 25, ))), - child: Stack( + child: Column( children: [ - Positioned.fill( + Expanded( child: SingleChildScrollView( - padding: EdgeInsets.only(bottom: 100 + bottomInset), + padding: EdgeInsets.only(bottom: 20 + bottomInset), child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -195,6 +201,7 @@ class _RoundViewState extends State { ' ${AppLocalizations.of(context).points}'), trailing: SizedBox( width: 100, + key: _textFieldKeys[originalIndex], child: CupertinoTextField( maxLength: 3, focusNode: _focusNodeList[originalIndex], @@ -248,11 +255,8 @@ class _RoundViewState extends State { ), ), ), - Positioned( - left: 0, - right: 0, - bottom: bottomInset, - child: KeyboardVisibilityBuilder(builder: (context, visible) { + KeyboardVisibilityBuilder( + builder: (context, visible) { if (!visible) { return Container( height: 80, @@ -284,8 +288,8 @@ class _RoundViewState extends State { } else { return const SizedBox.shrink(); } - }), - ) + }, + ), ], ), ); @@ -371,8 +375,18 @@ class _RoundViewState extends State { final currentPos = originalIndices.indexOf(index); if (currentPos < originalIndices.length - 1) { + final nextIndex = originalIndices[currentPos + 1]; FocusScope.of(context) .requestFocus(_focusNodeList[originalIndices[currentPos + 1]]); + + WidgetsBinding.instance.addPostFrameCallback((_) { + Scrollable.ensureVisible( + _textFieldKeys[nextIndex].currentContext!, + duration: const Duration(milliseconds: 300), + curve: Curves.easeOut, + alignment: 0.55, + ); + }); } else { _focusNodeList[index].unfocus(); } From a58a1eb766ec9beceb481d4d3523d28e5adfe448 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 22:19:08 +0200 Subject: [PATCH 324/353] Added null check --- .../views/home/active_game/round_view.dart | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/presentation/views/home/active_game/round_view.dart b/lib/presentation/views/home/active_game/round_view.dart index 614f39e..14b1f94 100644 --- a/lib/presentation/views/home/active_game/round_view.dart +++ b/lib/presentation/views/home/active_game/round_view.dart @@ -379,14 +379,17 @@ class _RoundViewState extends State { FocusScope.of(context) .requestFocus(_focusNodeList[originalIndices[currentPos + 1]]); - WidgetsBinding.instance.addPostFrameCallback((_) { - Scrollable.ensureVisible( - _textFieldKeys[nextIndex].currentContext!, - duration: const Duration(milliseconds: 300), - curve: Curves.easeOut, - alignment: 0.55, - ); - }); + final scrollContext = _textFieldKeys[nextIndex].currentContext; + if (scrollContext != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + Scrollable.ensureVisible( + scrollContext, + duration: const Duration(milliseconds: 300), + curve: Curves.easeOut, + alignment: 0.55, + ); + }); + } } else { _focusNodeList[index].unfocus(); } From 917736139f9fab484f9cbd228ed9f2315b385184 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 22:39:57 +0200 Subject: [PATCH 325/353] Updated view --- .../home/active_game/active_game_view.dart | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/presentation/views/home/active_game/active_game_view.dart b/lib/presentation/views/home/active_game/active_game_view.dart index 60ae16d..07209f8 100644 --- a/lib/presentation/views/home/active_game/active_game_view.dart +++ b/lib/presentation/views/home/active_game/active_game_view.dart @@ -8,6 +8,7 @@ import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_ import 'package:cabo_counter/presentation/views/home/active_game/points_view.dart'; import 'package:cabo_counter/presentation/views/home/active_game/round_view.dart'; import 'package:cabo_counter/presentation/views/home/create_game_view.dart'; +import 'package:cabo_counter/services/config_service.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:collection/collection.dart'; import 'package:confetti/confetti.dart'; @@ -65,6 +66,29 @@ class _ActiveGameViewState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), + child: Text( + AppLocalizations.of(context).game, + style: CustomTheme.rowTitle, + ), + ), + CupertinoListTile( + title: Text(AppLocalizations.of(context).name), + trailing: Text( + gameSession.gameTitle, + style: TextStyle(color: CustomTheme.primaryColor), + ), + ), + CupertinoListTile( + title: Text(AppLocalizations.of(context).mode), + trailing: Text( + gameSession.isPointsLimitEnabled + ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' + : AppLocalizations.of(context).unlimited, + style: TextStyle(color: CustomTheme.primaryColor), + ), + ), Padding( padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), child: Text( @@ -79,6 +103,8 @@ class _ActiveGameViewState extends State { itemBuilder: (BuildContext context, int index) { int playerIndex = sortedPlayerIndices[index]; return CupertinoListTile( + padding: + const EdgeInsets.fromLTRB(14, 5, 14, 0), title: Row( children: [ _getPlacementTextWidget(index), From 7001d6137aed7f020beec19b6a58677e6a6ec9fa Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 22:41:09 +0200 Subject: [PATCH 326/353] Updated version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 1dbde3a..3fe9367 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.7+661 +version: 0.5.8+667 environment: sdk: ^3.5.4 From 742e76466612dda4d94075fa338345d62af65c59 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 17 Aug 2025 22:56:38 +0200 Subject: [PATCH 327/353] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1c7a24..44c0dcc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CABO Counter -![Version](https://img.shields.io/badge/Version-0.5.3-orange) +![Version](https://img.shields.io/badge/Version-0.5.8-orange) ![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter) ![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart) ![iOS](https://img.shields.io/badge/iOS-18.5-white?logo=apple) From d48c72502969839401c6326e5f19afcd0fed318b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 00:17:24 +0200 Subject: [PATCH 328/353] Updated link constants --- lib/core/constants.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index d91b4bd..d29a23b 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -6,12 +6,12 @@ class Constants { static const String kInstagramLink = 'https://instagram.felixkirchner.de'; static const String kGithubLink = 'https://github.felixkirchner.de'; static const String kGithubIssuesLink = - 'https://cabocounter-issues.felixkirchner.de'; + 'https://cabo-counter-issues.felixkirchner.de'; static const String kGithubWikiLink = - 'https://cabocounter-wiki.felixkirchner.de'; + 'https://cabo-counter-wiki.felixkirchner.de'; static const String kEmail = 'cabocounter@felixkirchner.de'; static const String kPrivacyPolicyLink = - 'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68'; + 'https://cabo-counter-privacy.felixkirchner.de'; static const String kImprintLink = 'https://imprint.felixkirchner.de'; static RateMyApp rateMyApp = RateMyApp( From 040644b63018f8cef8f1c26613726afa5b43099e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:05:31 +0200 Subject: [PATCH 329/353] Updated workflow for licenses --- .github/workflows/flutter.yml | 44 +++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 58064f3..d614575 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -8,22 +8,43 @@ on: pull_request: jobs: - lint: - runs-on: macos-latest + generate_licenses: + if: github.event_name == 'push' && github.ref == 'refs/heads/develop + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Flutter + uses: subosito/flutter-action@v1.5.3 + with: + flutter-version: '3.32.1' + channel: "stable" + + - name: Get dependencies + run: flutter pub get + + - name: Generate oss_licenses.dart + run: flutter pub run flutter_oss_licenses:generate.dart -o lib/presentation/views/about/licenses/oss_licenses.dart + + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code - uses: actions/checkout@v4 - name: Set Up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.29.2' + flutter-version: '3.32.1' channel: 'stable' - name: Check Formatting run: flutter analyze format: - runs-on: macos-latest + runs-on: ubuntu-latest needs: lint if: ${{ failure() && needs.lint.result == 'failure' && github.event_name == 'push' && github.ref == 'refs/heads/develop'}} steps: @@ -32,7 +53,7 @@ jobs: - name: Set Up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.29.2' + flutter-version: '3.32.1' channel: 'stable' - name: Get & upgrade dependencies @@ -64,7 +85,7 @@ jobs: git push test: - runs-on: macos-latest + runs-on: ubuntu-latest if: always() needs: [lint, format] @@ -74,15 +95,18 @@ jobs: - name: Set Up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.29.2' + flutter-version: '3.32.1' channel: 'stable' + + - name: Get dependencies + run: flutter pub get - name: Run Tests run: flutter test build: - runs-on: macos-latest + runs-on: ubuntu-latest if: false # skips job needs: [lint, format, test] @@ -92,10 +116,10 @@ jobs: - name: Set Up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.29.2' + flutter-version: '3.32.1' channel: 'stable' - - name: Install dependencies + - name: Get dependencies run: flutter pub get - name: Analyze project source From 4c6b05ac4418ffa7b85ac5e324ab87c17f3d1857 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:06:16 +0200 Subject: [PATCH 330/353] Typo in flutter.yml --- .github/workflows/flutter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index d614575..f51ee0c 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - - uses: actions/checkout@v4 + uses: actions/checkout@v4 - name: Set Up Flutter uses: subosito/flutter-action@v2 From e8b3238e7e315257570c5f25b2ab5f4459b25c02 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:06:53 +0200 Subject: [PATCH 331/353] Updated typo again --- .github/workflows/flutter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index f51ee0c..35f9ebe 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -9,7 +9,7 @@ on: jobs: generate_licenses: - if: github.event_name == 'push' && github.ref == 'refs/heads/develop + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' runs-on: ubuntu-latest steps: From 192516e3f956fa46a5415e19c141cabc181ef340 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:11:46 +0200 Subject: [PATCH 332/353] Update oss_licenses.dart --- .../views/about/licenses/oss_licenses.dart | 5463 ----------------- 1 file changed, 5463 deletions(-) diff --git a/lib/presentation/views/about/licenses/oss_licenses.dart b/lib/presentation/views/about/licenses/oss_licenses.dart index f070f1e..8b13789 100644 --- a/lib/presentation/views/about/licenses/oss_licenses.dart +++ b/lib/presentation/views/about/licenses/oss_licenses.dart @@ -1,5464 +1 @@ -// cSpell:disable -/// This code was generated by flutter_oss_licenses -/// https://pub.dev/packages/flutter_oss_licenses -const ossLicenses = [ - Package( - name: '_fe_analyzer_shared', - description: - 'Logic that is shared between the front_end and analyzer packages.', - repository: - 'https://github.com/dart-lang/sdk/tree/main/pkg/_fe_analyzer_shared', - authors: [], - version: '85.0.0', - license: '''Copyright 2019, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'analyzer', - description: - 'This package provides a library that performs static analysis of Dart code.', - repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/analyzer', - authors: [], - version: '7.5.2', - license: '''Copyright 2013, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'args', - description: - 'Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/args', - authors: [], - version: '2.7.0', - license: '''Copyright 2013, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'async', - description: - "Utility functions and classes related to the 'dart:async' library.", - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/async', - authors: [], - version: '2.13.0', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'boolean_selector', - description: - "A flexible syntax for boolean expressions, based on a simplified version of Dart's expression syntax.", - repository: - 'https://github.com/dart-lang/tools/tree/main/pkgs/boolean_selector', - authors: [], - version: '2.1.2', - license: '''Copyright 2016, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'characters', - description: - 'String replacement with operations that are Unicode/grapheme cluster aware.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/characters', - authors: [], - version: '1.4.0', - license: '''Copyright 2019, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'checked_yaml', - description: - 'Generate more helpful exceptions when decoding YAML documents using package:json_serializable and package:yaml.', - repository: - 'https://github.com/google/json_serializable.dart/tree/master/checked_yaml', - authors: [], - version: '2.0.3', - license: '''Copyright 2019, the Dart project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'cli_config', - description: - 'A library to take config values from configuration files, CLI arguments, and environment variables.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/cli_config', - authors: [], - version: '0.2.0', - license: '''Copyright 2023, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'clock', - description: 'A fakeable wrapper for dart:core clock APIs.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/clock', - authors: [], - version: '1.1.2', - license: '''Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'collection', - description: - 'Collections and utilities functions and classes related to collections.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/collection', - authors: [], - version: '1.19.1', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'confetti', - description: - 'Blast colorful confetti all over the screen. Celebrate in app achievements with style. Control the velocity, angle, gravity and amount of confetti.', - homepage: 'https://github.com/funwithflutter/flutter_confetti', - authors: [], - version: '0.6.0', - license: '''The MIT License (MIT) -Copyright (c) 2018 Felix Angelov - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'convert', - description: - 'Utilities for converting between data representations. Provides a number of Sink, Codec, Decoder, and Encoder types.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/convert', - authors: [], - version: '3.1.2', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'coverage', - description: 'Coverage data manipulation and formatting', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/coverage', - authors: [], - version: '1.14.0', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'cross_file', - description: - 'An abstraction to allow working with files across multiple platforms.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/cross_file', - authors: [], - version: '0.3.4+2', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'crypto', - description: - 'Implementations of SHA, MD5, and HMAC cryptographic functions.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/crypto', - authors: [], - version: '3.0.6', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'cupertino_icons', - description: - 'Default icons asset for Cupertino widgets based on Apple styled icons', - repository: - 'https://github.com/flutter/packages/tree/main/third_party/packages/cupertino_icons', - authors: [], - version: '1.0.8', - license: '''The MIT License (MIT) - -Copyright (c) 2016 Vladimir Kharlampidi - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'dart_pubspec_licenses', - description: - 'A library to make it easy to extract OSS license information from Dart packages using pubspec.yaml', - homepage: - 'https://github.com/espresso3389/flutter_oss_licenses/tree/master/packages/dart_pubspec_licenses', - repository: 'https://github.com/espresso3389/flutter_oss_licenses', - authors: [], - version: '2.0.3', - license: '''MIT License - -Copyright (c) 2019 Takashi Kawasaki - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'dio', - description: '''A powerful HTTP networking package, -supports Interceptors, -Aborting and canceling a request, -Custom adapters, Transformers, etc. -''', - homepage: 'https://github.com/cfug/dio', - repository: 'https://github.com/cfug/dio/blob/main/dio', - authors: [], - version: '5.8.0+1', - license: '''MIT License - -Copyright (c) 2018 Wen Du (wendux) -Copyright (c) 2022 The CFUG Team - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'dio_web_adapter', - description: 'An adapter that supports Dio on Web.', - homepage: 'https://github.com/cfug/dio', - repository: 'https://github.com/cfug/dio/blob/main/plugins/web_adapter', - authors: [], - version: '2.1.1', - license: '''MIT License - -Copyright (c) 2018 Wen Du (wendux) -Copyright (c) 2022 The CFUG Team - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'fake_async', - description: - 'Fake asynchronous events such as timers and microtasks for deterministic testing.', - repository: 'https://github.com/dart-lang/test/tree/master/pkgs/fake_async', - authors: [], - version: '1.3.3', - license: '''Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'ffi', - description: - 'Utilities for working with Foreign Function Interface (FFI) code.', - repository: 'https://github.com/dart-lang/native/tree/main/pkgs/ffi', - authors: [], - version: '2.1.4', - license: '''Copyright 2019, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'file', - description: - 'A pluggable, mockable file system abstraction for Dart. Supports local file system access, as well as in-memory file systems, record-replay file systems, and chroot file systems.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/file', - authors: [], - version: '7.0.1', - license: '''Copyright 2017, the Dart project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'file_picker', - description: - 'A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.', - homepage: 'https://github.com/miguelpruivo/plugins_flutter_file_picker', - repository: 'https://github.com/miguelpruivo/flutter_file_picker', - authors: [], - version: '10.1.9', - license: '''MIT License - -Copyright (c) 2018 Miguel Ruivo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'file_saver', - description: - 'This package will help you save file with a single method on any platform including macOS, iOS, Android, Windows, Web, Linux.', - homepage: 'https://hassanansari.dev', - repository: 'https://github.com/incrediblezayed/file_saver', - authors: [], - version: '0.2.14', - license: '''BSD 3-Clause License - -Copyright (c) 2021, Hassan Ansari -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'fixnum', - description: - 'Library for 32- and 64-bit signed fixed-width integers with consistent behavior between native and JS runtimes.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/fixnum', - authors: [], - version: '1.1.1', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter', - description: 'A framework for writing Flutter applications', - homepage: 'https://flutter.dev', - authors: [], - version: '3.32.1', - license: '''Copyright 2014 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: true, - isDirectDependency: true, - ), - Package( - name: 'flutter_keyboard_visibility', - description: - 'Flutter plugin for discovering the state of the soft-keyboard visibility on Android and iOS.', - homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - authors: [], - version: '6.0.0', - license: '''The MIT License - -Copyright (c) 2022 Jason Rai -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'flutter_keyboard_visibility_linux', - description: - "An implementation for the linux platform of `flutter_keyboard_visibility'", - homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - authors: [], - version: '1.0.0', - license: '''The MIT License - -Copyright (c) 2022 Jason Rai -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter_keyboard_visibility_macos', - description: - "An implementation for the macOS platform of `flutter_keyboard_visibility'", - homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - authors: [], - version: '1.0.0', - license: '''The MIT License - -Copyright (c) 2022 Jason Rai -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter_keyboard_visibility_platform_interface', - description: - 'A common platform interface for the flutter_keyboard_visibility plugin.', - homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - authors: [], - version: '2.0.0', - license: '''The MIT License - -Copyright (c) 2006-2020 -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter_keyboard_visibility_web', - description: - "An implementation for the web platform of `flutter_keyboard_visibility'", - homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - authors: [], - version: '2.0.0', - license: '''The MIT License - -Copyright (c) 2006-2020 -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter_keyboard_visibility_windows', - description: - "An implementation for the Windows platform of `flutter_keyboard_visibility'", - homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', - authors: [], - version: '1.0.0', - license: '''The MIT License - -Copyright (c) 2022 Jason Rai -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter_lints', - description: - 'Recommended lints for Flutter apps, packages, and plugins to encourage good coding practices.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/flutter_lints', - authors: [], - version: '5.0.0', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter_oss_licenses', - description: - 'A tool to generate detail and better OSS license list using pubspec.yaml/lock files.', - homepage: - 'https://github.com/espresso3389/flutter_oss_licenses/tree/master/packages/flutter_oss_licenses', - repository: 'https://github.com/espresso3389/flutter_oss_licenses', - authors: [], - version: '2.0.3', - license: '''MIT License - -Copyright (c) 2019 Takashi Kawasaki - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'flutter_plugin_android_lifecycle', - description: - 'Flutter plugin for accessing an Android Lifecycle within other plugins.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/flutter_plugin_android_lifecycle', - authors: [], - version: '2.0.28', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'flutter_rating_bar', - description: - 'A simple yet fully customizable ratingbar for flutter which also include a rating bar indicator, supporting any fraction of rating.', - homepage: 'https://sarbagyastha.com.np', - repository: 'https://github.com/sarbagyastha/flutter_rating_bar', - authors: [], - version: '4.0.1', - license: '''The MIT License (MIT) - -Copyright (c) 2021 Sarbagya Dhaubanjar - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'font_awesome_flutter', - description: - 'The Font Awesome Icon pack available as Flutter Icons. Provides 2000 additional icons to use in your apps.', - repository: 'https://github.com/fluttercommunity/font_awesome_flutter', - authors: [], - version: '10.8.0', - license: '''MIT License - -Copyright (c) 2017 Brian Egan -Copyright (c) 2020 Michael Spiss -Font Awesome Icons by @fontawesome - https://fontawesome.com -License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'frontend_server_client', - description: - 'Client code to start and interact with the frontend_server compiler from the Dart SDK.', - repository: - 'https://github.com/dart-lang/webdev/tree/master/frontend_server_client', - authors: [], - version: '4.0.0', - license: '''Copyright 2020, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'glob', - description: 'A library to perform Bash-style file and directory globbing.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/glob', - authors: [], - version: '2.1.3', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'http', - description: - 'A composable, multi-platform, Future-based API for HTTP requests.', - repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http', - authors: [], - version: '1.4.0', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'http_multi_server', - description: - 'A dart:io HttpServer wrapper that handles requests from multiple servers.', - repository: - 'https://github.com/dart-lang/http/tree/master/pkgs/http_multi_server', - authors: [], - version: '3.2.2', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'http_parser', - description: - 'A platform-independent package for parsing and serializing HTTP formats.', - repository: - 'https://github.com/dart-lang/http/tree/master/pkgs/http_parser', - authors: [], - version: '4.1.2', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'intl', - description: - 'Contains code to deal with internationalized/localized messages, date and number formatting and parsing, bi-directional text, and other internationalization issues.', - repository: 'https://github.com/dart-lang/i18n/tree/main/pkgs/intl', - authors: [], - version: '0.20.2', - license: '''Copyright 2013, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'io', - description: - 'Utilities for the Dart VM Runtime including support for ANSI colors, file copying, and standard exit code values.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/io', - authors: [], - version: '1.0.5', - license: '''Copyright 2017, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'js', - description: - 'Annotations to create static Dart interfaces for JavaScript APIs.', - repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/js', - authors: [], - version: '0.7.2', - license: '''Copyright 2012, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'json_annotation', - description: - 'Classes and helper functions that support JSON code generation via the `json_serializable` package.', - repository: - 'https://github.com/google/json_serializable.dart/tree/master/json_annotation', - authors: [], - version: '4.9.0', - license: '''Copyright 2017, the Dart project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'json_schema', - description: 'JSON Schema implementation in Dart', - homepage: 'https://github.com/workiva/json_schema', - authors: [], - version: '5.2.1', - license: '''Copyright 2013-2022 Workiva Inc. - -Licensed under the Boost Software License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.boost.org/LICENSE_1_0.txt - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -This software or document includes material copied from or derived -from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite), -Copyright (c) 2012 Julian Berman, which is licensed under the following terms: - - Copyright (c) 2012 Julian Berman - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'leak_tracker', - description: - 'A framework for memory leak tracking for Dart and Flutter applications.', - repository: - 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker', - authors: [], - version: '10.0.9', - license: '''Copyright 2022, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'leak_tracker_flutter_testing', - description: 'An internal package to test leak tracking with Flutter.', - repository: - 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_flutter_testing', - authors: [], - version: '3.0.9', - license: '''Copyright 2022, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'leak_tracker_testing', - description: 'Leak tracking code intended for usage in tests.', - repository: - 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_testing', - authors: [], - version: '3.0.1', - license: '''Copyright 2022, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'lints', - description: - """Official Dart lint rules. Defines the 'core' and 'recommended' set of lints suggested by the Dart team. -""", - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/lints', - authors: [], - version: '5.1.1', - license: '''Copyright 2021, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'logger', - description: - 'Small, easy to use and extensible logger which prints beautiful logs.', - repository: 'https://github.com/SourceHorizon/logger', - authors: [], - version: '2.5.0', - license: '''MIT License - -Copyright (c) 2019 Simon Leier -Copyright (c) 2019 Harm Aarts -Copyright (c) 2023 Severin Hamader - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'logging', - description: - 'Provides APIs for debugging and error logging, similar to loggers in other languages, such as the Closure JS Logger and java.util.logging.Logger.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/logging', - authors: [], - version: '1.3.0', - license: '''Copyright 2013, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'matcher', - description: - 'Support for specifying test expectations via an extensible Matcher class. Also includes a number of built-in Matcher implementations for common cases.', - repository: 'https://github.com/dart-lang/test/tree/master/pkgs/matcher', - authors: [], - version: '0.12.17', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'material_color_utilities', - description: - 'Algorithms and utilities that power the Material Design 3 color system, including choosing theme colors from images and creating tones of colors; all in a new color space.', - repository: - 'https://github.com/material-foundation/material-color-utilities/tree/main/dart', - authors: [], - version: '0.11.1', - license: '''Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 Google LLC - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'meta', - description: - "Annotations used to express developer intentions that can't otherwise be deduced by statically analyzing source code.", - repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/meta', - authors: [], - version: '1.16.0', - license: '''Copyright 2016, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'mime', - description: - 'Utilities for handling media (MIME) types, including determining a type from a file extension and file contents.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/mime', - authors: [], - version: '2.0.0', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'node_preamble', - description: - 'Better node.js preamble for dart2js, use it in your build system.', - homepage: 'https://github.com/mbullington/node_preamble.dart', - authors: ['Michael Bullington '], - version: '2.0.2', - license: '''The MIT License (MIT) - -Copyright (c) 2015 Michael Bullington - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -=== - -Copyright 2012, the Dart project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'package_config', - description: - 'Support for reading and writing Dart Package Configuration files.', - repository: - 'https://github.com/dart-lang/tools/tree/main/pkgs/package_config', - authors: [], - version: '2.2.0', - license: '''Copyright 2019, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'package_info_plus', - description: - 'Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android.', - homepage: 'https://github.com/fluttercommunity/plus_plugins', - repository: - 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus/package_info_plus', - authors: [], - version: '8.3.0', - license: '''Copyright 2017 The Chromium Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'package_info_plus_platform_interface', - description: - 'A common platform interface for the package_info_plus plugin.', - homepage: 'https://github.com/fluttercommunity/plus_plugins', - repository: - 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/', - authors: [], - version: '3.2.0', - license: '''Copyright 2017 The Chromium Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'path', - description: - 'A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/path', - authors: [], - version: '1.9.1', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'path_provider', - description: - 'Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider', - authors: [], - version: '2.1.5', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'path_provider_android', - description: 'Android implementation of the path_provider plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android', - authors: [], - version: '2.2.17', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'path_provider_foundation', - description: 'iOS and macOS implementation of the path_provider plugin', - repository: - 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation', - authors: [], - version: '2.4.1', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'path_provider_linux', - description: 'Linux implementation of the path_provider plugin', - repository: - 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_linux', - authors: [], - version: '2.2.1', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'path_provider_platform_interface', - description: 'A common platform interface for the path_provider plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_platform_interface', - authors: [], - version: '2.1.2', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'path_provider_windows', - description: 'Windows implementation of the path_provider plugin', - repository: - 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_windows', - authors: [], - version: '2.3.0', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'platform', - description: - 'A pluggable, mockable platform information abstraction for Dart.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/platform', - authors: [], - version: '3.1.6', - license: '''Copyright 2017, the Dart project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'plugin_platform_interface', - description: - 'Reusable base class for platform interfaces of Flutter federated plugins, to help enforce best practices.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/plugin_platform_interface', - authors: [], - version: '2.1.8', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'pool', - description: - 'Manage a finite pool of resources. Useful for controlling concurrent file system or network requests.', - repository: 'https://github.com/dart-lang/pool', - authors: [], - version: '1.5.1', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'pub_semver', - description: - "Versions and version constraints implementing pub's versioning policy. This is very similar to vanilla semver, with a few corner cases.", - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/pub_semver', - authors: [], - version: '2.2.0', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'pubspec_parse', - description: - 'Simple package for parsing pubspec.yaml files with a type-safe API and rich error reporting.', - repository: - 'https://github.com/dart-lang/tools/tree/main/pkgs/pubspec_parse', - authors: [], - version: '1.5.0', - license: '''Copyright 2018, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'quiver', - description: - 'Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.', - repository: 'https://github.com/google/quiver-dart', - authors: [], - version: '3.2.2', - license: '''Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'rate_my_app', - description: - 'Allows to kindly ask users to rate your app if custom conditions are met (eg. install time, number of launches, etc...).', - homepage: 'https://github.com/Skyost/RateMyApp', - authors: [], - version: '2.3.2', - license: '''MIT License - -Copyright (c) 2019 Hugo DELAUNAY "Skyost" - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'reorderables', - description: - 'Reorderable table, row, column, wrap, sliver list that allow drag and drop of their children.', - homepage: 'https://github.com/hanshengchiu/reorderables', - authors: [], - version: '0.4.4', - license: '''MIT License - -Copyright (c) 2019 Hansheng Chiu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'rfc_6901', - description: - 'JSON Pointer (RFC 6901). Reads/writes referred values in JSON documents.', - homepage: 'https://github.com/f3ath/rfc-6901-dart', - authors: [], - version: '0.2.0', - license: '''MIT License - -Copyright (c) 2021 The Конь - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shared_preferences', - description: - 'Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences', - authors: [], - version: '2.5.3', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'shared_preferences_android', - description: 'Android implementation of the shared_preferences plugin', - repository: - 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android', - authors: [], - version: '2.4.10', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shared_preferences_foundation', - description: - 'iOS and macOS implementation of the shared_preferences plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation', - authors: [], - version: '2.5.4', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shared_preferences_linux', - description: 'Linux implementation of the shared_preferences plugin', - repository: - 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux', - authors: [], - version: '2.4.1', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shared_preferences_platform_interface', - description: - 'A common platform interface for the shared_preferences plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_platform_interface', - authors: [], - version: '2.4.1', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shared_preferences_web', - description: 'Web platform implementation of shared_preferences', - repository: - 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_web', - authors: [], - version: '2.4.3', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shared_preferences_windows', - description: 'Windows implementation of shared_preferences', - repository: - 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_windows', - authors: [], - version: '2.4.1', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shelf', - description: - '''A model for web server middleware that encourages composition and easy reuse. -''', - repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf', - authors: [], - version: '1.4.2', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shelf_packages_handler', - description: 'A shelf handler for serving a `packages/` directory.', - repository: - 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_packages_handler', - authors: [], - version: '3.0.2', - license: '''Copyright 2016, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shelf_static', - description: - 'Static file server support for the shelf package and ecosystem.', - repository: - 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_static', - authors: [], - version: '1.1.3', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'shelf_web_socket', - description: - 'A shelf handler that wires up a listener for every connection.', - repository: - 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_web_socket', - authors: [], - version: '3.0.0', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'source_map_stack_trace', - description: 'A package for applying source maps to stack traces.', - repository: - 'https://github.com/dart-lang/tools/tree/main/pkgs/source_map_stack_trace', - authors: [], - version: '2.1.2', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'source_maps', - description: 'A library to programmatically manipulate source map files.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_maps', - authors: [], - version: '0.10.13', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'source_span', - description: - 'Provides a standard representation for source code locations and spans.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_span', - authors: [], - version: '1.10.1', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'sprintf', - description: - 'Dart implementation of sprintf. Provides simple printf like formatting such as sprintf("hello %s", ["world"]);', - homepage: 'https://github.com/Naddiseo/dart-sprintf', - authors: [], - version: '7.0.0', - license: '''Copyright (c) 2012, Richard Eames -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'stack_trace', - description: - 'A package for manipulating stack traces and printing them readably.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/stack_trace', - authors: [], - version: '1.12.1', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'stream_channel', - description: - 'An abstraction for two-way communication channels based on the Dart Stream class.', - repository: - 'https://github.com/dart-lang/tools/tree/main/pkgs/stream_channel', - authors: [], - version: '2.1.4', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'string_scanner', - description: 'A class for parsing strings using a sequence of patterns.', - repository: - 'https://github.com/dart-lang/tools/tree/main/pkgs/string_scanner', - authors: [], - version: '1.4.1', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'syncfusion_flutter_charts', - description: - 'A Flutter Charts library which includes data visualization widgets such as cartesian and circular charts, to create real-time, interactive, high-performance, animated charts.', - homepage: - 'https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_charts', - authors: [], - version: '30.1.37', - license: '''Syncfusion® License - -Syncfusion® Flutter Chart package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. - -To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars (\$1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. - -Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. - -Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion® license containing all terms and conditions. - -The Syncfusion® license that contains the terms and conditions can be found at -https://www.syncfusion.com/content/downloads/syncfusion_license.pdf''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'syncfusion_flutter_core', - description: - 'Syncfusion Flutter Core is a dependent package for all the Syncfusion Flutter widgets.', - homepage: - 'https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_core', - authors: [], - version: '30.1.42', - license: '''Syncfusion® License - -Syncfusion® Flutter Core package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. - -To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars (\$1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. - -Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. - -Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion® license containing all terms and conditions. - -The Syncfusion® license that contains the terms and conditions can be found at -https://www.syncfusion.com/content/downloads/syncfusion_license.pdf''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'term_glyph', - description: 'Useful Unicode glyphs and ASCII substitutes.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/term_glyph', - authors: [], - version: '1.2.2', - license: '''Copyright 2017, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'test', - description: - 'A full featured library for writing and running Dart tests across platforms.', - repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test', - authors: [], - version: '1.25.15', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'test_api', - description: - 'The user facing API for structuring Dart tests and checking expectations.', - repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_api', - authors: [], - version: '0.7.4', - license: '''Copyright 2018, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'test_core', - description: - 'A basic library for writing tests and running them on the VM.', - repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_core', - authors: [], - version: '0.6.8', - license: '''Copyright 2018, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'typed_data', - description: - 'Utility functions and classes related to the dart:typed_data library.', - repository: 'https://github.com/dart-lang/core/tree/main/pkgs/typed_data', - authors: [], - version: '1.4.0', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'uri', - description: - 'Utilities for building and parsing URIs, including support for parsing URI templates as defined in RFC 6570.', - repository: 'https://github.com/google/uri.dart', - authors: [], - version: '1.0.0', - license: '''Copyright 2013, the Dart project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'url_launcher', - description: - 'Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher', - authors: [], - version: '6.3.1', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'url_launcher_android', - description: 'Android implementation of the url_launcher plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_android', - authors: [], - version: '6.3.16', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'url_launcher_ios', - description: 'iOS implementation of the url_launcher plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_ios', - authors: [], - version: '6.3.3', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'url_launcher_linux', - description: 'Linux implementation of the url_launcher plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_linux', - authors: [], - version: '3.2.1', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'url_launcher_macos', - description: 'macOS implementation of the url_launcher plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_macos', - authors: [], - version: '3.2.2', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'url_launcher_platform_interface', - description: 'A common platform interface for the url_launcher plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_platform_interface', - authors: [], - version: '2.3.2', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'url_launcher_web', - description: 'Web platform implementation of url_launcher', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_web', - authors: [], - version: '2.4.1', - license: '''url_launcher_web - -Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------------- -platform_detect - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017 Workiva Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'url_launcher_windows', - description: 'Windows implementation of the url_launcher plugin.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_windows', - authors: [], - version: '3.1.4', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'uuid', - description: - '''RFC4122 (v1, v4, v5, v6, v7, v8) UUID Generator and Parser for Dart -''', - repository: 'https://github.com/Daegalus/dart-uuid', - authors: [], - version: '4.5.1', - license: '''Copyright (c) 2021 Yulian Kuncheff - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: true, - ), - Package( - name: 'vector_math', - description: 'A Vector Math library for 2D and 3D applications.', - repository: 'https://github.com/google/vector_math.dart', - authors: [], - version: '2.1.4', - license: '''Copyright 2015, Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Copyright (C) 2013 Andrew Magill - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'vm_service', - description: - 'A library to communicate with a service implementing the Dart VM service protocol.', - repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/vm_service', - authors: [], - version: '15.0.0', - license: '''Copyright 2015, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'watcher', - description: - 'A file system watcher. It monitors changes to contents of directories and sends notifications when files have been added, removed, or modified.', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/watcher', - authors: [], - version: '1.1.1', - license: '''Copyright 2014, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'web', - description: 'Lightweight browser API bindings built around JS interop.', - repository: 'https://github.com/dart-lang/web', - authors: [], - version: '1.1.1', - license: '''Copyright 2023, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'web_socket', - description: - 'Any easy-to-use library for communicating with WebSockets that has multiple implementations.', - repository: 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket', - authors: [], - version: '1.0.1', - license: '''Copyright 2024, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'web_socket_channel', - description: - 'StreamChannel wrappers for WebSockets. Provides a cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying StreamChannel.', - repository: - 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket_channel', - authors: [], - version: '3.0.3', - license: '''Copyright 2016, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'webkit_inspection_protocol', - description: - '''A client for the Chrome DevTools Protocol (previously called the Webkit Inspection Protocol). -''', - repository: 'https://github.com/google/webkit_inspection_protocol.dart', - authors: [], - version: '1.2.1', - license: '''Copyright 2013, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'win32', - description: - '''Access common Win32 APIs directly from Dart using FFI — no C required! -''', - homepage: 'https://win32.pub', - repository: 'https://github.com/halildurmus/win32', - authors: [], - version: '5.13.0', - license: '''BSD 3-Clause License - -Copyright (c) 2024, Halil Durmus - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'xdg_directories', - description: - 'A Dart package for reading XDG directory configuration information on Linux.', - repository: - 'https://github.com/flutter/packages/tree/main/packages/xdg_directories', - authors: [], - version: '1.1.0', - license: '''Copyright 2013 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), - Package( - name: 'yaml', - description: - 'A parser for YAML, a human-friendly data serialization standard', - repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/yaml', - authors: [], - version: '3.1.3', - license: '''Copyright (c) 2014, the Dart project authors. -Copyright (c) 2006, Kirill Simonov. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.''', - isMarkdown: false, - isSdk: false, - isDirectDependency: false, - ), -]; - -/// Package license definition. -class Package { - /// Package name - final String name; - - /// Description - final String description; - - /// Website URL - final String? homepage; - - /// Repository URL - final String? repository; - - /// Authors - final List authors; - - /// Version - final String version; - - /// License - final String? license; - - /// Whether the license is in markdown format or not (plain text). - final bool isMarkdown; - - /// Whether the package is included in the SDK or not. - final bool isSdk; - - /// Whether the package is direct dependency or not. - final bool isDirectDependency; - - const Package({ - required this.name, - required this.description, - this.homepage, - this.repository, - required this.authors, - required this.version, - this.license, - required this.isMarkdown, - required this.isSdk, - required this.isDirectDependency, - }); -} From 60891622ead915b627ace3ee59088bdd09c69182 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:14:22 +0200 Subject: [PATCH 333/353] Upgraded workflow --- .github/workflows/flutter.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 35f9ebe..5a06062 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -28,8 +28,27 @@ jobs: - name: Generate oss_licenses.dart run: flutter pub run flutter_oss_licenses:generate.dart -o lib/presentation/views/about/licenses/oss_licenses.dart + - name: Check for changes + id: check_changes + run: | + if [[ $(git status --porcelain) ]]; then + echo "changes_detected=true" >> $GITHUB_OUTPUT + else + echo "changes_detected=false" >> $GITHUB_OUTPUT + fi + + - name: Commit Changes + if: steps.check_changes.outputs.changes_detected == 'true' + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + git add . + git commit -m "Actions: Licenses updated [skip ci]" + git push + lint: runs-on: ubuntu-latest + needs: generate_licenses steps: - name: Checkout code uses: actions/checkout@v4 From 014802a378a6a0330eeff9a95c751fa7d879722e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:19:52 +0200 Subject: [PATCH 334/353] Update flutter.yml --- .github/workflows/flutter.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 5a06062..3039ad1 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -26,25 +26,25 @@ jobs: run: flutter pub get - name: Generate oss_licenses.dart - run: flutter pub run flutter_oss_licenses:generate.dart -o lib/presentation/views/about/licenses/oss_licenses.dart + run: flutter pub run flutter_oss_licenses:generate -o lib/presentation/views/about/licenses/oss_licenses.dart - - name: Check for changes - id: check_changes - run: | - if [[ $(git status --porcelain) ]]; then - echo "changes_detected=true" >> $GITHUB_OUTPUT - else - echo "changes_detected=false" >> $GITHUB_OUTPUT - fi + #- name: Check for changes + # id: check_changes + # run: | + # if [[ $(git status --porcelain) ]]; then + # echo "changes_detected=true" >> $GITHUB_OUTPUT + # else + # echo "changes_detected=false" >> $GITHUB_OUTPUT + # fi - - name: Commit Changes - if: steps.check_changes.outputs.changes_detected == 'true' - run: | - git config --global user.name "GitHub Actions" - git config --global user.email "actions@github.com" - git add . - git commit -m "Actions: Licenses updated [skip ci]" - git push + #- name: Commit Changes + # if: steps.check_changes.outputs.changes_detected == 'true' + # run: | + # git config --global user.name "GitHub Actions" + # git config --global user.email "actions@github.com" + # git add . + # git commit -m "Actions: Licenses updated [skip ci]" + # git push lint: runs-on: ubuntu-latest From f6d90551b6968a1e5e902084c7f38e0cfdd83546 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:24:42 +0200 Subject: [PATCH 335/353] Update flutter.yml --- .github/workflows/flutter.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 3039ad1..3586942 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -37,14 +37,13 @@ jobs: # echo "changes_detected=false" >> $GITHUB_OUTPUT # fi - #- name: Commit Changes - # if: steps.check_changes.outputs.changes_detected == 'true' - # run: | - # git config --global user.name "GitHub Actions" - # git config --global user.email "actions@github.com" - # git add . - # git commit -m "Actions: Licenses updated [skip ci]" - # git push + - name: Commit Changes + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + git add . + git commit -m "Actions: Licenses updated [skip ci]" + git push lint: runs-on: ubuntu-latest From 4a659167cb28406beb8f3701cfba46317bf4043c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:26:42 +0200 Subject: [PATCH 336/353] Update flutter.yml --- .github/workflows/flutter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 3586942..2f086f2 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -9,7 +9,7 @@ on: jobs: generate_licenses: - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + if: github.event_name == 'push' #&& github.ref == 'refs/heads/develop' runs-on: ubuntu-latest steps: From a4292ecede159c1415fa14b24bda6ebf0502ad8e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:27:14 +0200 Subject: [PATCH 337/353] Update flutter.yml --- .github/workflows/flutter.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 2f086f2..275fd48 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -2,9 +2,9 @@ name: Flutter on: push: - branches: - - "develop" - - "main" + #branches: + # - "develop" + #- "main" pull_request: jobs: From a07142b5b577d2bcb7cfccd7b81d0fd55cc6895b Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 18 Aug 2025 11:28:49 +0000 Subject: [PATCH 338/353] Actions: Licenses updated [skip ci] --- lib/l10n/generated/app_localizations.dart | 29 +- lib/l10n/generated/app_localizations_de.dart | 6 +- lib/l10n/generated/app_localizations_en.dart | 6 +- .../views/about/licenses/oss_licenses.dart | 5898 +++++++++++++++++ 4 files changed, 5925 insertions(+), 14 deletions(-) diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index ad31f5a..1539e77 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -63,7 +63,7 @@ import 'app_localizations_en.dart'; /// property. abstract class AppLocalizations { AppLocalizations(String locale) - : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); final String localeName; @@ -86,16 +86,16 @@ abstract class AppLocalizations { /// of delegates is preferred or required. static const List> localizationsDelegates = >[ - delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ]; + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; /// A list of this localizations delegate's supported locales. static const List supportedLocales = [ Locale('de'), - Locale('en') + Locale('en'), ]; /// No description provided for @app_name. @@ -487,7 +487,11 @@ abstract class AppLocalizations { /// In de, this message translates to: /// **'{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}'** String bonus_points_message( - int playerCount, String names, int pointLimit, int bonusPoints); + int playerCount, + String names, + int pointLimit, + int bonusPoints, + ); /// No description provided for @end_of_game_title. /// @@ -775,8 +779,9 @@ AppLocalizations lookupAppLocalizations(Locale locale) { } throw FlutterError( - 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.'); + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.', + ); } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 069a214..d1a0a7e 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -214,7 +214,11 @@ class AppLocalizationsDe extends AppLocalizations { @override String bonus_points_message( - int playerCount, String names, int pointLimit, int bonusPoints) { + int playerCount, + String names, + int pointLimit, + int bonusPoints, + ) { String _temp0 = intl.Intl.pluralLogic( playerCount, locale: localeName, diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 777d979..2f34bd2 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -211,7 +211,11 @@ class AppLocalizationsEn extends AppLocalizations { @override String bonus_points_message( - int playerCount, String names, int pointLimit, int bonusPoints) { + int playerCount, + String names, + int pointLimit, + int bonusPoints, + ) { String _temp0 = intl.Intl.pluralLogic( playerCount, locale: localeName, diff --git a/lib/presentation/views/about/licenses/oss_licenses.dart b/lib/presentation/views/about/licenses/oss_licenses.dart index 8b13789..310bcce 100644 --- a/lib/presentation/views/about/licenses/oss_licenses.dart +++ b/lib/presentation/views/about/licenses/oss_licenses.dart @@ -1 +1,5899 @@ +// cSpell:disable +/// This code was generated by flutter_oss_licenses +/// https://pub.dev/packages/flutter_oss_licenses +const ossLicenses = [ + Package( + name: '_fe_analyzer_shared', + description: 'Logic that is shared between the front_end and analyzer packages.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/_fe_analyzer_shared', + authors: [], + version: '85.0.0', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'analyzer', + description: 'This package provides a library that performs static analysis of Dart code.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/analyzer', + authors: [], + version: '7.7.1', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'args', + description: 'Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/args', + authors: [], + version: '2.7.0', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'async', + description: "Utility functions and classes related to the 'dart:async' library.", + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/async', + authors: [], + version: '2.13.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'boolean_selector', + description: "A flexible syntax for boolean expressions, based on a simplified version of Dart's expression syntax.", + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/boolean_selector', + authors: [], + version: '2.1.2', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'characters', + description: 'String replacement with operations that are Unicode/grapheme cluster aware.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/characters', + authors: [], + version: '1.4.0', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'cli_config', + description: 'A library to take config values from configuration files, CLI arguments, and environment variables.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/cli_config', + authors: [], + version: '0.2.0', + license: '''Copyright 2023, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'clock', + description: 'A fakeable wrapper for dart:core clock APIs.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/clock', + authors: [], + version: '1.1.2', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'collection', + description: 'Collections and utilities functions and classes related to collections.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/collection', + authors: [], + version: '1.19.1', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'confetti', + description: 'Blast colorful confetti all over the screen. Celebrate in app achievements with style. Control the velocity, angle, gravity and amount of confetti.', + homepage: 'https://github.com/funwithflutter/flutter_confetti', + authors: [], + version: '0.6.0', + license: '''The MIT License (MIT) +Copyright (c) 2018 Felix Angelov + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'convert', + description: 'Utilities for converting between data representations. Provides a number of Sink, Codec, Decoder, and Encoder types.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/convert', + authors: [], + version: '3.1.2', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'coverage', + description: 'Coverage data manipulation and formatting', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/coverage', + authors: [], + version: '1.15.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'cross_file', + description: 'An abstraction to allow working with files across multiple platforms.', + repository: 'https://github.com/flutter/packages/tree/main/packages/cross_file', + authors: [], + version: '0.3.4+2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'crypto', + description: 'Implementations of SHA, MD5, and HMAC cryptographic functions.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/crypto', + authors: [], + version: '3.0.6', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'cupertino_icons', + description: 'Default icons asset for Cupertino widgets based on Apple styled icons', + repository: 'https://github.com/flutter/packages/tree/main/third_party/packages/cupertino_icons', + authors: [], + version: '1.0.8', + license: '''The MIT License (MIT) + +Copyright (c) 2016 Vladimir Kharlampidi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'dart_pubspec_licenses', + description: 'A library to make it easy to extract OSS license information from Dart packages using pubspec.yaml', + homepage: 'https://github.com/espresso3389/flutter_oss_licenses/tree/master/packages/dart_pubspec_licenses', + repository: 'https://github.com/espresso3389/flutter_oss_licenses', + authors: [], + version: '2.0.3', + license: '''MIT License + +Copyright (c) 2019 Takashi Kawasaki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'dbus', + description: 'A native Dart implementation of the D-Bus message bus client. This package allows Dart applications to directly access services on the Linux desktop.', + homepage: 'https://github.com/canonical/dbus.dart', + authors: [], + version: '0.7.11', + license: '''Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'dio', + description: '''A powerful HTTP networking package, +supports Interceptors, +Aborting and canceling a request, +Custom adapters, Transformers, etc. +''', + homepage: 'https://github.com/cfug/dio', + repository: 'https://github.com/cfug/dio/blob/main/dio', + authors: [], + version: '5.9.0', + license: '''MIT License + +Copyright (c) 2018 Wen Du (wendux) +Copyright (c) 2022 The CFUG Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'dio_web_adapter', + description: 'An adapter that supports Dio on Web.', + homepage: 'https://github.com/cfug/dio', + repository: 'https://github.com/cfug/dio/blob/main/plugins/web_adapter', + authors: [], + version: '2.1.1', + license: '''MIT License + +Copyright (c) 2018 Wen Du (wendux) +Copyright (c) 2022 The CFUG Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'fake_async', + description: 'Fake asynchronous events such as timers and microtasks for deterministic testing.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/fake_async', + authors: [], + version: '1.3.3', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'ffi', + description: 'Utilities for working with Foreign Function Interface (FFI) code.', + repository: 'https://github.com/dart-lang/native/tree/main/pkgs/ffi', + authors: [], + version: '2.1.4', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'file', + description: 'A pluggable, mockable file system abstraction for Dart. Supports local file system access, as well as in-memory file systems, record-replay file systems, and chroot file systems.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/file', + authors: [], + version: '7.0.1', + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'file_picker', + description: 'A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.', + homepage: 'https://github.com/miguelpruivo/plugins_flutter_file_picker', + repository: 'https://github.com/miguelpruivo/flutter_file_picker', + authors: [], + version: '10.3.1', + license: '''MIT License + +Copyright (c) 2018 Miguel Ruivo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'file_saver', + description: 'This package will help you save file with a single method on any platform including macOS, iOS, Android, Windows, Web, Linux.', + homepage: 'https://hassanansari.dev', + repository: 'https://github.com/incrediblezayed/file_saver', + authors: [], + version: '0.2.14', + license: '''BSD 3-Clause License + +Copyright (c) 2021, Hassan Ansari +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'fixnum', + description: 'Library for 32- and 64-bit signed fixed-width integers with consistent behavior between native and JS runtimes.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/fixnum', + authors: [], + version: '1.1.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter', + description: 'A framework for writing Flutter applications', + homepage: 'https://flutter.dev', + authors: [], + version: '3.32.1', + license: '''Copyright 2014 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: true, + isDirectDependency: true, + ), + Package( + name: 'flutter_keyboard_visibility', + description: 'Flutter plugin for discovering the state of the soft-keyboard visibility on Android and iOS.', + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '6.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'flutter_keyboard_visibility_linux', + description: "An implementation for the linux platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '1.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_macos', + description: "An implementation for the macOS platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '1.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_platform_interface', + description: 'A common platform interface for the flutter_keyboard_visibility plugin.', + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '2.0.0', + license: '''The MIT License + +Copyright (c) 2006-2020 +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_web', + description: "An implementation for the web platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '2.0.0', + license: '''The MIT License + +Copyright (c) 2006-2020 +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_keyboard_visibility_windows', + description: "An implementation for the Windows platform of `flutter_keyboard_visibility'", + homepage: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + repository: 'https://github.com/MisterJimson/flutter_keyboard_visibility', + authors: [], + version: '1.0.0', + license: '''The MIT License + +Copyright (c) 2022 Jason Rai +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_lints', + description: 'Recommended lints for Flutter apps, packages, and plugins to encourage good coding practices.', + repository: 'https://github.com/flutter/packages/tree/main/packages/flutter_lints', + authors: [], + version: '5.0.0', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_oss_licenses', + description: 'A tool to generate detail and better OSS license list using pubspec.yaml/lock files.', + homepage: 'https://github.com/espresso3389/flutter_oss_licenses/tree/master/packages/flutter_oss_licenses', + repository: 'https://github.com/espresso3389/flutter_oss_licenses', + authors: [], + version: '2.0.3', + license: '''MIT License + +Copyright (c) 2019 Takashi Kawasaki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'flutter_plugin_android_lifecycle', + description: 'Flutter plugin for accessing an Android Lifecycle within other plugins.', + repository: 'https://github.com/flutter/packages/tree/main/packages/flutter_plugin_android_lifecycle', + authors: [], + version: '2.0.29', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'flutter_rating_bar', + description: 'A simple yet fully customizable ratingbar for flutter which also include a rating bar indicator, supporting any fraction of rating.', + homepage: 'https://sarbagyastha.com.np', + repository: 'https://github.com/sarbagyastha/flutter_rating_bar', + authors: [], + version: '4.0.1', + license: '''The MIT License (MIT) + +Copyright (c) 2021 Sarbagya Dhaubanjar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'font_awesome_flutter', + description: 'The Font Awesome Icon pack available as Flutter Icons. Provides 2000 additional icons to use in your apps.', + repository: 'https://github.com/fluttercommunity/font_awesome_flutter', + authors: [], + version: '10.9.1', + license: '''MIT License + +Copyright (c) 2017 Brian Egan +Copyright (c) 2020 Michael Spiss +Font Awesome Icons by @fontawesome - https://fontawesome.com +License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'frontend_server_client', + description: 'Client code to start and interact with the frontend_server compiler from the Dart SDK.', + repository: 'https://github.com/dart-lang/webdev/tree/master/frontend_server_client', + authors: [], + version: '4.0.0', + license: '''Copyright 2020, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'glob', + description: 'A library to perform Bash-style file and directory globbing.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/glob', + authors: [], + version: '2.1.3', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'google_fonts', + description: 'A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling.', + repository: 'https://github.com/material-foundation/flutter-packages/tree/main/packages/google_fonts', + authors: [], + version: '6.3.0', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'http', + description: 'A composable, multi-platform, Future-based API for HTTP requests.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http', + authors: [], + version: '1.5.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'http_multi_server', + description: 'A dart:io HttpServer wrapper that handles requests from multiple servers.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http_multi_server', + authors: [], + version: '3.2.2', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'http_parser', + description: 'A platform-independent package for parsing and serializing HTTP formats.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http_parser', + authors: [], + version: '4.1.2', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'intl', + description: 'Contains code to deal with internationalized/localized messages, date and number formatting and parsing, bi-directional text, and other internationalization issues.', + repository: 'https://github.com/dart-lang/i18n/tree/main/pkgs/intl', + authors: [], + version: '0.20.2', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'io', + description: 'Utilities for the Dart VM Runtime including support for ANSI colors, file copying, and standard exit code values.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/io', + authors: [], + version: '1.0.5', + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'js', + description: 'Annotations to create static Dart interfaces for JavaScript APIs.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/js', + authors: [], + version: '0.7.2', + license: '''Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'json_annotation', + description: 'Classes and helper functions that support JSON code generation via the `json_serializable` package.', + repository: 'https://github.com/google/json_serializable.dart/tree/master/json_annotation', + authors: [], + version: '4.9.0', + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'json_schema', + description: 'JSON Schema implementation in Dart', + homepage: 'https://github.com/workiva/json_schema', + authors: [], + version: '5.2.1', + license: '''Copyright 2013-2022 Workiva Inc. + +Licensed under the Boost Software License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.boost.org/LICENSE_1_0.txt + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +This software or document includes material copied from or derived +from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite), +Copyright (c) 2012 Julian Berman, which is licensed under the following terms: + + Copyright (c) 2012 Julian Berman + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'leak_tracker', + description: 'A framework for memory leak tracking for Dart and Flutter applications.', + repository: 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker', + authors: [], + version: '10.0.9', + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'leak_tracker_flutter_testing', + description: 'An internal package to test leak tracking with Flutter.', + repository: 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_flutter_testing', + authors: [], + version: '3.0.9', + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'leak_tracker_testing', + description: 'Leak tracking code intended for usage in tests.', + repository: 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_testing', + authors: [], + version: '3.0.1', + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'lints', + description: """Official Dart lint rules. Defines the 'core' and 'recommended' set of lints suggested by the Dart team. +""", + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/lints', + authors: [], + version: '5.1.1', + license: '''Copyright 2021, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'logger', + description: 'Small, easy to use and extensible logger which prints beautiful logs.', + repository: 'https://github.com/SourceHorizon/logger', + authors: [], + version: '2.6.1', + license: '''MIT License + +Copyright (c) 2019 Simon Leier +Copyright (c) 2019 Harm Aarts +Copyright (c) 2023 Severin Hamader + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'logging', + description: 'Provides APIs for debugging and error logging, similar to loggers in other languages, such as the Closure JS Logger and java.util.logging.Logger.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/logging', + authors: [], + version: '1.3.0', + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'matcher', + description: 'Support for specifying test expectations via an extensible Matcher class. Also includes a number of built-in Matcher implementations for common cases.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/matcher', + authors: [], + version: '0.12.17', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'material_color_utilities', + description: 'Algorithms and utilities that power the Material Design 3 color system, including choosing theme colors from images and creating tones of colors; all in a new color space.', + repository: 'https://github.com/material-foundation/material-color-utilities/tree/main/dart', + authors: [], + version: '0.11.1', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'meta', + description: "Annotations used to express developer intentions that can't otherwise be deduced by statically analyzing source code.", + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/meta', + authors: [], + version: '1.16.0', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'mime', + description: 'Utilities for handling media (MIME) types, including determining a type from a file extension and file contents.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/mime', + authors: [], + version: '2.0.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'node_preamble', + description: 'Better node.js preamble for dart2js, use it in your build system.', + homepage: 'https://github.com/mbullington/node_preamble.dart', + authors: ['Michael Bullington '], + version: '2.0.2', + license: '''The MIT License (MIT) + +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=== + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'package_config', + description: 'Support for reading and writing Dart Package Configuration files.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/package_config', + authors: [], + version: '2.2.0', + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'package_info_plus', + description: 'Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android.', + homepage: 'https://github.com/fluttercommunity/plus_plugins', + repository: 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus/package_info_plus', + authors: [], + version: '8.3.1', + license: '''Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'package_info_plus_platform_interface', + description: 'A common platform interface for the package_info_plus plugin.', + homepage: 'https://github.com/fluttercommunity/plus_plugins', + repository: 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/', + authors: [], + version: '3.2.1', + license: '''Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path', + description: 'A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/path', + authors: [], + version: '1.9.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider', + description: 'Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider', + authors: [], + version: '2.1.5', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'path_provider_android', + description: 'Android implementation of the path_provider plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android', + authors: [], + version: '2.2.17', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_foundation', + description: 'iOS and macOS implementation of the path_provider plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation', + authors: [], + version: '2.4.2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_linux', + description: 'Linux implementation of the path_provider plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_linux', + authors: [], + version: '2.2.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_platform_interface', + description: 'A common platform interface for the path_provider plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_platform_interface', + authors: [], + version: '2.1.2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'path_provider_windows', + description: 'Windows implementation of the path_provider plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_windows', + authors: [], + version: '2.3.0', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'petitparser', + description: 'A dynamic parser framework to build efficient grammars and parsers quickly.', + homepage: 'https://petitparser.github.io', + repository: 'https://github.com/petitparser/dart-petitparser', + authors: [], + version: '7.0.1', + license: '''The MIT License + +Copyright (c) 2006-2024 Lukas Renggli. +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'platform', + description: 'A pluggable, mockable platform information abstraction for Dart.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/platform', + authors: [], + version: '3.1.6', + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'plugin_platform_interface', + description: 'Reusable base class for platform interfaces of Flutter federated plugins, to help enforce best practices.', + repository: 'https://github.com/flutter/packages/tree/main/packages/plugin_platform_interface', + authors: [], + version: '2.1.8', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'pool', + description: 'Manage a finite pool of resources. Useful for controlling concurrent file system or network requests.', + repository: 'https://github.com/dart-lang/pool', + authors: [], + version: '1.5.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'pub_semver', + description: "Versions and version constraints implementing pub's versioning policy. This is very similar to vanilla semver, with a few corner cases.", + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/pub_semver', + authors: [], + version: '2.2.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'quiver', + description: 'Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.', + repository: 'https://github.com/google/quiver-dart', + authors: [], + version: '3.2.2', + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'rate_my_app', + description: 'Allows to kindly ask users to rate your app if custom conditions are met (eg. install time, number of launches, etc...).', + homepage: 'https://github.com/Skyost/RateMyApp', + authors: [], + version: '2.3.2', + license: '''MIT License + +Copyright (c) 2019 Hugo DELAUNAY "Skyost" + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'reorderables', + description: 'Reorderable table, row, column, wrap, sliver list that allow drag and drop of their children.', + homepage: 'https://github.com/hanshengchiu/reorderables', + authors: [], + version: '0.4.4', + license: '''MIT License + +Copyright (c) 2019 Hansheng Chiu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'rfc_6901', + description: 'JSON Pointer (RFC 6901). Reads/writes referred values in JSON documents.', + homepage: 'https://github.com/f3ath/rfc-6901-dart', + authors: [], + version: '0.2.0', + license: '''MIT License + +Copyright (c) 2021 The Конь + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences', + description: 'Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.', + repository: 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences', + authors: [], + version: '2.5.3', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'shared_preferences_android', + description: 'Android implementation of the shared_preferences plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android', + authors: [], + version: '2.4.11', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_foundation', + description: 'iOS and macOS implementation of the shared_preferences plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation', + authors: [], + version: '2.5.4', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_linux', + description: 'Linux implementation of the shared_preferences plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux', + authors: [], + version: '2.4.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_platform_interface', + description: 'A common platform interface for the shared_preferences plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_platform_interface', + authors: [], + version: '2.4.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_web', + description: 'Web platform implementation of shared_preferences', + repository: 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_web', + authors: [], + version: '2.4.3', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shared_preferences_windows', + description: 'Windows implementation of shared_preferences', + repository: 'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_windows', + authors: [], + version: '2.4.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf', + description: '''A model for web server middleware that encourages composition and easy reuse. +''', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf', + authors: [], + version: '1.4.2', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf_packages_handler', + description: 'A shelf handler for serving a `packages/` directory.', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_packages_handler', + authors: [], + version: '3.0.2', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf_static', + description: 'Static file server support for the shelf package and ecosystem.', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_static', + authors: [], + version: '1.1.3', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'shelf_web_socket', + description: 'A shelf handler that wires up a listener for every connection.', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_web_socket', + authors: [], + version: '3.0.0', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'source_map_stack_trace', + description: 'A package for applying source maps to stack traces.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_map_stack_trace', + authors: [], + version: '2.1.2', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'source_maps', + description: 'A library to programmatically manipulate source map files.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_maps', + authors: [], + version: '0.10.13', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'source_span', + description: 'Provides a standard representation for source code locations and spans.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_span', + authors: [], + version: '1.10.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'sprintf', + description: 'Dart implementation of sprintf. Provides simple printf like formatting such as sprintf("hello %s", ["world"]);', + homepage: 'https://github.com/Naddiseo/dart-sprintf', + authors: [], + version: '7.0.0', + license: '''Copyright (c) 2012, Richard Eames +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'stack_trace', + description: 'A package for manipulating stack traces and printing them readably.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/stack_trace', + authors: [], + version: '1.12.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'stream_channel', + description: 'An abstraction for two-way communication channels based on the Dart Stream class.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/stream_channel', + authors: [], + version: '2.1.4', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'string_scanner', + description: 'A class for parsing strings using a sequence of patterns.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/string_scanner', + authors: [], + version: '1.4.1', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'syncfusion_flutter_charts', + description: 'A Flutter Charts library which includes data visualization widgets such as cartesian and circular charts, to create real-time, interactive, high-performance, animated charts.', + homepage: 'https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_charts', + authors: [], + version: '30.2.5', + license: '''Syncfusion® License + +Syncfusion® Flutter Chart package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. + +To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. + +Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. + +Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion® license containing all terms and conditions. + +The Syncfusion® license that contains the terms and conditions can be found at +https://www.syncfusion.com/content/downloads/syncfusion_license.pdf''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'syncfusion_flutter_core', + description: 'Syncfusion Flutter Core is a dependent package for all the Syncfusion Flutter widgets.', + homepage: 'https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_core', + authors: [], + version: '30.2.5', + license: '''Syncfusion® License + +Syncfusion® Flutter Core package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. + +To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. + +Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. + +Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion® license containing all terms and conditions. + +The Syncfusion® license that contains the terms and conditions can be found at +https://www.syncfusion.com/content/downloads/syncfusion_license.pdf''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'term_glyph', + description: 'Useful Unicode glyphs and ASCII substitutes.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/term_glyph', + authors: [], + version: '1.2.2', + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'test', + description: 'A full featured library for writing and running Dart tests across platforms.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test', + authors: [], + version: '1.25.15', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'test_api', + description: 'The user facing API for structuring Dart tests and checking expectations.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_api', + authors: [], + version: '0.7.4', + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'test_core', + description: 'A basic library for writing tests and running them on the VM.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_core', + authors: [], + version: '0.6.8', + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'typed_data', + description: 'Utility functions and classes related to the dart:typed_data library.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/typed_data', + authors: [], + version: '1.4.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'uri', + description: 'Utilities for building and parsing URIs, including support for parsing URI templates as defined in RFC 6570.', + repository: 'https://github.com/google/uri.dart', + authors: [], + version: '1.0.0', + license: '''Copyright 2013, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher', + description: 'Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher', + authors: [], + version: '6.3.2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'url_launcher_android', + description: 'Android implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_android', + authors: [], + version: '6.3.17', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_ios', + description: 'iOS implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_ios', + authors: [], + version: '6.3.4', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_linux', + description: 'Linux implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_linux', + authors: [], + version: '3.2.1', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_macos', + description: 'macOS implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_macos', + authors: [], + version: '3.2.3', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_platform_interface', + description: 'A common platform interface for the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_platform_interface', + authors: [], + version: '2.3.2', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_web', + description: 'Web platform implementation of url_launcher', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_web', + authors: [], + version: '2.4.1', + license: '''url_launcher_web + +Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +platform_detect + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Workiva Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'url_launcher_windows', + description: 'Windows implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_windows', + authors: [], + version: '3.1.4', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'uuid', + description: '''RFC4122 (v1, v4, v5, v6, v7, v8) UUID Generator and Parser for Dart +''', + repository: 'https://github.com/Daegalus/dart-uuid', + authors: [], + version: '4.5.1', + license: '''Copyright (c) 2021 Yulian Kuncheff + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: true, + ), + Package( + name: 'vector_math', + description: 'A Vector Math library for 2D and 3D applications.', + repository: 'https://github.com/google/vector_math.dart', + authors: [], + version: '2.1.4', + license: '''Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2013 Andrew Magill + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'vm_service', + description: 'A library to communicate with a service implementing the Dart VM service protocol.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/vm_service', + authors: [], + version: '15.0.0', + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'watcher', + description: 'A file system watcher. It monitors changes to contents of directories and sends notifications when files have been added, removed, or modified.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/watcher', + authors: [], + version: '1.1.2', + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'web', + description: 'Lightweight browser API bindings built around JS interop.', + repository: 'https://github.com/dart-lang/web', + authors: [], + version: '1.1.1', + license: '''Copyright 2023, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'web_socket', + description: 'Any easy-to-use library for communicating with WebSockets that has multiple implementations.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket', + authors: [], + version: '1.0.1', + license: '''Copyright 2024, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'web_socket_channel', + description: 'StreamChannel wrappers for WebSockets. Provides a cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying StreamChannel.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket_channel', + authors: [], + version: '3.0.3', + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'webkit_inspection_protocol', + description: '''A client for the Chrome DevTools Protocol (previously called the Webkit Inspection Protocol). +''', + repository: 'https://github.com/google/webkit_inspection_protocol.dart', + authors: [], + version: '1.2.1', + license: '''Copyright 2013, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'win32', + description: '''Access common Win32 APIs directly from Dart using FFI — no C required! +''', + homepage: 'https://win32.pub', + repository: 'https://github.com/halildurmus/win32', + authors: [], + version: '5.14.0', + license: '''BSD 3-Clause License + +Copyright (c) 2024, Halil Durmus + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'xdg_directories', + description: 'A Dart package for reading XDG directory configuration information on Linux.', + repository: 'https://github.com/flutter/packages/tree/main/packages/xdg_directories', + authors: [], + version: '1.1.0', + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'xml', + description: 'A lightweight library for parsing, traversing, querying, transforming and building XML documents.', + homepage: 'https://github.com/renggli/dart-xml', + authors: [], + version: '6.6.1', + license: '''The MIT License + +Copyright (c) 2006-2025 Lukas Renggli. +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + Package( + name: 'yaml', + description: 'A parser for YAML, a human-friendly data serialization standard', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/yaml', + authors: [], + version: '3.1.3', + license: '''Copyright (c) 2014, the Dart project authors. +Copyright (c) 2006, Kirill Simonov. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + isMarkdown: false, + isSdk: false, + isDirectDependency: false, + ), + +]; + +/// Package license definition. +class Package { + /// Package name + final String name; + /// Description + final String description; + /// Website URL + final String? homepage; + /// Repository URL + final String? repository; + /// Authors + final List authors; + /// Version + final String version; + /// License + final String? license; + /// Whether the license is in markdown format or not (plain text). + final bool isMarkdown; + /// Whether the package is included in the SDK or not. + final bool isSdk; + /// Whether the package is direct dependency or not. + final bool isDirectDependency; + + const Package({ + required this.name, + required this.description, + this.homepage, + this.repository, + required this.authors, + required this.version, + this.license, + required this.isMarkdown, + required this.isSdk, + required this.isDirectDependency, + }); +} From ef7a58409ddd43d5b3fc9e0923f0f1a12a2dec2b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:30:32 +0200 Subject: [PATCH 339/353] Update flutter.yml --- .github/workflows/flutter.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 275fd48..a051711 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -9,7 +9,7 @@ on: jobs: generate_licenses: - if: github.event_name == 'push' #&& github.ref == 'refs/heads/develop' + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' runs-on: ubuntu-latest steps: @@ -28,16 +28,17 @@ jobs: - name: Generate oss_licenses.dart run: flutter pub run flutter_oss_licenses:generate -o lib/presentation/views/about/licenses/oss_licenses.dart - #- name: Check for changes - # id: check_changes - # run: | - # if [[ $(git status --porcelain) ]]; then - # echo "changes_detected=true" >> $GITHUB_OUTPUT - # else - # echo "changes_detected=false" >> $GITHUB_OUTPUT - # fi + - name: Check for changes + id: check_changes + run: | + if [[ $(git status --porcelain) ]]; then + echo "changes_detected=true" >> $GITHUB_OUTPUT + else + echo "changes_detected=false" >> $GITHUB_OUTPUT + fi - name: Commit Changes + if: steps.check_changes.outputs.changes_detected == 'true' run: | git config --global user.name "GitHub Actions" git config --global user.email "actions@github.com" From 2cdc1188afbee5080e39e5017f82d984bfd32a93 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:30:43 +0200 Subject: [PATCH 340/353] Update flutter.yml --- .github/workflows/flutter.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index a051711..8319bd1 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -2,9 +2,9 @@ name: Flutter on: push: - #branches: - # - "develop" - #- "main" + branches: + - "develop" + - "main" pull_request: jobs: From 3901975f27f53738a6662fb14a2adc7d3ccf57dc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:37:10 +0200 Subject: [PATCH 341/353] Implemented escaping --- .github/workflows/flutter.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 8319bd1..6f85fa9 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -28,6 +28,10 @@ jobs: - name: Generate oss_licenses.dart run: flutter pub run flutter_oss_licenses:generate -o lib/presentation/views/about/licenses/oss_licenses.dart + - name: Escape dollar signs in licenses + run: | + sed -i 's/\$/\\$/g' lib/presentation/views/about/licenses/oss_licenses.dart' + - name: Check for changes id: check_changes run: | From 5c3cc7ac83a61d86226318847f80277e27708374 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:37:37 +0200 Subject: [PATCH 342/353] Push --- .github/workflows/flutter.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 6f85fa9..ffa27fa 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -2,14 +2,14 @@ name: Flutter on: push: - branches: - - "develop" - - "main" + #branches: + #- "develop" + #- "main" pull_request: jobs: generate_licenses: - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + if: github.event_name == 'push' #&& github.ref == 'refs/heads/develop' runs-on: ubuntu-latest steps: From 2f919a6e2952c79087bf46e1f8f1f2464ba98068 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:40:25 +0200 Subject: [PATCH 343/353] push 2 --- .github/workflows/flutter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index ffa27fa..1a3a6dd 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -30,7 +30,7 @@ jobs: - name: Escape dollar signs in licenses run: | - sed -i 's/\$/\\$/g' lib/presentation/views/about/licenses/oss_licenses.dart' + sed -i 's/\$/\\$/g' lib/presentation/views/about/licenses/oss_licenses.dart - name: Check for changes id: check_changes From 90a360f7503c09a80d2a10632f9f6705bcc12fa0 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 18 Aug 2025 11:42:10 +0000 Subject: [PATCH 344/353] Actions: Licenses updated [skip ci] --- lib/presentation/views/about/licenses/oss_licenses.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/about/licenses/oss_licenses.dart b/lib/presentation/views/about/licenses/oss_licenses.dart index 310bcce..dfd9ded 100644 --- a/lib/presentation/views/about/licenses/oss_licenses.dart +++ b/lib/presentation/views/about/licenses/oss_licenses.dart @@ -4685,7 +4685,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', Syncfusion® Flutter Chart package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. -To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. +To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars (\$1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. @@ -4707,7 +4707,7 @@ https://www.syncfusion.com/content/downloads/syncfusion_license.pdf''', Syncfusion® Flutter Core package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. -To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. +To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars (\$1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion® terms and conditions. Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. From 3b4ee5e95dd02c714dced4ce01eb0925c7367e4a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:47:24 +0200 Subject: [PATCH 345/353] Update flutter.yml --- .github/workflows/flutter.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 1a3a6dd..5bdd4ce 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -2,14 +2,14 @@ name: Flutter on: push: - #branches: - #- "develop" - #- "main" + branches: + - "develop" + - "main" pull_request: jobs: generate_licenses: - if: github.event_name == 'push' #&& github.ref == 'refs/heads/develop' + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' runs-on: ubuntu-latest steps: From 3cbf632188380c603e5b0f0c622292ed8650ad14 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 18 Aug 2025 13:51:53 +0200 Subject: [PATCH 346/353] Delete lib/presentation/views/points_view.dart --- lib/presentation/views/points_view.dart | 141 ------------------------ 1 file changed, 141 deletions(-) delete mode 100644 lib/presentation/views/points_view.dart diff --git a/lib/presentation/views/points_view.dart b/lib/presentation/views/points_view.dart deleted file mode 100644 index 1379785..0000000 --- a/lib/presentation/views/points_view.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'package:cabo_counter/core/custom_theme.dart'; -import 'package:cabo_counter/data/game_session.dart'; -import 'package:cabo_counter/l10n/generated/app_localizations.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -class PointsView extends StatefulWidget { - final GameSession gameSession; - - const PointsView({super.key, required this.gameSession}); - - @override - State createState() => _PointsViewState(); -} - -class _PointsViewState extends State { - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text(AppLocalizations.of(context).point_overview), - previousPageTitle: AppLocalizations.of(context).back, - ), - child: SingleChildScrollView( - padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: DataTable( - dataRowMinHeight: 60, - dataRowMaxHeight: 60, - dividerThickness: 0.5, - columnSpacing: 20, - columns: [ - const DataColumn( - numeric: true, - headingRowAlignment: MainAxisAlignment.center, - label: Text( - '#', - style: TextStyle(fontWeight: FontWeight.bold), - ), - columnWidth: IntrinsicColumnWidth(flex: 0.5)), - ...widget.gameSession.players.map( - (player) => DataColumn( - label: FittedBox( - fit: BoxFit.fill, - child: Text( - player, - style: const TextStyle(fontWeight: FontWeight.bold), - )), - headingRowAlignment: MainAxisAlignment.center, - columnWidth: const IntrinsicColumnWidth(flex: 1)), - ), - ], - rows: [ - ...List.generate( - widget.gameSession.roundList.length, - (roundIndex) { - final round = widget.gameSession.roundList[roundIndex]; - return DataRow( - cells: [ - DataCell(Align( - alignment: Alignment.center, - child: Text( - '${roundIndex + 1}', - style: const TextStyle(fontSize: 20), - ), - )), - ...List.generate(widget.gameSession.players.length, - (playerIndex) { - final int score = round.scores[playerIndex]; - final int update = round.scoreUpdates[playerIndex]; - final bool saidCabo = - round.caboPlayerIndex == playerIndex; - return DataCell( - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: update <= 0 - ? CustomTheme.pointLossColor - : CustomTheme.pointGainColor, - borderRadius: BorderRadius.circular(8), - ), - child: Text( - '${update >= 0 ? '+' : ''}$update', - style: const TextStyle( - color: CupertinoColors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 4), - Text('$score', - style: TextStyle( - fontWeight: saidCabo - ? FontWeight.bold - : FontWeight.normal, - )), - ], - ), - ), - ); - }), - ], - ); - }, - ), - DataRow( - cells: [ - const DataCell(Align( - alignment: Alignment.center, - child: Text( - 'Σ', - style: - TextStyle(fontSize: 25, fontWeight: FontWeight.bold), - ), - )), - ...widget.gameSession.playerScores.map( - (score) => DataCell( - Center( - child: Text( - '$score', - style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.bold), - ), - ), - ), - ), - ], - ), - ], - ), - ), - ), - ); - } -} From 2cc7253626a0d34f1ce153c18a671ea19037b31d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 19 Aug 2025 17:56:04 +0200 Subject: [PATCH 347/353] Corrected links --- lib/core/constants.dart | 4 +-- lib/l10n/generated/app_localizations.dart | 29 ++++++++------------ lib/l10n/generated/app_localizations_de.dart | 6 +--- lib/l10n/generated/app_localizations_en.dart | 6 +--- pubspec.yaml | 2 +- 5 files changed, 17 insertions(+), 30 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index d29a23b..aa453c2 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -11,8 +11,8 @@ class Constants { 'https://cabo-counter-wiki.felixkirchner.de'; static const String kEmail = 'cabocounter@felixkirchner.de'; static const String kPrivacyPolicyLink = - 'https://cabo-counter-privacy.felixkirchner.de'; - static const String kImprintLink = 'https://imprint.felixkirchner.de'; + 'https://cabo-counter-datenschutz.felixkirchner.de'; + static const String kImprintLink = 'https://impressum.felixkirchner.de'; static RateMyApp rateMyApp = RateMyApp( appStoreIdentifier: '6747105718', diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 1539e77..ad31f5a 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -63,7 +63,7 @@ import 'app_localizations_en.dart'; /// property. abstract class AppLocalizations { AppLocalizations(String locale) - : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); final String localeName; @@ -86,16 +86,16 @@ abstract class AppLocalizations { /// of delegates is preferred or required. static const List> localizationsDelegates = >[ - delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ]; + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; /// A list of this localizations delegate's supported locales. static const List supportedLocales = [ Locale('de'), - Locale('en'), + Locale('en') ]; /// No description provided for @app_name. @@ -487,11 +487,7 @@ abstract class AppLocalizations { /// In de, this message translates to: /// **'{playerCount, plural, =1{{names} hat exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommt deshalb {bonusPoints} Punkte abgezogen!} other{{names} haben exakt das Punktelimit von {pointLimit} Punkten erreicht und bekommen deshalb jeweils {bonusPoints} Punkte abgezogen!}}'** String bonus_points_message( - int playerCount, - String names, - int pointLimit, - int bonusPoints, - ); + int playerCount, String names, int pointLimit, int bonusPoints); /// No description provided for @end_of_game_title. /// @@ -779,9 +775,8 @@ AppLocalizations lookupAppLocalizations(Locale locale) { } throw FlutterError( - 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.', - ); + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index d1a0a7e..069a214 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -214,11 +214,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String bonus_points_message( - int playerCount, - String names, - int pointLimit, - int bonusPoints, - ) { + int playerCount, String names, int pointLimit, int bonusPoints) { String _temp0 = intl.Intl.pluralLogic( playerCount, locale: localeName, diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 2f34bd2..777d979 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -211,11 +211,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String bonus_points_message( - int playerCount, - String names, - int pointLimit, - int bonusPoints, - ) { + int playerCount, String names, int pointLimit, int bonusPoints) { String _temp0 = intl.Intl.pluralLogic( playerCount, locale: localeName, diff --git a/pubspec.yaml b/pubspec.yaml index 3fe9367..d1e8929 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.8+667 +version: 0.5.8+670 environment: sdk: ^3.5.4 From af92aa621af0f1c16ab50c37a723127adcd8df30 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 19 Aug 2025 19:18:31 +0200 Subject: [PATCH 348/353] Added comments --- lib/core/constants.dart | 24 ++++++++++++++++++- lib/core/custom_theme.dart | 24 +++++++++++++++++++ lib/data/game_session.dart | 15 ++---------- lib/main.dart | 6 +++++ lib/presentation/views/about/about_view.dart | 2 +- .../about/licenses/license_detail_view.dart | 9 +++++-- .../views/about/licenses/license_view.dart | 10 ++++++-- .../home/active_game/active_game_view.dart | 7 ++++++ .../views/home/active_game/graph_view.dart | 5 ++++ .../home/active_game/mode_selection_view.dart | 6 +++++ .../views/home/active_game/points_view.dart | 7 ++++++ .../views/home/active_game/round_view.dart | 13 ++++++++++ .../views/home/create_game_view.dart | 6 +++++ .../views/home/main_menu_view.dart | 5 ++++ .../views/home/settings_view.dart | 4 ++++ lib/presentation/views/tab_view.dart | 10 +++++++- lib/presentation/widgets/custom_button.dart | 4 ++++ lib/presentation/widgets/custom_form_row.dart | 5 ++++ lib/presentation/widgets/custom_stepper.dart | 11 +++++++++ lib/services/config_service.dart | 8 ++++--- lib/services/local_storage_service.dart | 7 +++--- pubspec.yaml | 2 +- test/data/game_session_test.dart | 4 ---- 23 files changed, 163 insertions(+), 31 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index aa453c2..c7f7589 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,19 +1,41 @@ import 'package:rate_my_app/rate_my_app.dart'; +/// A utility class that holds constant values and configuration settings +/// used throughout the application, such as external links, email addresses, +/// and timing parameters for UI elements. +/// +/// This class also provides an instance of [RateMyApp] for managing +/// in-app rating prompts. class Constants { + /// Indicates the current development phase of the app static const String appDevPhase = 'Beta'; + /// Links to various social media profiles and resources related to the app. + /// URL to my Instagram profile static const String kInstagramLink = 'https://instagram.felixkirchner.de'; + + /// URL to my GitHub profile static const String kGithubLink = 'https://github.felixkirchner.de'; + + /// URL to the GitHub issues page for reporting bugs or requesting features. static const String kGithubIssuesLink = 'https://cabo-counter-issues.felixkirchner.de'; + + /// URL to the GitHub wiki for additional documentation and guides. static const String kGithubWikiLink = 'https://cabo-counter-wiki.felixkirchner.de'; + + /// Official email address for user inquiries and support. static const String kEmail = 'cabocounter@felixkirchner.de'; + + /// URL to the app's privacy policy page. static const String kPrivacyPolicyLink = 'https://cabo-counter-datenschutz.felixkirchner.de'; - static const String kImprintLink = 'https://impressum.felixkirchner.de'; + /// URL to the app's imprint page, containing legal information. + static const String kLegalLink = 'https://impressum.felixkirchner.de'; + + /// Instance of [RateMyApp] configured to prompt users for app store ratings. static RateMyApp rateMyApp = RateMyApp( appStoreIdentifier: '6747105718', minDays: 15, diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 74b735f..62d0afb 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -1,13 +1,29 @@ import 'package:flutter/cupertino.dart'; class CustomTheme { + /// Main Theme of the App + /// Primary white color mainly used for text static Color white = CupertinoColors.white; + + /// Red color, typically used for destructive actions or error states static Color red = CupertinoColors.destructiveRed; + + /// Primary color of the app, used for buttons, highlights, and interactive elements static Color primaryColor = CupertinoColors.systemGreen; + + /// Background color for the main app scaffold and views static Color backgroundColor = const Color(0xFF101010); + + /// Background color for main UI elements like cards or containers. static Color mainElementBackgroundColor = CupertinoColors.darkBackgroundGray; + + /// Background color for player tiles in lists. static Color playerTileColor = CupertinoColors.secondaryLabel; + + /// Background color for buttons and interactive controls. static Color buttonBackgroundColor = const Color(0xFF202020); + + /// Color used to highlight the kamikaze button and players static Color kamikazeColor = CupertinoColors.systemYellow; // Line Colors for GraphView @@ -18,25 +34,33 @@ class CustomTheme { static final Color graphColor5 = primaryColor; // Colors for PointsView + /// Color used to indicate a loss of points in the UI. static Color pointLossColor = primaryColor; + + /// Color used to indicate a gain of points in the UI. static const Color pointGainColor = Color(0xFFF44336); + // Text Styles + /// Text style for mode titles, typically used in headers or section titles. static TextStyle modeTitle = TextStyle( color: primaryColor, fontSize: 20, fontWeight: FontWeight.bold, ); + /// Default text style for mode descriptions. static const TextStyle modeDescription = TextStyle( fontSize: 16, ); + /// Text style for titles of sections of [CupertinoListTile]. static TextStyle rowTitle = TextStyle( fontSize: 20, color: primaryColor, fontWeight: FontWeight.bold, ); + /// Text style for round titles, used for prominent display of the round title static TextStyle roundTitle = TextStyle( fontSize: 60, color: white, diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index ddc3104..c0a3347 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -77,17 +77,6 @@ class GameSession extends ChangeNotifier { roundList = (json['roundList'] as List).map((e) => Round.fromJson(e)).toList(); - /// Returns the length of the longest player name. - int getMaxLengthOfPlayerNames() { - int length = 0; - for (String player in players) { - if (player.length >= length) { - length = player.length; - } - } - return length; - } - /// Assigns 50 points to all players except the kamikaze player. /// [kamikazePlayerIndex] is the index of the kamikaze player. void applyKamikaze(int roundNum, int kamikazePlayerIndex) { @@ -242,8 +231,8 @@ class GameSession extends ChangeNotifier { /// It then checks if any player has exceeded 100 points. If so, it sets /// isGameFinished to true and calls the _setWinner() method to determine /// the winner. - /// It returns a list of players indices who reached 100 points in the current - /// round for the [RoundView] to show a popup + /// It returns a list of players indices who reached 100 points (bonus player) + /// in the current round for the [RoundView] to show a popup List updatePoints() { List bonusPlayers = []; _sumPoints(); diff --git a/lib/main.dart b/lib/main.dart index 8b45434..adaffdb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,8 +9,11 @@ import 'package:flutter/services.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + // Ensure the app runs in portrait mode only await SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + + // Initialize services await ConfigService.initConfig(); await VersionService.init(); runApp(const App()); @@ -38,6 +41,9 @@ class _AppState extends State with WidgetsBindingObserver { } @override + + /// Every time the app goes into the background or is closed, + /// save the current game sessions to local storage. void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.paused || state == AppLifecycleState.detached) { diff --git a/lib/presentation/views/about/about_view.dart b/lib/presentation/views/about/about_view.dart index 25431ec..5ed90c6 100644 --- a/lib/presentation/views/about/about_view.dart +++ b/lib/presentation/views/about/about_view.dart @@ -56,7 +56,7 @@ class AboutView extends StatelessWidget { sizeStyle: CupertinoButtonSize.medium, padding: EdgeInsets.zero, child: Text(AppLocalizations.of(context).imprint), - onPressed: () => launchUrl(Uri.parse(Constants.kImprintLink)), + onPressed: () => launchUrl(Uri.parse(Constants.kLegalLink)), ), CupertinoButton( sizeStyle: CupertinoButtonSize.medium, diff --git a/lib/presentation/views/about/licenses/license_detail_view.dart b/lib/presentation/views/about/licenses/license_detail_view.dart index 787c686..16b75e3 100644 --- a/lib/presentation/views/about/licenses/license_detail_view.dart +++ b/lib/presentation/views/about/licenses/license_detail_view.dart @@ -3,8 +3,13 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart' show AppLocalizations; import 'package:flutter/cupertino.dart'; -/// A view that displays the details of a specific open source software license. -/// It shows the title and the full license text in a scrollable view. +/// Displays the details of a specific open source software license in a Cupertino-style view. +/// +/// This view presents the license title and its full text in a scrollable layout. +/// +/// Required parameters: +/// - [title]: The name of the license. +/// - [license]: The full license text to display. class LicenseDetailView extends StatelessWidget { final String title, license; const LicenseDetailView( diff --git a/lib/presentation/views/about/licenses/license_view.dart b/lib/presentation/views/about/licenses/license_view.dart index 0b54f76..6fecbde 100644 --- a/lib/presentation/views/about/licenses/license_view.dart +++ b/lib/presentation/views/about/licenses/license_view.dart @@ -6,8 +6,14 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -/// A view that displays a list of the open source software licenses used in the app. -/// It allows users to tap on a license to view its details in a separate screen. +/// Displays a list of open source software licenses used in the app. +/// +/// Users can tap on a license to view its details on a separate screen. +/// This view uses a Cupertino design and supports localization. +/// +/// See also: +/// - [LicenseDetailView] for displaying license details. +/// - [ossLicenses] for the list of licenses. class LicenseView extends StatelessWidget { const LicenseView({super.key}); diff --git a/lib/presentation/views/home/active_game/active_game_view.dart b/lib/presentation/views/home/active_game/active_game_view.dart index 07209f8..3a4c0e5 100644 --- a/lib/presentation/views/home/active_game/active_game_view.dart +++ b/lib/presentation/views/home/active_game/active_game_view.dart @@ -15,6 +15,13 @@ import 'package:confetti/confetti.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +/// Displays the active game view, showing game details, player rankings, rounds, and statistics. +/// +/// This view allows users to interact with an ongoing game session, including viewing player scores, +/// navigating through rounds, ending or deleting the game, exporting game data, and starting a new game +/// with the same settings. It also provides visual feedback such as confetti animation when the game ends. +/// +/// The widget listens to changes in the provided [GameSession] and updates the UI accordingly. class ActiveGameView extends StatefulWidget { final GameSession gameSession; const ActiveGameView({super.key, required this.gameSession}); diff --git a/lib/presentation/views/home/active_game/graph_view.dart b/lib/presentation/views/home/active_game/graph_view.dart index f23be15..b7251d6 100644 --- a/lib/presentation/views/home/active_game/graph_view.dart +++ b/lib/presentation/views/home/active_game/graph_view.dart @@ -4,6 +4,11 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; +/// A widget that displays the cumulative scoring history of a game session as a line graph. +/// +/// The [GraphView] visualizes the progression of each player's score over multiple rounds +/// using a line chart. It supports dynamic coloring for each player, axis formatting, +/// and handles cases where insufficient data is available to render the graph. class GraphView extends StatefulWidget { final GameSession gameSession; diff --git a/lib/presentation/views/home/active_game/mode_selection_view.dart b/lib/presentation/views/home/active_game/mode_selection_view.dart index 86db5ff..34777cb 100644 --- a/lib/presentation/views/home/active_game/mode_selection_view.dart +++ b/lib/presentation/views/home/active_game/mode_selection_view.dart @@ -8,6 +8,12 @@ enum GameMode { unlimited, } +/// A stateless widget that displays a menu for selecting the game mode. +/// +/// The [ModeSelectionMenu] allows the user to choose between different game modes: +/// - Point limit mode with a specified [pointLimit] +/// - Unlimited mode +/// - Optionally, no default mode if [showDeselection] is true class ModeSelectionMenu extends StatelessWidget { final int pointLimit; final bool showDeselection; diff --git a/lib/presentation/views/home/active_game/points_view.dart b/lib/presentation/views/home/active_game/points_view.dart index 7844872..eb541e8 100644 --- a/lib/presentation/views/home/active_game/points_view.dart +++ b/lib/presentation/views/home/active_game/points_view.dart @@ -4,6 +4,13 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +/// Displays an overview of points for each player and round in the current game session. +/// +/// The [PointsView] widget shows a table with all rounds and player scores, +/// including score updates and highlights for players who said "Cabo". +/// It uses a Cupertino-style layout and adapts to the number of players. +/// +/// Requires a [GameSession] to provide player and round data. class PointsView extends StatefulWidget { final GameSession gameSession; diff --git a/lib/presentation/views/home/active_game/round_view.dart b/lib/presentation/views/home/active_game/round_view.dart index 14b1f94..35b85d6 100644 --- a/lib/presentation/views/home/active_game/round_view.dart +++ b/lib/presentation/views/home/active_game/round_view.dart @@ -8,6 +8,19 @@ import 'package:flutter/services.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +/// A view for displaying and managing a single round +/// +/// This widget allows users to input and review scores for each player in a round, +/// select the player who called CABO, and handle special cases such as Kamikaze rounds. +/// It manages the round state, validates input, and coordinates navigation between rounds. +/// +/// Features: +/// - Rotates player order based on the previous round's winner. +/// - Supports Kamikaze rounds with dedicated UI and logic. +/// - Handles score input, validation, and updates to the game session. +/// - Displays bonus point popups when applicable. +/// +/// Requires a [GameSession] and the current [roundNumber]. class RoundView extends StatefulWidget { final GameSession gameSession; final int roundNumber; diff --git a/lib/presentation/views/home/create_game_view.dart b/lib/presentation/views/home/create_game_view.dart index 2a3f3d8..f181721 100644 --- a/lib/presentation/views/home/create_game_view.dart +++ b/lib/presentation/views/home/create_game_view.dart @@ -20,6 +20,12 @@ enum CreateStatus { noPlayerName, } +/// A view for creating a new game session in the Cabo Counter app. +/// +/// The [CreateGameView] allows users to input a game title, select a game mode, +/// add and reorder player names, and validate all required fields before +/// starting a new game. It provides feedback dialogs for missing or invalid +/// input and navigates to the active game view upon successful creation. class CreateGameView extends StatefulWidget { final GameMode gameMode; final String? gameTitle; diff --git a/lib/presentation/views/home/main_menu_view.dart b/lib/presentation/views/home/main_menu_view.dart index 3363511..240783a 100644 --- a/lib/presentation/views/home/main_menu_view.dart +++ b/lib/presentation/views/home/main_menu_view.dart @@ -16,6 +16,11 @@ enum PreRatingDialogDecision { yes, no, cancel } enum BadRatingDialogDecision { email, cancel } +/// Home screen of the app that displays a list of game sessions. +/// +/// The [MainMenuView] is the main entry point for the app's home screen. +/// It displays a list of existing game sessions, allows users to create new games, +/// access settings, and handles user feedback dialogs for app rating and support. class MainMenuView extends StatefulWidget { const MainMenuView({super.key}); diff --git a/lib/presentation/views/home/settings_view.dart b/lib/presentation/views/home/settings_view.dart index d8e8d6c..802663c 100644 --- a/lib/presentation/views/home/settings_view.dart +++ b/lib/presentation/views/home/settings_view.dart @@ -11,6 +11,10 @@ import 'package:flutter/cupertino.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; +/// Settings and information page for the app. +/// +/// [SettingsView] is a settings page for the app, allowing users to configure game options, +/// manage game data (import, export, delete), and view app information. class SettingsView extends StatefulWidget { const SettingsView({super.key}); diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index e8469f7..d24e411 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -4,7 +4,15 @@ import 'package:cabo_counter/presentation/views/about/about_view.dart'; import 'package:cabo_counter/presentation/views/home/main_menu_view.dart'; import 'package:flutter/cupertino.dart'; -/// A view that provides a tabbed interface for navigating between the main menu and the about section. +/// TabBar for navigating between the main menu and about section. +/// +/// [TabView] is a [StatefulWidget] that provides a tabbed interface for navigating +/// between the main menu and the about section of the app. It uses a +/// [CupertinoTabScaffold] with two tabs: +/// - Home (MainMenuView) +/// - About (AboutView) +/// +/// The tab labels are provided via localization. class TabView extends StatefulWidget { const TabView({super.key}); diff --git a/lib/presentation/widgets/custom_button.dart b/lib/presentation/widgets/custom_button.dart index 0feb799..2b68b44 100644 --- a/lib/presentation/widgets/custom_button.dart +++ b/lib/presentation/widgets/custom_button.dart @@ -1,6 +1,10 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:flutter/cupertino.dart'; +/// A customizable button widget using Cupertino style. +/// +/// Displays a button with a child widget and optional callback. +/// The button uses a medium size, rounded corners, and a custom background color. class CustomButton extends StatelessWidget { final Widget child; final VoidCallback? onPressed; diff --git a/lib/presentation/widgets/custom_form_row.dart b/lib/presentation/widgets/custom_form_row.dart index 7a2526b..751e487 100644 --- a/lib/presentation/widgets/custom_form_row.dart +++ b/lib/presentation/widgets/custom_form_row.dart @@ -2,6 +2,11 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/presentation/widgets/custom_stepper.dart'; import 'package:flutter/cupertino.dart'; +/// A customizable form row widget with a prefix icon, text, and optional suffix widget. +/// +/// Displays a row with an icon and text on the left side. +/// Optionally, a suffix widget (e.g. a stepper) can be shown on the right side. +/// The row is styled as a [CupertinoButton] and can react to taps. class CustomFormRow extends StatefulWidget { final String prefixText; final IconData prefixIcon; diff --git a/lib/presentation/widgets/custom_stepper.dart b/lib/presentation/widgets/custom_stepper.dart index a05a4cb..be41048 100644 --- a/lib/presentation/widgets/custom_stepper.dart +++ b/lib/presentation/widgets/custom_stepper.dart @@ -1,6 +1,17 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:flutter/cupertino.dart'; // Für iOS-Style +/// A custom stepper widget for incrementing and decrementing a value. +/// +/// The [CustomStepper] widget allows increasing and decreasing a value +/// within a defined range ([minValue] to [maxValue]) in fixed steps. +/// +/// Properties: +/// - [minValue]: The minimum value. +/// - [maxValue]: The maximum value. +/// - [initialValue]: The initial value (optional, defaults to [minValue]). +/// - [step]: The step size. +/// - [onChanged]: Callback triggered when the value changes. class CustomStepper extends StatefulWidget { final int minValue; final int maxValue; diff --git a/lib/services/config_service.dart b/lib/services/config_service.dart index 4ff68d9..419e461 100644 --- a/lib/services/config_service.dart +++ b/lib/services/config_service.dart @@ -1,10 +1,12 @@ import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart'; import 'package:shared_preferences/shared_preferences.dart'; -/// This class handles the configuration settings for the app. -/// It uses SharedPreferences to store and retrieve the personal configuration of the app. -/// Currently it provides methods to initialize, get, and set the point limit and cabo penalty. +/// A service class for managing and persisting app configuration settings using `SharedPreferences`. +/// +/// Provides methods to initialize, retrieve, update, and reset configuration values such as point limit, +/// cabo penalty, and game mode. Ensures that user preferences are stored locally and persist across app restarts. class ConfigService { + // Keys for the stored values static const String _keyPointLimit = 'pointLimit'; static const String _keyCaboPenalty = 'caboPenalty'; static const String _keyGameMode = 'gameMode'; diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index 29ac58b..2c99d36 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -55,6 +55,7 @@ class LocalStorageService { try { final file = await _getFilePath(); + // Check if the file exists if (!await file.exists()) { print( '[local_storage_service.dart] Es existiert noch keine Datei mit Spieldaten'); @@ -65,11 +66,13 @@ class LocalStorageService { '[local_storage_service.dart] Es existiert bereits eine Datei mit Spieldaten'); final jsonString = await file.readAsString(); + // Check if the file is empty if (jsonString.isEmpty) { print('[local_storage_service.dart] Die gefundene Datei ist leer'); return false; } + // Validate the JSON schema if (!await _validateJsonSchema(jsonString, true)) { print( '[local_storage_service.dart] Die Datei konnte nicht validiert werden'); @@ -148,7 +151,6 @@ class LocalStorageService { /// Opens the file picker to import a JSON file and loads the game data from it. static Future importJsonFile() async { final path = await FilePicker.platform.pickFiles( - dialogTitle: 'Wähle eine Datei mit Spieldaten aus', type: FileType.custom, allowedExtensions: ['json'], ); @@ -162,9 +164,8 @@ class LocalStorageService { try { final jsonString = await _readFileContent(path.files.single); + // Checks if the JSON String is in the gameList format if (await _validateJsonSchema(jsonString, true)) { - // Checks if the JSON String is in the gameList format - final jsonData = json.decode(jsonString) as List; List importedList = jsonData .map((jsonItem) => diff --git a/pubspec.yaml b/pubspec.yaml index d1e8929..0264645 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.8+670 +version: 0.5.8+671 environment: sdk: ^3.5.4 diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index 9654bad..8e16d2a 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -62,10 +62,6 @@ void main() { }); group('Helper Functions', () { - test('getMaxLengthOfPlayerNames', () { - expect(session.getMaxLengthOfPlayerNames(), equals(7)); // Charlie (7) - }); - test('increaseRound', () { expect(session.roundNumber, 1); session.increaseRound(); From 510ef81d530985a56b8937341158a5534cc6f895 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 19 Aug 2025 22:58:34 +0200 Subject: [PATCH 349/353] Updated pipelines --- .github/workflows/pull_request.yml | 40 +++++++++++++++++++++ .github/workflows/{flutter.yml => push.yml} | 6 ++-- 2 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/pull_request.yml rename .github/workflows/{flutter.yml => push.yml} (94%) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..3b41b0f --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,40 @@ +name: Pull_Request + +on: + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set Up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.32.1' + channel: 'stable' + + - name: Check Formatting + run: flutter analyze + + test: + runs-on: ubuntu-latest + if: always() + needs: [lint, format] + + steps: + - uses: actions/checkout@v4 + + - name: Set Up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.32.1' + channel: 'stable' + + - name: Get dependencies + run: flutter pub get + + - name: Run Tests + run: flutter test \ No newline at end of file diff --git a/.github/workflows/flutter.yml b/.github/workflows/push.yml similarity index 94% rename from .github/workflows/flutter.yml rename to .github/workflows/push.yml index 5bdd4ce..83f87e8 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/push.yml @@ -1,15 +1,13 @@ -name: Flutter +name: Push on: push: branches: - "develop" - "main" - pull_request: jobs: generate_licenses: - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' runs-on: ubuntu-latest steps: @@ -69,7 +67,7 @@ jobs: format: runs-on: ubuntu-latest needs: lint - if: ${{ failure() && needs.lint.result == 'failure' && github.event_name == 'push' && github.ref == 'refs/heads/develop'}} + if: ${{ failure() && needs.lint.result == 'failure'}} steps: - uses: actions/checkout@v4 From ffaa260dd93c1ed0c12d7c8eecc549c64a40c876 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 19 Aug 2025 22:59:49 +0200 Subject: [PATCH 350/353] Updated pipeline --- .github/workflows/pull_request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 3b41b0f..a4dd237 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -22,7 +22,7 @@ jobs: test: runs-on: ubuntu-latest if: always() - needs: [lint, format] + needs: lint steps: - uses: actions/checkout@v4 From 93b82e377f4a86e13e295644542d2dbf7f651781 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 19 Aug 2025 23:01:07 +0200 Subject: [PATCH 351/353] Update pipeline names --- .github/workflows/pull_request.yml | 2 +- .github/workflows/push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index a4dd237..0e4b9f9 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1,4 +1,4 @@ -name: Pull_Request +name: Pull Request Pipeline on: pull_request: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 83f87e8..d61e8c7 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -1,4 +1,4 @@ -name: Push +name: Push Pipeline on: push: From e1a414b1f02e17ebe4058f8a73084b4e45ca4cd0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 19 Aug 2025 23:06:25 +0200 Subject: [PATCH 352/353] Updated pipeline --- .github/workflows/push.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index d61e8c7..d8d185b 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -51,6 +51,7 @@ jobs: lint: runs-on: ubuntu-latest needs: generate_licenses + if: always() steps: - name: Checkout code uses: actions/checkout@v4 From db2192b47bdb707db50b4c42dbfd0821dba0a8dd Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 20 Aug 2025 08:54:23 +0200 Subject: [PATCH 353/353] Updated String --- lib/l10n/arb/app_de.arb | 2 +- lib/l10n/arb/app_en.arb | 2 +- lib/l10n/generated/app_localizations.dart | 4 ++-- lib/l10n/generated/app_localizations_de.dart | 2 +- lib/l10n/generated/app_localizations_en.dart | 2 +- lib/presentation/views/about/about_view.dart | 2 +- pubspec.yaml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index bd83532..86ef939 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -24,7 +24,7 @@ "licenses": "Lizenzen", "license_details": "Lizenzdetails", "no_license_text": "Keine Lizenz verfügbar", - "imprint": "Impressum", + "legal_notice": "Impressum", "empty_text_1": "Ganz schön leer hier...", "empty_text_2": "Füge über den Button oben rechts eine neue Runde hinzu", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 8fa17c1..59c3aa0 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -23,7 +23,7 @@ "about": "About", "licenses": "Licenses", "license_details": "License Details", - "imprint": "Imprint", + "legal_notice": "Legal Notice", "no_license_text": "No license available", "empty_text_1": "Pretty empty here...", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index ad31f5a..0ca7043 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -224,11 +224,11 @@ abstract class AppLocalizations { /// **'Keine Lizenz verfügbar'** String get no_license_text; - /// No description provided for @imprint. + /// No description provided for @legal_notice. /// /// In de, this message translates to: /// **'Impressum'** - String get imprint; + String get legal_notice; /// No description provided for @empty_text_1. /// diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 069a214..85d89ad 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -72,7 +72,7 @@ class AppLocalizationsDe extends AppLocalizations { String get no_license_text => 'Keine Lizenz verfügbar'; @override - String get imprint => 'Impressum'; + String get legal_notice => 'Impressum'; @override String get empty_text_1 => 'Ganz schön leer hier...'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 777d979..cfbc4c0 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -72,7 +72,7 @@ class AppLocalizationsEn extends AppLocalizations { String get no_license_text => 'No license available'; @override - String get imprint => 'Imprint'; + String get legal_notice => 'Legal Notice'; @override String get empty_text_1 => 'Pretty empty here...'; diff --git a/lib/presentation/views/about/about_view.dart b/lib/presentation/views/about/about_view.dart index 5ed90c6..7ea1609 100644 --- a/lib/presentation/views/about/about_view.dart +++ b/lib/presentation/views/about/about_view.dart @@ -55,7 +55,7 @@ class AboutView extends StatelessWidget { CupertinoButton( sizeStyle: CupertinoButtonSize.medium, padding: EdgeInsets.zero, - child: Text(AppLocalizations.of(context).imprint), + child: Text(AppLocalizations.of(context).legal_notice), onPressed: () => launchUrl(Uri.parse(Constants.kLegalLink)), ), CupertinoButton( diff --git a/pubspec.yaml b/pubspec.yaml index 0264645..27eedcd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.5.8+671 +version: 0.5.8+674 environment: sdk: ^3.5.4