From 799b7d8403c504bd66ff0cc13eee497d8ce1e8bc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 9 Jan 2026 21:12:09 +0100 Subject: [PATCH 01/64] Implemented new nav bar with selected animation --- lib/core/custom_theme.dart | 2 + .../main_menu/custom_navigation_bar.dart | 89 ++++++++++--------- lib/presentation/widgets/navbar_item.dart | 69 ++++++++++++-- pubspec.yaml | 2 +- 4 files changed, 110 insertions(+), 52 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index a6c6376..3f15ad9 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -11,6 +11,8 @@ class CustomTheme { static Color onBoxColor = const Color(0xFF181818); static Color boxBorder = const Color(0xFF272727); static const Color textColor = Colors.white; + static Color navBarItemSelectedColor = primaryColor.withValues(green: 0.4); + static Color navBarItemUnselectedColor = Colors.white.withValues(alpha: 0.6); // ==================== Border Radius ==================== static const double standardBorderRadius = 12.0; diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index a8b18c8..15f15b6 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; @@ -70,50 +72,49 @@ class _CustomNavigationBarState extends State backgroundColor: CustomTheme.backgroundColor, body: tabs[currentIndex], extendBody: true, - bottomNavigationBar: SafeArea( - minimum: const EdgeInsets.only(bottom: 30), - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24), - color: CustomTheme.primaryColor, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(24), - child: SizedBox( - height: 60, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - NavbarItem( - index: 0, - isSelected: currentIndex == 0, - icon: Icons.home_rounded, - label: loc.home, - onTabTapped: onTabTapped, - ), - NavbarItem( - index: 1, - isSelected: currentIndex == 1, - icon: Icons.gamepad_rounded, - label: loc.matches, - onTabTapped: onTabTapped, - ), - NavbarItem( - index: 2, - isSelected: currentIndex == 2, - icon: Icons.group_rounded, - label: loc.groups, - onTabTapped: onTabTapped, - ), - NavbarItem( - index: 3, - isSelected: currentIndex == 3, - icon: Icons.bar_chart_rounded, - label: loc.statistics, - onTabTapped: onTabTapped, - ), - ], + bottomNavigationBar: ClipRRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: Container( + decoration: BoxDecoration( + color: CustomTheme.boxColor.withValues(alpha: 0.8), + ), + child: SafeArea( + child: SizedBox( + height: 70, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + NavbarItem( + index: 0, + isSelected: currentIndex == 0, + icon: Icons.home_rounded, + label: loc.home, + onTabTapped: onTabTapped, + ), + NavbarItem( + index: 1, + isSelected: currentIndex == 1, + icon: Icons.gamepad_rounded, + label: loc.matches, + onTabTapped: onTabTapped, + ), + NavbarItem( + index: 2, + isSelected: currentIndex == 2, + icon: Icons.group_rounded, + label: loc.groups, + onTabTapped: onTabTapped, + ), + NavbarItem( + index: 3, + isSelected: currentIndex == 3, + icon: Icons.bar_chart_rounded, + label: loc.statistics, + onTabTapped: onTabTapped, + ), + ], + ), ), ), ), diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index 13a8d4d..6e2e24e 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; /// A navigation bar item widget that represents a single tab in a navigation bar. /// - [index]: The index of the tab. @@ -35,7 +36,45 @@ class NavbarItem extends StatefulWidget { State createState() => _NavbarItemState(); } -class _NavbarItemState extends State { +class _NavbarItemState extends State + with SingleTickerProviderStateMixin { + /// Animation controller for the scale animation + late AnimationController _animationController; + + /// Scale animation for the icon when selected + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + + _scaleAnimation = Tween(begin: 1.0, end: 1.2).animate( + CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOutBack, + ), + ); + + if (widget.isSelected) { + _animationController.forward(); + } + } + + // Retrigger animation on selection change + @override + void didUpdateWidget(NavbarItem oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.isSelected && !oldWidget.isSelected) { + _animationController.forward(); + } else if (!widget.isSelected && oldWidget.isSelected) { + _animationController.reverse(); + } + } + @override Widget build(BuildContext context) { return Expanded( @@ -48,19 +87,29 @@ class _NavbarItemState extends State { mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - widget.icon, - color: widget.isSelected ? Colors.white : Colors.black, + ScaleTransition( + scale: widget.isSelected + ? _scaleAnimation + : const AlwaysStoppedAnimation(1.0), + child: Icon( + widget.icon, + color: widget.isSelected + ? CustomTheme.navBarItemSelectedColor + : CustomTheme.navBarItemUnselectedColor, + size: 26, + ), ), const SizedBox(height: 4), Text( widget.label, style: TextStyle( - color: widget.isSelected ? Colors.white : Colors.black, - fontSize: 12, + color: widget.isSelected + ? CustomTheme.navBarItemSelectedColor + : CustomTheme.navBarItemUnselectedColor, + fontSize: widget.isSelected ? 12 : 11, fontWeight: widget.isSelected ? FontWeight.bold - : FontWeight.normal, + : FontWeight.w500, ), ), ], @@ -69,4 +118,10 @@ class _NavbarItemState extends State { ), ); } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } } diff --git a/pubspec.yaml b/pubspec.yaml index e79ca17..74df2a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+21 +version: 0.0.1+69 environment: sdk: ^3.8.1 From 8ca4e3210e2b2e15263dbe33ff5bd7890fdb958e Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 11:28:21 +0100 Subject: [PATCH 02/64] remove button in match view for testing --- lib/presentation/views/main_menu/match_view/match_view.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index ecfa9ca..9da007b 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -105,7 +105,8 @@ class _MatchViewState extends State { ), Positioned( bottom: MediaQuery.paddingOf(context).bottom, - child: CustomWidthButton( + child: SizedBox.shrink() + /* CustomWidthButton( text: loc.create_match, sizeRelativeToWidth: 0.90, onPressed: () async { @@ -118,6 +119,7 @@ class _MatchViewState extends State { ); }, ), + */ ), ], ), From ab20bd764b67e015e73b3957c6229e11c4bcecd3 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 11:30:00 +0100 Subject: [PATCH 03/64] implement draft blur navbar --- .../main_menu/custom_navigation_bar.dart | 61 ++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 9c5c846..d3b7007 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -73,14 +73,59 @@ class _CustomNavigationBarState extends State backgroundColor: CustomTheme.backgroundColor, body: tabs[currentIndex], extendBody: true, - bottomNavigationBar: ClipRRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - decoration: BoxDecoration( - color: CustomTheme.boxColor.withValues(alpha: 0.8), + bottomNavigationBar: SizedBox( + height: 70 + MediaQuery.of(context).padding.bottom, + child: Stack( + children: [ + // Dynamisch generierte Blur-Layer für ultra-smooth Übergang + ...List.generate(35, (index) { + // Verwende kubische Kurve für noch natürlicheren, weicheren Übergang + final progress = index / 34.0; // 0.0 bis 1.0 + final cubic = progress * progress * progress; // Kubische Kurve + final blurStrength = 0.5 + (cubic * 50.0); // Sehr sanft von 0.5 bis 50.5 + + // Höhe geht jetzt komplett von 100% bis 0% (ganz nach unten) + // Mit extra Dichte am unteren Ende für weicheren Übergang + final heightFactor = index < 25 + ? 1.0 - (progress * 0.7) // Erste 25 Layer: 100% bis 30% + : 0.3 - ((index - 25) / 34.0); // Letzte 10 Layer: 30% bis 0% (dichter) + + return Positioned( + left: 0, + right: 0, + bottom: 0, + height: (70 + MediaQuery.of(context).padding.bottom) * heightFactor.clamp(0.05, 1.0), + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: blurStrength, + sigmaY: blurStrength, + ), + child: Container( + color: Colors.transparent, + ), + ), + ), + ); + }), + // Gradient-Overlay + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + CustomTheme.boxColor.withValues(alpha: 1), + CustomTheme.boxColor.withValues(alpha: 0.0), + ], + stops: const [0.4, 1], + ), + ), + ), ), - child: SafeArea( + // Navbar-Inhalt + SafeArea( child: SizedBox( height: 70, child: Row( @@ -118,7 +163,7 @@ class _CustomNavigationBarState extends State ), ), ), - ), + ], ), ), ); From 76ce3af6437690ae004fae3c909f77539859a380 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 15:26:10 +0100 Subject: [PATCH 04/64] implement custom alert dialog --- .../views/main_menu/settings_view.dart | 11 +++---- .../widgets/custom_alert_dialog.dart | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 lib/presentation/widgets/custom_alert_dialog.dart diff --git a/lib/presentation/views/main_menu/settings_view.dart b/lib/presentation/views/main_menu/settings_view.dart index 0fa7085..d416deb 100644 --- a/lib/presentation/views/main_menu/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view.dart @@ -5,6 +5,7 @@ import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart'; import 'package:game_tracker/services/data_transfer_service.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:game_tracker/presentation/widgets/custom_alert_dialog.dart'; class SettingsView extends StatefulWidget { const SettingsView({super.key}); @@ -92,17 +93,17 @@ class _SettingsViewState extends State { onPressed: () { showDialog( context: context, - builder: (context) => AlertDialog( - title: Text('${loc.delete_all_data}?'), - content: Text(loc.this_cannot_be_undone), + builder: (context) => CustomAlertDialog( + title: '${loc.delete_all_data}?', + content: loc.this_cannot_be_undone, actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), - child: Text(loc.cancel), + child: Text(loc.cancel, style: TextStyle(color: CustomTheme.textColor),), ), TextButton( onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.delete), + child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor),), ), ], ), diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/custom_alert_dialog.dart new file mode 100644 index 0000000..6a6019a --- /dev/null +++ b/lib/presentation/widgets/custom_alert_dialog.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class CustomAlertDialog extends StatelessWidget { + final String title; + final String content; + final List actions; + + const CustomAlertDialog({ + super.key, + required this.title, + required this.content, + required this.actions, + }); + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(title, style: const TextStyle(color: CustomTheme.textColor,),), + content: Text(content, style: const TextStyle(color: CustomTheme.textColor),), + actions: actions, + backgroundColor: CustomTheme.boxColor, + shape: RoundedRectangleBorder( + borderRadius: CustomTheme.standardBorderRadiusAll, + side: BorderSide(color: CustomTheme.boxBorder), + ), + ); + } +} From 3ceae8341b56461d6d376d54f7fa57afa481cb79 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 15:26:50 +0100 Subject: [PATCH 05/64] add const --- lib/presentation/views/main_menu/settings_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/settings_view.dart b/lib/presentation/views/main_menu/settings_view.dart index d416deb..500a550 100644 --- a/lib/presentation/views/main_menu/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view.dart @@ -99,7 +99,7 @@ class _SettingsViewState extends State { actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), - child: Text(loc.cancel, style: TextStyle(color: CustomTheme.textColor),), + child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor),), ), TextButton( onPressed: () => Navigator.of(context).pop(true), From 22ce742d4333a80d9b759de160591245b98ddbfa Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 17:14:28 +0100 Subject: [PATCH 06/64] change button alignment & remove InkWell Animation --- lib/presentation/views/main_menu/settings_view.dart | 9 +++++++++ lib/presentation/widgets/custom_alert_dialog.dart | 1 + 2 files changed, 10 insertions(+) diff --git a/lib/presentation/views/main_menu/settings_view.dart b/lib/presentation/views/main_menu/settings_view.dart index 500a550..5814537 100644 --- a/lib/presentation/views/main_menu/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view.dart @@ -98,13 +98,22 @@ class _SettingsViewState extends State { content: loc.this_cannot_be_undone, actions: [ TextButton( + style: TextButton.styleFrom( + splashFactory: NoSplash.splashFactory, + overlayColor: Colors.transparent, + ), onPressed: () => Navigator.of(context).pop(false), child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor),), ), TextButton( + style: TextButton.styleFrom( + splashFactory: NoSplash.splashFactory, + overlayColor: Colors.transparent, + ), onPressed: () => Navigator.of(context).pop(true), child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor),), ), + ], ), ).then((confirmed) { diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/custom_alert_dialog.dart index 6a6019a..2456b56 100644 --- a/lib/presentation/widgets/custom_alert_dialog.dart +++ b/lib/presentation/widgets/custom_alert_dialog.dart @@ -20,6 +20,7 @@ class CustomAlertDialog extends StatelessWidget { content: Text(content, style: const TextStyle(color: CustomTheme.textColor),), actions: actions, backgroundColor: CustomTheme.boxColor, + actionsAlignment: MainAxisAlignment.spaceAround, shape: RoundedRectangleBorder( borderRadius: CustomTheme.standardBorderRadiusAll, side: BorderSide(color: CustomTheme.boxBorder), From 1ebcfc9e57e1685fe75a0c2438ab297c8de2f0c9 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 17:21:05 +0100 Subject: [PATCH 07/64] implement animation --- .../views/main_menu/settings_view.dart | 73 +++++++++++++++---- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/lib/presentation/views/main_menu/settings_view.dart b/lib/presentation/views/main_menu/settings_view.dart index 5814537..cab26ef 100644 --- a/lib/presentation/views/main_menu/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view.dart @@ -97,23 +97,14 @@ class _SettingsViewState extends State { title: '${loc.delete_all_data}?', content: loc.this_cannot_be_undone, actions: [ - TextButton( - style: TextButton.styleFrom( - splashFactory: NoSplash.splashFactory, - overlayColor: Colors.transparent, - ), + _PressableButton( onPressed: () => Navigator.of(context).pop(false), - child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor),), + child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor)), ), - TextButton( - style: TextButton.styleFrom( - splashFactory: NoSplash.splashFactory, - overlayColor: Colors.transparent, - ), + _PressableButton( onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor),), + child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor)), ), - ], ), ).then((confirmed) { @@ -227,3 +218,59 @@ class _SettingsViewState extends State { }); } } + +class _PressableButton extends StatefulWidget { + final VoidCallback onPressed; + final Widget child; + + const _PressableButton({required this.onPressed, required this.child}); + + @override + State<_PressableButton> createState() => _PressableButtonState(); +} + +class _PressableButtonState extends State<_PressableButton> { + bool _isPressed = false; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: (_) => setState(() => _isPressed = true), + onTapUp: (_) => setState(() => _isPressed = false), + onTapCancel: () => setState(() => _isPressed = false), + onTap: widget.onPressed, + child: AnimatedScale( + scale: _isPressed ? 0.95 : 1.0, + duration: const Duration(milliseconds: 100), + child: AnimatedOpacity( + opacity: _isPressed ? 0.6 : 1.0, + duration: const Duration(milliseconds: 100), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: widget.child, + ), + ), + ), + ); + } +} + + +/* + TextButton( + style: TextButton.styleFrom( + splashFactory: NoSplash.splashFactory, + overlayColor: Colors.transparent, + ), + onPressed: () => Navigator.of(context).pop(false), + child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor),), + ), + TextButton( + style: TextButton.styleFrom( + splashFactory: NoSplash.splashFactory, + overlayColor: Colors.transparent, + ), + onPressed: () => Navigator.of(context).pop(true), + child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor),), + ), + */ From 0fb6208345772524613625bf7b1cdde9eba60256 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:23:34 +0100 Subject: [PATCH 08/64] Created new buttons for the main menu --- .../widgets/buttons/main_menu_button.dart | 98 +++++++++++++++++++ pubspec.yaml | 3 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 lib/presentation/widgets/buttons/main_menu_button.dart diff --git a/lib/presentation/widgets/buttons/main_menu_button.dart b/lib/presentation/widgets/buttons/main_menu_button.dart new file mode 100644 index 0000000..9e6ed80 --- /dev/null +++ b/lib/presentation/widgets/buttons/main_menu_button.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; + +/// A button for the main menu with an optional icon and a press animation. +/// - [text]: The text of the button. +/// - [icon]: The icon of the button. +/// - [onPressed]: The callback to be invoked when the button is pressed. +class MainMenuButton extends StatefulWidget { + const MainMenuButton({ + super.key, + required this.text, + this.icon, + required this.onPressed, + }); + + /// The text of the button. + final String text; + + /// The icon of the button. + final IconData? icon; + + /// The callback to be invoked when the button is pressed. + final void Function() onPressed; + + @override + State createState() => _MainMenuButtonState(); +} + +class _MainMenuButtonState extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + + _animationController = AnimationController( + duration: const Duration(milliseconds: 100), + vsync: this, + ); + + _scaleAnimation = Tween(begin: 1.0, end: 0.95).animate( + CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), + ); + } + + @override + Widget build(BuildContext context) { + return ScaleTransition( + scale: _scaleAnimation, + child: GestureDetector( + onTapDown: (_) { + _animationController.forward(); + }, + onTapUp: (_) async { + await _animationController.reverse(); + if (mounted) { + widget.onPressed(); + } + }, + onTapCancel: () { + _animationController.reverse(); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(30), + ), + padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 15), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (widget.icon != null) ...[ + Icon(widget.icon, size: 28, color: Colors.black), + const SizedBox(width: 7), + ], + Text( + widget.text, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ], + ), + ), + ), + ); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 1b033f2..a7a2df7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+149 +version: 0.0.1+153 environment: sdk: ^3.8.1 @@ -23,6 +23,7 @@ dependencies: flutter_localizations: sdk: flutter package_info_plus: ^9.0.0 + fluttericon: ^2.0.0 dev_dependencies: flutter_test: From cde40ef2935baea1379a39345bff14cd1720dff7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:23:43 +0100 Subject: [PATCH 09/64] Updated buttons in main menu --- .../views/main_menu/group_view/groups_view.dart | 8 ++++---- .../views/main_menu/match_view/match_view.dart | 13 ++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart index 239aa23..ec5fc44 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -8,7 +8,7 @@ import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; @@ -79,10 +79,10 @@ class _GroupsViewState extends State { ), ), Positioned( - bottom: MediaQuery.paddingOf(context).bottom, - child: CustomWidthButton( + bottom: MediaQuery.paddingOf(context).bottom + 20, + child: MainMenuButton( text: loc.create_group, - sizeRelativeToWidth: 0.90, + icon: Icons.group_add, onPressed: () async { await Navigator.push( context, diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index 9da007b..7705d18 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -1,6 +1,7 @@ import 'dart:core' hide Match; import 'package:flutter/material.dart'; +import 'package:fluttericon/rpg_awesome_icons.dart'; import 'package:game_tracker/core/adaptive_page_route.dart'; import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; @@ -12,7 +13,7 @@ import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/create_match_view.dart'; import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; @@ -104,11 +105,10 @@ class _MatchViewState extends State { ), ), Positioned( - bottom: MediaQuery.paddingOf(context).bottom, - child: SizedBox.shrink() - /* CustomWidthButton( - text: loc.create_match, - sizeRelativeToWidth: 0.90, + bottom: MediaQuery.paddingOf(context).bottom + 20, + child: MainMenuButton( + text: 'Spiel erstellen', + icon: RpgAwesome.clovers_card, onPressed: () async { Navigator.push( context, @@ -119,7 +119,6 @@ class _MatchViewState extends State { ); }, ), - */ ), ], ), From 8bf2b9e3ddf1b8fab6cc61970040004b6e6c3971 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:31:30 +0100 Subject: [PATCH 10/64] Updated navbar item color & size --- lib/core/custom_theme.dart | 4 ++-- lib/presentation/widgets/navbar_item.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 3f15ad9..cfe9b5a 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -11,8 +11,8 @@ class CustomTheme { static Color onBoxColor = const Color(0xFF181818); static Color boxBorder = const Color(0xFF272727); static const Color textColor = Colors.white; - static Color navBarItemSelectedColor = primaryColor.withValues(green: 0.4); - static Color navBarItemUnselectedColor = Colors.white.withValues(alpha: 0.6); + static Color navBarItemSelectedColor = primaryColor.withGreen(100); + static Color navBarItemUnselectedColor = Colors.grey.shade400; // ==================== Border Radius ==================== static const double standardBorderRadius = 12.0; diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index 6e2e24e..abf7acc 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -96,7 +96,7 @@ class _NavbarItemState extends State color: widget.isSelected ? CustomTheme.navBarItemSelectedColor : CustomTheme.navBarItemUnselectedColor, - size: 26, + size: 32, ), ), const SizedBox(height: 4), diff --git a/pubspec.yaml b/pubspec.yaml index a7a2df7..7978e22 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+153 +version: 0.0.1+159 environment: sdk: ^3.8.1 From 679f4c94d978357a68df1be40798e068631ae4a8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:33:20 +0100 Subject: [PATCH 11/64] Updated button size --- lib/presentation/widgets/buttons/main_menu_button.dart | 6 +++--- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/widgets/buttons/main_menu_button.dart b/lib/presentation/widgets/buttons/main_menu_button.dart index 9e6ed80..d29566c 100644 --- a/lib/presentation/widgets/buttons/main_menu_button.dart +++ b/lib/presentation/widgets/buttons/main_menu_button.dart @@ -66,19 +66,19 @@ class _MainMenuButtonState extends State color: Colors.white, borderRadius: BorderRadius.circular(30), ), - padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 15), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14), child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ if (widget.icon != null) ...[ - Icon(widget.icon, size: 28, color: Colors.black), + Icon(widget.icon, size: 26, color: Colors.black), const SizedBox(width: 7), ], Text( widget.text, style: const TextStyle( - fontSize: 20, + fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black, ), diff --git a/pubspec.yaml b/pubspec.yaml index 7978e22..6ff77df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+159 +version: 0.0.1+160 environment: sdk: ^3.8.1 From 9344f8212ca351cbc39b18e0a506a4c2326d8bae Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:55:52 +0100 Subject: [PATCH 12/64] Updated version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 6ff77df..e57c3bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+160 +version: 0.0.5+161 environment: sdk: ^3.8.1 From fa7740101b9f87eeae15bb3cb2e0e1f9184f7d69 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 19:34:35 +0100 Subject: [PATCH 13/64] Small changes on navbar --- .../main_menu/custom_navigation_bar.dart | 39 +++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index d3b7007..4ff61f6 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -77,38 +77,41 @@ class _CustomNavigationBarState extends State height: 70 + MediaQuery.of(context).padding.bottom, child: Stack( children: [ - // Dynamisch generierte Blur-Layer für ultra-smooth Übergang - ...List.generate(35, (index) { - // Verwende kubische Kurve für noch natürlicheren, weicheren Übergang - final progress = index / 34.0; // 0.0 bis 1.0 - final cubic = progress * progress * progress; // Kubische Kurve - final blurStrength = 0.5 + (cubic * 50.0); // Sehr sanft von 0.5 bis 50.5 + // Dynamically generated blur layers for ultra-smooth transition + ...List.generate(34, (index) { + // Use cubic curve for an even more natural, smoother transition + final progress = index / 34.0; // 0.0 to 1.0 + final cubic = progress * progress * progress; // cubic curve + final blurStrength = + 0.5 + (cubic * 50.0); // Very smooth from 0.5 to 50.5 - // Höhe geht jetzt komplett von 100% bis 0% (ganz nach unten) - // Mit extra Dichte am unteren Ende für weicheren Übergang + // Height goes completely from 100% to 0% (all the way down) + // With extra density at the bottom for softer transition final heightFactor = index < 25 - ? 1.0 - (progress * 0.7) // Erste 25 Layer: 100% bis 30% - : 0.3 - ((index - 25) / 34.0); // Letzte 10 Layer: 30% bis 0% (dichter) + // First 25 layers: 100% to 30% + ? 1.0 - (progress * 0.7) + // Last 10 layers: 30% to 0% (denser) + : 0.3 - ((index - 25) / 34.0); return Positioned( left: 0, right: 0, bottom: 0, - height: (70 + MediaQuery.of(context).padding.bottom) * heightFactor.clamp(0.05, 1.0), + height: + (70 + MediaQuery.of(context).padding.bottom) * + heightFactor.clamp(0.05, 1.0), child: ClipRect( child: BackdropFilter( filter: ImageFilter.blur( sigmaX: blurStrength, sigmaY: blurStrength, ), - child: Container( - color: Colors.transparent, - ), + child: Container(color: Colors.transparent), ), ), ); }), - // Gradient-Overlay + // Gradient overlay Positioned.fill( child: Container( decoration: BoxDecoration( @@ -117,14 +120,16 @@ class _CustomNavigationBarState extends State end: Alignment.topCenter, colors: [ CustomTheme.boxColor.withValues(alpha: 1), + CustomTheme.boxColor.withValues(alpha: 0.5), + CustomTheme.boxColor.withValues(alpha: 0.2), CustomTheme.boxColor.withValues(alpha: 0.0), ], - stops: const [0.4, 1], + stops: const [0.0, 0.4, 0.8, 1], ), ), ), ), - // Navbar-Inhalt + // Navbar content SafeArea( child: SizedBox( height: 70, diff --git a/pubspec.yaml b/pubspec.yaml index e57c3bc..8844c81 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.5+161 +version: 0.0.5+166 environment: sdk: ^3.8.1 From d5bd0bca5f6f6ea92da4a28cf90fb3d8da9d9d91 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 23:19:37 +0100 Subject: [PATCH 14/64] Fixed displayment bug with TopCenteredMessage --- lib/presentation/widgets/player_selection.dart | 1 + lib/presentation/widgets/top_centered_message.dart | 8 +++++++- pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index 9280ae0..c5bb5de 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -181,6 +181,7 @@ class _PlayerSelectionState extends State { icon: Icons.info, title: loc.info, message: _getInfoText(context), + fullscreen: false, ), child: ListView.builder( itemCount: suggestedPlayers.length, diff --git a/lib/presentation/widgets/top_centered_message.dart b/lib/presentation/widgets/top_centered_message.dart index c15c93d..ecd863c 100644 --- a/lib/presentation/widgets/top_centered_message.dart +++ b/lib/presentation/widgets/top_centered_message.dart @@ -10,6 +10,7 @@ class TopCenteredMessage extends StatelessWidget { required this.icon, required this.title, required this.message, + this.fullscreen = true, }); /// The icon to display above the title. @@ -21,13 +22,18 @@ class TopCenteredMessage extends StatelessWidget { /// The message text to display below the title. final String message; + final bool fullscreen; + @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.only(top: 100), + padding: fullscreen ? const EdgeInsets.only(top: 100) : null, margin: const EdgeInsets.symmetric(horizontal: 10), alignment: Alignment.topCenter, child: Column( + mainAxisAlignment: fullscreen + ? MainAxisAlignment.start + : MainAxisAlignment.center, children: [ Icon(icon, size: 45), const SizedBox(height: 10), diff --git a/pubspec.yaml b/pubspec.yaml index 2afff43..9bc63cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.5+143 +version: 0.0.5+144 environment: sdk: ^3.8.1 From d7f4b1c227f10c83b956e9db6724b3fdd180ec6c Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Tue, 13 Jan 2026 20:41:03 +0100 Subject: [PATCH 15/64] seperate button into widget & change to agreed design --- .../views/main_menu/settings_view.dart | 61 +------------------ .../buttons/animated_dialog_button.dart | 48 +++++++++++++++ 2 files changed, 51 insertions(+), 58 deletions(-) create mode 100644 lib/presentation/widgets/buttons/animated_dialog_button.dart diff --git a/lib/presentation/views/main_menu/settings_view.dart b/lib/presentation/views/main_menu/settings_view.dart index cab26ef..21b9d64 100644 --- a/lib/presentation/views/main_menu/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/widgets/buttons/animated_dialog_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart'; import 'package:game_tracker/services/data_transfer_service.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -97,11 +98,11 @@ class _SettingsViewState extends State { title: '${loc.delete_all_data}?', content: loc.this_cannot_be_undone, actions: [ - _PressableButton( + AnimatedDialogButton( onPressed: () => Navigator.of(context).pop(false), child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor)), ), - _PressableButton( + AnimatedDialogButton( onPressed: () => Navigator.of(context).pop(true), child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor)), ), @@ -218,59 +219,3 @@ class _SettingsViewState extends State { }); } } - -class _PressableButton extends StatefulWidget { - final VoidCallback onPressed; - final Widget child; - - const _PressableButton({required this.onPressed, required this.child}); - - @override - State<_PressableButton> createState() => _PressableButtonState(); -} - -class _PressableButtonState extends State<_PressableButton> { - bool _isPressed = false; - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTapDown: (_) => setState(() => _isPressed = true), - onTapUp: (_) => setState(() => _isPressed = false), - onTapCancel: () => setState(() => _isPressed = false), - onTap: widget.onPressed, - child: AnimatedScale( - scale: _isPressed ? 0.95 : 1.0, - duration: const Duration(milliseconds: 100), - child: AnimatedOpacity( - opacity: _isPressed ? 0.6 : 1.0, - duration: const Duration(milliseconds: 100), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: widget.child, - ), - ), - ), - ); - } -} - - -/* - TextButton( - style: TextButton.styleFrom( - splashFactory: NoSplash.splashFactory, - overlayColor: Colors.transparent, - ), - onPressed: () => Navigator.of(context).pop(false), - child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor),), - ), - TextButton( - style: TextButton.styleFrom( - splashFactory: NoSplash.splashFactory, - overlayColor: Colors.transparent, - ), - onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor),), - ), - */ diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart new file mode 100644 index 0000000..cf49c19 --- /dev/null +++ b/lib/presentation/widgets/buttons/animated_dialog_button.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +/// A custom animated button widget that provides a scaling and opacity effect +/// when pressed. This widget is designed to be used in dialogs or other UI +/// components where a visually appealing button is required. +class AnimatedDialogButton extends StatefulWidget { + /// Callback function that is triggered when the button is pressed. + final VoidCallback onPressed; + + /// The child widget to be displayed inside the button, typically a text or icon. + final Widget child; + + /// Creates an instance of `AnimatedDialogButton`. + /// + /// The [onPressed] and [child] parameters are required. + const AnimatedDialogButton({required this.onPressed, required this.child}); + + @override + State createState() => _AnimatedDialogButtonState(); +} + +class _AnimatedDialogButtonState extends State { + bool _isPressed = false; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: (_) => setState(() => _isPressed = true), + onTapUp: (_) => setState(() => _isPressed = false), + onTapCancel: () => setState(() => _isPressed = false), + onTap: widget.onPressed, + child: AnimatedScale( + scale: _isPressed ? 0.95 : 1.0, + duration: const Duration(milliseconds: 100), + child: AnimatedOpacity( + opacity: _isPressed ? 0.6 : 1.0, + duration: const Duration(milliseconds: 100), + child: Container( + decoration: CustomTheme.standardBoxDecoration, + padding: EdgeInsets.symmetric(horizontal: 26, vertical: 6), + child: widget.child, + ), + ), + ), + ); + } +} From d662680a340371d9d901315394af533f1c23648d Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Tue, 13 Jan 2026 20:46:42 +0100 Subject: [PATCH 16/64] fix dart analysis errors --- lib/presentation/widgets/buttons/animated_dialog_button.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart index cf49c19..42104b2 100644 --- a/lib/presentation/widgets/buttons/animated_dialog_button.dart +++ b/lib/presentation/widgets/buttons/animated_dialog_button.dart @@ -14,7 +14,7 @@ class AnimatedDialogButton extends StatefulWidget { /// Creates an instance of `AnimatedDialogButton`. /// /// The [onPressed] and [child] parameters are required. - const AnimatedDialogButton({required this.onPressed, required this.child}); + const AnimatedDialogButton({super.key, required this.onPressed, required this.child}); @override State createState() => _AnimatedDialogButtonState(); @@ -38,7 +38,7 @@ class _AnimatedDialogButtonState extends State { duration: const Duration(milliseconds: 100), child: Container( decoration: CustomTheme.standardBoxDecoration, - padding: EdgeInsets.symmetric(horizontal: 26, vertical: 6), + padding: const EdgeInsets.symmetric(horizontal: 26, vertical: 6), child: widget.child, ), ), From 4161e1e88bcede3643de9ed7ae8ef5a8c5f92dbb Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Tue, 13 Jan 2026 20:50:54 +0100 Subject: [PATCH 17/64] add docs to custom_alert_dialog.dart --- lib/presentation/widgets/custom_alert_dialog.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/custom_alert_dialog.dart index 2456b56..5dc8b9a 100644 --- a/lib/presentation/widgets/custom_alert_dialog.dart +++ b/lib/presentation/widgets/custom_alert_dialog.dart @@ -1,9 +1,19 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A custom alert dialog widget that follows the application's design theme. +/// +/// This widget provides a styled alternative to the default Flutter AlertDialog, +/// with consistent colors, borders, and layout that match the app's custom theme. class CustomAlertDialog extends StatelessWidget { + /// The title text displayed at the top of the dialog. final String title; + + /// The main content text displayed in the body of the dialog. final String content; + + /// A list of action widgets (typically buttons) displayed at the bottom of the dialog. + /// These actions are horizontally spaced around the dialog's width. final List actions; const CustomAlertDialog({ From 82ad2b74f829e857a949cb607d77349d1b1bea6c Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Tue, 13 Jan 2026 21:16:59 +0100 Subject: [PATCH 18/64] refactor: enhance documentation and fix punctuation in localization strings --- 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 +- .../buttons/animated_dialog_button.dart | 12 +++++------ .../widgets/custom_alert_dialog.dart | 20 +++++++++---------- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 6aee6ee..7091586 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -79,7 +79,7 @@ "stats": "Statistiken", "successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt", "there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht", - "this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden", + "this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden.", "today_at": "Heute um", "undo": "Rückgängig", "unknown_exception": "Unbekannter Fehler (siehe Konsole)", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index c311050..6eb7613 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -356,7 +356,7 @@ "stats": "Stats", "successfully_added_player": "Successfully added player {playerName}", "there_is_no_group_matching_your_search": "There is no group matching your search", - "this_cannot_be_undone": "This can't be undone", + "this_cannot_be_undone": "This can't be undone.", "today_at": "Today at", "undo": "Undo", "unknown_exception": "Unknown Exception (see console)", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 399dc85..e78d69b 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -575,7 +575,7 @@ abstract class AppLocalizations { /// Warning message for irreversible actions /// /// In en, this message translates to: - /// **'This can\'t be undone'** + /// **'This can\'t be undone.'** String get this_cannot_be_undone; /// Date format for today diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index f4d0f8c..8ecc0a7 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -262,7 +262,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get this_cannot_be_undone => - 'Dies kann nicht rückgängig gemacht werden'; + 'Dies kann nicht rückgängig gemacht werden.'; @override String get today_at => 'Heute um'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 6c4ac74..b911676 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -261,7 +261,7 @@ class AppLocalizationsEn extends AppLocalizations { 'There is no group matching your search'; @override - String get this_cannot_be_undone => 'This can\'t be undone'; + String get this_cannot_be_undone => 'This can\'t be undone.'; @override String get today_at => 'Today at'; diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart index 42104b2..c0ce560 100644 --- a/lib/presentation/widgets/buttons/animated_dialog_button.dart +++ b/lib/presentation/widgets/buttons/animated_dialog_button.dart @@ -4,18 +4,18 @@ import 'package:game_tracker/core/custom_theme.dart'; /// A custom animated button widget that provides a scaling and opacity effect /// when pressed. This widget is designed to be used in dialogs or other UI /// components where a visually appealing button is required. +/// +/// Parameters: +/// - [onPressed]: Callback function that is triggered when the button is pressed. +/// - [child]: The child widget to be displayed inside the button, typically a text or icon. class AnimatedDialogButton extends StatefulWidget { + const AnimatedDialogButton({super.key, required this.onPressed, required this.child}); + /// Callback function that is triggered when the button is pressed. final VoidCallback onPressed; - /// The child widget to be displayed inside the button, typically a text or icon. final Widget child; - /// Creates an instance of `AnimatedDialogButton`. - /// - /// The [onPressed] and [child] parameters are required. - const AnimatedDialogButton({super.key, required this.onPressed, required this.child}); - @override State createState() => _AnimatedDialogButtonState(); } diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/custom_alert_dialog.dart index 5dc8b9a..832369a 100644 --- a/lib/presentation/widgets/custom_alert_dialog.dart +++ b/lib/presentation/widgets/custom_alert_dialog.dart @@ -5,17 +5,13 @@ import 'package:game_tracker/core/custom_theme.dart'; /// /// This widget provides a styled alternative to the default Flutter AlertDialog, /// with consistent colors, borders, and layout that match the app's custom theme. +/// +/// Parameters: +/// - [title]: The title text displayed at the top of the dialog. +/// - [content]: The main content text displayed in the body of the dialog. +/// - [actions]: A list of action widgets (typically buttons) displayed at the bottom +/// of the dialog. These actions are horizontally spaced around the dialog's width. class CustomAlertDialog extends StatelessWidget { - /// The title text displayed at the top of the dialog. - final String title; - - /// The main content text displayed in the body of the dialog. - final String content; - - /// A list of action widgets (typically buttons) displayed at the bottom of the dialog. - /// These actions are horizontally spaced around the dialog's width. - final List actions; - const CustomAlertDialog({ super.key, required this.title, @@ -23,6 +19,10 @@ class CustomAlertDialog extends StatelessWidget { required this.actions, }); + final String title; + final String content; + final List actions; + @override Widget build(BuildContext context) { return AlertDialog( From efdb5e036137a42f53b0be072615bf46192ee836 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 13 Jan 2026 21:44:38 +0100 Subject: [PATCH 19/64] Fixed snackbar --- .../settings_view/settings_view.dart | 394 ++++++++++-------- 1 file changed, 212 insertions(+), 182 deletions(-) diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index 1843c90..e32696d 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -37,194 +37,223 @@ class _SettingsViewState extends State { Widget build(BuildContext context) { final loc = AppLocalizations.of(context); return ScaffoldMessenger( - child: Scaffold( - appBar: AppBar(backgroundColor: CustomTheme.backgroundColor), - backgroundColor: CustomTheme.backgroundColor, - body: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16, bottom: 10), - child: Text( - textAlign: TextAlign.start, - loc.settings, - style: const TextStyle( - fontSize: 28, - fontWeight: FontWeight.bold, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16, top: 10, bottom: 10), - child: Text( - textAlign: TextAlign.start, - loc.data, - style: const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - ), - ), - ), - SettingsListTile( - title: loc.export_data, - icon: Icons.upload, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: () async { - final String json = - await DataTransferService.getAppDataAsJson(context); - final result = await DataTransferService.exportData( - json, - 'game_tracker-data', - ); - if (!context.mounted) return; - showExportSnackBar(context: context, result: result); - }, - ), - SettingsListTile( - title: loc.import_data, - icon: Icons.download, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: () async { - final result = await DataTransferService.importData(context); - if (!context.mounted) return; - showImportSnackBar(context: context, result: result); - }, - ), - SettingsListTile( - title: loc.delete_all_data, - icon: Icons.delete, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('${loc.delete_all_data}?'), - content: Text(loc.this_cannot_be_undone), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text(loc.cancel), - ), - TextButton( - onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.delete), - ), - ], + child: Builder( + builder: (scaffoldMessengerContext) { + return Scaffold( + appBar: AppBar(backgroundColor: CustomTheme.backgroundColor), + backgroundColor: CustomTheme.backgroundColor, + body: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16, bottom: 10), + child: Text( + textAlign: TextAlign.start, + loc.settings, + style: const TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + ), ), - ).then((confirmed) { - if (confirmed == true && context.mounted) { - DataTransferService.deleteAllData(context); - showSnackbar( - context: context, - message: AppLocalizations.of( - context, - ).data_successfully_deleted, + ), + Padding( + padding: const EdgeInsets.only( + left: 16, + top: 10, + bottom: 10, + ), + child: Text( + textAlign: TextAlign.start, + loc.data, + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ), + SettingsListTile( + title: loc.export_data, + icon: Icons.upload, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () async { + final String json = + await DataTransferService.getAppDataAsJson( + scaffoldMessengerContext, + ); + final result = await DataTransferService.exportData( + json, + 'game_tracker-data', ); - } - }); - }, - ), - Padding( - padding: const EdgeInsets.only(left: 16, top: 10, bottom: 10), - child: Text( - textAlign: TextAlign.start, - loc.legal, - style: const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, + if (!scaffoldMessengerContext.mounted) return; + showExportSnackBar( + context: scaffoldMessengerContext, + result: result, + ); + }, ), - ), - ), - SettingsListTile( - title: loc.licenses, - icon: Icons.insert_drive_file, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const LicensesView(), - ), - ); - }, - ), - SettingsListTile( - title: loc.legal_notice, - icon: Icons.account_balance_sharp, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: null, - ), - SettingsListTile( - title: loc.privacy_policy, - icon: Icons.gpp_good_rounded, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: null, - ), - Padding( - padding: const EdgeInsets.only(top: 30, bottom: 20), - child: Center( - child: Column( - spacing: 4, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 40, - children: [ - GestureDetector( - child: const Icon(Icons.language), - onTap: () => { - launchUrl(Uri.parse('https://liquid-dev.de')), - }, + SettingsListTile( + title: loc.import_data, + icon: Icons.download, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () async { + final result = await DataTransferService.importData( + scaffoldMessengerContext, + ); + if (!scaffoldMessengerContext.mounted) return; + showImportSnackBar( + context: scaffoldMessengerContext, + result: result, + ); + }, + ), + SettingsListTile( + title: loc.delete_all_data, + icon: Icons.delete, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () { + showDialog( + context: scaffoldMessengerContext, + builder: (dialogContext) => AlertDialog( + title: Text('${loc.delete_all_data}?'), + content: Text(loc.this_cannot_be_undone), + actions: [ + TextButton( + onPressed: () => + Navigator.of(dialogContext).pop(false), + child: Text(loc.cancel), ), - GestureDetector( - child: const FaIcon(FontAwesomeIcons.github), - onTap: () => { - launchUrl( - Uri.parse( - 'https://github.com/liquiddevelopmentde', - ), - ), - }, - ), - GestureDetector( - child: Icon( - Platform.isIOS - ? CupertinoIcons.mail_solid - : Icons.email, - ), - onTap: () => launchUrl( - Uri.parse('mailto:hi@liquid-dev.de'), - ), + TextButton( + onPressed: () => + Navigator.of(dialogContext).pop(true), + child: Text(loc.delete), ), ], ), - ), - Text( - '© ${DateFormat('yyyy').format(DateTime.now())} Liquid Development', - style: TextStyle( - color: Colors.grey.shade600, - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - Text( - 'Version ${_packageInfo.version} (${_packageInfo.buildNumber})', - style: TextStyle( - color: Colors.grey.shade600, - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - ], + ).then((confirmed) { + if (confirmed == true && + scaffoldMessengerContext.mounted) { + DataTransferService.deleteAllData( + scaffoldMessengerContext, + ); + showSnackbar( + context: scaffoldMessengerContext, + message: AppLocalizations.of( + scaffoldMessengerContext, + ).data_successfully_deleted, + ); + } + }); + }, ), - ), + Padding( + padding: const EdgeInsets.only( + left: 16, + top: 10, + bottom: 10, + ), + child: Text( + textAlign: TextAlign.start, + loc.legal, + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ), + SettingsListTile( + title: loc.licenses, + icon: Icons.insert_drive_file, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const LicensesView(), + ), + ); + }, + ), + SettingsListTile( + title: loc.legal_notice, + icon: Icons.account_balance_sharp, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: null, + ), + SettingsListTile( + title: loc.privacy_policy, + icon: Icons.gpp_good_rounded, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: null, + ), + Padding( + padding: const EdgeInsets.only(top: 30, bottom: 20), + child: Center( + child: Column( + spacing: 4, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 40, + children: [ + GestureDetector( + child: const Icon(Icons.language), + onTap: () => { + launchUrl( + Uri.parse('https://liquid-dev.de'), + ), + }, + ), + GestureDetector( + child: const FaIcon(FontAwesomeIcons.github), + onTap: () => { + launchUrl( + Uri.parse( + 'https://github.com/liquiddevelopmentde', + ), + ), + }, + ), + GestureDetector( + child: Icon( + Platform.isIOS + ? CupertinoIcons.mail_solid + : Icons.email, + ), + onTap: () => launchUrl( + Uri.parse('mailto:hi@liquid-dev.de'), + ), + ), + ], + ), + ), + Text( + '© ${DateFormat('yyyy').format(DateTime.now())} Liquid Development', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + Text( + 'Version ${_packageInfo.version} (${_packageInfo.buildNumber})', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ], ), - ], - ), - ), + ), + ); + }, ), ); } @@ -285,10 +314,11 @@ class _SettingsViewState extends State { Duration duration = const Duration(seconds: 3), VoidCallback? action, }) { + if (!context.mounted) return; + final loc = AppLocalizations.of(context); - final messenger = ScaffoldMessenger.of(context); - messenger.hideCurrentSnackBar(); - messenger.showSnackBar( + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message, style: const TextStyle(color: Colors.white)), backgroundColor: CustomTheme.onBoxColor, From 7be0b96491c66f33750aeae1b6744afd1352b119 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 13 Jan 2026 21:45:22 +0100 Subject: [PATCH 20/64] Added hiding to prevent stacking snackbars --- lib/presentation/widgets/player_selection.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index c5bb5de..2b9bb50 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -295,6 +295,7 @@ class _PlayerSelectionState extends State { /// [message] - The message to display in the snackbar. void showSnackBarMessage(String message) { if (!context.mounted) return; + ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: CustomTheme.boxColor, From 4019ed083ff75e6abecffcf6e9a2247f64a69401 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Tue, 13 Jan 2026 21:53:45 +0100 Subject: [PATCH 21/64] add background color option to AnimatedDialogButton --- .../main_menu/settings_view/settings_view.dart | 3 ++- .../widgets/buttons/animated_dialog_button.dart | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index 1304f4a..34381c4 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -111,7 +111,8 @@ class _SettingsViewState extends State { ), AnimatedDialogButton( onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor)), + child: Text(loc.delete, style: TextStyle(color: CustomTheme.textColor)), + backgroundColor: CustomTheme.secondaryColor, ), ], ), diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart index c0ce560..a93f7cf 100644 --- a/lib/presentation/widgets/buttons/animated_dialog_button.dart +++ b/lib/presentation/widgets/buttons/animated_dialog_button.dart @@ -8,13 +8,18 @@ import 'package:game_tracker/core/custom_theme.dart'; /// Parameters: /// - [onPressed]: Callback function that is triggered when the button is pressed. /// - [child]: The child widget to be displayed inside the button, typically a text or icon. +/// - [backgroundColor]: Optional background color for the button container. If null, uses the standard box color from CustomTheme. class AnimatedDialogButton extends StatefulWidget { - const AnimatedDialogButton({super.key, required this.onPressed, required this.child}); + const AnimatedDialogButton({ + super.key, + required this.onPressed, + required this.child, + this.backgroundColor, + }); - /// Callback function that is triggered when the button is pressed. final VoidCallback onPressed; - /// The child widget to be displayed inside the button, typically a text or icon. final Widget child; + final Color? backgroundColor; @override State createState() => _AnimatedDialogButtonState(); @@ -37,7 +42,11 @@ class _AnimatedDialogButtonState extends State { opacity: _isPressed ? 0.6 : 1.0, duration: const Duration(milliseconds: 100), child: Container( - decoration: CustomTheme.standardBoxDecoration, + decoration: widget.backgroundColor != null + ? CustomTheme.standardBoxDecoration.copyWith( + color: widget.backgroundColor, + ) + : CustomTheme.standardBoxDecoration, padding: const EdgeInsets.symmetric(horizontal: 26, vertical: 6), child: widget.child, ), From db51990695d60144175ea136cb62dfafd17002f6 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Tue, 13 Jan 2026 22:17:38 +0100 Subject: [PATCH 22/64] Revert "add background color option to AnimatedDialogButton" This reverts commit 4019ed083ff75e6abecffcf6e9a2247f64a69401. --- .../main_menu/settings_view/settings_view.dart | 3 +-- .../widgets/buttons/animated_dialog_button.dart | 17 ++++------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index 34381c4..1304f4a 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -111,8 +111,7 @@ class _SettingsViewState extends State { ), AnimatedDialogButton( onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.delete, style: TextStyle(color: CustomTheme.textColor)), - backgroundColor: CustomTheme.secondaryColor, + child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor)), ), ], ), diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart index a93f7cf..c0ce560 100644 --- a/lib/presentation/widgets/buttons/animated_dialog_button.dart +++ b/lib/presentation/widgets/buttons/animated_dialog_button.dart @@ -8,18 +8,13 @@ import 'package:game_tracker/core/custom_theme.dart'; /// Parameters: /// - [onPressed]: Callback function that is triggered when the button is pressed. /// - [child]: The child widget to be displayed inside the button, typically a text or icon. -/// - [backgroundColor]: Optional background color for the button container. If null, uses the standard box color from CustomTheme. class AnimatedDialogButton extends StatefulWidget { - const AnimatedDialogButton({ - super.key, - required this.onPressed, - required this.child, - this.backgroundColor, - }); + const AnimatedDialogButton({super.key, required this.onPressed, required this.child}); + /// Callback function that is triggered when the button is pressed. final VoidCallback onPressed; + /// The child widget to be displayed inside the button, typically a text or icon. final Widget child; - final Color? backgroundColor; @override State createState() => _AnimatedDialogButtonState(); @@ -42,11 +37,7 @@ class _AnimatedDialogButtonState extends State { opacity: _isPressed ? 0.6 : 1.0, duration: const Duration(milliseconds: 100), child: Container( - decoration: widget.backgroundColor != null - ? CustomTheme.standardBoxDecoration.copyWith( - color: widget.backgroundColor, - ) - : CustomTheme.standardBoxDecoration, + decoration: CustomTheme.standardBoxDecoration, padding: const EdgeInsets.symmetric(horizontal: 26, vertical: 6), child: widget.child, ), From bb79eecdfdf21d2a5f9abddb48f395d91312873e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 13 Jan 2026 22:24:31 +0100 Subject: [PATCH 23/64] Updated and added comments --- lib/core/adaptive_page_route.dart | 4 + lib/core/constants.dart | 1 + lib/core/custom_theme.dart | 1 + .../main_menu/custom_navigation_bar.dart | 2 + .../group_view/create_group_view.dart | 1 + .../main_menu/group_view/groups_view.dart | 1 + .../views/main_menu/home_view.dart | 2 + .../create_match/choose_game_view.dart | 12 ++- .../create_match/choose_group_view.dart | 19 ++-- .../create_match/choose_ruleset_view.dart | 12 ++- .../create_match/create_match_view.dart | 9 +- .../match_view/match_result_view.dart | 8 +- .../main_menu/match_view/match_view.dart | 1 + .../licenses/license_detail_view.dart | 7 +- .../settings_view/licenses_view.dart | 1 + .../settings_view/settings_view.dart | 2 + .../views/main_menu/statistics_view.dart | 1 + lib/presentation/widgets/app_skeleton.dart | 8 +- .../widgets/buttons/custom_width_button.dart | 12 +-- .../widgets/buttons/main_menu_button.dart | 8 +- .../widgets/buttons/quick_create_button.dart | 6 +- lib/presentation/widgets/navbar_item.dart | 12 +-- .../widgets/player_selection.dart | 14 +-- .../widgets/text_input/custom_search_bar.dart | 18 ++-- .../widgets/text_input/text_input_field.dart | 8 +- .../widgets/tiles/choose_tile.dart | 8 +- .../widgets/tiles/custom_radio_list_tile.dart | 8 +- .../widgets/tiles/group_tile.dart | 6 +- lib/presentation/widgets/tiles/info_tile.dart | 14 +-- .../widgets/tiles/license_tile.dart | 7 +- .../widgets/tiles/match_summary_tile.dart | 95 ------------------- .../widgets/tiles/match_tile.dart | 12 +-- .../widgets/tiles/quick_info_tile.dart | 14 +-- .../widgets/tiles/settings_list_tile.dart | 10 +- .../widgets/tiles/statistics_tile.dart | 14 +-- .../widgets/tiles/text_icon_list_tile.dart | 8 +- .../widgets/tiles/text_icon_tile.dart | 8 +- .../tiles/title_description_list_tile.dart | 14 +-- .../widgets/top_centered_message.dart | 8 +- 39 files changed, 177 insertions(+), 219 deletions(-) delete mode 100644 lib/presentation/widgets/tiles/match_summary_tile.dart diff --git a/lib/core/adaptive_page_route.dart b/lib/core/adaptive_page_route.dart index ba68557..4b0f9b4 100644 --- a/lib/core/adaptive_page_route.dart +++ b/lib/core/adaptive_page_route.dart @@ -1,7 +1,11 @@ import 'dart:io'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +/// Returns a platform-adaptive page route based on the current platform. +/// - On iOS, it returns a [CupertinoPageRoute]. +/// - On other platforms, it returns a [MaterialPageRoute]. Route adaptivePageRoute({ required Widget Function(BuildContext) builder, bool fullscreenDialog = false, diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 8d3c8cc..4ed41c0 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,3 +1,4 @@ +/// Application-wide constants class Constants { Constants._(); // Private constructor to prevent instantiation diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index cfe9b5a..12ac4a8 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +/// Theme class that defines colors, border radius, padding, and decorations class CustomTheme { CustomTheme._(); // Private constructor to prevent instantiation diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 3d1fa96..a110419 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -12,6 +12,8 @@ import 'package:game_tracker/presentation/views/main_menu/statistics_view.dart'; import 'package:game_tracker/presentation/widgets/navbar_item.dart'; class CustomNavigationBar extends StatefulWidget { + /// A custom navigation bar widget that provides tabbed navigation + /// between different views: Home, Matches, Groups, and Statistics. const CustomNavigationBar({super.key}); @override diff --git a/lib/presentation/views/main_menu/group_view/create_group_view.dart b/lib/presentation/views/main_menu/group_view/create_group_view.dart index 8192c6b..719b47d 100644 --- a/lib/presentation/views/main_menu/group_view/create_group_view.dart +++ b/lib/presentation/views/main_menu/group_view/create_group_view.dart @@ -11,6 +11,7 @@ import 'package:game_tracker/presentation/widgets/text_input/text_input_field.da import 'package:provider/provider.dart'; class CreateGroupView extends StatefulWidget { + /// A view that allows the user to create a new group const CreateGroupView({super.key}); @override diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart index ec5fc44..10ae148 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -14,6 +14,7 @@ import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; class GroupsView extends StatefulWidget { + /// A view that displays a list of groups const GroupsView({super.key}); @override diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index affbe92..2f25d5a 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -15,6 +15,8 @@ import 'package:game_tracker/presentation/widgets/tiles/quick_info_tile.dart'; import 'package:provider/provider.dart'; class HomeView extends StatefulWidget { + /// The main home view of the application, displaying quick info, + /// recent matches, and quick create options. const HomeView({super.key}); @override diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart index 5976f72..32868e4 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart @@ -6,15 +6,21 @@ import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.d import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart'; class ChooseGameView extends StatefulWidget { - final List<(String, String, Ruleset)> games; - final int initialGameIndex; - + /// A view that allows the user to choose a game from a list of available games + /// - [games]: A list of tuples containing the game name, description and ruleset + /// - [initialGameIndex]: The index of the initially selected game const ChooseGameView({ super.key, required this.games, required this.initialGameIndex, }); + /// A list of tuples containing the game name, description and ruleset + final List<(String, String, Ruleset)> games; + + /// The index of the initially selected game + final int initialGameIndex; + @override State createState() => _ChooseGameViewState(); } diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart index 9e34460..00a0276 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart @@ -7,15 +7,21 @@ import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; class ChooseGroupView extends StatefulWidget { - final List groups; - final String initialGroupId; - + /// A view that allows the user to choose a group from a list of groups. + /// - [groups]: A list of available groups to choose from + /// - [initialGroupId]: The ID of the initially selected group const ChooseGroupView({ super.key, required this.groups, required this.initialGroupId, }); + /// A list of available groups to choose from + final List groups; + + /// The ID of the initially selected group + final String initialGroupId; + @override State createState() => _ChooseGroupViewState(); } @@ -140,10 +146,11 @@ class _ChooseGroupViewState extends State { filteredGroups.clear(); filteredGroups.addAll( widget.groups.where( - (group) => - group.name.toLowerCase().contains(query.toLowerCase()) || + (group) => + group.name.toLowerCase().contains(query.toLowerCase()) || group.members.any( - (player) => player.name.toLowerCase().contains(query.toLowerCase()), + (player) => + player.name.toLowerCase().contains(query.toLowerCase()), ), ), ); diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart index ca021af..3b1f37b 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart @@ -5,15 +5,21 @@ import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart'; class ChooseRulesetView extends StatefulWidget { - final List<(Ruleset, String)> rulesets; - final int initialRulesetIndex; - + /// A view that allows the user to choose a ruleset from a list of available rulesets + /// - [rulesets]: A list of tuples containing the ruleset and its description + /// - [initialRulesetIndex]: The index of the initially selected ruleset const ChooseRulesetView({ super.key, required this.rulesets, required this.initialRulesetIndex, }); + /// A list of tuples containing the ruleset and its description + final List<(Ruleset, String)> rulesets; + + /// The index of the initially selected ruleset + final int initialRulesetIndex; + @override State createState() => _ChooseRulesetViewState(); } diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index b9885a4..694a82d 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -18,9 +18,13 @@ import 'package:game_tracker/presentation/widgets/tiles/choose_tile.dart'; import 'package:provider/provider.dart'; class CreateMatchView extends StatefulWidget { - final VoidCallback? onWinnerChanged; + /// A view that allows creating a new match + /// [onWinnerChanged]: Optional callback invoked when the winner is changed const CreateMatchView({super.key, this.onWinnerChanged}); + /// Optional callback invoked when the winner is changed + final VoidCallback? onWinnerChanged; + @override State createState() => _CreateMatchViewState(); } @@ -202,7 +206,8 @@ class _CreateMatchViewState extends State { if (selectedGroup != null) { filteredPlayerList = playerList .where( - (p) => !selectedGroup!.members.any((m) => m.id == p.id), + (p) => + !selectedGroup!.members.any((m) => m.id == p.id), ) .toList(); } else { diff --git a/lib/presentation/views/main_menu/match_view/match_result_view.dart b/lib/presentation/views/main_menu/match_view/match_result_view.dart index 0d624f0..1deb385 100644 --- a/lib/presentation/views/main_menu/match_view/match_result_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_result_view.dart @@ -8,11 +8,17 @@ import 'package:game_tracker/presentation/widgets/tiles/custom_radio_list_tile.d import 'package:provider/provider.dart'; class MatchResultView extends StatefulWidget { + /// A view that allows selecting and saving the winner of a match + /// [match]: The match for which the winner is to be selected + /// [onWinnerChanged]: Optional callback invoked when the winner is changed + const MatchResultView({super.key, required this.match, this.onWinnerChanged}); + + /// The match for which the winner is to be selected final Match match; + /// Optional callback invoked when the winner is changed final VoidCallback? onWinnerChanged; - const MatchResultView({super.key, required this.match, this.onWinnerChanged}); @override State createState() => _MatchResultViewState(); } diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index 7705d18..b656c61 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -19,6 +19,7 @@ import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; class MatchView extends StatefulWidget { + /// A view that displays a list of matches const MatchView({super.key}); @override diff --git a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart index 02c3adf..e46fc31 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart @@ -5,10 +5,13 @@ import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses import 'package:url_launcher/url_launcher.dart'; class LicenseDetailView extends StatelessWidget { - final Package package; - + /// A detailed view displaying information about a software package license. + /// - [package]: The package data to be displayed. const LicenseDetailView({super.key, required this.package}); + /// The package data to be displayed. + final Package package; + @override Widget build(BuildContext context) { final loc = AppLocalizations.of(context); diff --git a/lib/presentation/views/main_menu/settings_view/licenses_view.dart b/lib/presentation/views/main_menu/settings_view/licenses_view.dart index 603162f..58aae5b 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses_view.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses_view.dart @@ -5,6 +5,7 @@ import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses import 'package:game_tracker/presentation/widgets/tiles/license_tile.dart'; class LicensesView extends StatelessWidget { + /// A view that displays a list of open source licenses used in the app const LicensesView({super.key}); @override diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index e32696d..4f8c73a 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -14,6 +14,8 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; class SettingsView extends StatefulWidget { + /// The settings view of the application, allowing users to manage data + /// and view legal information. const SettingsView({super.key}); @override diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index 53569ad..fc7165d 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -10,6 +10,7 @@ import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; class StatisticsView extends StatefulWidget { + /// A view that displays player statistics const StatisticsView({super.key}); @override diff --git a/lib/presentation/widgets/app_skeleton.dart b/lib/presentation/widgets/app_skeleton.dart index 1d74456..98f2ca7 100644 --- a/lib/presentation/widgets/app_skeleton.dart +++ b/lib/presentation/widgets/app_skeleton.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:skeletonizer/skeletonizer.dart'; -/// A widget that provides a skeleton loading effect to its child widget tree. -/// - [child]: The widget tree to apply the skeleton effect to. -/// - [enabled]: A boolean to enable or disable the skeleton effect. -/// - [fixLayoutBuilder]: A boolean to fix the layout builder for AnimatedSwitcher. class AppSkeleton extends StatefulWidget { + /// A widget that provides a skeleton loading effect to its child widget tree. + /// - [child]: The widget tree to apply the skeleton effect to. + /// - [enabled]: A boolean to enable or disable the skeleton effect. + /// - [fixLayoutBuilder]: A boolean to fix the layout builder for AnimatedSwitcher. const AppSkeleton({ super.key, required this.child, diff --git a/lib/presentation/widgets/buttons/custom_width_button.dart b/lib/presentation/widgets/buttons/custom_width_button.dart index 7e52648..8d45540 100644 --- a/lib/presentation/widgets/buttons/custom_width_button.dart +++ b/lib/presentation/widgets/buttons/custom_width_button.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; -/// A custom button widget that is designed to have a width relative to the screen size. -/// It supports three types of buttons: primary, secondary, and text buttons. -/// - [text]: The text to display on the button. -/// - [buttonType]: The type of button to display. Defaults to [ButtonType.primary]. -/// - [sizeRelativeToWidth]: The size of the button relative to the width of the screen. -/// - [onPressed]: The callback to be invoked when the button is pressed. class CustomWidthButton extends StatelessWidget { + /// A custom button widget that is designed to have a width relative to the screen size. + /// It supports three types of buttons: primary, secondary, and text buttons. + /// - [text]: The text to display on the button. + /// - [buttonType]: The type of button to display. Defaults to [ButtonType.primary]. + /// - [sizeRelativeToWidth]: The size of the button relative to the width of the screen. + /// - [onPressed]: The callback to be invoked when the button is pressed. const CustomWidthButton({ super.key, required this.text, diff --git a/lib/presentation/widgets/buttons/main_menu_button.dart b/lib/presentation/widgets/buttons/main_menu_button.dart index d29566c..747c31e 100644 --- a/lib/presentation/widgets/buttons/main_menu_button.dart +++ b/lib/presentation/widgets/buttons/main_menu_button.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -/// A button for the main menu with an optional icon and a press animation. -/// - [text]: The text of the button. -/// - [icon]: The icon of the button. -/// - [onPressed]: The callback to be invoked when the button is pressed. class MainMenuButton extends StatefulWidget { + /// A button for the main menu with an optional icon and a press animation. + /// - [text]: The text of the button. + /// - [icon]: The icon of the button. + /// - [onPressed]: The callback to be invoked when the button is pressed. const MainMenuButton({ super.key, required this.text, diff --git a/lib/presentation/widgets/buttons/quick_create_button.dart b/lib/presentation/widgets/buttons/quick_create_button.dart index 40ebeab..e013186 100644 --- a/lib/presentation/widgets/buttons/quick_create_button.dart +++ b/lib/presentation/widgets/buttons/quick_create_button.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A button widget designed for quick creating matches in the [HomeView] -/// - [text]: The text to display on the button. -/// - [onPressed]: The callback to be invoked when the button is pressed. class QuickCreateButton extends StatefulWidget { + /// A button widget designed for quick creating matches in the [HomeView] + /// - [text]: The text to display on the button. + /// - [onPressed]: The callback to be invoked when the button is pressed. const QuickCreateButton({ super.key, required this.text, diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index abf7acc..45f2976 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A navigation bar item widget that represents a single tab in a navigation bar. -/// - [index]: The index of the tab. -/// - [isSelected]: A boolean indicating whether the tab is currently selected. -/// - [icon]: The icon to display for the tab. -/// - [label]: The label to display for the tab. -/// - [onTabTapped]: The callback to be invoked when the tab is tapped. class NavbarItem extends StatefulWidget { + /// A navigation bar item widget that represents a single tab in a navigation bar. + /// - [index]: The index of the tab. + /// - [isSelected]: A boolean indicating whether the tab is currently selected. + /// - [icon]: The icon to display for the tab. + /// - [label]: The label to display for the tab. + /// - [onTabTapped]: The callback to be invoked when the tab is tapped. const NavbarItem({ super.key, required this.index, diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index 2b9bb50..8b2f2c1 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -11,14 +11,14 @@ import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; -/// A widget that allows users to select players from a list, -/// with search functionality and the ability to add new players. -/// - [availablePlayers]: An optional list of players to choose from. If null, all -/// players from the database are used. -/// - [initialSelectedPlayers]: An optional list of players that should be pre-selected. -/// - [onChanged]: A callback function that is invoked whenever the selection changes, -/// providing the updated list of selected players. class PlayerSelection extends StatefulWidget { + /// A widget that allows users to select players from a list, + /// with search functionality and the ability to add new players. + /// - [availablePlayers]: An optional list of players to choose from. If null, + /// all players from the database are used. + /// - [initialSelectedPlayers]: An optional list of players that should be pre-selected. + /// - [onChanged]: A callback function that is invoked whenever the selection + /// changes, providing the updated list of selected players. const PlayerSelection({ super.key, this.availablePlayers, diff --git a/lib/presentation/widgets/text_input/custom_search_bar.dart b/lib/presentation/widgets/text_input/custom_search_bar.dart index bf7971a..1b453da 100644 --- a/lib/presentation/widgets/text_input/custom_search_bar.dart +++ b/lib/presentation/widgets/text_input/custom_search_bar.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A custom search bar widget that encapsulates a [SearchBar] with additional customization options. -/// - [controller]: The controller for the search bar's text input. -/// - [hintText]: The hint text displayed in the search bar when it is empty. -/// - [trailingButtonShown]: Whether to show the trailing button. -/// - [trailingButtonicon]: The icon for the trailing button. -/// - [trailingButtonEnabled]: Whether the trailing button is in enabled state. -/// - [onTrailingButtonPressed]: The callback invoked when the trailing button is pressed. -/// - [onChanged]: The callback invoked when the text in the search bar changes. -/// - [constraints]: The constraints for the search bar. class CustomSearchBar extends StatelessWidget { + /// A custom search bar widget that encapsulates a [SearchBar] with additional customization options. + /// - [controller]: The controller for the search bar's text input. + /// - [hintText]: The hint text displayed in the search bar when it is empty. + /// - [trailingButtonShown]: Whether to show the trailing button. + /// - [trailingButtonicon]: The icon for the trailing button. + /// - [trailingButtonEnabled]: Whether the trailing button is in enabled state. + /// - [onTrailingButtonPressed]: The callback invoked when the trailing button is pressed. + /// - [onChanged]: The callback invoked when the text in the search bar changes. + /// - [constraints]: The constraints for the search bar. const CustomSearchBar({ super.key, required this.controller, diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index a409c68..7d11767 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A custom text input field widget that encapsulates a [TextField] with specific styling. -/// - [controller]: The controller for the text input field. -/// - [onChanged]: The callback invoked when the text in the field changes. -/// - [hintText]: The hint text displayed in the text input field when it is empty class TextInputField extends StatelessWidget { + /// A custom text input field widget that encapsulates a [TextField] with specific styling. + /// - [controller]: The controller for the text input field. + /// - [onChanged]: The callback invoked when the text in the field changes. + /// - [hintText]: The hint text displayed in the text input field when it is empty const TextInputField({ super.key, required this.controller, diff --git a/lib/presentation/widgets/tiles/choose_tile.dart b/lib/presentation/widgets/tiles/choose_tile.dart index f6ec940..595816e 100644 --- a/lib/presentation/widgets/tiles/choose_tile.dart +++ b/lib/presentation/widgets/tiles/choose_tile.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A tile widget that allows users to choose an option by tapping on it. -/// - [title]: The title text displayed on the tile. -/// - [trailingText]: Optional trailing text displayed on the tile. -/// - [onPressed]: The callback invoked when the tile is tapped. class ChooseTile extends StatefulWidget { + /// A tile widget that allows users to choose an option by tapping on it. + /// - [title]: The title text displayed on the tile. + /// - [trailingText]: Optional trailing text displayed on the tile. + /// - [onPressed]: The callback invoked when the tile is tapped. const ChooseTile({ super.key, required this.title, diff --git a/lib/presentation/widgets/tiles/custom_radio_list_tile.dart b/lib/presentation/widgets/tiles/custom_radio_list_tile.dart index 706aabb..2d8dc7a 100644 --- a/lib/presentation/widgets/tiles/custom_radio_list_tile.dart +++ b/lib/presentation/widgets/tiles/custom_radio_list_tile.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A custom radio list tile widget that encapsulates a [Radio] button with additional styling and functionality. -/// - [text]: The text to display next to the radio button. -/// - [value]: The value associated with the radio button. -/// - [onContainerTap]: The callback invoked when the container is tapped. class CustomRadioListTile extends StatelessWidget { + /// A custom radio list tile widget that encapsulates a [Radio] button with additional styling and functionality. + /// - [text]: The text to display next to the radio button. + /// - [value]: The value associated with the radio button. + /// - [onContainerTap]: The callback invoked when the container is tapped. const CustomRadioListTile({ super.key, required this.text, diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart index 64d9caa..a06c6b5 100644 --- a/lib/presentation/widgets/tiles/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -3,10 +3,10 @@ import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/dto/group.dart'; import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; -/// A tile widget that displays information about a group, including its name and members. -/// - [group]: The group data to be displayed. -/// - [isHighlighted]: Whether the tile should be highlighted. class GroupTile extends StatelessWidget { + /// A tile widget that displays information about a group, including its name and members. + /// - [group]: The group data to be displayed. + /// - [isHighlighted]: Whether the tile should be highlighted. const GroupTile({super.key, required this.group, this.isHighlighted = false}); /// The group data to be displayed. diff --git a/lib/presentation/widgets/tiles/info_tile.dart b/lib/presentation/widgets/tiles/info_tile.dart index 3e11679..280c7d7 100644 --- a/lib/presentation/widgets/tiles/info_tile.dart +++ b/lib/presentation/widgets/tiles/info_tile.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A tile widget that displays a title with an icon and some content below it. -/// - [title]: The title text displayed on the tile. -/// - [icon]: The icon displayed next to the title. -/// - [content]: The content widget displayed below the title. -/// - [padding]: Optional padding for the tile content. -/// - [height]: Optional height for the tile. -/// - [width]: Optional width for the tile. class InfoTile extends StatefulWidget { + /// A tile widget that displays a title with an icon and some content below it. + /// - [title]: The title text displayed on the tile. + /// - [icon]: The icon displayed next to the title. + /// - [content]: The content widget displayed below the title. + /// - [padding]: Optional padding for the tile content. + /// - [height]: Optional height for the tile. + /// - [width]: Optional width for the tile. const InfoTile({ super.key, required this.title, diff --git a/lib/presentation/widgets/tiles/license_tile.dart b/lib/presentation/widgets/tiles/license_tile.dart index 5850d9e..14ee2bf 100644 --- a/lib/presentation/widgets/tiles/license_tile.dart +++ b/lib/presentation/widgets/tiles/license_tile.dart @@ -4,10 +4,13 @@ import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; class LicenseTile extends StatelessWidget { - final Package package; - + /// A tile widget that displays information about a software package license. + /// - [package]: The package data to be displayed. const LicenseTile({super.key, required this.package}); + /// The package data to be displayed. + final Package package; + @override Widget build(BuildContext context) { return GestureDetector( diff --git a/lib/presentation/widgets/tiles/match_summary_tile.dart b/lib/presentation/widgets/tiles/match_summary_tile.dart deleted file mode 100644 index 719037b..0000000 --- a/lib/presentation/widgets/tiles/match_summary_tile.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:skeletonizer/skeletonizer.dart'; - -class MatchSummaryTile extends StatefulWidget { - final String matchTitle; - final String game; - final String ruleset; - final String players; - final String winner; - - const MatchSummaryTile({ - super.key, - required this.matchTitle, - required this.game, - required this.ruleset, - required this.players, - required this.winner, - }); - - @override - State createState() => _MatchSummaryTileState(); -} - -class _MatchSummaryTileState extends State { - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - widget.matchTitle, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - const SizedBox(width: 5), - Text( - widget.game, - style: const TextStyle(fontSize: 14, color: Colors.grey), - ), - ], - ), - const SizedBox(height: 5), - Container( - padding: const EdgeInsets.symmetric(horizontal: 4), - height: 20, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: CustomTheme.primaryColor, - ), - child: Skeleton.ignore( - child: Text( - widget.ruleset, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - ), - Center( - heightFactor: 1.5, - child: Text( - widget.players, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - Center( - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 4), - width: 220, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: Colors.yellow.shade300, - ), - child: Skeleton.ignore( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.emoji_events, color: Colors.black, size: 20), - Text( - widget.winner, - textAlign: TextAlign.center, - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black87, - ), - ), - ], - ), - ), - ), - ), - ], - ); - } -} diff --git a/lib/presentation/widgets/tiles/match_tile.dart b/lib/presentation/widgets/tiles/match_tile.dart index 88ae1f1..11cdea0 100644 --- a/lib/presentation/widgets/tiles/match_tile.dart +++ b/lib/presentation/widgets/tiles/match_tile.dart @@ -6,13 +6,13 @@ import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; import 'package:intl/intl.dart'; -/// A tile widget that displays information about a match, including its name, -/// creation date, associated group, winner, and players. -/// - [match]: The match data to be displayed. -/// - [onTap]: The callback invoked when the tile is tapped. -/// - [width]: Optional width for the tile. -/// - [compact]: Whether to display the tile in a compact mode class MatchTile extends StatefulWidget { + /// A tile widget that displays information about a match, including its name, + /// creation date, associated group, winner, and players. + /// - [match]: The match data to be displayed. + /// - [onTap]: The callback invoked when the tile is tapped. + /// - [width]: Optional width for the tile. + /// - [compact]: Whether to display the tile in a compact mode const MatchTile({ super.key, required this.match, diff --git a/lib/presentation/widgets/tiles/quick_info_tile.dart b/lib/presentation/widgets/tiles/quick_info_tile.dart index 839f6c3..4d6ef2e 100644 --- a/lib/presentation/widgets/tiles/quick_info_tile.dart +++ b/lib/presentation/widgets/tiles/quick_info_tile.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A tile widget that displays a title with an icon and a numeric value below it. -/// - [title]: The title text displayed on the tile. -/// - [icon]: The icon displayed next to the title. -/// - [value]: The numeric value displayed below the title. -/// - [height]: Optional height for the tile. -/// - [width]: Optional width for the tile. -/// - [padding]: Optional padding for the tile content. class QuickInfoTile extends StatefulWidget { + /// A tile widget that displays a title with an icon and a numeric value below it. + /// - [title]: The title text displayed on the tile. + /// - [icon]: The icon displayed next to the title. + /// - [value]: The numeric value displayed below the title. + /// - [height]: Optional height for the tile. + /// - [width]: Optional width for the tile. + /// - [padding]: Optional padding for the tile content. const QuickInfoTile({ super.key, required this.title, diff --git a/lib/presentation/widgets/tiles/settings_list_tile.dart b/lib/presentation/widgets/tiles/settings_list_tile.dart index ba05225..53fb041 100644 --- a/lib/presentation/widgets/tiles/settings_list_tile.dart +++ b/lib/presentation/widgets/tiles/settings_list_tile.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A customizable settings list tile widget that displays an icon, title, and an optional suffix widget. -/// - [icon]: The icon displayed on the left side of the tile. -/// - [title]: The title text displayed next to the icon. -/// - [suffixWidget]: An optional widget displayed on the right side of the tile. -/// - [onPressed]: The callback invoked when the tile is tapped. class SettingsListTile extends StatelessWidget { + /// A customizable settings list tile widget that displays an icon, title, and an optional suffix widget. + /// - [icon]: The icon displayed on the left side of the tile. + /// - [title]: The title text displayed next to the icon. + /// - [suffixWidget]: An optional widget displayed on the right side of the tile. + /// - [onPressed]: The callback invoked when the tile is tapped. const SettingsListTile({ super.key, required this.icon, diff --git a/lib/presentation/widgets/tiles/statistics_tile.dart b/lib/presentation/widgets/tiles/statistics_tile.dart index 2c0ced0..2ac0dfd 100644 --- a/lib/presentation/widgets/tiles/statistics_tile.dart +++ b/lib/presentation/widgets/tiles/statistics_tile.dart @@ -4,14 +4,14 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; -/// A tile widget that displays statistical data using horizontal bars. -/// - [icon]: The icon displayed next to the title. -/// - [title]: The title text displayed on the tile. -/// - [width]: The width of the tile. -/// - [values]: A list of tuples containing labels and their corresponding numeric values. -/// - [itemCount]: The maximum number of items to display. -/// - [barColor]: The color of the bars representing the values. class StatisticsTile extends StatelessWidget { + /// A tile widget that displays statistical data using horizontal bars. + /// - [icon]: The icon displayed next to the title. + /// - [title]: The title text displayed on the tile. + /// - [width]: The width of the tile. + /// - [values]: A list of tuples containing labels and their corresponding numeric values. + /// - [itemCount]: The maximum number of items to display. + /// - [barColor]: The color of the bars representing the values. const StatisticsTile({ super.key, required this.icon, diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart index 7d3fe1c..e468e95 100644 --- a/lib/presentation/widgets/tiles/text_icon_list_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A list tile widget that displays text with an optional icon button. -/// - [text]: The text to display in the tile. -/// - [onPressed]: The callback to be invoked when the icon is pressed. -/// - [iconEnabled]: A boolean to determine if the icon should be displayed. class TextIconListTile extends StatelessWidget { + /// A list tile widget that displays text with an optional icon button. + /// - [text]: The text to display in the tile. + /// - [onPressed]: The callback to be invoked when the icon is pressed. + /// - [iconEnabled]: A boolean to determine if the icon should be displayed. const TextIconListTile({ super.key, required this.text, diff --git a/lib/presentation/widgets/tiles/text_icon_tile.dart b/lib/presentation/widgets/tiles/text_icon_tile.dart index 7142b27..90c32b7 100644 --- a/lib/presentation/widgets/tiles/text_icon_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_tile.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A tile widget that displays text with an optional icon that can be tapped. -/// - [text]: The text to display in the tile. -/// - [iconEnabled]: A boolean to determine if the icon should be displayed. -/// - [onIconTap]: The callback to be invoked when the icon is tapped. class TextIconTile extends StatelessWidget { + /// A tile widget that displays text with an optional icon that can be tapped. + /// - [text]: The text to display in the tile. + /// - [iconEnabled]: A boolean to determine if the icon should be displayed. + /// - [onIconTap]: The callback to be invoked when the icon is tapped. const TextIconTile({ super.key, required this.text, diff --git a/lib/presentation/widgets/tiles/title_description_list_tile.dart b/lib/presentation/widgets/tiles/title_description_list_tile.dart index 781149e..3141cbe 100644 --- a/lib/presentation/widgets/tiles/title_description_list_tile.dart +++ b/lib/presentation/widgets/tiles/title_description_list_tile.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A list tile widget that displays a title and description, with optional highlighting and badge. -/// - [title]: The title text displayed on the tile. -/// - [description]: The description text displayed below the title. -/// - [onPressed]: The callback invoked when the tile is tapped. -/// - [isHighlighted]: A boolean to determine if the tile should be highlighted. -/// - [badgeText]: Optional text to display in a badge on the right side of the title. -/// - [badgeColor]: Optional color for the badge background. class TitleDescriptionListTile extends StatelessWidget { + /// A list tile widget that displays a title and description, with optional highlighting and badge. + /// - [title]: The title text displayed on the tile. + /// - [description]: The description text displayed below the title. + /// - [onPressed]: The callback invoked when the tile is tapped. + /// - [isHighlighted]: A boolean to determine if the tile should be highlighted. + /// - [badgeText]: Optional text to display in a badge on the right side of the title. + /// - [badgeColor]: Optional color for the badge background. const TitleDescriptionListTile({ super.key, required this.title, diff --git a/lib/presentation/widgets/top_centered_message.dart b/lib/presentation/widgets/top_centered_message.dart index ecd863c..e651180 100644 --- a/lib/presentation/widgets/top_centered_message.dart +++ b/lib/presentation/widgets/top_centered_message.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -/// A widget that displays a message centered at the top of the screen with an icon, title, and message. -/// - [icon]: The icon to display above the title. -/// - [title]: The title text to display. -/// - [message]: The message text to display below the title. class TopCenteredMessage extends StatelessWidget { + /// A widget that displays a message centered at the top of the screen with an icon, title, and message. + /// - [icon]: The icon to display above the title. + /// - [title]: The title text to display. + /// - [message]: The message text to display below the title. const TopCenteredMessage({ super.key, required this.icon, From 5350113ee14e71a66ad304fbe16a6ec631a51e36 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 13 Jan 2026 22:54:19 +0100 Subject: [PATCH 24/64] Updated doc strings --- .../buttons/animated_dialog_button.dart | 18 ++++++++------- .../widgets/custom_alert_dialog.dart | 23 +++++++++---------- pubspec.yaml | 2 +- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart index c0ce560..65c0510 100644 --- a/lib/presentation/widgets/buttons/animated_dialog_button.dart +++ b/lib/presentation/widgets/buttons/animated_dialog_button.dart @@ -1,18 +1,20 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A custom animated button widget that provides a scaling and opacity effect -/// when pressed. This widget is designed to be used in dialogs or other UI -/// components where a visually appealing button is required. -/// -/// Parameters: -/// - [onPressed]: Callback function that is triggered when the button is pressed. -/// - [child]: The child widget to be displayed inside the button, typically a text or icon. class AnimatedDialogButton extends StatefulWidget { - const AnimatedDialogButton({super.key, required this.onPressed, required this.child}); + /// A custom animated button widget that provides a scaling and opacity effect + /// when pressed. + /// - [onPressed]: Callback function that is triggered when the button is pressed. + /// - [child]: The child widget to be displayed inside the button, typically a text or icon. + const AnimatedDialogButton({ + super.key, + required this.onPressed, + required this.child, + }); /// Callback function that is triggered when the button is pressed. final VoidCallback onPressed; + /// The child widget to be displayed inside the button, typically a text or icon. final Widget child; diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/custom_alert_dialog.dart index 832369a..af5b45a 100644 --- a/lib/presentation/widgets/custom_alert_dialog.dart +++ b/lib/presentation/widgets/custom_alert_dialog.dart @@ -1,17 +1,13 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -/// A custom alert dialog widget that follows the application's design theme. -/// -/// This widget provides a styled alternative to the default Flutter AlertDialog, -/// with consistent colors, borders, and layout that match the app's custom theme. -/// -/// Parameters: -/// - [title]: The title text displayed at the top of the dialog. -/// - [content]: The main content text displayed in the body of the dialog. -/// - [actions]: A list of action widgets (typically buttons) displayed at the bottom -/// of the dialog. These actions are horizontally spaced around the dialog's width. class CustomAlertDialog extends StatelessWidget { + /// A custom alert dialog widget that provides a os unspecific AlertDialog, + /// with consistent colors, borders, and layout that match the app's custom theme. + /// - [title]: The title text displayed at the top of the dialog. + /// - [content]: The main content text displayed in the body of the dialog. + /// - [actions]: A list of action widgets (typically buttons) displayed at the bottom + /// of the dialog. These actions are horizontally spaced around the dialog's width. const CustomAlertDialog({ super.key, required this.title, @@ -26,8 +22,11 @@ class CustomAlertDialog extends StatelessWidget { @override Widget build(BuildContext context) { return AlertDialog( - title: Text(title, style: const TextStyle(color: CustomTheme.textColor,),), - content: Text(content, style: const TextStyle(color: CustomTheme.textColor),), + title: Text(title, style: const TextStyle(color: CustomTheme.textColor)), + content: Text( + content, + style: const TextStyle(color: CustomTheme.textColor), + ), actions: actions, backgroundColor: CustomTheme.boxColor, actionsAlignment: MainAxisAlignment.spaceAround, diff --git a/pubspec.yaml b/pubspec.yaml index 83d5079..46efd94 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.6+209 +version: 0.0.7+211 environment: sdk: ^3.8.1 From 2cadab004d0b8204fa0164db2b0981d36db94ec9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 13 Jan 2026 22:58:35 +0100 Subject: [PATCH 25/64] Merge cleaning --- .../main_menu/settings_view/settings_view.dart | 16 +++++++++++++--- pubspec.yaml | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index e34d75b..b51cad0 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -123,11 +123,21 @@ class _SettingsViewState extends State { actions: [ AnimatedDialogButton( onPressed: () => Navigator.of(context).pop(false), - child: Text(loc.cancel, style: const TextStyle(color: CustomTheme.textColor)), + child: Text( + loc.cancel, + style: const TextStyle( + color: CustomTheme.textColor, + ), + ), ), AnimatedDialogButton( onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.delete, style: TextStyle(color: CustomTheme.secondaryColor)), + child: Text( + loc.delete, + style: TextStyle( + color: CustomTheme.secondaryColor, + ), + ), ), ], ), @@ -135,7 +145,7 @@ class _SettingsViewState extends State { if (confirmed == true && context.mounted) { DataTransferService.deleteAllData(context); showSnackbar( - context: context, + context: scaffoldMessengerContext, message: AppLocalizations.of( context, ).data_successfully_deleted, diff --git a/pubspec.yaml b/pubspec.yaml index 46efd94..e9fd894 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.7+211 +version: 0.0.7+212 environment: sdk: ^3.8.1 From 1b709707b5fe73e04ad555252cb0b0e9ccc758c2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 16 Jan 2026 21:41:20 +0100 Subject: [PATCH 26/64] Added constants --- analysis_options.yaml | 3 ++- lib/core/constants.dart | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 30e5d08..04172d4 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -10,4 +10,5 @@ linter: prefer_const_declarations: true prefer_const_literals_to_create_immutables: true unnecessary_const: true - lines_longer_than_80_chars: false \ No newline at end of file + lines_longer_than_80_chars: false + constant_identifier_names: false \ No newline at end of file diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 4ed41c0..f193332 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -3,5 +3,20 @@ class Constants { Constants._(); // Private constructor to prevent instantiation /// Minimum duration of all app skeletons - static Duration minimumSkeletonDuration = const Duration(milliseconds: 250); + static const Duration minimumSkeletonDuration = Duration(milliseconds: 250); + + /// Maximum length for player names + static const int MAX_PLAYER_NAME_LENGTH = 32; + + /// Maximum length for group names + static const int MAX_GROUP_NAME_LENGTH = 32; + + /// Maximum length for match names + static const int MAX_MATCH_NAME_LENGTH = 256; + + /// Maximum length for game names + static const int MAX_GAME_NAME_LENGTH = 256; + + /// Maximum length for team names + static const int MAX_TEAM_NAME_LENGTH = 256; } From b7930d5e2e33f9957f795c3902f857b88b1e3e25 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 16 Jan 2026 21:41:42 +0100 Subject: [PATCH 27/64] Adjusted constant name --- lib/core/constants.dart | 2 +- lib/presentation/views/main_menu/group_view/groups_view.dart | 2 +- lib/presentation/views/main_menu/home_view.dart | 2 +- lib/presentation/views/main_menu/match_view/match_view.dart | 2 +- lib/presentation/views/main_menu/statistics_view.dart | 2 +- lib/presentation/widgets/player_selection.dart | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index f193332..646a14e 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -3,7 +3,7 @@ class Constants { Constants._(); // Private constructor to prevent instantiation /// Minimum duration of all app skeletons - static const Duration minimumSkeletonDuration = Duration(milliseconds: 250); + static const Duration MINIMUM_SKELETON_DURATION = Duration(milliseconds: 250); /// Maximum length for player names static const int MAX_PLAYER_NAME_LENGTH = 32; diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart index 10ae148..b9fff84 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -107,7 +107,7 @@ class _GroupsViewState extends State { void loadGroups() { Future.wait([ db.groupDao.getAllGroups(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) { loadedGroups = results[0] as List; setState(() { diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 2f25d5a..f28341e 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -195,7 +195,7 @@ class _HomeViewState extends State { db.matchDao.getMatchCount(), db.groupDao.getGroupCount(), db.matchDao.getAllMatches(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) { matchCount = results[0] as int; groupCount = results[1] as int; diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index b656c61..e85bf77 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -130,7 +130,7 @@ class _MatchViewState extends State { void loadGames() { Future.wait([ db.matchDao.getAllMatches(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) { if (mounted) { setState(() { diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index fc7165d..f87a3fb 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -106,7 +106,7 @@ class _StatisticsViewState extends State { Future.wait([ db.matchDao.getAllMatches(), db.playerDao.getAllPlayers(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) async { if (!mounted) return; final matches = results[0] as List; diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index 8b2f2c1..587c8af 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -219,7 +219,7 @@ class _PlayerSelectionState extends State { void loadPlayerList() { _allPlayersFuture = Future.wait([ db.playerDao.getAllPlayers(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) => results[0] as List); if (mounted) { _allPlayersFuture.then((loadedPlayers) { From 783f772da1ac6a99aada944999bbdc4a784b172d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 16 Jan 2026 21:52:58 +0100 Subject: [PATCH 28/64] Implemented constants --- .../views/main_menu/group_view/create_group_view.dart | 2 ++ .../match_view/create_match/create_match_view.dart | 2 ++ .../widgets/text_input/custom_search_bar.dart | 10 ++++++++++ .../widgets/text_input/text_input_field.dart | 6 ++++++ pubspec.yaml | 2 +- 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/group_view/create_group_view.dart b/lib/presentation/views/main_menu/group_view/create_group_view.dart index 719b47d..da7eb1d 100644 --- a/lib/presentation/views/main_menu/group_view/create_group_view.dart +++ b/lib/presentation/views/main_menu/group_view/create_group_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/data/db/database.dart'; @@ -58,6 +59,7 @@ class _CreateGroupViewState extends State { child: TextInputField( controller: _groupNameController, hintText: loc.group_name, + maxLength: Constants.MAX_GROUP_NAME_LENGTH, ), ), Expanded( diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index 694a82d..ea9cfd5 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/adaptive_page_route.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/data/db/database.dart'; @@ -136,6 +137,7 @@ class _CreateMatchViewState extends State { child: TextInputField( controller: _matchNameController, hintText: hintText ?? '', + maxLength: Constants.MAX_MATCH_NAME_LENGTH, ), ), ChooseTile( diff --git a/lib/presentation/widgets/text_input/custom_search_bar.dart b/lib/presentation/widgets/text_input/custom_search_bar.dart index 1b453da..76bb6e5 100644 --- a/lib/presentation/widgets/text_input/custom_search_bar.dart +++ b/lib/presentation/widgets/text_input/custom_search_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; class CustomSearchBar extends StatelessWidget { @@ -49,6 +50,15 @@ class CustomSearchBar extends StatelessWidget { @override Widget build(BuildContext context) { + /// Enforce maximum length on the input text + const maxLength = Constants.MAX_PLAYER_NAME_LENGTH; + if (controller.text.length > maxLength) { + controller.text = controller.text.substring(0, maxLength); + controller.selection = TextSelection.fromPosition( + TextPosition(offset: controller.text.length), + ); + } + return SearchBar( controller: controller, constraints: diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index 7d11767..37f9ce4 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -6,11 +6,13 @@ class TextInputField extends StatelessWidget { /// - [controller]: The controller for the text input field. /// - [onChanged]: The callback invoked when the text in the field changes. /// - [hintText]: The hint text displayed in the text input field when it is empty + /// - [maxLength]: The maximum length of the input text. const TextInputField({ super.key, required this.controller, required this.hintText, this.onChanged, + this.maxLength, }); /// The controller for the text input field. @@ -22,11 +24,15 @@ class TextInputField extends StatelessWidget { /// The hint text displayed in the text input field when it is empty. final String hintText; + /// The maximum length of the input text. + final int? maxLength; + @override Widget build(BuildContext context) { return TextField( controller: controller, onChanged: onChanged, + maxLength: maxLength, decoration: InputDecoration( filled: true, fillColor: CustomTheme.boxColor, diff --git a/pubspec.yaml b/pubspec.yaml index e9fd894..9f957c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.7+212 +version: 0.0.7+213 environment: sdk: ^3.8.1 From a8129eb13427ebce0ab48c4be59c892203274cbb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 16 Jan 2026 23:34:47 +0100 Subject: [PATCH 29/64] Implemented first version of group profile --- lib/l10n/arb/app_de.arb | 7 + lib/l10n/arb/app_en.arb | 28 ++ lib/l10n/generated/app_localizations.dart | 42 +++ lib/l10n/generated/app_localizations_de.dart | 21 ++ lib/l10n/generated/app_localizations_en.dart | 21 ++ .../group_view/group_profile_view.dart | 271 ++++++++++++++++++ .../main_menu/group_view/groups_view.dart | 21 +- .../widgets/tiles/group_tile.dart | 119 ++++---- pubspec.yaml | 2 +- 9 files changed, 479 insertions(+), 53 deletions(-) create mode 100644 lib/presentation/views/main_menu/group_view/group_profile_view.dart diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 7091586..2ef9ee9 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -4,6 +4,7 @@ "all_players_selected": "Alle Spieler:innen ausgewählt", "amount_of_matches": "Anzahl der Spiele", "app_name": "Game Tracker", + "best_player": "Beste:r Spieler:in", "cancel": "Abbrechen", "choose_game": "Spielvorlage wählen", "choose_group": "Gruppe wählen", @@ -13,6 +14,7 @@ "create_match": "Spiel erstellen", "create_new_group": "Neue Gruppe erstellen", "create_new_match": "Neues Spiel erstellen", + "created_on": "Erstellt am", "data": "Daten", "data_successfully_deleted": "Daten erfolgreich gelöscht", "data_successfully_exported": "Daten erfolgreich exportiert", @@ -20,6 +22,8 @@ "days_ago": "vor {count} Tagen", "delete": "Löschen", "delete_all_data": "Alle Daten löschen", + "delete_group": "Gruppe löschen", + "edit_group": "Gruppe bearbeiten", "error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen", "error_reading_file": "Fehler beim Lesen der Datei", "export_canceled": "Export abgebrochen", @@ -29,6 +33,7 @@ "game_name": "Spielvorlagenname", "group": "Gruppe", "group_name": "Gruppenname", + "group_profile": "Gruppenprofil", "groups": "Gruppen", "home": "Startseite", "import_canceled": "Import abgebrochen", @@ -42,6 +47,7 @@ "match_in_progress": "Spiel läuft...", "match_name": "Spieltitel", "matches": "Spiele", + "members": "Mitglieder", "most_points": "Höchste Punkte", "no_data_available": "Keine Daten verfügbar", "no_groups_created_yet": "Noch keine Gruppen erstellt", @@ -57,6 +63,7 @@ "none": "Kein", "none_group": "Keine", "not_available": "Nicht verfügbar", + "played_matches": "Gespielte Spiele", "player_name": "Spieler:innenname", "players": "Spieler:innen", "players_count": "{count} Spieler", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 6eb7613..fa4adc8 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -12,6 +12,9 @@ "@app_name": { "description": "The name of the App" }, + "@best_player": { + "description": "Label for best player statistic" + }, "@cancel": { "description": "Cancel button text" }, @@ -39,6 +42,9 @@ "@create_new_match": { "description": "Button text to create a new match" }, + "@created_on": { + "description": "Label for creation date" + }, "@data": { "description": "Data label" }, @@ -65,6 +71,12 @@ "@delete_all_data": { "description": "Confirmation dialog for deleting all data" }, + "@delete_group": { + "description": "Button text to delete a group" + }, + "@edit_group": { + "description": "Button text to edit a group" + }, "@error_creating_group": { "description": "Error message when group creation fails" }, @@ -92,6 +104,9 @@ "@group_name": { "description": "Placeholder for group name input" }, + "@group_profile": { + "description": "Title for group profile view" + }, "@groups": { "description": "Label for groups" }, @@ -131,6 +146,9 @@ "@matches": { "description": "Label for matches" }, + "@members": { + "description": "Label for group members" + }, "@most_points": { "description": "Title for most points ruleset" }, @@ -176,6 +194,9 @@ "@not_available": { "description": "Abbreviation for not available" }, + "@played_matches": { + "description": "Label for played matches statistic" + }, "@player_name": { "description": "Placeholder for player name input" }, @@ -281,6 +302,7 @@ "all_players_selected": "All players selected", "amount_of_matches": "Amount of Matches", "app_name": "Game Tracker", + "best_player": "Best Player", "cancel": "Cancel", "choose_game": "Choose Game", "choose_group": "Choose Group", @@ -289,6 +311,7 @@ "create_group": "Create Group", "create_match": "Create match", "create_new_group": "Create new group", + "created_on": "Created on", "create_new_match": "Create new match", "data": "Data", "data_successfully_deleted": "Data successfully deleted", @@ -297,6 +320,8 @@ "days_ago": "{count} days ago", "delete": "Delete", "delete_all_data": "Delete all data", + "delete_group": "Delete Group", + "edit_group": "Edit Group", "error_creating_group": "Error while creating group, please try again", "error_reading_file": "Error reading file", "export_canceled": "Export canceled", @@ -306,6 +331,7 @@ "game_name": "Game Name", "group": "Group", "group_name": "Group name", + "group_profile": "Group Profile", "groups": "Groups", "home": "Home", "import_canceled": "Import canceled", @@ -319,6 +345,7 @@ "match_in_progress": "Match in progress...", "match_name": "Match name", "matches": "Matches", + "members": "Members", "most_points": "Most Points", "no_data_available": "No data available", "no_groups_created_yet": "No groups created yet", @@ -334,6 +361,7 @@ "none": "None", "none_group": "None", "not_available": "Not available", + "played_matches": "Played Matches", "player_name": "Player name", "players": "Players", "players_count": "{count} Players", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index e78d69b..57dbdd8 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -122,6 +122,12 @@ abstract class AppLocalizations { /// **'Game Tracker'** String get app_name; + /// Label for best player statistic + /// + /// In en, this message translates to: + /// **'Best Player'** + String get best_player; + /// Cancel button text /// /// In en, this message translates to: @@ -170,6 +176,12 @@ abstract class AppLocalizations { /// **'Create new group'** String get create_new_group; + /// Label for creation date + /// + /// In en, this message translates to: + /// **'Created on'** + String get created_on; + /// Button text to create a new match /// /// In en, this message translates to: @@ -218,6 +230,18 @@ abstract class AppLocalizations { /// **'Delete all data'** String get delete_all_data; + /// Button text to delete a group + /// + /// In en, this message translates to: + /// **'Delete Group'** + String get delete_group; + + /// Button text to edit a group + /// + /// In en, this message translates to: + /// **'Edit Group'** + String get edit_group; + /// Error message when group creation fails /// /// In en, this message translates to: @@ -272,6 +296,12 @@ abstract class AppLocalizations { /// **'Group name'** String get group_name; + /// Title for group profile view + /// + /// In en, this message translates to: + /// **'Group Profile'** + String get group_profile; + /// Label for groups /// /// In en, this message translates to: @@ -350,6 +380,12 @@ abstract class AppLocalizations { /// **'Matches'** String get matches; + /// Label for group members + /// + /// In en, this message translates to: + /// **'Members'** + String get members; + /// Title for most points ruleset /// /// In en, this message translates to: @@ -440,6 +476,12 @@ abstract class AppLocalizations { /// **'Not available'** String get not_available; + /// Label for played matches statistic + /// + /// In en, this message translates to: + /// **'Played Matches'** + String get played_matches; + /// Placeholder for player name input /// /// In en, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 8ecc0a7..f78f9f4 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -20,6 +20,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get app_name => 'Game Tracker'; + @override + String get best_player => 'Beste:r Spieler:in'; + @override String get cancel => 'Abbrechen'; @@ -46,6 +49,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get create_new_group => 'Neue Gruppe erstellen'; + @override + String get created_on => 'Erstellt am'; + @override String get create_new_match => 'Neues Spiel erstellen'; @@ -72,6 +78,12 @@ class AppLocalizationsDe extends AppLocalizations { @override String get delete_all_data => 'Alle Daten löschen'; + @override + String get delete_group => 'Gruppe löschen'; + + @override + String get edit_group => 'Gruppe bearbeiten'; + @override String get error_creating_group => 'Fehler beim Erstellen der Gruppe, bitte erneut versuchen'; @@ -100,6 +112,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get group_name => 'Gruppenname'; + @override + String get group_profile => 'Gruppenprofil'; + @override String get groups => 'Gruppen'; @@ -139,6 +154,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get matches => 'Spiele'; + @override + String get members => 'Mitglieder'; + @override String get most_points => 'Höchste Punkte'; @@ -185,6 +203,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get not_available => 'Nicht verfügbar'; + @override + String get played_matches => 'Gespielte Spiele'; + @override String get player_name => 'Spieler:innenname'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index b911676..32512c7 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -20,6 +20,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get app_name => 'Game Tracker'; + @override + String get best_player => 'Best Player'; + @override String get cancel => 'Cancel'; @@ -46,6 +49,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get create_new_group => 'Create new group'; + @override + String get created_on => 'Created on'; + @override String get create_new_match => 'Create new match'; @@ -72,6 +78,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get delete_all_data => 'Delete all data'; + @override + String get delete_group => 'Delete Group'; + + @override + String get edit_group => 'Edit Group'; + @override String get error_creating_group => 'Error while creating group, please try again'; @@ -100,6 +112,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get group_name => 'Group name'; + @override + String get group_profile => 'Group Profile'; + @override String get groups => 'Groups'; @@ -139,6 +154,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get matches => 'Matches'; + @override + String get members => 'Members'; + @override String get most_points => 'Most Points'; @@ -185,6 +203,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get not_available => 'Not available'; + @override + String get played_matches => 'Played Matches'; + @override String get player_name => 'Player name'; diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart new file mode 100644 index 0000000..90151c1 --- /dev/null +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -0,0 +1,271 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/adaptive_page_route.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart'; +import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; +import 'package:game_tracker/presentation/widgets/buttons/animated_dialog_button.dart'; +import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; +import 'package:game_tracker/presentation/widgets/custom_alert_dialog.dart'; +import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; +import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +class GroupProfileView extends StatefulWidget { + /// A view that displays the profile of a group + /// - [group]: The group to display + const GroupProfileView({ + super.key, + required this.group, + required this.callback, + }); + + /// The group to display + final Group group; + + final VoidCallback callback; + + @override + State createState() => _GroupProfileViewState(); +} + +class _GroupProfileViewState extends State { + late final AppDatabase db; + bool isLoading = true; + + /// Total matches played in this group + int totalMatches = 0; + + String bestPlayer = ''; + + @override + void initState() { + super.initState(); + db = Provider.of(context, listen: false); + _loadStatistics(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + + return Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar( + title: Text(loc.group_profile), + actions: [ + IconButton( + icon: const Icon(Icons.delete), + onPressed: () async { + showDialog( + context: context, + builder: (context) => CustomAlertDialog( + title: '${loc.delete_group}?', + content: loc.this_cannot_be_undone, + actions: [ + AnimatedDialogButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text( + loc.cancel, + style: const TextStyle(color: CustomTheme.textColor), + ), + ), + AnimatedDialogButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text( + loc.delete, + style: TextStyle(color: CustomTheme.secondaryColor), + ), + ), + ], + ), + ).then((confirmed) async { + if (confirmed! && context.mounted) { + await db.groupDao.deleteGroup(groupId: widget.group.id); + if (!context.mounted) return; + Navigator.pop(context); + widget.callback.call(); + } + }); + }, + ), + ], + ), + body: SafeArea( + child: Stack( + alignment: Alignment.center, + children: [ + ListView( + padding: const EdgeInsets.only( + left: 12, + right: 12, + top: 20, + bottom: 100, + ), + children: [ + Center( + child: Container( + width: 55, + height: 55, + decoration: BoxDecoration( + color: CustomTheme.primaryColor.withGreen(40), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + Icons.group, + size: 38, + color: CustomTheme.secondaryColor, + ), + ), + ), + const SizedBox(height: 10), + Text( + widget.group.name, + style: const TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + color: CustomTheme.textColor, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 5), + Text( + "${loc.created_on} ${DateFormat('dd.MM.yyyy').format(widget.group.createdAt)}", + style: const TextStyle( + fontSize: 12, + color: CustomTheme.textColor, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 20), + InfoTile( + title: loc.members, + icon: Icons.people, + content: Wrap( + spacing: 8, + runSpacing: 8, + children: widget.group.members.map((member) { + return TextIconTile( + text: member.name, + iconEnabled: false, + ); + }).toList(), + ), + ), + const SizedBox(height: 15), + InfoTile( + title: loc.statistics, + icon: Icons.bar_chart, + content: AppSkeleton( + enabled: isLoading, + child: Column( + children: [ + _buildStatRow( + loc.members, + widget.group.members.length.toString(), + ), + _buildStatRow( + loc.played_matches, + totalMatches.toString(), + ), + _buildStatRow(loc.best_player, bestPlayer), + ], + ), + ), + ), + ], + ), + Positioned( + bottom: MediaQuery.paddingOf(context).bottom, + child: MainMenuButton( + text: loc.edit_group, + icon: Icons.edit, + onPressed: () async { + await Navigator.push( + context, + adaptivePageRoute( + builder: (context) { + return const CreateGroupView(); + }, + ), + ); + }, + ), + ), + ], + ), + ), + ); + } + + /// Builds a single statistic row with a label and value + Widget _buildStatRow(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Text( + label, + style: const TextStyle( + fontSize: 16, + color: CustomTheme.textColor, + ), + ), + ], + ), + Text( + value, + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + ], + ), + ); + } + + /// Loads statistics for this group + Future _loadStatistics() async { + final matches = await db.matchDao.getAllMatches(); + final groupMatches = matches + .where((match) => match.group?.id == widget.group.id) + .toList(); + + setState(() { + totalMatches = groupMatches.length; + bestPlayer = _getBestPlayer(groupMatches); + isLoading = false; + }); + } + + /// Determines the best player in the group based on match wins + String _getBestPlayer(List matches) { + final bestPlayerCounts = {}; + + // Count wins for each player + for (var match in matches) { + if (match.winner != null) { + bestPlayerCounts.update( + match.winner!, + (value) => value + 1, + ifAbsent: () => 1, + ); + } + } + + // Sort players by win count + final sortedPlayers = bestPlayerCounts.entries.toList() + ..sort((a, b) => b.value.compareTo(a.value)); + + // Get the best player + bestPlayer = sortedPlayers.isNotEmpty ? sortedPlayers.first.key.name : '-'; + + return bestPlayer; + } +} diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart index 10ae148..0083f26 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -7,6 +7,7 @@ import 'package:game_tracker/data/dto/group.dart'; import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/group_view/group_profile_view.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; @@ -74,7 +75,22 @@ class _GroupsViewState extends State { height: MediaQuery.paddingOf(context).bottom - 20, ); } - return GroupTile(group: groups[index]); + return GroupTile( + group: groups[index], + onTap: () async { + await Navigator.push( + context, + adaptivePageRoute( + builder: (context) { + return GroupProfileView( + group: groups[index], + callback: loadGroups, + ); + }, + ), + ); + }, + ); }, ), ), @@ -105,6 +121,9 @@ class _GroupsViewState extends State { } void loadGroups() { + setState(() { + isLoading = true; + }); Future.wait([ db.groupDao.getAllGroups(), Future.delayed(Constants.minimumSkeletonDuration), diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart index a06c6b5..c035a04 100644 --- a/lib/presentation/widgets/tiles/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -3,11 +3,17 @@ import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/dto/group.dart'; import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; -class GroupTile extends StatelessWidget { +class GroupTile extends StatefulWidget { /// A tile widget that displays information about a group, including its name and members. /// - [group]: The group data to be displayed. /// - [isHighlighted]: Whether the tile should be highlighted. - const GroupTile({super.key, required this.group, this.isHighlighted = false}); + /// - [onTap]: Callback function to be executed when the tile is tapped. + const GroupTile({ + super.key, + required this.group, + this.isHighlighted = false, + this.onTap, + }); /// The group data to be displayed. final Group group; @@ -15,61 +21,72 @@ class GroupTile extends StatelessWidget { /// Whether the tile should be highlighted. final bool isHighlighted; + /// Callback function to be executed when the tile is tapped. + final VoidCallback? onTap; + + @override + State createState() => _GroupTileState(); +} + +class _GroupTileState extends State { @override Widget build(BuildContext context) { - return AnimatedContainer( - margin: CustomTheme.standardMargin, - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), - decoration: isHighlighted - ? CustomTheme.highlightedBoxDecoration - : CustomTheme.standardBoxDecoration, - duration: const Duration(milliseconds: 150), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Text( - group.name, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - ), - Row( - children: [ - Text( - '${group.members.length}', + return GestureDetector( + onTap: widget.onTap, + child: AnimatedContainer( + margin: CustomTheme.standardMargin, + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + decoration: widget.isHighlighted + ? CustomTheme.highlightedBoxDecoration + : CustomTheme.standardBoxDecoration, + duration: const Duration(milliseconds: 150), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Text( + widget.group.name, + overflow: TextOverflow.ellipsis, style: const TextStyle( - fontWeight: FontWeight.w900, + fontWeight: FontWeight.bold, fontSize: 18, ), ), - const SizedBox(width: 3), - const Icon(Icons.group, size: 22), - ], - ), - ], - ), - const SizedBox(height: 5), - Wrap( - alignment: WrapAlignment.start, - crossAxisAlignment: WrapCrossAlignment.start, - spacing: 12.0, - runSpacing: 8.0, - children: [ - for (var member in [ - ...group.members, - ]..sort((a, b) => a.name.compareTo(b.name))) - TextIconTile(text: member.name, iconEnabled: false), - ], - ), - const SizedBox(height: 2.5), - ], + ), + Row( + children: [ + Text( + '${widget.group.members.length}', + style: const TextStyle( + fontWeight: FontWeight.w900, + fontSize: 18, + ), + ), + const SizedBox(width: 3), + const Icon(Icons.group, size: 22), + ], + ), + ], + ), + const SizedBox(height: 5), + Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 12.0, + runSpacing: 8.0, + children: [ + for (var member in [ + ...widget.group.members, + ]..sort((a, b) => a.name.compareTo(b.name))) + TextIconTile(text: member.name, iconEnabled: false), + ], + ), + const SizedBox(height: 2.5), + ], + ), ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index e9fd894..3f5a5f8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.7+212 +version: 0.0.7+221 environment: sdk: ^3.8.1 From 6a0896d818f2ed5caf9883c793787349e81f3bb6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 00:52:09 +0100 Subject: [PATCH 30/64] Implemented ColoredIconContainer --- .../group_view/group_profile_view.dart | 33 +++++------ .../licenses/license_detail_view.dart | 19 ++----- lib/presentation/widgets/colored_icon.dart | 57 +++++++++++++++++++ .../widgets/tiles/license_tile.dart | 17 ++---- .../widgets/tiles/settings_list_tile.dart | 17 ++---- pubspec.yaml | 2 +- 6 files changed, 89 insertions(+), 56 deletions(-) create mode 100644 lib/presentation/widgets/colored_icon.dart diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index 90151c1..2555020 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -1,15 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/adaptive_page_route.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/db/database.dart'; import 'package:game_tracker/data/dto/group.dart'; import 'package:game_tracker/data/dto/match.dart'; import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; import 'package:game_tracker/presentation/widgets/buttons/animated_dialog_button.dart'; import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon.dart'; import 'package:game_tracker/presentation/widgets/custom_alert_dialog.dart'; import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; @@ -108,19 +107,11 @@ class _GroupProfileViewState extends State { bottom: 100, ), children: [ - Center( - child: Container( - width: 55, - height: 55, - decoration: BoxDecoration( - color: CustomTheme.primaryColor.withGreen(40), - borderRadius: BorderRadius.circular(10), - ), - child: Icon( - Icons.group, - size: 38, - color: CustomTheme.secondaryColor, - ), + const Center( + child: ColoredIconContainer( + icon: Icons.group, + containerSize: 55, + iconSize: 38, ), ), const SizedBox(height: 10), @@ -185,15 +176,19 @@ class _GroupProfileViewState extends State { child: MainMenuButton( text: loc.edit_group, icon: Icons.edit, - onPressed: () async { + onPressed: () { + // TODO: Uncomment when GroupDetailView is implemented + /* await Navigator.push( context, adaptivePageRoute( builder: (context) { - return const CreateGroupView(); + + return const GroupDetailView(); }, ), - ); + );*/ + print('Edit Group pressed'); }, ), ), @@ -204,6 +199,8 @@ class _GroupProfileViewState extends State { } /// Builds a single statistic row with a label and value + /// - [label]: The label of the statistic + /// - [value]: The value of the statistic Widget _buildStatRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), diff --git a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart index e46fc31..5c5e709 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon.dart'; import 'package:url_launcher/url_launcher.dart'; class LicenseDetailView extends StatelessWidget { @@ -29,19 +30,11 @@ class LicenseDetailView extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - margin: const EdgeInsetsGeometry.only(right: 15), - width: 60, - height: 60, - decoration: BoxDecoration( - color: CustomTheme.primaryColor.withAlpha(40), - borderRadius: BorderRadius.circular(10), - ), - child: Icon( - Icons.description, - color: CustomTheme.primaryColor, - size: 30, - ), + const ColoredIconContainer( + icon: Icons.description, + margin: EdgeInsetsGeometry.only(right: 15), + containerSize: 60, + iconSize: 30, ), Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/presentation/widgets/colored_icon.dart b/lib/presentation/widgets/colored_icon.dart new file mode 100644 index 0000000..be51cd2 --- /dev/null +++ b/lib/presentation/widgets/colored_icon.dart @@ -0,0 +1,57 @@ +import 'package:flutter/cupertino.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class ColoredIconContainer extends StatelessWidget { + /// A customizable container widget that displays an icon with a colored background. + /// - [icon]: The icon to be displayed inside the container. + /// - [containerSize]: The size of the container (width and height). + /// - [iconSize]: The size of the icon inside the container. + /// - [margin]: Optional margin around the container. + /// - [padding]: Optional padding inside the container. + const ColoredIconContainer({ + super.key, + required this.icon, + this.containerSize = 44, + this.iconSize = 28, + this.margin, + this.padding, + }); + + /// The icon to be displayed inside the container. + final IconData icon; + + /// The size of the container (width and height). + final double containerSize; + + /// The size of the icon inside the container. + final double iconSize; + + /// Optional margin around the container. + final EdgeInsetsGeometry? margin; + + /// Optional padding inside the container. + final EdgeInsetsGeometry? padding; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Container( + width: containerSize, + height: containerSize, + margin: margin, + padding: padding, + decoration: BoxDecoration( + color: CustomTheme.primaryColor.withAlpha(40), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + icon, + size: iconSize, + color: CustomTheme.primaryColor.withGreen(40), + ), + ), + ], + ); + } +} diff --git a/lib/presentation/widgets/tiles/license_tile.dart b/lib/presentation/widgets/tiles/license_tile.dart index 14ee2bf..3523adb 100644 --- a/lib/presentation/widgets/tiles/license_tile.dart +++ b/lib/presentation/widgets/tiles/license_tile.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart'; import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon.dart'; class LicenseTile extends StatelessWidget { /// A tile widget that displays information about a software package license. @@ -29,18 +30,10 @@ class LicenseTile extends StatelessWidget { ), child: Row( children: [ - Container( - width: 50, - height: 50, - decoration: BoxDecoration( - color: CustomTheme.primaryColor.withAlpha(40), - borderRadius: BorderRadius.circular(10), - ), - child: Icon( - Icons.description, - color: CustomTheme.primaryColor, - size: 32, - ), + const ColoredIconContainer( + icon: Icons.description, + containerSize: 50, + iconSize: 32, ), const SizedBox(width: 16), Expanded( diff --git a/lib/presentation/widgets/tiles/settings_list_tile.dart b/lib/presentation/widgets/tiles/settings_list_tile.dart index 53fb041..50f27d2 100644 --- a/lib/presentation/widgets/tiles/settings_list_tile.dart +++ b/lib/presentation/widgets/tiles/settings_list_tile.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon.dart'; class SettingsListTile extends StatelessWidget { /// A customizable settings list tile widget that displays an icon, title, and an optional suffix widget. @@ -46,18 +47,10 @@ class SettingsListTile extends StatelessWidget { Row( mainAxisSize: MainAxisSize.min, children: [ - Container( - width: 44, - height: 44, - decoration: BoxDecoration( - color: CustomTheme.primaryColor.withAlpha(40), - borderRadius: BorderRadius.circular(10), - ), - child: Icon( - icon, - size: 28, - color: CustomTheme.primaryColor.withGreen(40), - ), + ColoredIconContainer( + icon: icon, + containerSize: 44, + iconSize: 28, ), const SizedBox(width: 16), Text(title, style: const TextStyle(fontSize: 18)), diff --git a/pubspec.yaml b/pubspec.yaml index 3f5a5f8..e8de5ed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.7+221 +version: 0.0.7+227 environment: sdk: ^3.8.1 From fc6eb2b9cf3ea3490bbac698b5d4e4b7840d7034 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 00:52:13 +0100 Subject: [PATCH 31/64] Added comments --- lib/core/custom_theme.dart | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 12ac4a8..2c18073 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -5,14 +5,32 @@ class CustomTheme { CustomTheme._(); // Private constructor to prevent instantiation // ==================== Colors ==================== + + /// Primary color of the app theme static Color primaryColor = const Color(0xFF7505E4); + + /// Secondary color of the app theme static Color secondaryColor = const Color(0xFFAFA2FF); + + /// Background color of the app theme static Color backgroundColor = const Color(0xFF0B0B0B); + + /// Default color for boxes and containers static Color boxColor = const Color(0xFF101010); - static Color onBoxColor = const Color(0xFF181818); + + /// Default border color for boxes and containers static Color boxBorder = const Color(0xFF272727); + + /// Color for boxes and containers displayed on boxes + static Color onBoxColor = const Color(0xFF181818); + + /// Text color used throughout the app static const Color textColor = Colors.white; + + /// Selected color for the [NavbarItem] static Color navBarItemSelectedColor = primaryColor.withGreen(100); + + /// Unselected color for the [NavbarItem] static Color navBarItemUnselectedColor = Colors.grey.shade400; // ==================== Border Radius ==================== From abb0fcbbd62b220665b6321b6ca43b2ed5b06cca Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 00:57:28 +0100 Subject: [PATCH 32/64] Updated file name --- .../views/main_menu/group_view/group_profile_view.dart | 2 +- .../main_menu/settings_view/licenses/license_detail_view.dart | 2 +- .../widgets/{colored_icon.dart => colored_icon_container.dart} | 0 lib/presentation/widgets/tiles/license_tile.dart | 2 +- lib/presentation/widgets/tiles/settings_list_tile.dart | 2 +- pubspec.yaml | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename lib/presentation/widgets/{colored_icon.dart => colored_icon_container.dart} (100%) diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index 2555020..6a92c22 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -8,7 +8,7 @@ import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; import 'package:game_tracker/presentation/widgets/buttons/animated_dialog_button.dart'; import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; import 'package:game_tracker/presentation/widgets/custom_alert_dialog.dart'; import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; diff --git a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart index 5c5e709..54ff34e 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; import 'package:url_launcher/url_launcher.dart'; class LicenseDetailView extends StatelessWidget { diff --git a/lib/presentation/widgets/colored_icon.dart b/lib/presentation/widgets/colored_icon_container.dart similarity index 100% rename from lib/presentation/widgets/colored_icon.dart rename to lib/presentation/widgets/colored_icon_container.dart diff --git a/lib/presentation/widgets/tiles/license_tile.dart b/lib/presentation/widgets/tiles/license_tile.dart index 3523adb..33e5a45 100644 --- a/lib/presentation/widgets/tiles/license_tile.dart +++ b/lib/presentation/widgets/tiles/license_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart'; import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; class LicenseTile extends StatelessWidget { /// A tile widget that displays information about a software package license. diff --git a/lib/presentation/widgets/tiles/settings_list_tile.dart b/lib/presentation/widgets/tiles/settings_list_tile.dart index 50f27d2..d4bc6dc 100644 --- a/lib/presentation/widgets/tiles/settings_list_tile.dart +++ b/lib/presentation/widgets/tiles/settings_list_tile.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon.dart'; +import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; class SettingsListTile extends StatelessWidget { /// A customizable settings list tile widget that displays an icon, title, and an optional suffix widget. diff --git a/pubspec.yaml b/pubspec.yaml index e8de5ed..f64f521 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.7+227 +version: 0.0.8+227 environment: sdk: ^3.8.1 From 3addaa0f9d5bf227a1391135462d0332ac46391e Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sat, 17 Jan 2026 14:22:45 +0100 Subject: [PATCH 33/64] Disable resizing when using keyboard --- .../views/main_menu/group_view/create_group_view.dart | 1 + .../main_menu/match_view/create_match/choose_game_view.dart | 1 + .../main_menu/match_view/create_match/choose_group_view.dart | 1 + .../main_menu/match_view/create_match/create_match_view.dart | 1 + pubspec.yaml | 2 +- 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/group_view/create_group_view.dart b/lib/presentation/views/main_menu/group_view/create_group_view.dart index 719b47d..b342448 100644 --- a/lib/presentation/views/main_menu/group_view/create_group_view.dart +++ b/lib/presentation/views/main_menu/group_view/create_group_view.dart @@ -47,6 +47,7 @@ class _CreateGroupViewState extends State { final loc = AppLocalizations.of(context); return ScaffoldMessenger( child: Scaffold( + resizeToAvoidBottomInset: false, backgroundColor: CustomTheme.backgroundColor, appBar: AppBar(title: Text(loc.create_new_group)), body: SafeArea( diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart index 32868e4..3ff6e79 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart @@ -43,6 +43,7 @@ class _ChooseGameViewState extends State { final loc = AppLocalizations.of(context); return Scaffold( backgroundColor: CustomTheme.backgroundColor, + resizeToAvoidBottomInset: false, appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back_ios), diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart index 00a0276..592d765 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart @@ -43,6 +43,7 @@ class _ChooseGroupViewState extends State { final loc = AppLocalizations.of(context); return Scaffold( backgroundColor: CustomTheme.backgroundColor, + resizeToAvoidBottomInset: false, appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back_ios), diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index 694a82d..5509911 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -125,6 +125,7 @@ class _CreateMatchViewState extends State { final loc = AppLocalizations.of(context); return ScaffoldMessenger( child: Scaffold( + resizeToAvoidBottomInset: false, backgroundColor: CustomTheme.backgroundColor, appBar: AppBar(title: Text(loc.create_new_match)), body: SafeArea( diff --git a/pubspec.yaml b/pubspec.yaml index e9fd894..4d5b4bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.7+212 +version: 0.0.8+213 environment: sdk: ^3.8.1 From 9f44f02a35ab5c3376bfbadb24373523c4020ad8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 14:32:25 +0100 Subject: [PATCH 34/64] Changed length to 32 --- 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 646a14e..c1bc0fe 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -12,11 +12,11 @@ class Constants { static const int MAX_GROUP_NAME_LENGTH = 32; /// Maximum length for match names - static const int MAX_MATCH_NAME_LENGTH = 256; + static const int MAX_MATCH_NAME_LENGTH = 32; /// Maximum length for game names - static const int MAX_GAME_NAME_LENGTH = 256; + static const int MAX_GAME_NAME_LENGTH = 32; /// Maximum length for team names - static const int MAX_TEAM_NAME_LENGTH = 256; + static const int MAX_TEAM_NAME_LENGTH = 32; } From 0e747710abac955a5c4c17c26fcf0191d5f9ef74 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 14:33:24 +0100 Subject: [PATCH 35/64] Edited comment --- lib/presentation/widgets/text_input/text_input_field.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index 37f9ce4..b88eb21 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -6,7 +6,7 @@ class TextInputField extends StatelessWidget { /// - [controller]: The controller for the text input field. /// - [onChanged]: The callback invoked when the text in the field changes. /// - [hintText]: The hint text displayed in the text input field when it is empty - /// - [maxLength]: The maximum length of the input text. + /// - [maxLength]: Optional parameter for maximum length of the input text. const TextInputField({ super.key, required this.controller, @@ -24,7 +24,7 @@ class TextInputField extends StatelessWidget { /// The hint text displayed in the text input field when it is empty. final String hintText; - /// The maximum length of the input text. + /// Optional parameter for maximum length of the input text. final int? maxLength; @override From db41f40a5233e46feaeac591fbfd4f65d8967195 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 14:33:24 +0100 Subject: [PATCH 36/64] Edited comment --- lib/presentation/widgets/text_input/text_input_field.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index 37f9ce4..8f7a597 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -4,9 +4,9 @@ import 'package:game_tracker/core/custom_theme.dart'; class TextInputField extends StatelessWidget { /// A custom text input field widget that encapsulates a [TextField] with specific styling. /// - [controller]: The controller for the text input field. - /// - [onChanged]: The callback invoked when the text in the field changes. + /// - [onChanged]: Optional callback invoked when the text in the field changes. /// - [hintText]: The hint text displayed in the text input field when it is empty - /// - [maxLength]: The maximum length of the input text. + /// - [maxLength]: Optional parameter for maximum length of the input text. const TextInputField({ super.key, required this.controller, @@ -18,13 +18,13 @@ class TextInputField extends StatelessWidget { /// The controller for the text input field. final TextEditingController controller; - /// The callback invoked when the text in the field changes. + /// Optional callback invoked when the text in the field changes. final ValueChanged? onChanged; /// The hint text displayed in the text input field when it is empty. final String hintText; - /// The maximum length of the input text. + /// Optional parameter for maximum length of the input text. final int? maxLength; @override From ff47ef38c1d32f9f322426b8c77c854f6b50f7ea Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 14:51:12 +0100 Subject: [PATCH 37/64] Changed alignment --- .../views/main_menu/group_view/group_profile_view.dart | 5 ++++- lib/presentation/widgets/tiles/info_tile.dart | 6 +++++- pubspec.yaml | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index 6a92c22..1b19b6a 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -137,8 +137,11 @@ class _GroupProfileViewState extends State { InfoTile( title: loc.members, icon: Icons.people, + horizontalAlignment: CrossAxisAlignment.start, content: Wrap( - spacing: 8, + runAlignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 16, runSpacing: 8, children: widget.group.members.map((member) { return TextIconTile( diff --git a/lib/presentation/widgets/tiles/info_tile.dart b/lib/presentation/widgets/tiles/info_tile.dart index 280c7d7..78d7f28 100644 --- a/lib/presentation/widgets/tiles/info_tile.dart +++ b/lib/presentation/widgets/tiles/info_tile.dart @@ -17,6 +17,7 @@ class InfoTile extends StatefulWidget { this.padding, this.height, this.width, + this.horizontalAlignment = CrossAxisAlignment.center, }); /// The title text displayed on the tile. @@ -37,6 +38,9 @@ class InfoTile extends StatefulWidget { /// Optional width for the tile. final double? width; + /// The main axis alignment for the content. + final CrossAxisAlignment horizontalAlignment; + @override State createState() => _InfoTileState(); } @@ -51,7 +55,7 @@ class _InfoTileState extends State { decoration: CustomTheme.standardBoxDecoration, child: Column( mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: widget.horizontalAlignment, children: [ Row( children: [ diff --git a/pubspec.yaml b/pubspec.yaml index f64f521..1ea28cc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.8+227 +version: 0.0.8+230 environment: sdk: ^3.8.1 From 514e0f8064b06852e0feb3fc4c7a4fb4bbc0fe68 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 14:54:06 +0100 Subject: [PATCH 38/64] Changed date format --- .../views/main_menu/group_view/group_profile_view.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index 1b19b6a..c739973 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -126,7 +126,7 @@ class _GroupProfileViewState extends State { ), const SizedBox(height: 5), Text( - "${loc.created_on} ${DateFormat('dd.MM.yyyy').format(widget.group.createdAt)}", + "${loc.created_on} ${DateFormat('MMM d, yyyy').format(widget.group.createdAt)}", style: const TextStyle( fontSize: 12, color: CustomTheme.textColor, diff --git a/pubspec.yaml b/pubspec.yaml index 1ea28cc..8b52ca1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.8+230 +version: 0.0.8+231 environment: sdk: ^3.8.1 From ddd0a5d8bdb1755ceb84292b7f3093b4193e3865 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 15:17:33 +0100 Subject: [PATCH 39/64] Updated dateformat to localize --- .../views/main_menu/group_view/group_profile_view.dart | 2 +- lib/presentation/widgets/tiles/match_tile.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index c739973..072bbd6 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -126,7 +126,7 @@ class _GroupProfileViewState extends State { ), const SizedBox(height: 5), Text( - "${loc.created_on} ${DateFormat('MMM d, yyyy').format(widget.group.createdAt)}", + '${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(widget.group.createdAt)}', style: const TextStyle( fontSize: 12, color: CustomTheme.textColor, diff --git a/lib/presentation/widgets/tiles/match_tile.dart b/lib/presentation/widgets/tiles/match_tile.dart index 11cdea0..e1365c1 100644 --- a/lib/presentation/widgets/tiles/match_tile.dart +++ b/lib/presentation/widgets/tiles/match_tile.dart @@ -230,7 +230,7 @@ class _MatchTileState extends State { } else if (difference.inDays < 7) { return loc.days_ago(difference.inDays); } else { - return DateFormat('MMM d, yyyy').format(dateTime); + return '${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(dateTime)}'; } } From 8a38b9c3ea861933cc34e3e7d07776028d58cf72 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 15:17:33 +0100 Subject: [PATCH 40/64] Updated dateformat to localize --- .../views/main_menu/group_view/group_profile_view.dart | 2 +- lib/presentation/widgets/tiles/match_tile.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index c739973..072bbd6 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -126,7 +126,7 @@ class _GroupProfileViewState extends State { ), const SizedBox(height: 5), Text( - "${loc.created_on} ${DateFormat('MMM d, yyyy').format(widget.group.createdAt)}", + '${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(widget.group.createdAt)}', style: const TextStyle( fontSize: 12, color: CustomTheme.textColor, diff --git a/lib/presentation/widgets/tiles/match_tile.dart b/lib/presentation/widgets/tiles/match_tile.dart index 11cdea0..e1365c1 100644 --- a/lib/presentation/widgets/tiles/match_tile.dart +++ b/lib/presentation/widgets/tiles/match_tile.dart @@ -230,7 +230,7 @@ class _MatchTileState extends State { } else if (difference.inDays < 7) { return loc.days_ago(difference.inDays); } else { - return DateFormat('MMM d, yyyy').format(dateTime); + return '${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(dateTime)}'; } } diff --git a/pubspec.yaml b/pubspec.yaml index 6f6fd9b..a8159f8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.8+232 +version: 0.0.8+233 environment: sdk: ^3.8.1 From 92c62000af89d92f87d328c6d250115e480b1165 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sat, 17 Jan 2026 21:12:17 +0100 Subject: [PATCH 41/64] remove margin from title_description_list_tile.dart --- lib/presentation/widgets/tiles/title_description_list_tile.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/widgets/tiles/title_description_list_tile.dart b/lib/presentation/widgets/tiles/title_description_list_tile.dart index 3141cbe..a963d16 100644 --- a/lib/presentation/widgets/tiles/title_description_list_tile.dart +++ b/lib/presentation/widgets/tiles/title_description_list_tile.dart @@ -73,7 +73,6 @@ class TitleDescriptionListTile extends StatelessWidget { const Spacer(), Container( constraints: const BoxConstraints(maxWidth: 115), - margin: const EdgeInsets.only(top: 4), padding: const EdgeInsets.symmetric( vertical: 2, horizontal: 6, From 5f987806d67f4b0ee4c268f2b36529942371fc01 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sat, 17 Jan 2026 21:12:43 +0100 Subject: [PATCH 42/64] remove ruleset --- .../create_match/choose_ruleset_view.dart | 99 ------------------- .../create_match/create_match_view.dart | 49 +-------- 2 files changed, 2 insertions(+), 146 deletions(-) delete mode 100644 lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart deleted file mode 100644 index 3b1f37b..0000000 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart'; - -class ChooseRulesetView extends StatefulWidget { - /// A view that allows the user to choose a ruleset from a list of available rulesets - /// - [rulesets]: A list of tuples containing the ruleset and its description - /// - [initialRulesetIndex]: The index of the initially selected ruleset - const ChooseRulesetView({ - super.key, - required this.rulesets, - required this.initialRulesetIndex, - }); - - /// A list of tuples containing the ruleset and its description - final List<(Ruleset, String)> rulesets; - - /// The index of the initially selected ruleset - final int initialRulesetIndex; - - @override - State createState() => _ChooseRulesetViewState(); -} - -class _ChooseRulesetViewState extends State { - /// Currently selected ruleset index - late int selectedRulesetIndex; - - @override - void initState() { - selectedRulesetIndex = widget.initialRulesetIndex; - super.initState(); - } - - @override - Widget build(BuildContext context) { - final loc = AppLocalizations.of(context); - return DefaultTabController( - length: 2, - initialIndex: 0, - child: Scaffold( - backgroundColor: CustomTheme.backgroundColor, - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios), - onPressed: () { - Navigator.of(context).pop( - selectedRulesetIndex == -1 - ? null - : widget.rulesets[selectedRulesetIndex].$1, - ); - }, - ), - title: Text(loc.choose_ruleset), - ), - body: PopScope( - // This fixes that the Android Back Gesture didn't return the - // selectedRulesetIndex and therefore the selected Ruleset wasn't saved - canPop: false, - onPopInvokedWithResult: (bool didPop, Object? result) { - if (didPop) { - return; - } - Navigator.of(context).pop( - selectedRulesetIndex == -1 - ? null - : widget.rulesets[selectedRulesetIndex].$1, - ); - }, - child: ListView.builder( - padding: const EdgeInsets.only(bottom: 85), - itemCount: widget.rulesets.length, - itemBuilder: (BuildContext context, int index) { - return TitleDescriptionListTile( - onPressed: () async { - setState(() { - if (selectedRulesetIndex == index) { - selectedRulesetIndex = -1; - } else { - selectedRulesetIndex = index; - } - }); - }, - title: translateRulesetToString( - widget.rulesets[index].$1, - context, - ), - description: widget.rulesets[index].$2, - isHighlighted: selectedRulesetIndex == index, - ); - }, - ), - ), - ), - ); - } -} diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index ea9cfd5..db46159 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -10,7 +10,6 @@ import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_game_view.dart'; import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_group_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart'; import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; import 'package:game_tracker/presentation/widgets/player_selection.dart'; @@ -58,13 +57,6 @@ class _CreateMatchViewState extends State { /// the [ChooseGroupView] String selectedGroupId = ''; - /// The currently selected ruleset - Ruleset? selectedRuleset; - - /// The index of the currently selected ruleset in [rulesets] to mark it in - /// the [ChooseRulesetView] - int selectedRulesetIndex = -1; - /// The index of the currently selected game in [games] to mark it in /// the [ChooseGameView] int selectedGameIndex = -1; @@ -72,9 +64,6 @@ class _CreateMatchViewState extends State { /// The currently selected players List? selectedPlayers; - /// List of available rulesets with their localized string representations - late final List<(Ruleset, String)> _rulesets; - @override void initState() { super.initState(); @@ -107,20 +96,14 @@ class _CreateMatchViewState extends State { super.didChangeDependencies(); final loc = AppLocalizations.of(context); hintText ??= loc.match_name; - _rulesets = [ - (Ruleset.singleWinner, loc.ruleset_single_winner), - (Ruleset.singleLoser, loc.ruleset_single_loser), - (Ruleset.mostPoints, loc.ruleset_most_points), - (Ruleset.leastPoints, loc.ruleset_least_points), - ]; } - // TODO: Replace when games are implemented List<(String, String, Ruleset)> games = [ ('Example Game 1', 'This is a description', Ruleset.leastPoints), ('Example Game 2', '', Ruleset.singleWinner), ]; + @override Widget build(BuildContext context) { final loc = AppLocalizations.of(context); @@ -157,39 +140,12 @@ class _CreateMatchViewState extends State { setState(() { if (selectedGameIndex != -1) { hintText = games[selectedGameIndex].$1; - selectedRuleset = games[selectedGameIndex].$3; - selectedRulesetIndex = _rulesets.indexWhere( - (r) => r.$1 == selectedRuleset, - ); } else { hintText = loc.match_name; - selectedRuleset = null; } }); }, ), - ChooseTile( - title: loc.ruleset, - trailingText: selectedRuleset == null - ? loc.none - : translateRulesetToString(selectedRuleset!, context), - onPressed: () async { - selectedRuleset = await Navigator.of(context).push( - adaptivePageRoute( - builder: (context) => ChooseRulesetView( - rulesets: _rulesets, - initialRulesetIndex: selectedRulesetIndex, - ), - ), - ); - if (!mounted) return; - selectedRulesetIndex = _rulesets.indexWhere( - (r) => r.$1 == selectedRuleset, - ); - selectedGameIndex = -1; - setState(() {}); - }, - ), ChooseTile( title: loc.group, trailingText: selectedGroup == null @@ -274,7 +230,6 @@ class _CreateMatchViewState extends State { /// - Either a group is selected OR at least 2 players are selected bool _enableCreateGameButton() { return (selectedGroup != null || - (selectedPlayers != null && selectedPlayers!.length > 1)) && - selectedRuleset != null; + (selectedPlayers != null && selectedPlayers!.length > 1)); } } From 5c9f44e947f0aed187bf7d78ea00b7b70236f777 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sat, 17 Jan 2026 21:12:53 +0100 Subject: [PATCH 43/64] bump build nr --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9f957c2..c217de3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.7+213 +version: 0.0.7+215 environment: sdk: ^3.8.1 From f5924c475834bd138a109f7e2bb5691d8d3c2cdb Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sat, 17 Jan 2026 21:27:22 +0100 Subject: [PATCH 44/64] adjusted spacing & changed runAlignment to alignment --- .../views/main_menu/group_view/group_profile_view.dart | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index 072bbd6..e366834 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -139,9 +139,9 @@ class _GroupProfileViewState extends State { icon: Icons.people, horizontalAlignment: CrossAxisAlignment.start, content: Wrap( - runAlignment: WrapAlignment.start, + alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.start, - spacing: 16, + spacing: 12, runSpacing: 8, children: widget.group.members.map((member) { return TextIconTile( diff --git a/pubspec.yaml b/pubspec.yaml index a8159f8..432675a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.8+233 +version: 0.0.8+234 environment: sdk: ^3.8.1 From ed2d672dee40144fe4b50c810005d14cade61a6b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 22:40:56 +0100 Subject: [PATCH 45/64] Implemented maxLength attribute --- lib/presentation/widgets/player_selection.dart | 1 + .../widgets/text_input/custom_search_bar.dart | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index 587c8af..58b62ec 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -84,6 +84,7 @@ class _PlayerSelectionState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ CustomSearchBar( + maxLength: Constants.MAX_PLAYER_NAME_LENGTH, controller: _searchBarController, constraints: const BoxConstraints(maxHeight: 45, minHeight: 45), hintText: loc.search_for_players, diff --git a/lib/presentation/widgets/text_input/custom_search_bar.dart b/lib/presentation/widgets/text_input/custom_search_bar.dart index 76bb6e5..eefe6d7 100644 --- a/lib/presentation/widgets/text_input/custom_search_bar.dart +++ b/lib/presentation/widgets/text_input/custom_search_bar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; class CustomSearchBar extends StatelessWidget { @@ -22,6 +21,7 @@ class CustomSearchBar extends StatelessWidget { this.onTrailingButtonPressed, this.onChanged, this.constraints, + this.maxLength, }); /// The controller for the search bar's text input. @@ -48,15 +48,19 @@ class CustomSearchBar extends StatelessWidget { /// The constraints for the search bar. final BoxConstraints? constraints; + /// Optional parameter for maximum length of the input text. + final int? maxLength; + @override Widget build(BuildContext context) { /// Enforce maximum length on the input text - const maxLength = Constants.MAX_PLAYER_NAME_LENGTH; - if (controller.text.length > maxLength) { - controller.text = controller.text.substring(0, maxLength); - controller.selection = TextSelection.fromPosition( - TextPosition(offset: controller.text.length), - ); + if (maxLength != null) { + if (controller.text.length > maxLength!) { + controller.text = controller.text.substring(0, maxLength); + controller.selection = TextSelection.fromPosition( + TextPosition(offset: controller.text.length), + ); + } } return SearchBar( From 94c3bad02b57e2e7d93d7f8fe5b38f85f8c8c0ab Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 17 Jan 2026 22:41:02 +0100 Subject: [PATCH 46/64] Removed counter --- lib/presentation/widgets/text_input/text_input_field.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index 8f7a597..9d8680a 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:game_tracker/core/custom_theme.dart'; class TextInputField extends StatelessWidget { @@ -33,11 +34,14 @@ class TextInputField extends StatelessWidget { controller: controller, onChanged: onChanged, maxLength: maxLength, + maxLengthEnforcement: MaxLengthEnforcement.truncateAfterCompositionEnds, decoration: InputDecoration( filled: true, fillColor: CustomTheme.boxColor, hintText: hintText, hintStyle: const TextStyle(fontSize: 18), + // Hides the character counter + counterText: '', enabledBorder: OutlineInputBorder( borderRadius: const BorderRadius.all(Radius.circular(12)), borderSide: BorderSide(color: CustomTheme.boxBorder), From e9633a898c1712e58b990c87bd56bf2093716388 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sat, 17 Jan 2026 22:54:18 +0100 Subject: [PATCH 47/64] bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 19d2b43..33091e5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.8+236 +version: 0.0.9+236 environment: sdk: ^3.8.1 From 39e6e485ac66091c00b40bdf051dc1abeef095c1 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sat, 17 Jan 2026 22:54:22 +0100 Subject: [PATCH 48/64] remove newline --- .../main_menu/match_view/create_match/create_match_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index db46159..e106de7 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -103,7 +103,6 @@ class _CreateMatchViewState extends State { ('Example Game 2', '', Ruleset.singleWinner), ]; - @override Widget build(BuildContext context) { final loc = AppLocalizations.of(context); From e1dd40a1c37d71a8eb6b578e91d960b5fc044aca Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 18 Jan 2026 22:53:54 +0100 Subject: [PATCH 49/64] first app icon and theme update --- android/app/src/main/AndroidManifest.xml | 2 +- .../app/src/main/ic_launcher-playstore.png | Bin 8160 -> 17804 bytes .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 828 -> 1336 bytes .../mipmap-hdpi/ic_launcher_foreground.webp | Bin 448 -> 884 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 2346 -> 3002 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 656 -> 938 bytes .../mipmap-mdpi/ic_launcher_foreground.webp | Bin 348 -> 596 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 1546 -> 1896 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 1082 -> 1768 bytes .../mipmap-xhdpi/ic_launcher_foreground.webp | Bin 508 -> 1182 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 3276 -> 4246 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 1456 -> 2600 bytes .../mipmap-xxhdpi/ic_launcher_foreground.webp | Bin 704 -> 1804 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 5036 -> 6572 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 1982 -> 3454 bytes .../ic_launcher_foreground.webp | Bin 824 -> 2408 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 7024 -> 9244 bytes .../res/values/ic_launcher_background.xml | 3 +-- .../AppIcon.appiconset/1024.png | Bin 0 -> 56859 bytes .../AppIcon.appiconset/114.png | Bin 0 -> 4615 bytes .../AppIcon.appiconset/120.png | Bin 0 -> 4683 bytes .../AppIcon.appiconset/180.png | Bin 0 -> 7262 bytes .../Assets.xcassets/AppIcon.appiconset/29.png | Bin 0 -> 1163 bytes .../Assets.xcassets/AppIcon.appiconset/40.png | Bin 0 -> 1572 bytes .../Assets.xcassets/AppIcon.appiconset/57.png | Bin 0 -> 2241 bytes .../Assets.xcassets/AppIcon.appiconset/58.png | Bin 0 -> 2212 bytes .../Assets.xcassets/AppIcon.appiconset/60.png | Bin 0 -> 2347 bytes .../Assets.xcassets/AppIcon.appiconset/80.png | Bin 0 -> 3144 bytes .../Assets.xcassets/AppIcon.appiconset/87.png | Bin 0 -> 3447 bytes .../AppIcon.appiconset/Contents.json | 15 +-------------- .../AppIcon.appiconset/icon_x1024.png | Bin 9002 -> 0 bytes .../LauncherIcon.imageset/Contents.json | 13 ++----------- .../LauncherIcon.imageset/Logo-Rounded.png | Bin 0 -> 47780 bytes .../LauncherIcon.imageset/icon.png | Bin 9798 -> 0 bytes lib/core/custom_theme.dart | 4 ++-- .../widgets/buttons/quick_create_button.dart | 6 +++++- .../widgets/colored_icon_container.dart | 2 +- 37 files changed, 13 insertions(+), 32 deletions(-) create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_x1024.png create mode 100644 ios/Runner/Assets.xcassets/LauncherIcon.imageset/Logo-Rounded.png delete mode 100644 ios/Runner/Assets.xcassets/LauncherIcon.imageset/icon.png diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3c48c4a..1eca443 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ 2ArH 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

Fcbo7tIAAH3s)?#~j3J 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 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp index 41f81de898b4f7f754a286caf525e41b601ddbc3..1ab6d6cfa065f6ba30ebf6cb5b4862b834c3a3b7 100644 GIT binary patch literal 1336 zcmV-81;_eQNk&F61pok7MM6+kP&iB@1pojqN5Byf717=P-?SaA*tTukws{d>p0kt6 zw$q`qZTG2D*|zPZ&E9LDXaAydbzy7&0mcf(tUMLtlw;eTS>q}1eoi~K-A-qhv&S|I z*|u$)cGP3rw(XQ{yt$rY+s0App98zLZPm#vJ$29mzmezBC%C(Ng1f_m8VLZx=EBSj zHi|bOnX9a>?+Ue542l_4(ivy~T!(%F$c%S%Cy@K95eE6L26A6Df&{2ml$H>663o@V zgH0~!>~l$HH)Y)3lQex|)qX;>BD6&Hzggyz&NCNxT&Ru%(!Wrh1kbALW|?TQ-X(;K zJ1-Y8zM;F#aT>DgK*`--*jkf4=d9&_GnZ1^YCf&zu=ZK-_gf4uQ@~7vQ1Fji ztmb`lgv2Ojz8GoXqImTiV9(-^pD#11ESG~~N9fA~p zy=0@{QzW#;L_9e81T=x;6x{cZnT8QSKBi7R^nV{5%=6%QWQC=yKXF$pa7=GQw#(kd zKo|7JIPg8#5_VDu@@5Ad{kI^ z$d8+>q}J+#(t!||x$R4Xixe1_ZMS@*1t=W=fd}t3pIVFbYZ;W}rx{C`zf|ZBO8Z0T z5|{8gdhTc-x0y?=)dZ#V5}~oshxNiQCP4&->}BMFD||*N?F*p?D*z$xY6Zr*Hj6&R z#cmPQ5(2&2qmBX~bhdIRg~Fhe(s>wT5eTk2ZkgOfK!p0d!91Em%mt}oE$>^3vkU~& zFywjUf@^eym)jZ?{26dfa0%{ZA%PQ5T%-Y3Pz^ z7y%G-evWyR1J4mS4@QHN#z%%12>>BKZL)}CG>{fH3O^-1>H*;A!4WIy1fEN9L3oaf+dszFk%-@x)_+$m zPDOCgod6<)Xe2)Bzsvi~0Pd3$Y~){v_SScCh|ZVk5F+okXFS%~%D)V+5~?5|Oa7zz z30CuOH(it2+hL#f!UW%K^Kl%}M2tec+uVpgJO3Dav3iO4UoIJAapuY;V~WC< z!W707g)xOO#uUaBg)xOGj429Z3R7Y)%r35rK0E*T^SK*cHk>DjNJPMS&1Di%M|2Qf uL{IW>oP?-3shXr-6GI3Z6LH&ooOfPxS$0x2sY?FU@0Jpcz6OxYNCf~OHHw!2 literal 828 zcmV-C1H=4MNk&FA0{{S5MM6+kP&iB|0{{RoN5ByfN98uQZB^OlE0)uLMnTlzWG?TX z(}u&gjT}j{d!dIb|NHoQa?by|V>^y)+cws@_aPHuOGH3_BSzjmdqJvgZP~J)_xJyY z5jotQ1g;$jKmis7+(w?{pQ9aU;PAcy00IagfB<@c1`t310VJRW)PVr1v2Q>I%6)U| zv-2Jxti}rUhf~E0hye<~!V0j3q7;^bWLeD_LC&zk*;+0x^YK>?lf(P>)6Air-lilV zB62W+rDF{L`z}h1VZWk$dalad?c07G%L)uTFbFv#$Qj?VJxt@V4uqnLf&`YQ*zxi4 z_lnx(^*a^i@%(Z|{c^4?2KEl?>%m{`ZIq?H>!J*0__QU+(leVR1%6UxJC;)q z&>6==20nn_X*yQt`BZ@BRK`eO=l^bX>EN0M+CT(y2cwpNs9cLCORe?1(`mtabMLpl z5)d&tHh~5EdAohO3fZ!4o3^vAZQHhOE4FnR+qQEN+xgIiTWiKodyN^<{|OL(-(#Xk z@-jp_qA-GUOHZG_cxJW7Zb`Uk1Gw0i2}rabuRe%qtr+KCCnS-?dtb*oQQ~bvQXQRsM7-2mUp@aXRN_+`{0%e#?rnCZK8O?zIven6nZ?ctHE-^h@nVD#b)xSaC=royprsARA01Pk#3%$Rv&zU&)X#T-{>oM<%W%VH_ G{-y$;Ig}&- diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp index 9ba77a1cdeda8bdeffbb27fc4cfcdfc27076e1c5..15e3140b2cb6ee1a1b5f9e0d48ee9ce700f67169 100644 GIT binary patch literal 884 zcmV-)1B?7pNk&F&0{{S5MM6+kP&iCq0{{Rop+G1Q1s&M7P1{y``nGM`wrwM_t?b9P zZQHi3$p5cr+dDhw?zQ)+TC;w3BP83lZQ9Pc&x~!`wr#Uy+qRwjfoI51{U|YxhgeZvpn!s`ACR$1y=QyO8x(A3_Oz( z2vcAQUrOexR~cp%U~L>^_7(1xB(r2xJ~0sfDjWu5VHZh~OqWwR8CVtu7vV`sl1!2H zvjOlj3X=R`S^r6rWTLFf#*ij&5Y&M~BuSEtmv=VMH3<5`c{;|(yAhZc1f$>z9i!yk z2P_VPL2#jt5%O*aW(PqFI7-J*d6xryf*`B^tf3>BD{B{^Ob`Sf!Mi$U%NcG6yb~1# zOJFtI*v2-tv6G!;t`DpiL{S}@*EI~Y=Lt<;~CF*#v4A6c`a}z3X*+eh@T}% zl1x^~oNfsSwu&1PRqMXVpz^EYD0XOL~LDt*A#TZEToq7GH%XnEcEd!z4At8yAJECe>d^}3Cb_Xcnx0%Cn&u%C4sEpLX!;IE7U&=7WzbRQ+Jay-y009L?N zT6hB38~{(@Q+XIYI-K-GJJ~GZaqK%GJQU;@Jz2>ub0segdwR zPOMMN?{}@tu_FAFv2d!xE|R{7X`*s6(4lZ9!IfHi5LjI}hv5}1{cQl;DVrFdSjgX6 zs;mzGWGI^Qu(PDClYr($GXyTw+8w~0qFD!zXzhF8c+os&fSyspg^(YfDP0et*L#1ip5e0woq@3rVayY z7fTV?O1-g~Is&L$EJa~ad#b&U12nvxk|{~=YV<#bqOg_+)PBlK8r}h@S1d(fD@pCi zDh(e2)D6Q_0h%r#a!X@*=cs+DD>S?=P`OwlUeT*Qi!YWyBcFQ2PhA8Bmq9Cidr^B? K1pWT+*DnC+GnzC2 literal 448 zcmV;x0YCmyNk&Gv0RRA3MM6+kP&iDi0RR9mp+G1Qui`3_Y**<$?>%x3D$s*6RH27& z?y&(Ok|f1ec0VQ;&%d9igX#Zq5J{3EWzQZx$aw#*UIFv4jci-V`R*Uwd@QayGx~MI2vG$1VHgEBUiqQZ$$qmz*zs=Q%92@tcyw`y$;@aVJzbOlJ&YMj8!z6tka<| zx}kJ!A6l;|HZG3*2I%r~Ul?mRyI_xWOc>>TPggN7jNpK)VR~?*NG8h`64Gd|fZzEN z#t4pY*z3wxOBUm}_w)(gr18L=;(5@Wy~<;qy~UjA;I7UpI;Mmx$5sz_pZ>l{gt(nF qp8@z_XnLCnamoDsvC-)%cJ^IWb2FY*XH;J%rr3pI`ya6Ww~YnFd*2xV diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index c3f9a6838627d00b8df6f9085ab2fe754b5d97a8..9c1fa9a27d84e0a50a0be7d6a084314d7f4a8cd2 100644 GIT binary patch literal 3002 zcmV;r3q|x&Nk&Gp3jhFDMM6+kP&iDc3jhEwN5Byf6$gU0Z4>i{z3rzE5$PYQ(1yxt z(3lE2a4GWovueYOykR{59z65cq~U=6{y zfS{Z$Oc~qBbg|Q=%#qIOvH^Q)NP++mP-ZvVwp~}-wr$&X?}i{rvS};#zoUz1+cv*# z-u^Rk8%dF~OecH;UHShM$<05JF%mN~Gcz;mm=>qo^bUIUTbSvYdx5_>W1MxbnOV%r zj4yy~W~MfYrO3=Qu04-T8N;4&1+jUO%gl_UDl=3;vTfV6v#YUf+qP}n=C^U*%f0uU z7o(Ogq?3UhNs=NdMPE5i1*X}|#_8#0JZ5HQzWYe9ZQHb?@omMnZQHhO+qTmM+jdfR zbs@HG-G3OkZKNojS-hp=yC#=^%ScQIG4K@x$+KcNAzkV5)!3Gstyp)UxD8`2kZws&1y2zl?0$Ar4Jj44H=EGx=frA&}w zd-n^WsW05^g^=IPKs2DxwlVPLq$zWhOA%T$qik0Qx!1m-`RPRY9T5M_i%P70a^-YfcKPig%$~zX?fL^Q(2)3Zzu1QRa^P?F(UmzW7a0;*RoE zSJz=CQZ2`IGOE;wLc)3>!Z@MHoF+s+E?i-lTtT!T5H*3gg3%SGLxdY>QqcxH5%0oe zCQ_qNTNid?O_6%>*qj!c`1=*NFvz@LhTLcin%d32X>#xy9wE&!_m=uMNd6hey(vW8 zZA3Y!C3?)H{0grCFXjog5irw6AS&y7;wQBgx_i^ME-3TL z9Ud?(jI(tt(2C9nrP>(d)c=96-i1;?If!@;Ou|G^0kJQNEM%6<@m0NOMwNMk9U}Uc%$xe=xR?4?a0_KY>b>EKvI1N*43BBv}3WE zAe4b3*leGLL^aV~=?^(IGO|)ZX{K1OM2TzTPLp~NG982i+}pqxPL4M%0D!f^Piss& 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 QSj7W-o&C4o%B_Ke0cqZTg8%>k diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp index 936f08043347f0f07f81e6c8115e795105b53d3a..03e7dcdd6ba9d8a2ed44c7a6cba647934d4d13dd 100644 GIT binary patch literal 938 zcmV;b16BM|Nk&GZ0{{S5MM6+kP&iDL0{{RoFTe{Bp9Z0}ZPm)!=eyygAS(rF;dbxY z8w&v;l5AJi?m0J+K?f%AFXD@cFWqz2VIxV7(zAF^{^>ym?_lq4$5n0HsxqJb;qEjb z3UTN`97{m}1`XWh-gN)~B!Co901`k7$NVJEGtibV~JB5DRvRhC0UKoPBKsETS>R8bL#Q31o_S8I*$kvo-nk}MPpPX+n^x_zEY$MQWq{19(H#5<4x!u|d6cTY!uD+>$X z*Xw6LfkU$c!>ciuA(=fw|Yg@oG4zP*QeMej<0U`0A3P`h!l~?{UH;2A} zmyar|NV823Uj_P@$baeUOV_TVRvRzBS>i823Jh8P=a(_R8{HUVFAE9up`03mg0*7< MF=h8h?KU=*0OR()=l}o! literal 656 zcmV;B0&o3NNk&G90ssJ4MM6+kP&iC`0ssInFTe{B2jsT4-L`oEDQCM%`;Xzyt$R{PQ>4qHHwrZunyZfKI zq(KBs$%p{Rg<#y>9qzjU08&62$N?!J4P=0h^cfI=cz=C@G-*HrJWB$&0c3%+^fM5p z6QCo228IwolU6B$7wJEPE~efv4x}Rz47Er4Nt&fvl@e`IDKTa>MOu_P|D=u&N6P3JwdjEeqGS#9*a{Xva zI`#UGSCvW|pxw4zNJ_iA)E?VLk8RtwZS%heGs*DddlCJg0P<7%ywX8T1EQb?0vdtA z;UUQ|NI>IgWTbzB*wzX?i^C^Q3+ts>l_uEuzRJ%SW!`jGz^gY@wcaPGS^jj;>MN&?OssLZ?$BEc;tW qVNNbe1uSTPw{t*qdR}htB;%{csS&<*?{Z6rdyNRkx~0e9rvw07zc#-B diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp index 32a5d4b3d825950ef933b5ac4d25ffcc46390275..f0c4b2fb4ff487a202944f5fa02d8adc540cdc32 100644 GIT binary patch literal 596 zcmV-a0;~N}Nk&FY0ssJ4MM6+kP&iCL0ssInYrq;1g=E{dP1_moz1VhARLRK)*tSu# zZQJ<(t9DC4$+qnk+upTv_ueP1&6Hn+6hHt7z_Fuk+qSBIw(Vr2Eirn_UNn-~oNVJJ zfPnni5=kek*v=YyiT*E;%t5{)$#)KssgD8Pp^&!bSZkh+iU6OPtd2?i!(hfqzBED( z{6bZ-u-EUJ2tCjxy%8kk`OdVVuNf#=I1A1h^oK#pvs%n{N9c za00Mi7^#S-Oc*K1Ra8+$6%&{TlnP@d`Z31*;rJ&5TZC~Fdl+MW2{;ct(M3A{D|y5i z^HacIwSjV3tiWK#81qAbGXvNni;LJT@mDVx5#Sz%fBw!2u~f z1Rm%ikav0R@q7{SR|)(gR1Pty&ZOkj2Xf?4iDrCX#dHL^Nk&Fg0RRA3MM6+kP&iCS0RR9mYrq;17s58Sttj_Cz@-TyTeAPe*a}$M zVA@EMqndq7E&KdKe0IM~8%c6hvu~k=pMQ#v?$=Qy+fLQwoLM0N6yRS42Cxu*SP=k% zm+*Vv^xpS{MMs+b%eHh=hU0{k^(v|JU^y-7oP7OyO{6>3Nzgb)H@A_+o7 zDij8Up;oC?O2zm__K(rb{|{p9(HE1Pu4t$G!m+F3_|7rb^Ld`ighBN4pdj?)P^uV` zaJaT@+iYsvj8nHsZT|mnov7!rxF{m}KLNhCYr_evVeFQzZV%>^A(zo_R&|P8wquF% zhgXxCVKIc=xGq?2n#fIs^VQ;@fLuhl5R1d&LzY#oVR2m!BA3vPC-@*mk<0aoRb~FL uW6|F1EviXF+I?aECo!3S;jL)i9gCML77HVPs#<|biU;zf0+Td*%M<`dsj46V diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 2ee59a056d1bb6d5c4f8b7e0672432397213a300..3a011fb04049eb94ce940734000352c62611af8b 100644 GIT binary patch literal 1896 zcmV-u2bcI#Nk&Fs2LJ$9MM6+kP&iCe2LJ#sFTe{B6$e4K&E~KDogpG7fYjwh(vh}J zksSTDEQMSKo0*xJhOsF#rBmqYGgFmWeS=SY0PKorIDnX;#}#{8-u)v)S13znSULQ`Ex|kosa|A4E!KMmTvJ%ge_i)gf2H*#}Z=l^iMD<{khpX7P@r9 ztXrAiWWI?^S1fuJxuYD_%JEiw*z@;~Km7Olj%V35e4wPXNS5TPV)3p>kQC^=_u<`^ zZ_fmLXG8%asg@^bN{?Amm=vKJLuNkvWdt{JKmdqu?<`d(9!m;UuKItUby^QYsGV#B z0w;MBSteBo-xn0Z4*cgn|1MNzKw!>_?DjYg*^yz)EJVFPpx-5+$SFm_{W3eYe4jJU zPZNOGrU;P291QK8nkK0|!HO@*%v3Hd7tKk;o1R^d<}trDaHp3MLlRYUgKu9*&`vnk zXO)plp)qGyNOSs3CJ@(n$t#Fz;7yip z$20Ig&xI4THgXYMOD$}LA!th0-|yh3E^kg!%nc|W5-ck8-9-P?!SCNo_))d&dcf(b zT%`Pv>>0LTx4xko2@71~1tdl<90k8&Z|xJE&qW|;EH^VdM16(M(G5&W6HzWlKF$Epw5lydfKdHRnI{wGH1vDIsm` zeZyU)#{_Y0eUmm_KjFAZ>faCJQsKZWpfX#xk>0t8-d#z z>4*RlP;**mrJYxsIF#+Z3*|ic5ftBKuv=dvcXD+Vz9n=(hIvMddCPH31Y}rW% z7@tynj76dE_76hBrrV|ab30eZViOLw?wNyzGIBtYi=fBOl?qSA@29){dNel>h`#lO`M(uw2@f3B@xI?m;sO zXQGJwXuub0uGUWoV8D&rnt8;4+Qfw`7@TaP7!K}7Q}}mMmv2oHKz4ls@HM$k5r?4; z!MgWsV7IXfM$?5|=%05v6Bw*`8ddiC0Tv!FY-ONVzOO+z1D1@e8Q7=L0M*e;;G361 zG@mr_ZN}!#1#`VRDFOkkwszXmzDGB>W1$n$4;sdM>CT6r(Eq5RP~Rnhi>PyA?OU%{ zia^(`&9^}`5{4k1(v>k}^c`NZA!wLVV!0)^v&z`*iUR|Nzx9$GuhPYVjhPPcMnW1T z5Y^KHt#Aene?WUDfhG>L)Uvw&z>gt904@QvRk2}J<+8onknRF=q~b>eA~D3F#m&Hx zPp}c*%q_hg*FSZwaf|?YYdv3dOxp{INEiVVJ%zqfjlGDuzSO)TKo>Qqj%W?52WRbV z!&2|zSCL>Fsw=dBCl->(fvAX5X!(mn$KN2~MX(@5NIqfW@8qp>^g;1fCIi+)0B^;^ zur+tHU?HbAe(_JJ?hQ_~@n!MN3@Vmg+l3}HV@ioy)Bi(6 z(Z6*;155rSx9V*)d*W%N`;JrzFxrsr%;oYzgs@|;gNP731A1M&#OhzoshfDI{^T%1F8i8 literal 1546 zcmV+l2KD(;Nk&Ej1^@t8MM6+kP&iEX1pojqFTe{B6^DVeZBqZT_j`zl3Gf!GU}{df z^8cH*r1cW5XRz@Oop#voU^8OeW81bP+vYX*-mTc1Pw>lTGOs$}n2l9+!$vsRV>F}j z%Eq?h>HpaF3Qsl+S3b4JJkeBZhr@kOS2=RqMw0aZug+{Lw;;5L#ZNh$w*L&S=c z*y`R7h=6Qc+wo?_wr!7Uw=>(et(naWu-#j*k))VMtww|+hcqs!QjSOOUQ8QQ^L3kJ^^GtHi<4%6IN`tOX(Cf$Lm`I|5j}alfD|4mU{HsTHJUY< z3K{7iC&xVGM20ax4JcO%7^L-<{u4KnfAVlHr`e{X9#Ae6V9glO6h`D}6cUxs7z31} z7_f9%^9*^O;Z$l?7$Be=2*4Oeb%v9VJVOPO@vkB5B+MCgnsaivglKqOpcAm#MAVG9 zrBJzo97iLh%~X_ic+aK`Ib0^B`F;p?HQ}}bnWw$NG-`n|x-|JeaP`O3F~mT5G*d`U z=Mf0*S9w8z>Rq3E=(Iv1<+N4?NW`N_lqO}GM~>zJbSApA%zy(kt04izC;(!4w9#Dh zkLK!}#J)065d#thHb-*`0$o~~fW2)IBm_`m)+r1|NQb3c4?!p#eul=-H{!wIgA^3# z+vYbWsHw=+A{|jM$Wr*R-6oZos*oQi$xtXL8AHK-agG5(;p@V9Xm`+9SLo2Xng-B0 zIy9azKm*&o9&)idY!(qP?pOSxz%L7sva2P=Ugz|Y>gxOcFn}GpM5W2K%`5=!aVIN^ z-k~~-Ir~l*j^25**lszn%{i)aeYBZ{)lp6mA?h&Ejr` z2-b*Tvv%xSVt|oTzuuv%nxe=nd*8DBzGz*A-jyJATMG`oLy{=66fQ}?diOScJyl_` z-`A~7Ux<5U?pw;&Lr~MDB?)vJChhNI3lT|V7%0ir*Iv)h7ux|^fC2fiW`~UQ&nxq< z^%YfA@6e|kwBI)n((cVZ0~!S6Uz?s)Gb@UMU?@CD;o=0W{G6u0BoL!U);>Rd3G!V`O3S8j!wR5O8BO`H^V7(Wcs~A*YLYzvv3>N1Z+jSyE1l5&wtlb z!iA>7PNIe36#e_I$$9I$vnuZV3GT(3fMvj7U|42%_r8feMM=U9g=~3}Q0nZZclR(b zK69Lar+1BIz^?*s1Mh9#zTH2UW>aJ5E$?n z=vtl=wb--UHt$;7H8CI1Iu1{+j_kbu>Bj>b$F7~`m#+GZfxhyiyLtl>KE^W5fLi(P w1vU73G>4ED|9|M@d!M@C-OA}{8N+9h-Jdu1xb#O1NDL^io$^uoxT#qI*VCr~Bme*a diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 635adb5a294434fb7a2a313502de52f2b585a326..baf699938ef481e457b4e17eee556ddeeade35b7 100644 GIT binary patch literal 1768 zcmV)PEtR_XKhuYDeh(uLpEdoM(kF%)r4GwV9j=u+JSlZ}{L-aw`O^F3i08S7$vs?- zp-zcmPpJbX26Bub?5BjV7n>Fv2%&ozczA4<(&QNT`^k0uQmSu1atyx!PWrrGOkO$& zyw}R)9u{(lv-im%e#{ukAF6T;!G+p4K6Kq4WuK4x4ZYd85Czyd2Muh*5gi^AjKpqsR(-0*6ry) zwB=ARmR6s=(fE5P#v^}e~bB*&y1whX4RmGPaFf?QV=#8CmF0O}u0ro%yY#OSJ2xw zSel%fFvyzXKpcq?C*d5Zr}e2g&5Z3yu*i1tG-6&^2xX%rku<6OzYFEw60Y z4?>84wfvY5zXrc;fu!l#32cGmAcUBpB_#w{@5mxKL~z8FMa7pL!X+Vu5JR=-8v_f@ zKNXvoz%l$!3-(8X^Py>!73P)~VILddXmjHatcBzR=RwmoXb)_5b_|Tk6*g`e@UTdD zE;Q+@VnC^td*X`(ipO(~UNK`wBr;0d(XhbQe{VPxJzw@1nzENp1dHoX0e^RSI0Qw5 z<8%0oV4=?dthsLm5bF2ADbKlw{l}ouu3b0fSw26K+xlPkEQilR))$b zn$N1i*qC*GGy*}}o4*k>z^PC@7c_czV6zKj5Hvb5gT26RW?=38%OI$^X9X%yI}cP# z0V{6a0zsv%n{Y0uoe!!tfu+~%fuQ21O*ku#glfhp+LeH#AsCPOQ3a~iP!qI8fiFTZ z8BMT2br`i7SYp`$2r6vaf+5%ls@q~$(9QxZxpE%_{c%1B)k~q%t_K_q%;jKEYQ-K1 zYVBKwFO5;Hfppp|th{vt1ifE(m`(Cx{-1!$>XT}$4 zONoIL<1ZBd^$U65+|MF#LZ&JQ>pA)(~T{f@}b)nloOvXt=c=V`eLe=h&@q^utUU$#$+&pqfNBv!gKiJ~I} zm6lHu2>I1^t&a!4Yn{fVC2!vcpb~?atfcqL_F0v!8`J-mTe6Ty2R=4x%3+!g@0{4O>cYc_fnBrr$dAa+xT_nB+f9M z5S@GII4_ydWbb+IFS+7yxWc-fiL&bt#$9~O6ZW3xfyv3EA5CY$31Ng7>*!6kU*CNx zp^{KbsB`(}Uwts;uYsIxIw6t}Z|}WIw~pN81dQC~1`OTix%eAnJ@=1E=giaHlg7CG KBzHPbS_%OApI>GG literal 1082 zcmV-A1jYMONk&F81ONb6MM6+kP&iB_1ONapU%(d-CkHo@Bu7s5%-(}DiFyG4ErA9b zAaS-k(;!a3Z6wK&l+}G){qyAgcZkVLuM=)0*{+q@bH5hmM`uC)A&>|bSWo?X2Wqx$ z%a-%`KHS}jUjhbT0V*R98HN!^GzNf3B5HEiUf*+<0OQYNWGV^!e z-?iBefuS6BqpCitQb{Vw?Dij3sibcIVcbrxAR-X~gaQF27SX`UYIGyCON=TXgsKRT z$Zkl8h;FhPC8D4df{Sx?eBax;5r~RRi3)+O8v!MhIK1tRDoR9R|GE>2`@Z^GCPuHX zwYAs#^xot2`}qGGJ;{RQuWbqIls^6Z`kJ+ezrV?qwDhqRd0V#>(zb0c#wKrV+qN;= zwrzG^G27_ecD8NXTRmI9<$1H_`84K9BKki8>=$bq+ThDUdK&AiNb($LuG1S}H#Tg+gdri|4wm^7P7<}4GWraJwn8Xl z(bdb)+XL`vbLZ}J;Im^3@#%2mVKuPo{QN&K)N0%W*f1TTwqH)223}l}fzPr7j~)Z> zUhjd=;^S4-z$aIF|9;p0=DkW_#kmFJPn1>yOVzlghs!I0_pkM;d9`00I0`+L)AQD$ zqd>YPN1Z&Pfd^mJt9i2Zv^-$$==A7*)AN8zMyHO<%>zzt7cGFuzk;;nG6j|9vw7sl zVbXD)IWPSqD}7-Fc4{<7n9I)9zb8y?ZaX z{-{V@>L#T!cd zYNXhI0Hn8v;<+tpO>0@kJPN>hdBdloS4>{PQJ&Urwp?zuZZA8meg=5nM#xsu~9Fdx7_^#dn~d%yzjG*hnpOO^n5FH77k2Ilji z7Go0RKCn2zA@SnaWV)ouT@A1+WC9OhZm*lvE>Vw#fgj>WOlJSXrdmvDl_-KJAo@@3TMcr zd>P=TAYxMa0}J|E(S#&3tO|sRMoed5N15U=Npi;nOpTa*z|E!@mF9hbdxCgL>DH1LtY1T?J17tc;VB zz$@y~XMW&?Xp|)O8&=S)u{IUtwgku*C3S#3WNLFdK({EF3|yu@F958Jk|V(D>eFul z;He-+;`$EDX;PouWV*r}QMCh>wZD70UIf=w*QA@i8B`L%CiReG0HEK9&OaD%Yo?9|4ZV z$7m zj!^AB02kw94e*Fe=?S@Nn*q)SZH7NAv;1M1?T<=}Tn(Iyk6FNK)>nFC6|WDlH9i_K whZ-Cou^gK-+?6;!A`+V6p8xA6^uz+GMPe+8Q6+qSB#=l&iZfes96kc*h`<$iSsK=LE~ zqW|kx-|z2p{2GSqKR^(K0Kr1AhzM{H9{55Kz6kijz`)=S2O|Yup|UEQARDH>sc^wI zD`ke1@W`1KwWoLfrbkvL`LmLuG~*wV?6^=Ok-zGcqWs$*tFrxm8sp&KMR{+Xohnn0 z+y7t^LixVz$DX1JLRTb=hlM~2T}WX)Z+xB)^J%3DRY>7=*?C=ds?bw7AlkOADxo{< z?!pez?pAEEmH+<@Yg;s2-@Wg>9nt>@un7MP{|o^8R!K$lG`=$G7ENcEVpaq6|PhG zuY_aJ!`nyfIm1@jLFc^={g*T>vYE#ZI`q!viTr&Veh+?B%0qskDdiBqaN+Nh2SHft yj+C};FG`b!MLK3-{$XnlAh#1KY|OB{jxL!{BPw63_2m?Fe#;{KFZ?h3Us)SGNdlb! diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 5ddee6f61d683d3fedeb177fe17a8bdefc95a781..caf112bdca9a2536d63b5215a108795c628a32f0 100644 GIT binary patch literal 4246 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 literal 3276 zcmV;-3^VgmNk&G*3;+OEMM6+kP&iDu3;+NxU%(d-HHU(>ZKRk#?Cl;15itSXJE0;< z+fSE$#l;cA_-$v_Hbs)1bjA`hGcz;GV~;Ia%*@irVrFJ$W@(w3nR&OTyXt~X)6-Cu zA^Q_ETWnH^nI~j2GgZV|*P1rQ6*FURh#4>6QIscE$CxEDM@%EHg(Zede_+Aem`E`* zPP8mp%xQ_C6(L)8UhqUIv@ThKvc$|%i5a$pEm}_zZHT25gM>(u97ziP0H1^w6PZ=h zy=RhS+m74j?tgC{CZm4bi|;-FB%mr;v~8P?)Uln^OWC$)2R7BN5Jk(AVWN{=(wrRcnFA1}6+h(8h{0=^5ZUcZ#oBV%F+BI95nHeP6 z;Y3ha6}64zfZD?UwO26R$rAwEI}QP~A%LD50vI`_QaWx@LjcpH5F|Ct6fSf+1RpF4 zemetyP^;tXG#=!CtOtGm+CSyGe|XX(z%Lz^>guDW4gf=Z`^+Bne{6kqqHK1{=Kdi6 zuRl`E8|1m_WYZ~|ekl%q_mkI`P3_)y|G_hz`9N0y0NteOGARHI{_~HXWTy@CT-Rlj zC7V9kKr-OmXAmgo{BW|#yy~AP0sv~Nhf;tZAd-?vve#4DGz-oN@hRntWGohs`;11@ zw0Jxgi^T~cod5smH~lC8rRty*K-!m?{9OBGQzAGg@wnzQS`xIa#p8r<{_~sv7l2ab z=_Y`*m${tll5DyJw|!4WHJgOo*79t^kNftI0+_nOOaSTcOD3DcvgsB)9f&umJMoblFr09*Yx2#$$wkNq(FGFs!ba6otVoAt%oT&(nxvwLBuOb#I_4 zg-`%FSKQcw#E7C}gx~M$08|ksfY0m^JkKTyxAQp9ihB{zz*K+<)Ta*x_ogIKVU%!> zJ}LuDFtzp$JwPOxA41cJDm9IJ%+H!2fp;yL;QRAmDm_USF`KB=j`1E(QX2hz$-xYZ z2~9yHnIsVoU?+|Ve7%F5x{``$ylX_g zWGoCD5)-;vLNc{HN%nWzf9iH3GV>lbO(cI!zEe4E1I1ySy2}`rhI9VX#G4 zgBmmDf*BNrRv?i~8FvXDh|AlWij9I2Xi%(2dr-Ip7eq2t_lP<>PqJVrwAhUO}0i>YJ_g_M<7H}6YE@_rgocZ@9hg41`>zs@i#Kw!)XhkQ3 za&;y%bI^6Gn?B}If)_ICo@(1y2pGEVF9p@D+GpyygBwS*Od3}=%LFzF41dG2cK~mQQ4^* z8tlIo@z5MM8Q}bW zi~0L)OlmZ^q<%;KTtJS1_8|buRu4p$sSHI+)PNQAS||}sV$Gt#2my^|+xWc9vuZPO zaO8;QZENPMgCA?N?_=vVUASr)yH|O(o8@QI@8jgtURoxozVoAscNMgH3myEG&j>2)J9DHG>lkKbmMCv6fj&25b`8*~}ZP>}>Ze z(?J{+oSW*eYe|V0OC**M8b_ogOKhtka70t>THM)zHz>}gClRPR#WYoHs0bzEaKG_6 z9lv$$f0O<2?f6){tW+un|Z%^0np~#KucPw2oNCxmUj9 zjX8a&a2jCVP78>OmjY5HEtv|~7QQVfSTyiYUM3zhG#e+0(K{$M(0TFXuY~|lH{v4C z_UaUyB?AX1j;Iq`=YLPoh)V)aAP8s+0U-jtax<$9GYk`iQ=NbDBqS%>uk4Pw}v1Q&=w3L1o~?_du3+>q2a-+8qqApO3&UjaDE_0 zKnn)aQwKQ$^Ro3#_lOcK7$q;<)Q(RdI7S+RMnGE-@DZqI2A&PlO2e0u{wlMS)$1jB zHjzFZfx~tijsP!RWx@9K61QG>gvWo+*OD+VprFG}`efu0O`VNdzn+S+gorV!Q9iAn zG5Ee_-XLVbfi-uKAu!5(*Zfu~$sLh7Vew2{fLs7zS3<>E;=t6diIl{11v0`X+~f1H zsoFf{24IB$qX>-)6LCcS4st19d)ZMAAAwLNX9+q8EH=FJWU06nup>9i!esdKgRxUn zYbs>;@4sP;ZK;sqC1r=En9w9zM66}!`3HYB2_a=u2j0X$jlgD0+vjnG3+Uxa&kaxC z^xoA}fzLt%*7QL<5P{>ir#}zfT)90?6IXScnfVui)4;D-5bDS*Kz5W2aOwa4=1=AH za8=*=`<)DMKg!=C5OS8D4X6;9m<2&}|9?w=?e=eJF)6x^-~VcYpr8EaGz%TD0w143x+s2n5puLj;z;UD5k&EZb4s zCW4>ONhl%VoKH4r6S19+lI88({M$>7lN({6P;0<+fS4kfBe0t+_^e~sr@Zuy-77ATh`5s0P>MwiN;%jX@vzFqgKrA=)jvJ7Mc zNl73b5Hn<%jhCMR zUdy^?-9~r5tJG1mrxzYU2ywoW0@rmN$93I;lJf~6jIXwgsN7NA>+%`koj=}ikIYRo zP@$E~{m!((aa8#lP?@wR4U)Q)W}QcdXr?%_4y!Y?;Giq9UqRn*jt zt=pcFQM~t^jf=qkQp0^GH)(-Ntt0~e%clkglLE8x5IAIja|U?M_w!C%*52#Zyz|V) zI$vxx<6qfnR<&AQvu&s!TN+H;Kf9A!ZG&E}&D!dWe;e<7zSf;*mc94di=AlPJCApY z;a*;tL_h}>vj_qX0%4!C|MbDV@BG^gaLEAo=S<_CpjkuYygu*5`G1~qhjI20 zaEjr^DSB1z@zNFpEHW#7gJ{}Sr!6DB%MyD KBN5AD3=|8Fl|lCa diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 65379c15970a6d9eda447b381f005a6e1e2351b2..b29f1ee5eaed3d414a45dbbf9e7a9142101f8957 100644 GIT binary patch literal 2600 zcmV+@3fJ{gNk&E>3IG6CMM6+kP&iB!3IG5vkH8}k6^DVeZ8HDP{|bl*g>Bm)#la_f z+#4Hzry)dgwf$4&>>2ivy8 zwv+9BY}>YN+qP}1ij&T^ZQHhO+iBO{Gqcu}Z})L`y09}UPwb~Ws$#3NQ`)wz2|JsW zZQDt842fX?5MYzqwr$(CZOy1{<8KI(B%8K!|10{>wrzgf|39DpPXOyqE&OBn`z({~ zpUW)!na|bexxde{WHJ;pwa?W=%NXuLn zvt@{$U*`7Yd#uwKce3X+v;c;$I17BuGE|9)@br1GzKku2p)~w`mI=Ttsh;tBxU5l$ zVt*6y0$6P4TxJT-MZNK6l%)E~KjHEz*6B9*XG#GsOBJSwvL)v68CBC6l{6 z1OoM^S~VfxgRikKV9D=rlCD^TjY^H?u8&?(d#2rzUu{2Yr2t@UyP2(ehL6jmU(_7! zv|XjJ5y0MJxloHy^}cS$%yM&88;$0R#X5|t_4YcussJ1~Dcyqb6@$}V5X+M|>Hk(U z?w502WQ)E>T?%e5ep+wjsMs=~SjGY4ga>+&Z|uWP4iQJUaXatXA7R@z$+ud0@6s*+ z&o>VZC#n=lIa0{`1Au_7gM#Pu?^qM#0uKr4vYizCmp)quUH}Jt5SZWu!56LotOA3t z{I^X1OC`RpBrE-w^&8;iDhPWygDpq%GfxA8l?Fg_+rqwZP1@N4G7l0X^v z%b&5~%$O{Jx>F;;cd5VE1xo*?Y7=rH5VK;k80w6;U?n8qZV8m}U)e77j6b$Cc~*m{ z@Lj6ChCtcR@~g1NgqSo{w`n-kY>QPljy1 z;jH4AoO!CMF0g?BWlzPvq6i(5WTUeq-YLpXJMC103RFbxyAWq;cnC)CyG!^-d&kH_ z)}w+*d2TZIn89_-KF3*3q%=S3HbEEKX64&&zs<&F`BCc=c1*n9mFUSZty{>9uIu`o z+-|6?##scadMy4KK`7r{%2VnO4)lx@%b;ou+Tu2Dm*YH#&|cO-f&Hh(L|6A=M7TP^ zQXipE&DW3z-N~g;Wi;R{{<%Y({P#(ZDZl*R8&18c?r%@vHtxTXI2~+5&ID#MoLT~P zZ*GZoU`V*q6DM5926CV~y*TQO+CY%%`zM7t=sEQpJ9@;KO*9ylwz!SoT_;SZgCw63 zfN^nVQ8ZYP@UU_6ot7{)`&#@-DrU!-XEiWN0b$!W!W7Tk16%3NE{qmKVhbLU|B8J^ zM9F=faR@)+m60&Z%)EgF~-i}@~i zgSRZ;y|eI?^3zU;0#C^Yu&1S>1<~jyA7C96@?2+x$a+}#lhvoe0^Upjr25_vBGF10 zk~1?Fu+|9>V{9r!#NH*8WOfua)yU`?2+?rUT!fQuhAz?7VOYR-;alOCmI?)|3FKNSe#AyEYDS1gxpsdyRZ|RPLHx@wYvQ^cFcNI5Fy)f z;X8b>rLzCD`tUGF^Rq6(nh=s%P_`Iat(6o=y4ew-Aw)vOL7Jrp5-#^dNcF7&QMq2( z5@@x1CLqCLUxa3`VO{E@xKrNO_}Fm3HzK6iX=2Io<_0c~c(Vf$QtmdvJ#qL{aY7QK zaU#3}@#h92JOo=_uPdFCWid2ffy}@TBF)8zE{(Zy2}EHAW=84kw7Fg5Z89Q7mV=^o z;D!H#@NS?(@PNiAw&l-eA{2N`ddvRAa@{BX<-JXd@MOmS<)3Ki(Y5_|xr(rFVX zK!Uf=@y4oDB`%Vw^c6$Lz2rGS;?|uMDpr)-8q3q^zgy|=Tv`N35h`2Ze+#Cs+{akHt?j>B~bA92Xa`g9z@Pgz;MVz4=l z(O{^4G{7L?p7k-G0s}B98ojt@0YF9V-qxz+LHyhKE`U$KA(mq}%K1J($DPzq^^We= zqr)0yC!;6;tRDeVbz@$o097Ut_qK*3)#G-XnH$Ta_`m%{IOuc}kd8M&A@hzm0qJlV z3R)h=|J!b6Z|aRSPD~>1?P1w>K3)|x*v^>%u>cvyF_$ucN*$=xfqJv}XTN#Tdc>k~ zIbl(@oRIm+Ws5eW4|JemH$dg6AGtGkGO7Z=tmFcuLl}j|QI|^HkXJQ8wGPxG`0qcP zu^?9o5p7-OyK=Zq%z%_Wwc{#mg@oh*3fWqb))JYyhqp4M6f8 zfV8*;vK|+ACt3p#vt~z#VDyCuxjGZTxdy;J_M@zi9lPe-%&Q?nFtrq7=gtrWckUE| Ksj)zib*mI;Y#1#7 literal 1456 zcmV;h1yA}?Nk&Gf1pok7MM6+kP&iDR1pojqkH8}k)rOjYX&B;PIMDGLpbQMK z`C6CCwYEKtoWBV(Gv^LcZI=sRDw#@VhKiZF->t&T%uFS7#&U82Zbx(cry?zb*Bf>Q zojF;a1ucW;jMj16HiE?dtGoj4Id*1tb^!>DBsr3TKgtK-zp7`}N^opjJNB&Kwr$%s zh7h|-WsSh8lDTB1{QI!9o&NXxe%~_zaJ6kah|q%*xCHL!={1bGNZ=t4jaPK;)1?=_GFUu;792W~XK!AN%za=@jl@kzxB!Hn1UTOW7S%6xA+44Ur1WA$9 zA}JxHghVjb=@e1|kCGV{pyXozg&-@#R5YcPp?KNC?ff^Hi;Bjsz#z$;oPZ}4Q9box z`#2sB(`dK=%Iju91XEF!6ZE)+v(qK+rJ+CtXtwlBIB_8Z(Fb?YUNi1*skh+^?r0Hf_#Brv87t&x`+lLcLWUH)0JMFd*aW zIcq-5nGK+(W|SgUBergR+7}P|rGp+c#%-j0je#oAX)&(UVYvjyl)70=89><@2N(mw zkqMMrTao~HI^ZFKLo~fk#e~$Z&f42Z%QQ>FHDi0vcnw3mk zPw&8~tI2^WiqJE{tVzkl^-S9gTT(K9J%c?ke;*@KiRT&(>sIFj4*%;lYMOuzDVeaI z!BUr#gE^5WBJoKj24r}a>%=x_S58G$x-QvxFxhCM9%XOpc z`5A0_IZ=RIxcDKGZgWFa3eYRw&&f^yTaG-tJiGp+vKBAN(fwH3(s|a!p>>8 zx#g+g`@Vyq++;cB- zAbbh{r7J8z(iX?vS#OC_2O(kv-?XrQukTiP07*yKoC3h;h8!>~-D~k~3x?D|1{Ow8 zoSuOhXRo?_xikPez;A;daIW9S&XpN>*#b#$s+176ghVhlHT881r)FT`-bc}`F#!A! z1!e;5$mZAp-<)T!9^C8uRtql@APEQzV{W&w^Bg~u@43ajk(S9Q0+ifxK-~m45NJ+j z$vKZB&UtfW=KsP>@7gSUbq1;Y)miw`Oz&vtKVly@3(s-VoNS68P?rM?PJ@{M3lIak zR(Jq^HNw@1c6py_&+i=>_`MVTzIQ_9D|&qIXa}m*i2Vcn{$NRx$*6LG2Cz#2Z4K-# z@Yf*-1gjB7F!bYBRC0->b2^Oc79a!^fF7{az*QGdBmAmgR0HSV9RD9n=ZrSj0Vcrx z1IPenKA`a>tGdsZ|1A;_IXyaO^f}i7MiRhr0=)QgRgaH%W+&z9oHK{y+%$CrO_Oux Kz#KvLsZs#_gT*BP diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp index 8cd64ee12d161275fbc05d638e7fb51b53b6234d..3fbeec0bbae399859cc960281665cbad64739e6a 100644 GIT binary patch literal 1804 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 literal 5036 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 QHUX7VA{=mqfV@o?0TLzB5C8xG diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp index 7c56c5023541dc95b2235664e808e2d6444a68f9..c318c1c94aafa6cace0d4f47043229d89ec8cf58 100644 GIT binary patch literal 2408 zcmV-u377U#Nk&Fs2><|BMM6+kP&iCe2><{uufb~&rKky*h9Uly108QfOn|-*7IxtT zzw}1iwrSh8t)+pfG3K&u+qP}nwrzW@ZQHi(y{GLt+p^73f9BHAcO4<*#TG#Uwrx|A zls~g=+qP}nwr$(CZQCB(wr#VOS`z>_l5EuuMWkq$T#A61OnG0yC>B*+c+C9&d!BfX zb-jrGPXM9T|E>R9|F`~c{one(^?&RC*8i>lTmQHIZ~gy~Hwlx5JXD|_4QW7C3Xz`3 zyC8%q$0!c*CVxV6mybEmEb5Z_-3-bwk<0vs>fGfi7E_PNyAtGL3hxj{-6Z*r^^|?r zfud~XZ!}AkE7T=;H-W6I;~z9nlna!3*MNY|e2LEFU*?kf-2pPNmpD3>XDI$|0F`(T zRlCe@LkBv|#V&KHvm9OxZ@CaF*M+&x)M9Ds9nPxyz^E2+Uv@+m%vipuOn@A$= zafqpsCZBbsekH)OWVRjCNg`g(54N!bAeoMcI7;PO#3LZtc`Wl-Nk^IFX0`MdG495(FE3;VX1ta;d1qI+b5xY@= z|AXcGSSi&*lHchQkYu>qi0}x)gHS1@8cOnc-4ytVJZ7USiD2zReJ(Kr&J=*HULz%M zLic%BUuKx(Me7Lok78D%Bgxg$-3{9Z2wHd>8GpjS4{HvuR)PQV{zG8)Br7(Alz zttHLSPl3TkV>a{}W{UI(N=_H>h|zdHxI>}DoHRiX#eFi{j4VXe0wyb=I?{lhDbUeo zw1YlUp=?7+J||#<%~%zDO{o&~v|fsr2~0-7vudb$N@b{IYl;VCFd1pNr?&94QVHt{ z3N$kr)uGS!m{K9@y8>pIj3L1z3Z;G4WZe|UOvcLKhsqh&tA**A8>>R=Fu1CE{7;37wI0QzfGWm9wZlC=%o}86kEkd`me^dPP6Q`-ELa@8Bfm)Cl?kX!a6v zIr)jJCCyN74mwmof145FeT7deH*g9gC}QOE8Eb;ooTT*O33fNoyh_ODR41p|m$)$Lpf_pNux60C6?UDCI2Y9h*|1zs;Bey|a1BnGuuRE#R8V2zW7g zNTIw2&DBG3pKKOQ+#;|TVO|P8tx^wq+%SrJ z{y9Y&a!g3qZ|lb+B=@jtl@MscEQAyZVV zNXecQ7;G@6Kp&(~y+nOZz%_pn@NDooH591FjHLL79QL9R_tiossUb%tyHlXIy%-I> zze0@}>r(>G+Kb!4C)JU%<{Clq8yU?-PX1N%8>fzhHDCt{v^N)hpm$fOGiD|C3)p8a z&II?VC4x;igyMTrS&MZ1rbhUmT0+>{Hls*T&swx3skSyxEdeaKi2|#v#dhc$6l(Qp zqXm56ECRk%-TtZ`kM@?;DB_eb7L`b-b<9zZ9bw7&6qsZzW9{}Vk>$>AEr>V=6y-PUR!ZA_>|ffxF-yu_>z>SA{F1O zVJ50e@sh15P|;LWgWg6VAGZjYVJhYa*QjsK`Ok@9^3bBx4<;1QWBbW>b15+_xczsOXw0>!tav=I?LQj3@?SBFxdppD2* zTwR%h(SE%r+6jgS%yHie8EnCSr@~@*~ala$dCv z#XAHZ;t@5%Xc$$L{9!!+bZPjRtj{m5LKa1&;fHn z-xV;!Li7o)m$gy4DE3>3xxp88z(UXyMp8UxAr7c6zm>H&Elcq^VF&S;>NiGnT2itF z#h+w05CNa4CCtG@5qtI)g=buk6%8i;({Q#;Gt-2%E9h>9fDQ98hi z`kH`A2BInSc{2A~0m}_UkKlS8;7yW83D{*I#s>H60AJK>-4y2y#N6NuIv^1Bls<~b z48+Rd+d3c=^}K~BUNR6{f}iMsNYu-gpm^6n><)gd17cCHS%%^h1933;gAPbUy?%()b< zfNjBPuF&}PgXo(rMDf0X=obu@954{Yi4HCdHV`TJY)~OaDFYE=Ac?_*1B4w!n8Skz z?~|F3g-OF2;)4Y@$xFz^G-faF5z8J)zUC~02@^6h5pvOrj(Mj8#Ysu1^?&RC*8i>l aTmQHIZ~fo;zx99X|JMJl|6Bim7%%|!M1=eR literal 824 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 literal 7024 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 ON-T_6;OCLDM*{#6#_Ie4 diff --git a/android/app/src/main/res/values/ic_launcher_background.xml b/android/app/src/main/res/values/ic_launcher_background.xml index 2971c37..fd4cd85 100644 --- a/android/app/src/main/res/values/ic_launcher_background.xml +++ b/android/app/src/main/res/values/ic_launcher_background.xml @@ -1,5 +1,4 @@ - - @color/app_icon_background + #EF681F \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000000000000000000000000000000000000..94edbb68651a967f5c5f51ac239988d9ad3f2c4c GIT binary patch literal 56859 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

|<&P51ZM z+w0$ZN&FF)hAp$|-(wx82A!sYrgG?j`tdc%qR9uA`AO9G+gw_g-`*~UH$i6_)DSo2 z^wQGyiH);1_z$xFcE-OFjRJXc(h-@dK_LNp6*<~vWNlq4w)z~qOXm4gXL9!+5 zhX?4q^}+IxJ2MuR-KiB3$`WaF)q8%@*%tH*l*wqoEU)75rw(X%AvG`KDu+_w1Q)Ey zA^A^Q@4yKYManpbekvAr_F1=gEGsw=w(6J+X zbxjzO$)PIQqmnUP?)itU?_(mho)Qni!!Cb+P>}-ysX%>MU8`pn2f#14~Q3a1W`n^L3 zmjBr{i(7L!fKZSK9-=dybb%;yN~ZQ;v*&z}^{kbrU`N^Zd?na5;|9xtcv@}_{oy}KAAG5UhDWzfhfaN9Za z1HHt8>n=x@Ogilb=!_5}PR=95M_0OQ?D&vT;dt<#18jG!DpgQ{jhw6PRwr2VOwNB( zN6e~)p{~+}+Y^7b<0|MT)!+Y^T4Saq4?{Z#F5uwTej_cR==Xaij@_nZ=Uf9oRYDUo zQ)O{)IM&MTwl%(4zXTEXOH21lx--=cy%&9&Sk|Pso;k;`3i!4B=nPG6S0Z(j}`jshXiX2-rvDaW93e(c=0pO$XF}21TxS zkuBIl4NWR0j>2ApCS-pzm+({-4%D@rHW7dg zyFN^rwr&gP$$9*;Z|&o26~`W^m;Z}PGIQg|xAbPHu7~Vcy(|RbnRhx^Uu_I#R=Abx%Rcv_-G}8|HttSL^qSr zgSnPbiWkD5G<+0ZzwGXJ`;>uN}K%uXAi-Z%yUPOk;238M0wWjZ;6((h{Z3zZpdjDPQa6{1YzrLOJ1Y7?Gr z^q}C$Pmk9~z~u$TN2N2g8kEl-(>S%C7si{}yi$!lBWgaan5XpH`BLhj9Qq#9OKBb1 zF|rI$jE{0k5?%1Z{}ELrt+%Sxc-oTixxsbnrxlk$){R=u-*x{_2i9`I7V4Q3?UI}F zbj=d&t(9G5*}_4Uw!iI?fBUROJ)z$5ja|w(}-=n}JCL=Q?~`U6rEm zkMySsyXwHTqxRgS3wKV|Lk^0xHO+>p_{FSYRh*RBHHkdOvafpI_oE9*Y7&s!!ezS~J{tfVdziau6ssc=z7Iy-Tasm(eUi8LMqeH;$ zfGZgw>Gikj)}lqSfoK}zx}%ru10Jh0qO2ENK1wt3(d&W*^LK0RxG%N^_EY>Oxe}M* z>)!G5m`_*{XifMmj7!i14ALu}LrwI&8WakpC!cfRAei;>C{)${;ik(6yWcH~Wb3QL zogv{kfmV0I_u-8V9?Nrc@uUg!7gplJd>?7N`XD?d3+86g>kqoRHe@T~yK1`7&XDqS zfw4M?+8rpxe`2WVfx$-+LG~Vvb_u1m?FU^KW!PFb#P|k>MS*W)SDGVmB;jWNQ0U-m z9!y}TOCk7opW2nb_&VIkx5u9m{Jj-^)G9`?KzH=JYp=Z#J;NPY6~2VE1c*G0v&^0* zAa+H&=ub3$ghl>0;tb9L)Pqr$&0ee*^IzG4qTpMc8k(pqur)>_6$Arw@gR4)15n(b z+xj~1-q!#>e#!f>OTc3E#pGpB;^W7j-y0YOL~6)$jW zJ!aS=Ru2pO3Psese<g9}Rj# zg6IR1{*av}w4e6bpMIGkOqr7+P4MyO$STFP-Ui-R!nM(ZSi_~Mwmh@C)rIqvliLH1 zYG*F^W_Jk|pz18kFB2ch@pqnE!#ZaEUKWr8=Z(XvSl0E9NWwM@SC=xe$w^tsyy zG1Of_YNy0OGETvIXnf-T?EY1fy={B%D2VOs=7_`K^gD5|i TD6hG96C=@7)l;c?W*7Z`4>Qyy literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png new file mode 100644 index 0000000000000000000000000000000000000000..165a8a82d081ba0a3b2f35d17d86439a55170a1c GIT binary patch literal 4683 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 0000000000000000000000000000000000000000..b34695226a287fca93daa1876d9bd7f6162916a9 GIT binary patch literal 7262 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 TR1GS`J0w*lO~o2{tIz)jWUDW_ literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png new file mode 100644 index 0000000000000000000000000000000000000000..8745a0f7d2f1ca533a2bc0dda21dc47c07359f1e GIT binary patch literal 1163 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 WG%`ea^6W$a0000px`_J literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png new file mode 100644 index 0000000000000000000000000000000000000000..11c79f151f795b778ce477cc6ba5ccfe082b197b GIT binary patch literal 2241 zcmV;y2tN0TP)mk028JYX3H3`6e$x5op9VIX0= z(jJ=Xd3Mv4tydsA&?ZU5Cw}yy#ud)rbq2R&D^*mI1ICbgJ2ji z!P=+e##YBG@%HL)EQyq(*Xo`SP|+b>ZeW&z!NuD)>t;1Pz7C9ANsQQNqhu%Gi?JwiBPk6` zQeifm5fv51tvg?kWIhzh&i1=pB(oEMGud&_PsK=bkSZ4M{l$cxf9S%m54?l#7yJM^ zosNT4tJOXsolYm@ayibNK82^B$;G}^5qNEB(9~R$8emDaIEAg@}GZU zSh|W=-iZduRXYk6kDa;$t&YW)SG0&vm<@}?g5cm_gocLtgrrDPI`{SJ5uY>{sj>ll zkv|(IyL)OylKey=WpLZ%LHdVnSh0Ey&YwAreuIHqiva-vTr_<_k|?Dqn$P5J!s$~d z(Xb^EX(6m=HLNI*e5w{Tno(HWiFfwDg@SE`+&UW$>C0V7e9E3IE5)Wf4fcO060a@} z6fI>%f#eDS1&j4(+fj4Zje6~;NKBr?73Ks++XtD@Xpl5cd!??s3-QVG@L-S?b z-o;BV??OpdEb>#8&|BP)2uxYQko@UmS6vSdHW*M-S%C+aEyuvXfH#t3f#f53qp1<| z7kmrPrKxcAiRhuq$2-k035KML6;c*Uid)gGj>WYrT1aFv?xx9f#tKQF4OT@Sq@*u| zt*r@-FV2C-?dE<%NX80+?ABQrdu`OK< zokiGIA_$T{UcFMM!*3f5`2FuLVA0|wFqur=T6H{-{JLyu{u}0{rQ`WDC5lB@mx3TE zT?6G3WE^Y7*Y0p!|KnvSRBEn*;ZGgofuy1KFLkMBQY`<>~6n11%5-4 z>4XiLj;5*|``_A!?S(s_>-olXNd7{eC_TTib)OV;>>& zi7fQ@_j|Vw5`m4StmDO}YyFkav3z9)UVkVQdox102Sxt2Lj*!fvFoA^2d^7Yd!Ysk zzrFb1oRvgiD%D^sWGs-p!~XqdGg8v-$8+=5f-4^Zkb~RDmg-J?bi;ycSL?mqx#5s> z({$7d3JUU$jYWO>9)!juVtt$o=QqR)>fZScNl&k+nVd(>`Pt^WZ@ zM=ff9j3tsZhtgfI>&DWIHOPu_p<-japk}lGkYqec7MiLqlr@{Y<6>)FvI^(3W6)=t zEO%A1$gAqYiDok%f9z2x)q$LGj1;*onaNlpNuol+VYA|FMK!W!OYw0|>?A=Bd-hS< zY(vvuuj9UXDL&UErRsQPw_2bGiAGkG4HW{PjR=O^RM~;@78@>W>$sK&b>~JxQl~B` zFbHms??%>eQM4)Y-JKmsn3s<4M%YpPy-9-P56eHS>%ngt42X(L03-4JH&$ zW2jQ~IB}<~6kgX+}uXf=Mh zG7JfU(#fe^NjxYWoNf2aM7qPV{?y=H1q)c69zlR4L69WMPU0I!HjY`88I++y07-%& z{~t61IbAdZIbAdZIbHNGzP^it9|IbW0000GWMx7}Fh)T(GB`srLqRn&I5RLZcMc9f P00000NkvXXu0mjf5#kk8 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000000000000000000000000000000000000..6a990992f0bc08787d9295ac2cf75fe21192505e GIT binary patch literal 2212 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 JXpdj)zX0I5`B?w} diff --git a/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json index 2945b36..f17420d 100644 --- a/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json +++ b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json @@ -1,17 +1,8 @@ { "images" : [ { - "filename" : "icon.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" + "filename" : "Logo-Rounded.png", + "idiom" : "universal" } ], "info" : { diff --git a/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Logo-Rounded.png b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Logo-Rounded.png new file mode 100644 index 0000000000000000000000000000000000000000..a89cc4300729678537a32bb57a10597fd1e47f7b GIT binary patch literal 47780 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æK}$}4 zRM$W-okZkVJP*!B`o}9C#!CP9gRlQQGuC&}SBw3*Mj8>zUzr+fIy zphfII{XuslszVeuZ^xq>x`o;1>bqg0R#?Z_bXH&0!h2*1Ng_n~Z;&{K zdR7Whh9hW`IOq}0jC}=x(i>KHTjlZrQteg-Eoo zoJI6vmd6UF+&)Haj&NhH50oUEVa>;m35rbeZwxW4Nc_(*$Ng;?gb3lAsbxE!^-=_W`&^Cg zwAoIaZpzZOu{;D*Q7rfkp?!THW`{hPojVj?b@gf~qJV|`%X?pfuPqyOQqTd~ z5v~2mato6Tr3uE%v@R<{UVv??MVqEK?FERVKRG_Ua>4+cemlWw6EkqEV;_lrig%1Q z)DZZhpv&&XQ#^zW6^R?MFSXJim*0O0>GK-9u?a((kfhN&PuvpIiHKlABU+4@$w2b5gA zA#9?({4XL2l$IBh*;TD-N@A!Eq+RWZa=d33?OrU$>WS(0@Ij=M#iU8;{^1VWVYkE? z?NH#4Q=`?<)SnT8r3-_1B-+*4AwMI6QOxzoLyH8mJ^JRswDws4nf;@P(Hh26?aQwr zXqTNH)g~Y!HhZ7CfG;@x8uaAMBe|Ufa$pdsw9~cW+)s}VQ&8VM?ZTgYslXi`#uU}* zJsXAuGpLxIn=&A(TjR%jLag1JvH#CA^0=G=u&Qo@$6Dpdxz^fJV(#DxLaq z>6wrOZ%`8e@2M<%oG!mpYA#qQ+uEtKN@YN_mhRKwIB_fF3%~x@SaqHLEjd`91IVN9 zN;3=dug?dUmlb`C?kT6>FVTo7tS%Ef#M-_s#;GD?{-z@$PC$>8D|z8}68kPc%NQpb1?E{rQv?IU^B<3#Pusi}IU};gG#F4gxPu1MT>&W6OW{1yb#v+gb8rM6UI6l0`5u&7UJWKeo}U8IjRGZcbX93c1Dm z{t^BD&GzzZUoKi!KHLOPyb*cq+s1qJ!fJCoSR)HB%4ZOq$vrsu=`NED5K`Koid;ZxITod$d^d>P+}=#)UF>u8T~4ZaS?oZ%3}z%5 zbnDcL62Z61XLY>6L*ShCS>EbT*bYX0R6n$XpWs`MYov9NJ+6;_zCC}X^TN-J%uI{G z5~#L<9+_!5r_PWpC3leFRfVsF24OpYW;%XvZ_N|y_~%D36UKw;$n)OKu3P(Ms%q8u zE%-Kl@Z%~R81DdX;08vGe|=sjTh~I}i1RM7EjNa}-1(k|$0X*PJgUFS%41l&4hly0 zBf9RMp$Lqy1pa!&X^&IdB9m~$K9>2@Z7ORkMIfDXjCV5U&Ec!vnlgX#g80fJ=)b{4 z7kSP8>$<(vy1_?kynG*4!BZdS^J3+ z0;8442agRba7$$KJ&M1~y{{@4UHnh`^k)xU$`%eNwTZ66q{ZuvcSVu+mW9?b5t|O794voj?G0Af>z6(6z0*t{+)w7mC&=Hb<{b+N%=oZEA9^L7`aLdp< z!M^6(dyz_)W-(sCty{Ont+dyA-^HG^@2-CL2dV_A)Jxv0>}3aMyM1Iy7iz5NVVX}D z$tG5SRVa;~^5>VGE8l2U8oV^0`X&4NxyIl_-Q{DV!)Vku>FREwNb76bg9QeG=O1=r z!yZRsdQyB~gw#LmRM-c(yyGcBM)CpMI7_zQofZ3?Y6856)89 zFo^ZfEB2-&S};nJk@V18O@kG<%HIQJNu98AL5P=+xyn=cL%ilNQ;;lrZ!B0H<<>?O zr|)xlH?*ONU{iV>G8<@!^nH4U82bKHHI$YF682F|-yQyZE!VXC07z9!K0dG{^HK?? z%I3CEQpEU_E|%BI8K*ITFQ8F&9LIZ?1}v1vcw!tYWwL9>P@{-EL0^WVQS`ISX~ z?)hQgMp3)^u%-74fr8`RU*;t1im?qOSt6I*Uk6U4`T)f1X%AoA)+}PAC4f>z%Dn^Q zwB|zm_omqXX?E-S3NvrSR1Cn4O1qb#Vx#GUI)B~Gv3JHm`4Tjn`dxeE`ClKGyG<>L z^+=^Wf<)5(QZ0;BLLjC@w&Z5BPzY`|P`ypb0a06jnkb`deu}JqIe|@8e<*2haxgm$ z=+ZX!L`;D5e!6Ga>tomPs~6GqKVdNVjZpnnDDrXjQ^_+hiL1Q6eB9~KMkbCs+l5%o z`D#I2%0)CVi87bcG<~Q6{f@jtBhKeq6_4w6QNEvJ?jvFCH=`~fso=4VWiy%9aJ{*( z4{EoRb9;$vLjcX-_CXQsk}-b*Ub_x4&7#?o~oY9Ea|p*ln=00?#b{L5f7k z35X_7EHKBWT1_BCvXZ0Zha>`bty1AxP)QDvOHIqheb zhjL==-QudmGk|9;f)qosTrS)>kc$3Ul1ZN$53W4-@+7Xt1k@|yI=nRd#Ua{|Zoj;< z7ao7TRz=1<#qF6;^8%j6bXL02xrr_|$e)5+MT~TyJlk+MXBN^jue* zvElOaCZ-6VB2(2twGe+9CEDTu=vgG^Z8AK%#R;ENrS(59Gw7?>n!hh3XqUMps?;r9 z4*KFHMVU3=#ca}9K0Wm$714ExkIda(y7{7HAcT2owo2kVM=0_)F~o|3?REvkwyzvKF>#+hGN!5B2|@pdEBYO z$*{#U?Ul~b^53;c3UboYc29@(4Ghe2HEu(jPZ-ouz44`;z|6$h$Ky5hYvAUvNA*xp zhW5%yPO%>eDAZIh3q=P0sX8e*ST)}%Uoqdg!Zt83g2oH6H>$Z<+~*1ZlIh2&U~o)v zb`F_H1}o0T#OCl2d5|ELSLAc5R{x?1AgFPIgn68HKIEQ3BMG87BgJ)X2`09)DoO0; zBy9Il)WNEbL&r4u*ZYedMOcqYDqn5+2nVPoj0X3LF!%VQ5LB`BdS(3iP|w;NQsClH z^Ip&Ho1R%E4Xex1)9j_N%qQr?**Tph)bfck&eOg^>lzPED|w7{+~0+9&OEVSLTR#E z9r+r=nmPte&uDtpMRm@Aw~O>=l}p0xuX#|9m#*!M>>s1f&Lakl(5L}>cXqf`gD0Gz zKIDh462r!AHf$K%^rzuSxfqNB62S{SJilO&``xn?W_j&tnk)qLmHI^edI47xVbR&; zqmvkX9Q48ei4h;qE$N7_w5eKd`*?YfdTnjY0HtsR!jvNSr)K}X#ewg4=?~?ChlN7> zEUig1A>G4bsQMTS+L6Ro@;ISg?}?njurGnLzQbM!ZbFG%outv{Z}rgUbgg>)36AyO zeKVd`l+t?xp;i&VV=xITQwP4x?OY*?Gn6I+Kj*SR>C+NCc(cdJ?Ug5W(g{m{uqh*%{b?96 z2NU-|;#w_-dt$j>!Ku6nCxSPnn7o->&4l@D@v8XXjp-jb1}*?xYf-raW~J)ACUQ^86oqy1h*iM`bn z`3g*N`Yjg%r#`{nG^x6M?M*=SmXFe(0kw@>ZAw;%TrJL)5^SeJi(kR%_);15sB>j1 z#VIr&6o|#1m7(uT(ccmqa0}&N%F&0_<#r9|Ot{FC^`Zz3a1#oeET^0$J`f|8?E|OO z!rq#{KTp{iea)0EK|f~zp*Tk^Kk2`ho~7+1YG{{)?PSlteH)4Rb7)F6^7I$(d%k$J zZwBM2aw~dMwt49<0j51zw|lB}ujIx23V$*ZukN6e@a%h^g2odzjK~Y^{GTY-{Yf;p*eJ#FcRCg%+*fJ!^vI0)IEp;bw~(j=xrNv-b83>6)jUq3)Gu=z)0zOgfJ_ z#%jD@Q0`z(I|!tMyFbPo0w>?rZQLwim%n3B&t$WXcF&C%H3 z_>=kLtkrvbk6FA`>ZTvss`iN}1ykf}Vo$#*1M?L{y<4@#t=v^?R+kry?a0ud4n~M6 zU=L<%rV(UPpw4sD!n8N*Bo{RX$}Qh%md0dMEvDk!P|F*wqfyJ}wh_5m{qJp@@%b}c zT^%_U)ZTMMQttlWgwWFxmG+LvqZpt5^N;fJPO z=xZY59Va4~HfDVnmA3uBFg8Sn1F@8n5;vSPcrnJ!USgNL?%T&A!xL>OH6p{VYuZqu z*gjt8rz^|=)d`7N&&!cd6$$XIvTSvehcxp(c~@lpwe{V%qu3=6;I5q1kE~T*mi=i@ zz~wQh$7a6!v)zPy7H+2qh29!UC0JJ-YEIe8%jxgktVqPnQ`b>ctBW`@_RY!w7pM$n!TR?=aAW*?!(G zdmQf8s&-klWYB0YD}`X+?;KGF!};3d#dTZf*^5ixOUViSM#OLvWK#)OpIk?oFA8@& zxURT!B_IBmrQOy(eA%avvb7;W9U!0E_J;^IK@(E_Mw~IVd}ID(rd(mo(yo{Ap0Ft9 z4R}v_op}P{lY)KHrE;=`FU!`#Kn-4ex_3k4VEqL+n=zZ1x0zi58z`?05<_l92)TkgCop48H!$0S@eZK5hielDTk62oRpIN z5v&6$^!;HG`MjJo=uUN<;$Lt>pxkJyKDUn20}C)S5TQTmw-$0s04-JVUz>3h9^Vl+ zl*(|g7~736_g%H%A7A(jnu<`E3K^Q0Uyozk7iqY_wO2t?GvqlS98q%z>f1$Bs^8+< zSLbJ+9~G`$wvx4P*6^l{vscRAh}R(|KB;MnN8e^^q4Yo(o$Y43Sq$D}Ria-7N1soN zz(~EJc7y|TR^vi-_YtPVC#A(|m^3EXmtRZaFwdFuDeRpKuHh|)yCBk0dhyDqQF`r` zA#ibw@}tbmZ^X6ZBwxq>9q~R;Zu;lC>Xly&?=jOnR6*hofHOy>+}QN}yaX$wd_$s0 z61ZHib2@U>--Mm;@?^7H<{d`79|LUS zIM~^$xx}Y*8ch*4Wt$*J@xiz;qiE{Vlz8Ic>O6(NIuFj&)p}`xPY!<(Hzc0p=Jf4{)s;v)zldnK_F_!@MJC1N3*oYq)NwhQ+|RvuSJW9{cq?chhka>4p*$MdtXwbGH8o2(S?z9UFz5Ks7Vj_80~eDS#0%cD~{LQF*X zqSvri8?YL}dfy%6T0&y?R46@;#zL{k3~be@!Z37#_JvOIo-Fv$Cw{bs;^ag1x)uKa zj~&0?OozC*}mx zZ;Pc5hA^$2@rxkNTpHGfJvSTNDBE+5bsX6dFl909EG=%%xtNKxk?Un>p%aQJ2X93)jxMYR~%na?5P*XIu6c4zrV-4R3`wA z*8LsFUc@9oJW)ePrg+&Di&k&vJfM%xgw#2`3Wcq+r}^~cdA+FDP1kw|xHe#I)4+d;^u{=o?Cggssdq_b={8^663YArAWmw6-y zt~`8+_!5>TJ)#~wcdc&#nrWzdj+;hb4unj1aMsA#^X$tZ>SByBD-}~g#o6-&vaNk5 z{>Uc6@toMF%gw?aUkigdE!=FD5rGl!mM1I@O~xJ9p;_cg)&w*J)PR+$Jd$=ZBAislk1^ooMr zpK`gJ#%)2Pp9e$TnhEeAdbXY3^2>K})y>pj+&-BAu3CthZDi)PsV^I%4Y$UhF*mPB z&}>`3Ix_`Z1?}TzxHHn}=85AV^@6@v6oTFyvgMRhF2Sa2~H^Nd_C!#{5YTU~u z4kd}1YX*4L2UI?pzj)=WQVASfoL|_&zxVRhV8Qp=hamI-;_A}Osk79@T(E$0OT{pV zi&=8pQFVX=WbYri@w`%7BehhHIN!-?U7GqqUK{E#cx5SVXmEzAlUCyg7~K*Kus`Wr ziYyMeHxl^8?F_mam~tb5EyM53rDkUj8p8!^{T3coDx26QG`@C#ROocd~;k z(Z!^XYy(iAGGF1Dk`y24p@?Fk*I1#r`<08~1v_dMBl3l#1S7?f)c0=Ui=lLectCJf z<(lrC-`Wy5cKuG?^PK|OSr8DSpInppm*aG)JR__Ic8}NkKu(+>Qvg2e*jcboC>rq* zYc@uw7VQ@pbk;_^!tCG_tFgHu4h8C?q9BB+uwKexbpDYPH^)HV?n>?sQkD?#BK&pX zg%-O_jfhPOwf7?={k$cp=$-pLs@B4wfEDSX1NcqxDZ;fN37Z0)+qo-*fCf3Vf|~$< zW7##3KK<7swSxS%SL5#`0=!X=1;S+8F*Ml8VWeJLo!Flp^lJRP8|sy6Nauj)Ihk#4 ztQ>FwAk2#sc{x&qs0*)jBUNB3MOk!swIc2nmtp!jg?4ek?}YK?v>3h zB;oHx8$#7>p4jIsw{zU@cX9zzCj3V0s#RM<;wEw@+ykfA^{QEhGi9hhvWYXKw4Q=k zYmlEf{)3G8?}c9_=jYB7BGWgE{kXQWyvW(?U#Nf_aD}cb<>eHhdotO6j~7>49A4kK zV#b@#ekf8Ka7p0pb)+D)qf%`;gbR-C)(fkc`y%*P(AOre&Yx`9KT|*IJ+#IJ3P05s=3jw;!k8h|q%>RDGQ@F;{OEFL=N}8>F)Vco#^c14^T-LNv6*h+( z5L{rHX;d~G^Ju8^HtA;3<&KefJCuzV62%AH=L`;x3z=!`)(fwNthSoL(>ibG8;^&pRIf~jX9}PWDj_jEel(ar!)iHyC1xs>!*Uq) znfrpA!C+=V{-o^&j~CRcQw?wtBuHAP3pt=+aS{4Glba`bx$g*VPRRGDAm8KKe|y3q z+ipASQ7IXX4I1GEpS{WNgj>2cPN68*+}&He*S=S>_uJlPSGSvdL>JKf(8a)2B!i`- zp>=Gp^g36e+i(EYWOHy(4%bS#KUd!x$iMwzp-j6+w-rKJxHf;E=SbTBHh~ zO&>-a=e{ln>SZW1}QO7-;UagdplMLq*kqOX>*}1kJLZMhb#5k z?DcQBd1C`59(i90eT5<(b%w z`75I8jnvMKR_-VU5O}g#1JO1Iq+WMFSo~mPBmu`U!CTD(k=nn#?*;#;UzIq+J`HCN zB!Hjpj`QFgCo|XamuPkyOv?Oa3;(5~6bjP~!fGe+e_kxL@n=JMxdAouiF#UOGEk0O z5}8@_;nG0>7rtOdCFcnV$|&YOBu2CqR8qu`b^Wn8{{17+h9oFRXq13(5;0>9oxXFZ zsWk_a7~cnnjl~<6VVhh5{~gF1y`Ex6Qn>i1Y0N95x?}RtY3N}32j5(~1DDxx_DKK| zKYFT_3{z|=Ptd3h%V{oY`??nAH^Tl9YV5b2MZK{>Rx8$#YfHc0$IVLYx7@g*ahTRL z4A%fSSl%1!LyaZ_o`jDXxBDAB|N6tW7q)1???qNh8M-rdNUIh5I+unjy`2Ep4u@;$ z$!}sYj>a%Y`Cc!s_rOI@%Tv?Wo=@@c7o?aW|JXTKx7kU-cJL+iFXG_WNRGaC&~AXa zBu>O=Ewaf#9B3fKO`*;D3o!}QA%(86%v>tUUkZ8JEfoeoZXa{<_8d81zKBme^Z*2X z2>o%#pTekDTPO(gQB+)<57sz%W~aI4F(;8^YxK>HD1W%?JhJ#&zs-_EM`dNh;XZ%9 z2y|_TKk<8Q7zYF8f(b_7i>uXrhpE`dqUwr#(wCJl0;5Hxt^!PH$@?PO00bl^s@Fmn z>Pdm{J)wLIm7eD+PsVdw!}X6-!G@sf^pWnZzdf#)#R7gIq<031@+BlN`t6TSalA@f zLN2M-S~=m@8gFI*z0kqw`(x^sjV+9U8;Z~hBQTBn?xs(|w+rtb5C1hG;HR%z>t&cO zTZ#Pn{vLCK?lhd-(y_S{JDFDq5C_R0F zpiK?%2c^JIGuYrsBWhxkVgDP#$Q9A)XRXGpemUVao5MuOpu%;K z??)E~LZ7Yk&$LVL_|zkT(IMot29^uVU~<*W`mPK_)c*%CB@6hWeD4FA1VLYNIeF7Iua_ z^}joQg#1A4ck?A%MPpt5`6IFjIleYg9rSzdE%w@=4bvURmdG7tSL*==+E>lf%BvPK zZKSr3zdo0xsq>h)03zphjqCmQ*Q0Eq@OT(PeKPRiIyVQ$%zd|jCVI|LtBnkLIL19+0;lolbq$%&bqv>B2>S zHC-e)3yH;{^4m0rDd!J4!F^-@`^R!#?l4t7PwXgF*LV2=!B7d!H)Mc=V3(K0@>G1V z_{+a><@mhvB`mg3^! zuV1AM^Gb~cT8^RJeE#X~88bVbSvZg(^z}8I8l=*IUO{rkgD+_L(D#^cc7{H8x!CBl z98?)pMhZ3X6qkx(j0-bHoG!Pn&vi7kThG`h4vG7!-#(HvVrVXaZa=NvY8mT4U^kmNi`McXwhbU=iEU)_Y_qkq7Z|5<8)dOE7 zg1VvU^s3y}-*;6S<|#9&wAIh2&}*bQICIUDU^W`pOzpXxKb~OMHZ>nES3bsiwNJWO zt?fyuRUpb1DvgI`Y`v((i_0HR_3#_%FTT8h%S(slU%wVG?X22td)OQkxy)^Ey*txB zz(8$?JP0*L%f3R)hwj^hdB%m;eh~Ji{PP{|(ev!dGegXn_FfgzBEm6R&n^A9&%hv| zBZe~->z%ecSEvQ9rHTBka$!-6sx}s&e&vrA;BF}CAkXw2{1>a0$UaqTzW`@Sy;KP0 zQyCnV3gzsNfqObMy`pgA4NZgKiKOw_m8=PiAVe1Zdj6-KTdr21Hz#l`CGIN9_5*F5 z!eg(9tJ^;=e+ov(aozh!F`HwBeoMliZLKg`{(kQD zikjJ+&{r_W%mMn4PfnBU%5B2tNcmPW891y2+ww_>hL_{A7z67BYtqstg)}(GkG5|3 zdEB7y{0&G+$Dr2_j&MLRiFhWc>c6d4x7&yqI9DGMRzM?vm2`M;eQ)_=(I&sqx=_zM zaZg8qd5;E?Gt_1?*KG%4VR2_S3aT5WjSgSzt$*>u(u64T0cI6! z_DbVwP0v@cpEvG&oqer7GN)%h*l^^M_4Zr4HY?z4Qc$iJ>haq;<{yhjwAQw(Y=amD zsFJb)71u`XJG>bz=({&EsbBw3ao_#cWYPuthN_~lt}6)ATq%NpO78?w=|$;XlnzpZ zKxk1`&_zUpL0TXvy(+zDaWDVwO@p4h-_YZGYcoqJpCE}2J&FOfHt03Zp zy&PBsKvyGZ%OLjjuH~4{o5%K=uuHxT3T$dG10ggAQqp#;UgsmIkV8&==Y#oGM>vE6zmI0 z+;F7MS-Ve6!O%}GLd3XW-0SaSN7(NfpN5=|99F$HrugsXwAI+bUDgL){%#LdAPGrZ z$9veWxs4SG#BO@{_^bAIo?~~#+HE)lwE)89!p~jPz~Sf)f<1)}%U-?=j|&sfs~4_4 z$N0-dyM)^|_}-;@Ut?o=Szk5a8F&r|Iw^O?V!&mkuzjC#1ib&z`7G7Th6sC~Ffrjo zfAoo1-k5clc?#45LBRUbnXW~0wW3Ks{aa0A*d&XlmdQAYKDzSH#=dhIvrjj)Zw+)l zQ9|KC71Po19z%KiG!>c*R1Q2i1Z4s=y&eK((ubEJZIQz8CkXGkqK(PNv13m4PFHx{_JwitaW?;f5-WE_SAsMrI6!feB~BBwSf#F zQH=~ip^kCDMy3cDxMcoR6WHpK1zD}_P6J0|I=KqAwsP~%4;FhS+Ce_V+Ha2#&ny>x z%?J+=@jz$ETQysehJUuDsygZk%;YQSg3ZI3by~#<<_8BCv$IRUnGHQ(!6`1fu6M04 z3W+}UOJj$R(6J8ulnT_)6@)&;J6#OQ+Qpj+`=gA*%AQ@LLe%`t4bf*d8sMRs9*iS} zkeWTp-#?`}cT*jYQUv;5I1-Io*>z1R*<*FnqNafJmL9t(WjK029v?$hLs=++=#G*r zv`z-ib=Z522F=vY8Di3Tm4L3ryQ4jsz@uLRc+&!xVfYS10Z$v!yLg3`wS1Kj^QZ7> z1OpGC`=U?p2WQ)7z)Frf_w!STz4_?fwgdMge}4BYFmal7goD?xDB@)CX^n%a#S#) znm?EY;kc^r<*Q+HbgbvR1;b%LSsinN5>E6{$MrdsA^;{^fB=l$6?V4+Z&%Mp^1lE* z0`EgX^Q0%s?rE(uU1ls4Z({8W8N!5LG>gvoj~_pd!p25#dcC9Z9ve%#_+O`At})Yo zdiRYoQM=iiyHQ4PMifG55j<`+2~=@{6UBrFYX=eN9S7ZaqD(d(a0YwbTTTD*Z2$8K z9>EB#w&RYoMwCNp1t&H6nDSvD*zE3rZLlJ#6Lq4jbgE^y4vsq)y)Y+4up+2|?$rYz z+_VP}9dyQkF!n)-)PDxya;WVZm&f|Uqe18N zI0V@pg{LodJvyd_k(BsHczFp}(%LF^vqH~Hr$vT=J?Ns(dPKjCOp-&ouVDbl2(JSo zNx(gq7{1)uKG`6smsR4|l`03k?%CX4zlpl3##-JAPW2OJQ-KlHx+~hV_qddg^1+c{ zA@-iCWZB@wCfqtoz7I>T1SWYqX*BBGjT6tYsOCu8ju}f5Kh_s};iK{ImusD-hmqcc z^Yyjz^7;LDP86SHJ>_$!=%PK82cl98D7X1!E#))Q)|p48N#=5 zG7c&a;;diR?3oF07|-M+IF{?KAZi(PP6Fr`PE+1swlXvliUTstz&-EWRrxDzd|y~> z6C{&unSn|=)Yo4_eq7lzeg=Zu0MKu_a9zEW>$g>G-mQ{gbv_*i-$6eUS@c_v_u`|J7;1a<{4((QU{Y{LQG)oR>%hH!Xkld(h`8eC)_4yo za_f|KubJAdUF27KpaBU3e>bGU5i-1*6bp`28<76=;LYGiE7PjC=0+d_IlX(84^4lH z>rGscWFyOqDHaUkqJZJsmqTuX{jM_z%H4;_THG@i54QzwBWcqlZ}|dT>qHRb9D8ED z(nxgtqmHt}y|G%C>%T!V6XH^DzgOnCr12Q2R|~~}a4Hz4&>;cjLA80GwID`G?^Vr& zHt%DHA*OX6*;B193t;2y^s_SCz3siNXNcl5x^XI8PP9%R0-}0=K_|0GR5DrA_C8WX7zExLo}(=Ud5WxaK3-xYg9dK6);|ajmUNWUK(vlUHQeZV<9-RO?Fr!V zOlLEj$yML}J&=CH9H`U2mL;z41~hK1U-9yO$nfJVSUuu* z+ENRzD?6NMvUCBK3dHUD!K?Vcz-2ng*}l383ErtzyfQbgeiqNlE%}%K@&)$8kOHJS zwhSu}Vazi`nW?E_=MGo6E*u!4?XLO?;3E;xye=tD7hbch^Lfr@?1-&K=F$<9NM-0J zh#xI@`u?_@X+q-`hX_{$SQx;?-K^&wDoqx?MM|hP;^5$DC~G3A#@#g>T8_cC02@*! z0HyLNqOjrM`A~6O=4}v9#RrI;AFzdDXmKFOzC~qJ*6#K{%_%^Jp~N~Fpq|6|=Tg6m zv0%&crF$pBut$N^B#A9q0zO`RPv&jUwEGCu(?TY%a-)2URiH+Fk*Q}x61a<1sBUf$ zq-Ob8eHYtWmvZCh#gpJ^Et@U`o%R=sxBO^kLzKjgep9QgKK~(}M=-4TA&Hw1(PXSe z-4F{njTmHsngJIId1d$0U_b)5i=FgI90jLkWo_$Qu(WeQu$S(uHJc-%qewaHxW8%= ztfwrbpiDYHNt-0S?IY02JL(LXtKm1|R6w{C!LTJY53Nb>u`PVHLzjGU8`houy#_Ee zU$wjb(GVZsw5nO7XAnTom=T^?cKkV4>Q5-8W_}Win zb!H=r3RJMr=a%i3w9KcPf8h`@^FQbO6=5*GFG)MACo0CtTPol>LYL++<9H0l&yp$Evz&p7`9r6_2tJe~kvX;yLz*Xn!} zUR(8T`eiM$LE%8-rsD*+D=tWFf%#*(!Z^EQV`7Mbw-wJE2ZNLX+p`);{4cwT<&2d| zFkHg?%t;tM#>o2?t5mNMi2uNRDWGm?L>L4F)>LFIkKn8~{}xe^agiF>G02*91mdU9 z(oDIDV3)%AGVNmF2gJfFb#^{ke`=YqqP$rVi%4npp~VZ&b$jQDt-LNZ)___lGwyM;7bc%f{gh6F@sYv+K0(JgnssJe$4$K$o4&ZjdD zyNdbc>7- zWttWcby)~Qbn?Y9dVF5iq(;r$>82R3Fj{Hi%f+tRfG@sN`;MW2`=HM17~;=e3wh?>6Le#Mz@}6Eq(vvRN6ls0tL63zO(Qy z34QiY5z0Q2`*!m0AL0^h=%0VK2p%azp0_y1D4!ILk{A=?6&+h#={8tMSv)B^lijzx ze4lC%rEXp_X6um`q!352BLMWDEEmX6M0gGtj~*qAr|D{5CNIh0KrkY)EFbDh=A zuyMUbIkBeMKE~Wt#@5jX2aa{xb@I?=Uo?AvX>nYb^F6CwUdnuAy^BtT64_vwjc?>$ z{e7L1xKEhf{vG%7#m7g=$bQ0#P4JG;>WDydLxVL* z&Fmw_NATuE`*SFunu9Ov-E}jGsU0e&q;kZzj`Zk<&8x+3c`ej8nUr$Gr*o5~0|^gq zP!=*Dsvjli%r){}n>>I!i}XOafNfd?to{)^HMlpjYSEiQuCYim9Lt2j-ESf(jyBF zWq+~@sH+0PPbi#NK$vbfTv7{+snt?3)Oa;hKc)jOTT^GgER18Ux)>U&SlaSU=H60C zY3b~*wW&mw%-e(ZeXI(Li;Ib|a>)KHwT`)WynPlqIz5c32RY?ziDQYm9w2W$QY)l99>-8s`%}@YGx<7g^aWUxT z&|IbJHT9@>$Y)EvP`?hG)zgwkwKJ}X61M4m*Ysn^P2|_{?e5^&`o+?QgEUAl$ItBaV1mFT{vhj1vSy69)>1!p+P8=~2Dvu`H1Q|2bF;@*Wi}A=h?1y!z$Qun zn;_^Xb!zZj=85M~x&+7&n)T{YWG`XE8TW=xCt-f-Zj)VOQ|9PuNeyc*CBqSDsE3=v zf(M6&7L}ArswyjGLyccjSqMgPadCBX8DZtV`(53_elgPP8m%^PuY*GtHSf!o^k%J}Ld$igR9-EZPvNkg_V;4o+3>_$P zz(lihkfPMa_4+P;To-Gai>YTkYeHhn$>OLS zpAtCuh1aU8KcUvZ$OAS#_LwU@pa?s!;&ZK7b~$_Y6JkvPIl(@_4J2`*0!hef%Ixcn zZjL(Gzrp#0kCz>%B%{KK^1Lp>tOg9=oNqxnrlE2iZ^j%ZezU zP*5Xhm>!UtIB?i-sRyOfFb-6=*hWu$1_X@&%>~X>?{W>$p%8A^T!0YINP!^h30Nb_ zx;m`CzX!4z(|Orh@G6HeN{RNtxI;L)8bP^TeC5Aly`!_>$%6ps2w~r_@qGC=Y7&@#DM z;Um#f*^JOVa6cw+3%>-@fTs$lp9PM4mGsy`5F`o6N8rwBCo=d0hD!%B#%URXr_q0j zr@!K-%xA)&5pbU4OmkuO#&mG#U=jhCztPZA1c(~YzXPOjC3MW%{{CNI|MLH@%xUDV z1CsCv{Ch~AR(h4gLH>OXV8PH?eoQR@FIOK1DM|vF#OOlPY#z|c{|os3;gB~!h8~@r zx%?H-2V6u@Mw>WBsB++HA2T%8@0-67FcPS|tTqrg(j+9M+s?JAc2SK}{q;^G?;WkIzU=Jm(6q)L+_!abSm}>A2DZGX zTzspx#iH-_%Yg=g-S6$QR}w-E?k|rBrw4yQOn;i3ywjHhxp{yUW^H3rNNbF>?2K+o zq?QD<2ed;AfT&fe@&WfH2NbwMMoevxMj-k_wJ!Y9xb1~vm5%Ws?hyz6UaK}fSFf?h zwmx+(((45)JXI!Q$HZ5r|F${pS5yF*@Ua)FC0h? zt{6vi$f$A?Ufur~VO`>%A9mCuC(Du@3b`=KwG%o^nvvK_bP6p$ZUThDeDnETs|8`> z20tbJ9Irdl!Eb+ zhSfRGU1jIBE!o_Qsb=&O8Lxhm$ySpYj`Mn;h%?IVhca`)LIySH7h??ILAZ!B5r zD2*^sMNb;>Ld8T|!Kk?kkx)K50Rox9d_9QmL>Ly?3fVGdZi~JVA zslQqm!Y&Io9ghqT#)0DCu$65;o5e`TpLsOxVmxw%d(50un%VuK$Q43z?>;vrkxRoT zEOJ(CPQjiX;@j$I@!y}0G;_62iDH)p?qEFTJes4N$n9;n^vpSjaw0+rLJ&3t8qh$lz#$oHvtdN?`5|+8^4i16G`%$Sy{5Gyv+-34%dB8BSv*QuDAs`Zz&NZ0Kku` zCKN3lD$zsgcY}BCXE5VfT$)4cR#j=QXNuE8*eijxWTo3^Rpk1*=<3(;u*t35P8g1H zfB#hQY+goVV8Fr2o(FX4ZSYKdqJ3QS-lU8GMpO;?Zax4?zB{A7p>Mg|U7GX3+4AI} zkY{0iHX#t-tyvoRdBs~sfDa}4HsW09SYNQ)>NCxlnfc3b;3foLeEICDK*-)!-j^kIXzpz5`h2yI; z?af|pk*mU7b2;O6=h#6*!I8r?W3FsL)fyMwSDkQ;@g93k=qrq>-ZMs zq#z|el#CUbx}NT9+r3z(T8FWz%e4A~-M#4U;$1D`gRP741-;+ameekW_D~&@Gs8MU zhn-+b5dY_`HiyV9vAG$wOZ69eNDb24DSqsgSboIqT(Eu;^Wp@yJKxmJ#%Tw1?w_*e zix0dLvi|nWB{=nEkX{mN6aMDPDdPrru>*2BHuT$6bzWuQ5Rn(fZ8B2JpnTaBX|7dV zS=GV&almOkC)%rSVr78nH?&3!@9|{Eo-vg2Yma@?$Nng|jWPKI$LXR@2H%U(krtfD z;imqcJ}IkiOxUZ9r)qKArDOWm3z>F*l@c#?*afcfCWGkjmn%B<(xqR$edX|Z%73tM z&~muv{`iEGPh*&z0x3c@vtjqzmH?lTRLIPQrX}cWQm>4|NYPBK->#sggW1Pl0j0Ge zO0QPVIA6XH9G(3&a$yt6?UwE&r*`bN#Ssve?tCE?ZyJn3cCT8Q*gMDNeQc}DjVY1t;bTrQRz zx5ihR8r+nyd2`eB8w0O>`%(;~=HII_A$D<$fpf#QLbLIo^>2!ci!MKR7+Y)gl`k99$22_alM|amsePH0F_8cP&L8#D5)}%Lc5IeE zD>ySTH$n7!2oB);e@EbR^BJ=4`#>FvF-WUSKA_VaT z7c)^#8Cw4S{hEogn_9{M%9U3f=;8+i-*}dU+V9FOI_zsV_qTj;l+2p;U$xud_kT@% zS`NQzT-Ce*8bZ3wmuW!S14No72GpbW zw_QB}#;ERkjkrb4-^JnesOC%f2d)c;ACxYSG15MO4&Ln}L3>=HkK!f=2Rk{lpyoGl zJ?eJw14L65_y~84*fD@bG?5N#1`hW8Mc@#vDN!J*OYpX*V@B{0 zP#fbA5XT)Pl$0=o0_DY)Ohb5!9KN}v1Rw$_yE&pYl+sWR&VIB%xiG)TAUwUv6`aDtLDp2Bd%2`Oqt%)eqPW^W1J%W{L{Gk4zA~pmP6hM}Hb8 zA+9E~Es7142pw#{*pGEPMbLOYy?D0h5Z}3OaeZGT+|hWwJAQzUBX+~FP@-ub*7S=* z_Zc?A5EK!_+R=OM72A(0PLKh@*or+mEy=0lx&gN@G9uR&tL*@>QL$#y8@|&LKoF0* zf@f9u8Afl)EMO2|%Lh|C3$h=AKfblIXSZ|WSttp@+eDTqkVXia9XMg`S}KX-@>Pl* z2Xlf7r6k4gPXhXs5APVx{oDn0fU%5Tfc+_0MEdlJ|CNwTTxLeV=vhLU%IzS9FNCtD z&WoSVD?mByeH3YA0VQ9{1NohrxnVR8h5D;>n7=+)Eb=CXz%MxjOHC~SGTy!sUu2M8 z%|wyrpf#mYZ0KWMB)ytWymyS;)+4G^|D=pgrh69BKfUA^+vH_%tNQC+X}{?6NN{bj zaG4lnrc90tZ7+zlh=8)nuA#!?>D4S0knkWF{GaSrHoW9PO5-EM9au>6(EHjTo0@MK zjxr*x@9cveIQno1fQk|+F;59r1sMrz#jMlf>0Hk3qp~PkH8tr99>UML|1>p6+4z+<7G2SPpiOquV@)I0woRpNG(m*#*}pMtBH$2km=s zw3ZV|2lfyv;GL^(si(*(0kak;txWn>spz?Iw_ZpzD#Eu74SV~!{r06=WtxDLK^45 zwHET@B-y&)(PFl~77WODNz*Psh=-t`M`Ej5iaXFUPDu>N!aV*1A^d2n6n$a_k+x{d zuX;V(#Vi!F4HgG`$pku)@^%KqWvU~)w^f-a1x2IH*VI8_RlPFaOXiKM5-xAydQ_W4 zml!C#-B)5h?3b%;(*x*PFtb9sq}69!$7ADz{1?ntGeqCeq-7hj_ZgNX6%j+Wh1vu z2!VBaLidIt7eMTNF1PUZBk>K)l7i*z6dLFcMj^aHsuX<(1#ZQAUa3{+ndG0d zXD6G2g+dX^^sWB`j3&RdVP3s!GW)#|aM>-P9-{!mLn!G12Uk~}-G<(C_5d`lL{%AlOI3#o;KfBx z(R&Tz6_}+#G5h1>wkJYmy6X?6zTO4hB*TJ*wn;({3s{ozH|rxJT_byXe+ksgs3@FOcdX319WHN-W~KnZX5t4 z`L364q#WK99bPb-B^8bG*9go!_GX-13hOR zmUm#@*9N|ReSj|6_s3NE+^bKP|C1mPnf1^MZI?7%64M00^8Vt9Dad#^T~k!t=5d7V zcHb8rl``FsXg7M;waoO0xIV@pC?5=L1dp2DSH&j?h2BRmrqQPX*QV!+^uc85B~70E zgV00DOKcRxj~lHQ9D?os!r0upz*&UNH&YlEF}05yQK1Rz`gqr$0TakFX65o`&dmDB z3D9utz#zZ{Eugnvci1rh+X>ys+Ky|&XZ_ikC|x%#&VfB!gjQ|YiR?$*1Sr|wHgn0C zv;459e6hlp9V9)Ec)eg46@U&FQX(NVL4~v*AsGJ*JC_V}#P@3qJA>P|(3T>hc4$Yv z0JlD7KvM7bmPG~|wc=ARi(7%dvxc-UUoOmetUwY_qz4g%>u%WWxxrA^M_;}ov*H(ayELr|?`uf1-UoDB#HxKK4Er}k`TM|x= z62g1-F$dWnCCAj(Xm7*A-zsw^hWnyliEQr+8N1gj(m4bz6wP6oGL=viI$QY|MKYR+ zUjMeBbDE%U66KHP5*jA?fdd4-%V)U$PDr5eVdznEW%9X|3O8Z=Mq=Y-JXNTU7!8Co zoK5o1tk96?cC@E@=x{?i_wC2K-pczp(k50nBV~G6x3su9%Ai#aa7)|O0}-$+dxW>m zHfa;Nad*Hv9S*KVDqB1&C^w!kO|*M4?JK;!B9w6Hya-S6DG2(W?2lGKho8eA6d>`w zx&dK*kKWaB?)*KfTHmBxsy5@Mg0{2Zi;~2jDk@9RFSiU~g;1Zhe%YJp)j;v`t-+z3!_cTrOinbl+nVs zj*)K9ryE)JYXJJTV`m6>qgf~uik$6e*hk~JwX5f literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/LauncherIcon.imageset/icon.png b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/icon.png deleted file mode 100644 index ee71baa946aac78738951b35e8187ecc1c5375a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9798 zcmeHNd0bORyFM(6SV0SIEh0fh1w{!Kgh~jYpokz?u^=D>6;NcAB>}?fQrrNMB?=@! zsVJ*PHd*6JWC;Wj0s#`N0uhn`0TMz&awmT6y}f^b_pk5r$2s|B=FB^D-ZL}r^E~g| zJmF}ovUby22!d4Xj@q1rAO)7}TC*CI954Ft8T=@R9(4$e^TDFTWz2KOg%>hch5TGqej0t&E&5C8GxP%e8Jf}%#(fnYkhc28 zo*q+kGnVf+P|Tl$pUCa0cm%kH$VFn2HS-Bl&0*kr2Ygf7g36R>wmuEz)@2cJmXi+M zF9h371!DfSweM6N7oMvv&abge>K~aYM8RE2Qu;HWo_q8n$nf==2*`b5Ogg*cY*%^c z>t9K~SS$>YT(RpQzYR&MR{DG-@yT#Jt-`lkG6D?vSH+Cwgw3VowwKzw_Q6&qYJi>0 z&{q&BjHwq98ZV{E^~H*HOtaI@2zuz}A?js$twcLS?B~$>1$~qrb7U4zFS3f9ZsARI z6z2x-y4{63h5ZgPyX44`gIK|NQsGAFsl3-|#*I|AO_e5Os3B|b?{z?Xz~}^a-HrGE zC~ck?)}NTE+TYm2UIRH~0zV(h$$!sPdiAm_0R1M!81nudxIjHjgkrj26WUXUeLxu`; zfT<@P{UIYLVCoMg7{eW_2$>x!P?*U%l9rOam)TUu|B-4(;Tj_pp(lrB7kIdu zgQ)9+$t9|SjlZclD9z%etk6~>%)gWdSt$Ycd-c8`NWheN#GxZj$jkzl&Xf{j#!F`N zM^zmd?+VkyK7Y{x!`L$1L|1_B2GIzNCSKh<=XS@fNc(nil_NadDR(HNTTcBl?_tK+ z^-u8ZLdjL%MWS^@K9hvK5Iv2Jf4C4XcmF`s71b93M-C4eEMGUpWsxE-ADC-0y%B!S z7(=Yj2w8r3n>>BdmB5zw9+wTbbeTECoQ&=;K%H?ZN6{xAP;19iO)xdbMfn4?$!Mt4 z9C*xi|Igy9F5MnP$Gl#ZAj@>)h|tG0nad{Mgm>4(FvL|(Aq(cLETb+0ut#>< z4E{lWuq4$N`kOR0_2DG($+8Pw52gx}gIT$~z_hLtVKZ|V6t$z}m^=g}Lh@Q5P{;#k zLC~5lR1jUaBw8u0RIIpUWiqTRgO#1(-`x}EF0F_5-$_XUf$A6vh2ne*w%Kje2R#If zr3j6I5!7n_JZ{;E4YyWO>bR+{+kP9~d>U)4_b4A7t&&>3PF|Bh0(&U}{&50jkV?_y; z=8}mi%P8ymr8ruquYGnOOa)4Wsj(s$I1>88Uy*#?VeXCd+~wEF@y)T57z{jJ(*_|V2oKV?v6Vr<|;sjb88~Zz7Y1J;Q7nqM;!nm0I*Zs_sPk^ zB3_USf|0l1>|Sm}`$wJRjtZ3UkdT`?{QbZuDf^p*ZCxL2b38Aie;-tVpa!RcUJZ)=1V#V17YY9;Q>KW5n!{8rJ*qSr8LAL9 zP97iCD42#NkoL~B=V%SqU<&v@0=Fbt=`w;67TyBvpew^@HMU?}YZc9UTIOpI?Vp%K zDC|1cH3cV_9wvSv6~Hmb&`utI8bF#cMo3^K066V&>w^rg>Rbib0`gWIq5?SI z7G%I;7nA6KS{o|M+WKA|qNPV(p5F_j6z)~=g9!*9nOO)ypUML|Pj726;P z|NE&MbBh9goupmJi?nw~s?+<2d&Vnk{iW(6cjS5~k)g(Vqp?|Xuxz5@G^x68uE3Sv zQf94`{NI%aW{1No2(+e&%?+b>swV1U7_;hRkH4DQX#5k;<{52<*mX-j!>^%ll#?Et2$hlL4H5Urz zrx|YigpdS{O&Ys(2?#H*m@g0MMF$UXs(ah77SCJpr=1p08)fZry@+}k@I~*{4Hr6S9h3y|VAyDzf=s;V8y1dpO%agiCy!w{$nWlJ zTUDF~iFchhqQxvhu00hgKw?s)-u3?zyk{DsR>@4g73NFcCVW3JqeC$;M)a^(MG`)bL0$E=+MW*U6U&ql7CV@m_8zcl_6I* z?FQm6^>Uq%?-}J8EGmQd!{ofOfKk>{1S!TgTHHnsNRz`;*+7K2EBlZUA4cDK*H0Hx zYRHL>{^;UCt)trk6E>TCnXLU7DIalfWb4=F1x4i4|1C)P1J7G2aR%y}`D>{DL)s%i z4_Vv=Mp|$cCY(qp1&wp8bkk*h7kFZoz|6s$JSD59+sb?a*J}4;s_VPh8$ zYHiX8Trj`?)xG<^N)1i_k{zh}bKPdmeRGa^Kle;V8~!SDfOTtYYkOOUt_QLz#1U0C zaqvm!gQ4J-rdZzCEdI)O;E@$_@$Zt06(_DhzW=X~@8)|N&2^lDr%gV1aK4&eWEin6eM#}h|@$%17S5{W7wsj8qxd~s5zKwdb%KPONmu~FG#oHAG zrRMj1PtQ<4M5B-Hg9<_d|N1+8ps3tSOgeM{rtcAd=V}SyEp9Clhs!2ZxSRcDJ=IQ6 z-pWR|IsW9KvY;Kf&}4!ssaTfm!`iu4$GHyu-6XoL-KATT5&3wXO10?l57iYL1@jeq zIrs2BCYQJuhXmCWPj`@(c)t^Cx6xR(?*?5G?Ncp2R-it?>kII(oO@v@35XVJ6ZUj# zV_%BcH@NTFU2<7Z39dffBv+x zKUO(oEA=K|!=7Fil5|Y~IC^rl-0J+6t79womob8MKkhe1099vxIn_5U>uwzmBxLZ8 zi|-<}_sViO;Q92Nk&9>_vq8Ie^tRu=j`JqaURq_zodB0g!0c_@n!_lI!5_SJKR&7` zd7hzyRgT6gtM3zp=aa@r$62JrV?X587X&{46Ym=u^>kh8x_+2aDVBy{cuH8~-MGUO z@JgPLvt2x|ACV9>r!6ZeHM#n)u2`Bdtwl<`6cG= zUF_{uo^y=;>X7^zTqpV_RvF}Gdfk>AG1;Uh5&v&o7~Yl(-*#i3p8I1c2uMrw0S4}gWq}&U~Hb#~E)IR4bX!EgMUyOmUHM3kejZ@NQ zxYx!{NkDdNsxn$yGgb;_i-CLmFJErG{HUENOE__*jeBJ&JWo*oEvt-)IqpVezk0ue zfA2vH&UJaRZ|s#S(&be*knMg+O|@`_330Z6gY_}$`t^M<<(+}Et8RDD`=;8nrc5(2 z&7VBShQqt`JsE95X~7}^-aKm2o0IPS3M{LiS~6tI#Ken8?3JyZPDP_2_(!s$nGqdG zUS!hZMGILjQxyi=MJB}6-buliA~$8Wv>fpLICufK<92rTuegd$(nCeU`)!u~{A8!) zP%)B7apWSO)@?S6eR{_N;ojP6{@pJ?ZA7_6@n6m2V~2c0M0NNxRh4IEioa=h;7hq< zExP=ytI0>&i6HS=;tbO-3F*oMUATSIaqq2t2S`Cua+-bkYOKy<=Mpo29AysJsSUK{ z`@rqI;SYkw`(V(e8647wm~ofvCGS8w@V$jD2*oqfZ&%J>teiesIgs-oaug|ZNdga6 XGcZKiBsGHN4cQ%bw5dGgedWIZJ_t-k diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 2c18073..3ae77cd 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -7,10 +7,10 @@ class CustomTheme { // ==================== Colors ==================== /// Primary color of the app theme - static Color primaryColor = const Color(0xFF7505E4); + static Color primaryColor = const Color(0xFFef681f); /// Secondary color of the app theme - static Color secondaryColor = const Color(0xFFAFA2FF); + static Color secondaryColor = const Color(0xFFf2a981); /// Background color of the app theme static Color backgroundColor = const Color(0xFF0B0B0B); diff --git a/lib/presentation/widgets/buttons/quick_create_button.dart b/lib/presentation/widgets/buttons/quick_create_button.dart index e013186..0abf7d6 100644 --- a/lib/presentation/widgets/buttons/quick_create_button.dart +++ b/lib/presentation/widgets/buttons/quick_create_button.dart @@ -35,7 +35,11 @@ class _QuickCreateButtonState extends State { ), child: Text( widget.text, - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + style: const TextStyle( + color: CustomTheme.textColor, + fontWeight: FontWeight.bold, + fontSize: 16, + ), ), ); } diff --git a/lib/presentation/widgets/colored_icon_container.dart b/lib/presentation/widgets/colored_icon_container.dart index be51cd2..2cc97e2 100644 --- a/lib/presentation/widgets/colored_icon_container.dart +++ b/lib/presentation/widgets/colored_icon_container.dart @@ -48,7 +48,7 @@ class ColoredIconContainer extends StatelessWidget { child: Icon( icon, size: iconSize, - color: CustomTheme.primaryColor.withGreen(40), + color: CustomTheme.primaryColor.withBlue(40), ), ), ], From 53a33ca2e19928207369e45816c686563446f17b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 18 Jan 2026 22:58:28 +0100 Subject: [PATCH 50/64] Updated app name --- android/app/src/main/AndroidManifest.xml | 2 +- ios/Runner/Info.plist | 4 ++-- 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 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1eca443..e722349 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Game Tracker + Tallee CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -13,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - game_tracker + tallee CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index 2ef9ee9..74d541d 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -3,7 +3,7 @@ "all_players": "Alle Spieler:innen", "all_players_selected": "Alle Spieler:innen ausgewählt", "amount_of_matches": "Anzahl der Spiele", - "app_name": "Game Tracker", + "app_name": "Tallee", "best_player": "Beste:r Spieler:in", "cancel": "Abbrechen", "choose_game": "Spielvorlage wählen", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index fa4adc8..667c5c5 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -301,7 +301,7 @@ "all_players": "All players", "all_players_selected": "All players selected", "amount_of_matches": "Amount of Matches", - "app_name": "Game Tracker", + "app_name": "Tallee", "best_player": "Best Player", "cancel": "Cancel", "choose_game": "Choose Game", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 57dbdd8..b2a60c0 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -119,7 +119,7 @@ abstract class AppLocalizations { /// The name of the App /// /// In en, this message translates to: - /// **'Game Tracker'** + /// **'Tallee'** String get app_name; /// Label for best player statistic diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index f78f9f4..2f76fd2 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -18,7 +18,7 @@ class AppLocalizationsDe extends AppLocalizations { String get amount_of_matches => 'Anzahl der Spiele'; @override - String get app_name => 'Game Tracker'; + String get app_name => 'Tallee'; @override String get best_player => 'Beste:r Spieler:in'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 32512c7..cfcae20 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -18,7 +18,7 @@ class AppLocalizationsEn extends AppLocalizations { String get amount_of_matches => 'Amount of Matches'; @override - String get app_name => 'Game Tracker'; + String get app_name => 'Tallee'; @override String get best_player => 'Best Player'; From c6251740177daa49ec86f2de89746e99e09db5b9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 19 Jan 2026 16:07:12 +0100 Subject: [PATCH 51/64] Updated text color --- lib/core/custom_theme.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 3ae77cd..866ee43 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -7,25 +7,25 @@ class CustomTheme { // ==================== Colors ==================== /// Primary color of the app theme - static Color primaryColor = const Color(0xFFef681f); + static const Color primaryColor = Color(0xFFef681f); /// Secondary color of the app theme - static Color secondaryColor = const Color(0xFFf2a981); + static const Color secondaryColor = Color(0xFFf2a981); /// Background color of the app theme - static Color backgroundColor = const Color(0xFF0B0B0B); + static const backgroundColor = Color(0xFF0B0B0B); /// Default color for boxes and containers - static Color boxColor = const Color(0xFF101010); + static const Color boxColor = Color(0xFF101010); /// Default border color for boxes and containers - static Color boxBorder = const Color(0xFF272727); + static const Color boxBorder = Color(0xFF272727); /// Color for boxes and containers displayed on boxes - static Color onBoxColor = const Color(0xFF181818); + static const Color onBoxColor = Color(0xFF181818); /// Text color used throughout the app - static const Color textColor = Colors.white; + static const Color textColor = Color(0xFFFFFFFF); /// Selected color for the [NavbarItem] static Color navBarItemSelectedColor = primaryColor.withGreen(100); From 87d7fbebcd7f40739ee0b7493e8e6f34a600d404 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 19 Jan 2026 16:07:20 +0100 Subject: [PATCH 52/64] Updated quick create button color --- lib/presentation/widgets/buttons/quick_create_button.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/widgets/buttons/quick_create_button.dart b/lib/presentation/widgets/buttons/quick_create_button.dart index 0abf7d6..6dc9876 100644 --- a/lib/presentation/widgets/buttons/quick_create_button.dart +++ b/lib/presentation/widgets/buttons/quick_create_button.dart @@ -28,7 +28,7 @@ class _QuickCreateButtonState extends State { onPressed: widget.onPressed, style: ElevatedButton.styleFrom( minimumSize: const Size(140, 45), - backgroundColor: CustomTheme.primaryColor, + backgroundColor: CustomTheme.primaryColor.withAlpha(200).withBlue(40), shape: RoundedRectangleBorder( borderRadius: CustomTheme.standardBorderRadiusAll, ), From 9f71c22a56656cb06f5eab02776f37238d20e8c6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 19 Jan 2026 16:14:26 +0100 Subject: [PATCH 53/64] Fixed pipeline --- lib/core/custom_theme.dart | 6 +++--- .../views/main_menu/group_view/group_profile_view.dart | 4 +++- .../settings_view/licenses/license_detail_view.dart | 2 +- .../views/main_menu/settings_view/settings_view.dart | 2 +- lib/presentation/widgets/custom_alert_dialog.dart | 2 +- .../widgets/text_input/custom_search_bar.dart | 4 +++- lib/presentation/widgets/text_input/text_input_field.dart | 8 ++++---- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 866ee43..9400d3d 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -63,18 +63,18 @@ class CustomTheme { ); // ==================== App Bar Theme ==================== - static AppBarTheme appBarTheme = AppBarTheme( + static const AppBarTheme appBarTheme = AppBarTheme( backgroundColor: backgroundColor, foregroundColor: textColor, elevation: 0, scrolledUnderElevation: 0, centerTitle: true, - titleTextStyle: const TextStyle( + titleTextStyle: TextStyle( color: textColor, fontSize: 20, fontWeight: FontWeight.bold, overflow: TextOverflow.ellipsis, ), - iconTheme: const IconThemeData(color: textColor), + iconTheme: IconThemeData(color: textColor), ); } diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index e366834..b46fcbe 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -78,7 +78,9 @@ class _GroupProfileViewState extends State { onPressed: () => Navigator.of(context).pop(true), child: Text( loc.delete, - style: TextStyle(color: CustomTheme.secondaryColor), + style: const TextStyle( + color: CustomTheme.secondaryColor, + ), ), ), ], diff --git a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart index 54ff34e..5c48592 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart @@ -89,7 +89,7 @@ class LicenseDetailView extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, - style: TextStyle( + style: const TextStyle( fontSize: 12, color: CustomTheme.secondaryColor, decoration: TextDecoration.underline, diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index 7941cb5..244610e 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -136,7 +136,7 @@ class _SettingsViewState extends State { onPressed: () => Navigator.of(context).pop(true), child: Text( loc.delete, - style: TextStyle( + style: const TextStyle( color: CustomTheme.secondaryColor, ), ), diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/custom_alert_dialog.dart index af5b45a..5ca2b15 100644 --- a/lib/presentation/widgets/custom_alert_dialog.dart +++ b/lib/presentation/widgets/custom_alert_dialog.dart @@ -32,7 +32,7 @@ class CustomAlertDialog extends StatelessWidget { actionsAlignment: MainAxisAlignment.spaceAround, shape: RoundedRectangleBorder( borderRadius: CustomTheme.standardBorderRadiusAll, - side: BorderSide(color: CustomTheme.boxBorder), + side: const BorderSide(color: CustomTheme.boxBorder), ), ); } diff --git a/lib/presentation/widgets/text_input/custom_search_bar.dart b/lib/presentation/widgets/text_input/custom_search_bar.dart index eefe6d7..77f6eba 100644 --- a/lib/presentation/widgets/text_input/custom_search_bar.dart +++ b/lib/presentation/widgets/text_input/custom_search_bar.dart @@ -87,7 +87,9 @@ class CustomSearchBar extends StatelessWidget { const SizedBox(width: 5), ], backgroundColor: WidgetStateProperty.all(CustomTheme.boxColor), - side: WidgetStateProperty.all(BorderSide(color: CustomTheme.boxBorder)), + side: WidgetStateProperty.all( + const BorderSide(color: CustomTheme.boxBorder), + ), shape: WidgetStateProperty.all( RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index 9d8680a..bbb3e45 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -42,12 +42,12 @@ class TextInputField extends StatelessWidget { hintStyle: const TextStyle(fontSize: 18), // Hides the character counter counterText: '', - enabledBorder: OutlineInputBorder( - borderRadius: const BorderRadius.all(Radius.circular(12)), + enabledBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), borderSide: BorderSide(color: CustomTheme.boxBorder), ), - focusedBorder: OutlineInputBorder( - borderRadius: const BorderRadius.all(Radius.circular(12)), + focusedBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), borderSide: BorderSide(color: CustomTheme.boxBorder), ), floatingLabelBehavior: FloatingLabelBehavior.never, From ccd0c62e3c04c99fa8bd4d0731edd50e2491ee30 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 19 Jan 2026 20:04:58 +0100 Subject: [PATCH 54/64] Added launchscreen --- android/app/src/main/res/values/colors.xml | 3 +-- .../Contents.json | 6 +++--- .../LauncherIconOnly.imageset/Contents.json | 12 ++++++++++++ .../Icon-Transparent.png | Bin 0 -> 21544 bytes ios/Runner/Base.lproj/LaunchScreen.storyboard | 13 ++++++++++--- 5 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Icon-Transparent.png diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index 8f65602..2fdce4b 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -1,5 +1,4 @@ - #E6F1E4 - #0B0B0B + #ef681f \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/LauncherBackgroundColor.colorset/Contents.json b/ios/Runner/Assets.xcassets/LauncherBackgroundColor.colorset/Contents.json index 41fe6c8..7356209 100644 --- a/ios/Runner/Assets.xcassets/LauncherBackgroundColor.colorset/Contents.json +++ b/ios/Runner/Assets.xcassets/LauncherBackgroundColor.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.043", - "green" : "0.043", - "red" : "0.043" + "blue" : "0.122", + "green" : "0.408", + "red" : "0.937" } }, "idiom" : "universal" diff --git a/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json b/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json new file mode 100644 index 0000000..2002cdd --- /dev/null +++ b/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon-Transparent.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Icon-Transparent.png b/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Icon-Transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..f926570038dd32667ad97d6976ce79da6f8fa421 GIT binary patch literal 21544 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard index fb29ee2..a64dcfb 100644 --- a/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -1,9 +1,9 @@ - + - + @@ -24,6 +24,13 @@ + @@ -37,7 +44,7 @@ - + From c7b4623198a085cb641fc026d3dcbe3ef73f4472 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 20 Jan 2026 10:48:49 +0000 Subject: [PATCH 55/64] Workflows um Format Stage erweitern (#175) Extend workflows with format stage Co-authored-by: Gitea Actions [bot] <> Reviewed-on: https://git.yannick-weigert.de/liquid-development/game-tracker/pulls/175 Reviewed-by: gelbeinhalb --- .gitea/workflows/pull_request.yaml | 28 +++----- .gitea/workflows/push.yaml | 103 +++++++++++++++++++++-------- 2 files changed, 86 insertions(+), 45 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 43d36d2..5b88cdf 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -6,23 +6,17 @@ on: jobs: lint: runs-on: ubuntu-latest + steps: - name: Checkout code uses: actions/checkout@v4 - - name: Install jq - run: | - apt-get update - apt-get install -y jq - - name: Install Flutter (wget) run: | - wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz + wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz tar xf flutter_linux_3.38.2-stable.tar.xz - # Set Git safe directory for Flutter path git config --global --add safe.directory "$(pwd)/flutter" - # Set Flutter path - echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + echo "$(pwd)/flutter/bin" >> $GITEA_PATH - name: Get dependencies run: flutter pub get @@ -32,26 +26,22 @@ jobs: test: runs-on: ubuntu-latest + env: + RUNNER_TOOL_CACHE: /toolcache + steps: - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies - run: | - apt-get update - apt-get install -y jq - - name: Install Flutter (wget) run: | - wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz + wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz tar xf flutter_linux_3.38.2-stable.tar.xz - # Set Git safe directory for Flutter path git config --global --add safe.directory "$(pwd)/flutter" - # Set Flutter path - echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + echo "$(pwd)/flutter/bin" >> $GITEA_PATH - name: Get dependencies run: flutter pub get - name: Run tests - run: flutter test \ No newline at end of file + run: flutter test diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml index 700e96b..dfcee5f 100644 --- a/.gitea/workflows/push.yaml +++ b/.gitea/workflows/push.yaml @@ -7,44 +7,95 @@ on: - "main" jobs: - format: + test: runs-on: ubuntu-latest - if: false # Needs bot user steps: - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies + - name: Install Flutter (wget) run: | - apt-get update - apt-get install -y jq + wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz + tar xf flutter_linux_3.38.2-stable.tar.xz + git config --global --add safe.directory "$(pwd)/flutter" + echo "$(pwd)/flutter/bin" >> $GITEA_PATH + + - name: Get dependencies + run: flutter pub get + + - name: Run tests + run: flutter test + + format: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 - name: Install Flutter (wget) run: | - wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz + wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz tar xf flutter_linux_3.38.2-stable.tar.xz - # Set Git safe directory for Flutter path git config --global --add safe.directory "$(pwd)/flutter" - # Set Flutter path - echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + echo "$(pwd)/flutter/bin" >> $GITEA_PATH - - name: Get & upgrade dependencies - run: | - flutter pub get - flutter pub upgrade --major-versions + - name: Get dependencies + run: flutter pub get - - name: Auto-format - run: | - dart format lib - dart fix --apply lib + - name: Check code format + id: check_format + continue-on-error: true + run: flutter analyze lib test - # Needs credentials, push access and the right files need to be staged - - name: Commit Changes + - name: Format code + if: steps.check_format.outcome == 'failure' + env: + GITEA_TOKEN: ${{ secrets.BOT_TOKEN }} run: | - git config --global user.name "Gitea Actions" - git config --global user.email "actions@gitea.com" - git status - git add lib/ - git status - git commit -m "Actions: Auto-formatting [skip ci]" - git push + git fetch origin ${{ gitea.head_ref }} + git checkout ${{ gitea.head_ref }} + + dart fix --apply lib + dart fix --apply test + + if [ -n "$(git status --porcelain lib test)" ]; then + git config --global user.name "Gitea Actions [bot]" + git config --global user.email "actions@yannick-weigert.de" + git add lib test + git commit -m "Auto-format code [skip ci]" + git push origin HEAD:${{ gitea.head_ref }} + else + echo "No changes to commit" + fi + + - name: Verify format + run: flutter analyze lib test + + update_version: + runs-on: ubuntu-latest + needs: Format + if: gitea.ref == 'refs/heads/development' + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.BOT_TOKEN }} + ref: ${{ gitea.head_ref }} + + - name: Increment version number + uses: https://github.com/stikkyapp/update-pubspec-version@v2 + with: + strategy: 'patch' + path: './pubspec.yaml' + + + - name: Commit version update + env: + GITEA_TOKEN: ${{ secrets.BOT_TOKEN }} + run: | + git config --global user.name "Gitea Actions [bot]" + git config --global user.email "actions@yannick-weigert.de" + git add pubspec.yaml + git commit -m "Updated version number [skip ci]" + git push origin HEAD:${{ gitea.head_ref }} \ No newline at end of file From eb404f3ef20021763aeb7582390445823eb68bd7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 20 Jan 2026 11:54:15 +0100 Subject: [PATCH 56/64] Fixed push pipeline --- .gitea/workflows/push.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml index dfcee5f..ca931b7 100644 --- a/.gitea/workflows/push.yaml +++ b/.gitea/workflows/push.yaml @@ -5,6 +5,7 @@ on: branches: - "development" - "main" + - "hotfix/*" jobs: test: @@ -63,7 +64,7 @@ jobs: git config --global user.email "actions@yannick-weigert.de" git add lib test git commit -m "Auto-format code [skip ci]" - git push origin HEAD:${{ gitea.head_ref }} + git push origin HEAD:${{ gitea.ref_name }} else echo "No changes to commit" fi @@ -98,4 +99,4 @@ jobs: git config --global user.email "actions@yannick-weigert.de" git add pubspec.yaml git commit -m "Updated version number [skip ci]" - git push origin HEAD:${{ gitea.head_ref }} \ No newline at end of file + git push origin HEAD:${{ gitea.ref_name }} \ No newline at end of file From e9929426e028df8bdd6a6be96354ff389c989f5e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 20 Jan 2026 11:57:17 +0100 Subject: [PATCH 57/64] Removed development restriction --- .gitea/workflows/push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml index ca931b7..bcc94f0 100644 --- a/.gitea/workflows/push.yaml +++ b/.gitea/workflows/push.yaml @@ -75,7 +75,7 @@ jobs: update_version: runs-on: ubuntu-latest needs: Format - if: gitea.ref == 'refs/heads/development' + # if: gitea.ref == 'refs/heads/development' steps: - name: Checkout code uses: actions/checkout@v4 From 4c1c22123e6c995dd0f02ceaa623bb6a092bab0f Mon Sep 17 00:00:00 2001 From: "Gitea Actions [bot]" Date: Tue, 20 Jan 2026 10:59:27 +0000 Subject: [PATCH 58/64] Updated version number [skip ci] --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index a2f8c9d..938c169 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.10+237 +version: 0.0.11+238 environment: sdk: ^3.8.1 From 057f8c1d588516a31fac45545457de3b3bfc42a9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 20 Jan 2026 12:00:33 +0100 Subject: [PATCH 59/64] Changed workflow back to prod mode --- .gitea/workflows/push.yaml | 3 +-- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml index bcc94f0..63a3553 100644 --- a/.gitea/workflows/push.yaml +++ b/.gitea/workflows/push.yaml @@ -5,7 +5,6 @@ on: branches: - "development" - "main" - - "hotfix/*" jobs: test: @@ -75,7 +74,7 @@ jobs: update_version: runs-on: ubuntu-latest needs: Format - # if: gitea.ref == 'refs/heads/development' + if: gitea.ref == 'refs/heads/development' steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/pubspec.yaml b/pubspec.yaml index 938c169..0bb6c98 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.11+238 +version: 0.0.10+238 environment: sdk: ^3.8.1 From bc51b23563535dcb7318ea43c8a87d9b01a7be48 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 20 Jan 2026 12:03:31 +0100 Subject: [PATCH 60/64] Updated ref names --- .gitea/workflows/push.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml index 63a3553..20319e2 100644 --- a/.gitea/workflows/push.yaml +++ b/.gitea/workflows/push.yaml @@ -52,8 +52,8 @@ jobs: env: GITEA_TOKEN: ${{ secrets.BOT_TOKEN }} run: | - git fetch origin ${{ gitea.head_ref }} - git checkout ${{ gitea.head_ref }} + git fetch origin ${{ gitea.ref_name }} + git checkout ${{ gitea.ref_name }} dart fix --apply lib dart fix --apply test @@ -73,7 +73,7 @@ jobs: update_version: runs-on: ubuntu-latest - needs: Format + needs: format if: gitea.ref == 'refs/heads/development' steps: - name: Checkout code @@ -81,7 +81,7 @@ jobs: with: fetch-depth: 0 token: ${{ secrets.BOT_TOKEN }} - ref: ${{ gitea.head_ref }} + ref: ${{ gitea.ref_name }} - name: Increment version number uses: https://github.com/stikkyapp/update-pubspec-version@v2 From 8ee2b6cb067cf082663339dac843bb4c0ff00547 Mon Sep 17 00:00:00 2001 From: "Gitea Actions [bot]" Date: Tue, 20 Jan 2026 14:55:05 +0000 Subject: [PATCH 61/64] Updated version number [skip ci] --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 0bb6c98..c22d107 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.10+238 +version: 0.0.11+239 environment: sdk: ^3.8.1 From 6060afc54323771964c743b7af60cba8866d17f1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 22 Jan 2026 22:13:12 +0100 Subject: [PATCH 62/64] Renamed package & bundle identifier --- android/app/build.gradle.kts | 4 +- .../com/example/game_tracker/MainActivity.kt | 2 +- ios/Runner.xcodeproj/project.pbxproj | 11 +- ios/Runner/Info.plist | 20 +-- lib/core/enums.dart | 2 +- lib/data/dao/group_dao.dart | 10 +- lib/data/dao/group_match_dao.dart | 6 +- lib/data/dao/match_dao.dart | 10 +- lib/data/dao/player_dao.dart | 6 +- lib/data/dao/player_group_dao.dart | 8 +- lib/data/dao/player_match_dao.dart | 6 +- lib/data/db/database.dart | 24 ++-- lib/data/db/database.g.dart | 132 +++++++++--------- lib/data/db/tables/group_match_table.dart | 4 +- lib/data/db/tables/player_group_table.dart | 4 +- lib/data/db/tables/player_match_table.dart | 4 +- lib/data/dto/group.dart | 2 +- lib/data/dto/match.dart | 4 +- lib/main.dart | 8 +- .../main_menu/custom_navigation_bar.dart | 18 +-- .../group_view/create_group_view.dart | 20 +-- .../group_view/group_profile_view.dart | 26 ++-- .../main_menu/group_view/groups_view.dart | 26 ++-- .../views/main_menu/home_view.dart | 26 ++-- .../create_match/choose_game_view.dart | 10 +- .../create_match/choose_group_view.dart | 12 +- .../create_match/create_match_view.dart | 34 ++--- .../match_view/match_result_view.dart | 12 +- .../main_menu/match_view/match_view.dart | 28 ++-- .../licenses/license_detail_view.dart | 8 +- .../settings_view/licenses/oss_licenses.dart | 8 +- .../settings_view/licenses_view.dart | 8 +- .../settings_view/settings_view.dart | 18 +-- .../views/main_menu/statistics_view.dart | 16 +-- .../buttons/animated_dialog_button.dart | 2 +- .../widgets/buttons/custom_width_button.dart | 4 +- .../widgets/buttons/quick_create_button.dart | 2 +- .../widgets/colored_icon_container.dart | 2 +- .../widgets/custom_alert_dialog.dart | 2 +- lib/presentation/widgets/navbar_item.dart | 2 +- .../widgets/player_selection.dart | 20 +-- .../widgets/text_input/custom_search_bar.dart | 2 +- .../widgets/text_input/text_input_field.dart | 2 +- .../widgets/tiles/choose_tile.dart | 2 +- .../widgets/tiles/custom_radio_list_tile.dart | 2 +- .../widgets/tiles/group_tile.dart | 6 +- lib/presentation/widgets/tiles/info_tile.dart | 2 +- .../widgets/tiles/license_tile.dart | 8 +- .../widgets/tiles/match_tile.dart | 10 +- .../widgets/tiles/quick_info_tile.dart | 2 +- .../widgets/tiles/settings_list_tile.dart | 4 +- .../widgets/tiles/statistics_tile.dart | 4 +- .../widgets/tiles/text_icon_list_tile.dart | 2 +- .../widgets/tiles/text_icon_tile.dart | 2 +- .../tiles/title_description_list_tile.dart | 2 +- lib/services/data_transfer_service.dart | 67 +++++---- pubspec.yaml | 4 +- test/db_tests/game_test.dart | 8 +- test/db_tests/group_match_test.dart | 8 +- test/db_tests/group_test.dart | 6 +- test/db_tests/player_group_test.dart | 6 +- test/db_tests/player_match_test.dart | 8 +- test/db_tests/player_test.dart | 4 +- 63 files changed, 373 insertions(+), 359 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index edde6d6..0d5c4b8 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.example.game_tracker" + namespace = "de.liquid.tallee" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.game_tracker" + applicationId = "de.liquid.tallee" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/android/app/src/main/kotlin/com/example/game_tracker/MainActivity.kt b/android/app/src/main/kotlin/com/example/game_tracker/MainActivity.kt index 9790c15..b257cc9 100644 --- a/android/app/src/main/kotlin/com/example/game_tracker/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/game_tracker/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.game_tracker +package de.liquid.tallee import io.flutter.embedding.android.FlutterActivity diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8358b1c..d556582 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -152,7 +152,6 @@ B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */, E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -278,10 +277,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -478,7 +481,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker; + PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -661,7 +664,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker; + PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -684,7 +687,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker; + PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index bf7adb2..7e79382 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -22,13 +24,15 @@ ???? CFBundleVersion $(FLUTTER_BUILD_NUMBER) + LSApplicationQueriesSchemes + + https + http + LSRequiresIPhoneOS - LSApplicationQueriesSchemes - - https - http - + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -44,9 +48,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - \ No newline at end of file + diff --git a/lib/core/enums.dart b/lib/core/enums.dart index 17a01f6..53288e3 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; /// Button types used for styling the [CustomWidthButton] /// - [ButtonType.primary]: Primary button style. diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 98c602a..086cb2d 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -1,9 +1,9 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/group_table.dart'; -import 'package:game_tracker/data/db/tables/player_group_table.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/db/tables/group_table.dart'; +import 'package:tallee/data/db/tables/player_group_table.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/player.dart'; part 'group_dao.g.dart'; diff --git a/lib/data/dao/group_match_dao.dart b/lib/data/dao/group_match_dao.dart index d428fb5..de2eaf1 100644 --- a/lib/data/dao/group_match_dao.dart +++ b/lib/data/dao/group_match_dao.dart @@ -1,7 +1,7 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/group_match_table.dart'; -import 'package:game_tracker/data/dto/group.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/db/tables/group_match_table.dart'; +import 'package:tallee/data/dto/group.dart'; part 'group_match_dao.g.dart'; diff --git a/lib/data/dao/match_dao.dart b/lib/data/dao/match_dao.dart index 160686a..cc3a37f 100644 --- a/lib/data/dao/match_dao.dart +++ b/lib/data/dao/match_dao.dart @@ -1,9 +1,9 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/match_table.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/db/tables/match_table.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; part 'match_dao.g.dart'; diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index c8db800..8ac21f6 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -1,7 +1,7 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/player_table.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/db/tables/player_table.dart'; +import 'package:tallee/data/dto/player.dart'; part 'player_dao.g.dart'; diff --git a/lib/data/dao/player_group_dao.dart b/lib/data/dao/player_group_dao.dart index db45735..23da0c1 100644 --- a/lib/data/dao/player_group_dao.dart +++ b/lib/data/dao/player_group_dao.dart @@ -1,8 +1,8 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/player_group_table.dart'; -import 'package:game_tracker/data/db/tables/player_table.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/db/tables/player_group_table.dart'; +import 'package:tallee/data/db/tables/player_table.dart'; +import 'package:tallee/data/dto/player.dart'; part 'player_group_dao.g.dart'; diff --git a/lib/data/dao/player_match_dao.dart b/lib/data/dao/player_match_dao.dart index 7ebaee6..6700e85 100644 --- a/lib/data/dao/player_match_dao.dart +++ b/lib/data/dao/player_match_dao.dart @@ -1,7 +1,7 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/player_match_table.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/db/tables/player_match_table.dart'; +import 'package:tallee/data/dto/player.dart'; part 'player_match_dao.g.dart'; diff --git a/lib/data/db/database.dart b/lib/data/db/database.dart index e6c322f..4c70b21 100644 --- a/lib/data/db/database.dart +++ b/lib/data/db/database.dart @@ -1,18 +1,18 @@ import 'package:drift/drift.dart'; import 'package:drift_flutter/drift_flutter.dart'; -import 'package:game_tracker/data/dao/group_dao.dart'; -import 'package:game_tracker/data/dao/group_match_dao.dart'; -import 'package:game_tracker/data/dao/match_dao.dart'; -import 'package:game_tracker/data/dao/player_dao.dart'; -import 'package:game_tracker/data/dao/player_group_dao.dart'; -import 'package:game_tracker/data/dao/player_match_dao.dart'; -import 'package:game_tracker/data/db/tables/group_match_table.dart'; -import 'package:game_tracker/data/db/tables/group_table.dart'; -import 'package:game_tracker/data/db/tables/match_table.dart'; -import 'package:game_tracker/data/db/tables/player_group_table.dart'; -import 'package:game_tracker/data/db/tables/player_match_table.dart'; -import 'package:game_tracker/data/db/tables/player_table.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:tallee/data/dao/group_dao.dart'; +import 'package:tallee/data/dao/group_match_dao.dart'; +import 'package:tallee/data/dao/match_dao.dart'; +import 'package:tallee/data/dao/player_dao.dart'; +import 'package:tallee/data/dao/player_group_dao.dart'; +import 'package:tallee/data/dao/player_match_dao.dart'; +import 'package:tallee/data/db/tables/group_match_table.dart'; +import 'package:tallee/data/db/tables/group_table.dart'; +import 'package:tallee/data/db/tables/match_table.dart'; +import 'package:tallee/data/db/tables/player_group_table.dart'; +import 'package:tallee/data/db/tables/player_match_table.dart'; +import 'package:tallee/data/db/tables/player_table.dart'; part 'database.g.dart'; diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index 6bc493c..4fa56f9 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -527,6 +527,17 @@ class $MatchTableTable extends MatchTable final GeneratedDatabase attachedDatabase; final String? _alias; $MatchTableTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _winnerIdMeta = const VerificationMeta( + 'winnerId', + ); + @override + late final GeneratedColumn winnerId = GeneratedColumn( + 'winner_id', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); static const VerificationMeta _idMeta = const VerificationMeta('id'); @override late final GeneratedColumn id = GeneratedColumn( @@ -545,17 +556,6 @@ class $MatchTableTable extends MatchTable type: DriftSqlType.string, requiredDuringInsert: true, ); - static const VerificationMeta _winnerIdMeta = const VerificationMeta( - 'winnerId', - ); - @override - late final GeneratedColumn winnerId = GeneratedColumn( - 'winner_id', - aliasedName, - true, - type: DriftSqlType.string, - requiredDuringInsert: false, - ); static const VerificationMeta _createdAtMeta = const VerificationMeta( 'createdAt', ); @@ -568,7 +568,7 @@ class $MatchTableTable extends MatchTable requiredDuringInsert: true, ); @override - List get $columns => [id, name, winnerId, createdAt]; + List get $columns => [winnerId, id, name, createdAt]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -581,6 +581,12 @@ class $MatchTableTable extends MatchTable }) { final context = VerificationContext(); final data = instance.toColumns(true); + if (data.containsKey('winner_id')) { + context.handle( + _winnerIdMeta, + winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta), + ); + } if (data.containsKey('id')) { context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); } else if (isInserting) { @@ -594,12 +600,6 @@ class $MatchTableTable extends MatchTable } else if (isInserting) { context.missing(_nameMeta); } - if (data.containsKey('winner_id')) { - context.handle( - _winnerIdMeta, - winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta), - ); - } if (data.containsKey('created_at')) { context.handle( _createdAtMeta, @@ -617,6 +617,10 @@ class $MatchTableTable extends MatchTable MatchTableData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return MatchTableData( + winnerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}winner_id'], + ), id: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}id'], @@ -625,10 +629,6 @@ class $MatchTableTable extends MatchTable DriftSqlType.string, data['${effectivePrefix}name'], )!, - winnerId: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}winner_id'], - ), createdAt: attachedDatabase.typeMapping.read( DriftSqlType.dateTime, data['${effectivePrefix}created_at'], @@ -643,35 +643,35 @@ class $MatchTableTable extends MatchTable } class MatchTableData extends DataClass implements Insertable { + final String? winnerId; final String id; final String name; - final String? winnerId; final DateTime createdAt; const MatchTableData({ + this.winnerId, required this.id, required this.name, - this.winnerId, required this.createdAt, }); @override Map toColumns(bool nullToAbsent) { final map = {}; - map['id'] = Variable(id); - map['name'] = Variable(name); if (!nullToAbsent || winnerId != null) { map['winner_id'] = Variable(winnerId); } + map['id'] = Variable(id); + map['name'] = Variable(name); map['created_at'] = Variable(createdAt); return map; } MatchTableCompanion toCompanion(bool nullToAbsent) { return MatchTableCompanion( - id: Value(id), - name: Value(name), winnerId: winnerId == null && nullToAbsent ? const Value.absent() : Value(winnerId), + id: Value(id), + name: Value(name), createdAt: Value(createdAt), ); } @@ -682,9 +682,9 @@ class MatchTableData extends DataClass implements Insertable { }) { serializer ??= driftRuntimeOptions.defaultSerializer; return MatchTableData( + winnerId: serializer.fromJson(json['winnerId']), id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), - winnerId: serializer.fromJson(json['winnerId']), createdAt: serializer.fromJson(json['createdAt']), ); } @@ -692,29 +692,29 @@ class MatchTableData extends DataClass implements Insertable { Map toJson({ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return { + 'winnerId': serializer.toJson(winnerId), 'id': serializer.toJson(id), 'name': serializer.toJson(name), - 'winnerId': serializer.toJson(winnerId), 'createdAt': serializer.toJson(createdAt), }; } MatchTableData copyWith({ + Value winnerId = const Value.absent(), String? id, String? name, - Value winnerId = const Value.absent(), DateTime? createdAt, }) => MatchTableData( + winnerId: winnerId.present ? winnerId.value : this.winnerId, id: id ?? this.id, name: name ?? this.name, - winnerId: winnerId.present ? winnerId.value : this.winnerId, createdAt: createdAt ?? this.createdAt, ); MatchTableData copyWithCompanion(MatchTableCompanion data) { return MatchTableData( + winnerId: data.winnerId.present ? data.winnerId.value : this.winnerId, id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, - winnerId: data.winnerId.present ? data.winnerId.value : this.winnerId, createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, ); } @@ -722,75 +722,75 @@ class MatchTableData extends DataClass implements Insertable { @override String toString() { return (StringBuffer('MatchTableData(') + ..write('winnerId: $winnerId, ') ..write('id: $id, ') ..write('name: $name, ') - ..write('winnerId: $winnerId, ') ..write('createdAt: $createdAt') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name, winnerId, createdAt); + int get hashCode => Object.hash(winnerId, id, name, createdAt); @override bool operator ==(Object other) => identical(this, other) || (other is MatchTableData && + other.winnerId == this.winnerId && other.id == this.id && other.name == this.name && - other.winnerId == this.winnerId && other.createdAt == this.createdAt); } class MatchTableCompanion extends UpdateCompanion { + final Value winnerId; final Value id; final Value name; - final Value winnerId; final Value createdAt; final Value rowid; const MatchTableCompanion({ + this.winnerId = const Value.absent(), this.id = const Value.absent(), this.name = const Value.absent(), - this.winnerId = const Value.absent(), this.createdAt = const Value.absent(), this.rowid = const Value.absent(), }); MatchTableCompanion.insert({ + this.winnerId = const Value.absent(), required String id, required String name, - this.winnerId = const Value.absent(), required DateTime createdAt, this.rowid = const Value.absent(), }) : id = Value(id), name = Value(name), createdAt = Value(createdAt); static Insertable custom({ + Expression? winnerId, Expression? id, Expression? name, - Expression? winnerId, Expression? createdAt, Expression? rowid, }) { return RawValuesInsertable({ + if (winnerId != null) 'winner_id': winnerId, if (id != null) 'id': id, if (name != null) 'name': name, - if (winnerId != null) 'winner_id': winnerId, if (createdAt != null) 'created_at': createdAt, if (rowid != null) 'rowid': rowid, }); } MatchTableCompanion copyWith({ + Value? winnerId, Value? id, Value? name, - Value? winnerId, Value? createdAt, Value? rowid, }) { return MatchTableCompanion( + winnerId: winnerId ?? this.winnerId, id: id ?? this.id, name: name ?? this.name, - winnerId: winnerId ?? this.winnerId, createdAt: createdAt ?? this.createdAt, rowid: rowid ?? this.rowid, ); @@ -799,15 +799,15 @@ class MatchTableCompanion extends UpdateCompanion { @override Map toColumns(bool nullToAbsent) { final map = {}; + if (winnerId.present) { + map['winner_id'] = Variable(winnerId.value); + } if (id.present) { map['id'] = Variable(id.value); } if (name.present) { map['name'] = Variable(name.value); } - if (winnerId.present) { - map['winner_id'] = Variable(winnerId.value); - } if (createdAt.present) { map['created_at'] = Variable(createdAt.value); } @@ -820,9 +820,9 @@ class MatchTableCompanion extends UpdateCompanion { @override String toString() { return (StringBuffer('MatchTableCompanion(') + ..write('winnerId: $winnerId, ') ..write('id: $id, ') ..write('name: $name, ') - ..write('winnerId: $winnerId, ') ..write('createdAt: $createdAt, ') ..write('rowid: $rowid') ..write(')')) @@ -2339,17 +2339,17 @@ typedef $$GroupTableTableProcessedTableManager = >; typedef $$MatchTableTableCreateCompanionBuilder = MatchTableCompanion Function({ + Value winnerId, required String id, required String name, - Value winnerId, required DateTime createdAt, Value rowid, }); typedef $$MatchTableTableUpdateCompanionBuilder = MatchTableCompanion Function({ + Value winnerId, Value id, Value name, - Value winnerId, Value createdAt, Value rowid, }); @@ -2414,6 +2414,11 @@ class $$MatchTableTableFilterComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); + ColumnFilters get winnerId => $composableBuilder( + column: $table.winnerId, + builder: (column) => ColumnFilters(column), + ); + ColumnFilters get id => $composableBuilder( column: $table.id, builder: (column) => ColumnFilters(column), @@ -2424,11 +2429,6 @@ class $$MatchTableTableFilterComposer builder: (column) => ColumnFilters(column), ); - ColumnFilters get winnerId => $composableBuilder( - column: $table.winnerId, - builder: (column) => ColumnFilters(column), - ); - ColumnFilters get createdAt => $composableBuilder( column: $table.createdAt, builder: (column) => ColumnFilters(column), @@ -2494,6 +2494,11 @@ class $$MatchTableTableOrderingComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); + ColumnOrderings get winnerId => $composableBuilder( + column: $table.winnerId, + builder: (column) => ColumnOrderings(column), + ); + ColumnOrderings get id => $composableBuilder( column: $table.id, builder: (column) => ColumnOrderings(column), @@ -2504,11 +2509,6 @@ class $$MatchTableTableOrderingComposer builder: (column) => ColumnOrderings(column), ); - ColumnOrderings get winnerId => $composableBuilder( - column: $table.winnerId, - builder: (column) => ColumnOrderings(column), - ); - ColumnOrderings get createdAt => $composableBuilder( column: $table.createdAt, builder: (column) => ColumnOrderings(column), @@ -2524,15 +2524,15 @@ class $$MatchTableTableAnnotationComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); + GeneratedColumn get winnerId => + $composableBuilder(column: $table.winnerId, builder: (column) => column); + GeneratedColumn get id => $composableBuilder(column: $table.id, builder: (column) => column); GeneratedColumn get name => $composableBuilder(column: $table.name, builder: (column) => column); - GeneratedColumn get winnerId => - $composableBuilder(column: $table.winnerId, builder: (column) => column); - GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); @@ -2618,29 +2618,29 @@ class $$MatchTableTableTableManager $$MatchTableTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ + Value winnerId = const Value.absent(), Value id = const Value.absent(), Value name = const Value.absent(), - Value winnerId = const Value.absent(), Value createdAt = const Value.absent(), Value rowid = const Value.absent(), }) => MatchTableCompanion( + winnerId: winnerId, id: id, name: name, - winnerId: winnerId, createdAt: createdAt, rowid: rowid, ), createCompanionCallback: ({ + Value winnerId = const Value.absent(), required String id, required String name, - Value winnerId = const Value.absent(), required DateTime createdAt, Value rowid = const Value.absent(), }) => MatchTableCompanion.insert( + winnerId: winnerId, id: id, name: name, - winnerId: winnerId, createdAt: createdAt, rowid: rowid, ), diff --git a/lib/data/db/tables/group_match_table.dart b/lib/data/db/tables/group_match_table.dart index 3f77dcb..a12e83b 100644 --- a/lib/data/db/tables/group_match_table.dart +++ b/lib/data/db/tables/group_match_table.dart @@ -1,6 +1,6 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/tables/group_table.dart'; -import 'package:game_tracker/data/db/tables/match_table.dart'; +import 'package:tallee/data/db/tables/group_table.dart'; +import 'package:tallee/data/db/tables/match_table.dart'; class GroupMatchTable extends Table { TextColumn get groupId => diff --git a/lib/data/db/tables/player_group_table.dart b/lib/data/db/tables/player_group_table.dart index da2521b..8d484ef 100644 --- a/lib/data/db/tables/player_group_table.dart +++ b/lib/data/db/tables/player_group_table.dart @@ -1,6 +1,6 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/tables/group_table.dart'; -import 'package:game_tracker/data/db/tables/player_table.dart'; +import 'package:tallee/data/db/tables/group_table.dart'; +import 'package:tallee/data/db/tables/player_table.dart'; class PlayerGroupTable extends Table { TextColumn get playerId => diff --git a/lib/data/db/tables/player_match_table.dart b/lib/data/db/tables/player_match_table.dart index e155cd5..13ef36f 100644 --- a/lib/data/db/tables/player_match_table.dart +++ b/lib/data/db/tables/player_match_table.dart @@ -1,6 +1,6 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/tables/match_table.dart'; -import 'package:game_tracker/data/db/tables/player_table.dart'; +import 'package:tallee/data/db/tables/match_table.dart'; +import 'package:tallee/data/db/tables/player_table.dart'; class PlayerMatchTable extends Table { TextColumn get playerId => diff --git a/lib/data/dto/group.dart b/lib/data/dto/group.dart index 92dbd09..f02d98f 100644 --- a/lib/data/dto/group.dart +++ b/lib/data/dto/group.dart @@ -1,5 +1,5 @@ import 'package:clock/clock.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/dto/player.dart'; import 'package:uuid/uuid.dart'; class Group { diff --git a/lib/data/dto/match.dart b/lib/data/dto/match.dart index 9570f66..d3a8333 100644 --- a/lib/data/dto/match.dart +++ b/lib/data/dto/match.dart @@ -1,6 +1,6 @@ import 'package:clock/clock.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/player.dart'; import 'package:uuid/uuid.dart'; class Match { diff --git a/lib/main.dart b/lib/main.dart index 2f64e2e..0002531 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/custom_navigation_bar.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/custom_navigation_bar.dart'; void main() { runApp( diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index a110419..9e81a34 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -1,15 +1,15 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:game_tracker/core/adaptive_page_route.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/group_view/groups_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/home_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/match_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/settings_view/settings_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/statistics_view.dart'; -import 'package:game_tracker/presentation/widgets/navbar_item.dart'; +import 'package:tallee/core/adaptive_page_route.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/group_view/groups_view.dart'; +import 'package:tallee/presentation/views/main_menu/home_view.dart'; +import 'package:tallee/presentation/views/main_menu/match_view/match_view.dart'; +import 'package:tallee/presentation/views/main_menu/settings_view/settings_view.dart'; +import 'package:tallee/presentation/views/main_menu/statistics_view.dart'; +import 'package:tallee/presentation/widgets/navbar_item.dart'; class CustomNavigationBar extends StatefulWidget { /// A custom navigation bar widget that provides tabbed navigation diff --git a/lib/presentation/views/main_menu/group_view/create_group_view.dart b/lib/presentation/views/main_menu/group_view/create_group_view.dart index 4b34095..2b7ab86 100644 --- a/lib/presentation/views/main_menu/group_view/create_group_view.dart +++ b/lib/presentation/views/main_menu/group_view/create_group_view.dart @@ -1,15 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/constants.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; -import 'package:game_tracker/presentation/widgets/player_selection.dart'; -import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/constants.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:tallee/presentation/widgets/player_selection.dart'; +import 'package:tallee/presentation/widgets/text_input/text_input_field.dart'; class CreateGroupView extends StatefulWidget { /// A view that allows the user to create a new group diff --git a/lib/presentation/views/main_menu/group_view/group_profile_view.dart b/lib/presentation/views/main_menu/group_view/group_profile_view.dart index b46fcbe..d4b71ab 100644 --- a/lib/presentation/views/main_menu/group_view/group_profile_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_profile_view.dart @@ -1,19 +1,19 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/animated_dialog_button.dart'; -import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; -import 'package:game_tracker/presentation/widgets/custom_alert_dialog.dart'; -import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; -import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart'; +import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart'; +import 'package:tallee/presentation/widgets/colored_icon_container.dart'; +import 'package:tallee/presentation/widgets/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/tiles/info_tile.dart'; +import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart'; class GroupProfileView extends StatefulWidget { /// A view that displays the profile of a group diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart index 81922f5..6035fc8 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -1,18 +1,18 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/adaptive_page_route.dart'; -import 'package:game_tracker/core/constants.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/group_view/group_profile_view.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; -import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; -import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/adaptive_page_route.dart'; +import 'package:tallee/core/constants.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/group_view/create_group_view.dart'; +import 'package:tallee/presentation/views/main_menu/group_view/group_profile_view.dart'; +import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart'; +import 'package:tallee/presentation/widgets/tiles/group_tile.dart'; +import 'package:tallee/presentation/widgets/top_centered_message.dart'; class GroupsView extends StatefulWidget { /// A view that displays a list of groups diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index f28341e..63617b2 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -1,18 +1,18 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/adaptive_page_route.dart'; -import 'package:game_tracker/core/constants.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/quick_create_button.dart'; -import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; -import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart'; -import 'package:game_tracker/presentation/widgets/tiles/quick_info_tile.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/adaptive_page_route.dart'; +import 'package:tallee/core/constants.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart'; +import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/buttons/quick_create_button.dart'; +import 'package:tallee/presentation/widgets/tiles/info_tile.dart'; +import 'package:tallee/presentation/widgets/tiles/match_tile.dart'; +import 'package:tallee/presentation/widgets/tiles/quick_info_tile.dart'; class HomeView extends StatefulWidget { /// The main home view of the application, displaying quick info, diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart index 3ff6e79..447b9c5 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart'; -import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart'; +import 'package:tallee/presentation/widgets/tiles/title_description_list_tile.dart'; class ChooseGameView extends StatefulWidget { /// A view that allows the user to choose a game from a list of available games diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart index 592d765..9c60b16 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart'; -import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; -import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart'; +import 'package:tallee/presentation/widgets/tiles/group_tile.dart'; +import 'package:tallee/presentation/widgets/top_centered_message.dart'; class ChooseGroupView extends StatefulWidget { /// A view that allows the user to choose a group from a list of groups. diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index 2f512bb..8182ddb 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -1,21 +1,21 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/adaptive_page_route.dart'; -import 'package:game_tracker/core/constants.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_game_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_group_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; -import 'package:game_tracker/presentation/widgets/player_selection.dart'; -import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart'; -import 'package:game_tracker/presentation/widgets/tiles/choose_tile.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/adaptive_page_route.dart'; +import 'package:tallee/core/constants.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_game_view.dart'; +import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_group_view.dart'; +import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart'; +import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:tallee/presentation/widgets/player_selection.dart'; +import 'package:tallee/presentation/widgets/text_input/text_input_field.dart'; +import 'package:tallee/presentation/widgets/tiles/choose_tile.dart'; class CreateMatchView extends StatefulWidget { /// A view that allows creating a new match @@ -230,6 +230,6 @@ class _CreateMatchViewState extends State { /// - Either a group is selected OR at least 2 players are selected bool _enableCreateGameButton() { return (selectedGroup != null || - (selectedPlayers != null && selectedPlayers!.length > 1)); + (selectedPlayers != null && selectedPlayers!.length > 1)); } } diff --git a/lib/presentation/views/main_menu/match_view/match_result_view.dart b/lib/presentation/views/main_menu/match_view/match_result_view.dart index 1deb385..75015f0 100644 --- a/lib/presentation/views/main_menu/match_view/match_result_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_result_view.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/tiles/custom_radio_list_tile.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/tiles/custom_radio_list_tile.dart'; class MatchResultView extends StatefulWidget { /// A view that allows selecting and saving the winner of a match diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index e85bf77..c34a22f 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -2,21 +2,21 @@ import 'dart:core' hide Match; import 'package:flutter/material.dart'; import 'package:fluttericon/rpg_awesome_icons.dart'; -import 'package:game_tracker/core/adaptive_page_route.dart'; -import 'package:game_tracker/core/constants.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/create_match_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; -import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart'; -import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/adaptive_page_route.dart'; +import 'package:tallee/core/constants.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart'; +import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart'; +import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart'; +import 'package:tallee/presentation/widgets/tiles/match_tile.dart'; +import 'package:tallee/presentation/widgets/top_centered_message.dart'; class MatchView extends StatefulWidget { /// A view that displays a list of matches diff --git a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart index 5c48592..6e58108 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; +import 'package:tallee/presentation/widgets/colored_icon_container.dart'; import 'package:url_launcher/url_launcher.dart'; class LicenseDetailView extends StatelessWidget { diff --git a/lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart b/lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart index ef1109c..363ca24 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart @@ -8,7 +8,7 @@ // https://pub.dev/packages/dart_pubspec_licenses /// This package. -const thisPackage = _game_tracker; +const thisPackage = _tallee; /// All dependencies including transitive dependencies. const allDependencies = [ @@ -7291,9 +7291,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', ); -/// game_tracker 0.0.5+127 -const _game_tracker = Package( - name: 'game_tracker', +/// tallee 0.0.5+127 +const _tallee = Package( + name: 'tallee', description: 'Game Tracking App for Card Games', authors: [], version: '0.0.5+127', diff --git a/lib/presentation/views/main_menu/settings_view/licenses_view.dart b/lib/presentation/views/main_menu/settings_view/licenses_view.dart index 58aae5b..ed98c26 100644 --- a/lib/presentation/views/main_menu/settings_view/licenses_view.dart +++ b/lib/presentation/views/main_menu/settings_view/licenses_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; -import 'package:game_tracker/presentation/widgets/tiles/license_tile.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; +import 'package:tallee/presentation/widgets/tiles/license_tile.dart'; class LicensesView extends StatelessWidget { /// A view that displays a list of open source licenses used in the app diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index 244610e..d063e7c 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -3,16 +3,16 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses_view.dart'; -import 'package:game_tracker/presentation/widgets/buttons/animated_dialog_button.dart'; -import 'package:game_tracker/presentation/widgets/custom_alert_dialog.dart'; -import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart'; -import 'package:game_tracker/services/data_transfer_service.dart'; import 'package:intl/intl.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/views/main_menu/settings_view/licenses_view.dart'; +import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart'; +import 'package:tallee/presentation/widgets/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/tiles/settings_list_tile.dart'; +import 'package:tallee/services/data_transfer_service.dart'; import 'package:url_launcher/url_launcher.dart'; class SettingsView extends StatefulWidget { @@ -88,7 +88,7 @@ class _SettingsViewState extends State { ); final result = await DataTransferService.exportData( json, - 'game_tracker-data', + 'tallee-data', ); if (!scaffoldMessengerContext.mounted) return; showExportSnackBar( diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index f87a3fb..e552e54 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/constants.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/tiles/statistics_tile.dart'; -import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/constants.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/tiles/statistics_tile.dart'; +import 'package:tallee/presentation/widgets/top_centered_message.dart'; class StatisticsView extends StatefulWidget { /// A view that displays player statistics diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart index 65c0510..798edfa 100644 --- a/lib/presentation/widgets/buttons/animated_dialog_button.dart +++ b/lib/presentation/widgets/buttons/animated_dialog_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class AnimatedDialogButton extends StatefulWidget { /// A custom animated button widget that provides a scaling and opacity effect diff --git a/lib/presentation/widgets/buttons/custom_width_button.dart b/lib/presentation/widgets/buttons/custom_width_button.dart index 8d45540..489ceae 100644 --- a/lib/presentation/widgets/buttons/custom_width_button.dart +++ b/lib/presentation/widgets/buttons/custom_width_button.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; class CustomWidthButton extends StatelessWidget { /// A custom button widget that is designed to have a width relative to the screen size. diff --git a/lib/presentation/widgets/buttons/quick_create_button.dart b/lib/presentation/widgets/buttons/quick_create_button.dart index 6dc9876..f3aa588 100644 --- a/lib/presentation/widgets/buttons/quick_create_button.dart +++ b/lib/presentation/widgets/buttons/quick_create_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class QuickCreateButton extends StatefulWidget { /// A button widget designed for quick creating matches in the [HomeView] diff --git a/lib/presentation/widgets/colored_icon_container.dart b/lib/presentation/widgets/colored_icon_container.dart index 2cc97e2..fe0659f 100644 --- a/lib/presentation/widgets/colored_icon_container.dart +++ b/lib/presentation/widgets/colored_icon_container.dart @@ -1,5 +1,5 @@ import 'package:flutter/cupertino.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class ColoredIconContainer extends StatelessWidget { /// A customizable container widget that displays an icon with a colored background. diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/custom_alert_dialog.dart index 5ca2b15..84843b7 100644 --- a/lib/presentation/widgets/custom_alert_dialog.dart +++ b/lib/presentation/widgets/custom_alert_dialog.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class CustomAlertDialog extends StatelessWidget { /// A custom alert dialog widget that provides a os unspecific AlertDialog, diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index 45f2976..0b08371 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class NavbarItem extends StatefulWidget { /// A navigation bar item widget that represents a single tab in a navigation bar. diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index 58b62ec..bb3e3b9 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -1,15 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/constants.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart'; -import 'package:game_tracker/presentation/widgets/tiles/text_icon_list_tile.dart'; -import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; -import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/constants.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart'; +import 'package:tallee/presentation/widgets/tiles/text_icon_list_tile.dart'; +import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart'; +import 'package:tallee/presentation/widgets/top_centered_message.dart'; class PlayerSelection extends StatefulWidget { /// A widget that allows users to select players from a list, diff --git a/lib/presentation/widgets/text_input/custom_search_bar.dart b/lib/presentation/widgets/text_input/custom_search_bar.dart index 77f6eba..aeb71f2 100644 --- a/lib/presentation/widgets/text_input/custom_search_bar.dart +++ b/lib/presentation/widgets/text_input/custom_search_bar.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class CustomSearchBar extends StatelessWidget { /// A custom search bar widget that encapsulates a [SearchBar] with additional customization options. diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index bbb3e45..16f5072 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class TextInputField extends StatelessWidget { /// A custom text input field widget that encapsulates a [TextField] with specific styling. diff --git a/lib/presentation/widgets/tiles/choose_tile.dart b/lib/presentation/widgets/tiles/choose_tile.dart index 595816e..10ded6b 100644 --- a/lib/presentation/widgets/tiles/choose_tile.dart +++ b/lib/presentation/widgets/tiles/choose_tile.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class ChooseTile extends StatefulWidget { /// A tile widget that allows users to choose an option by tapping on it. diff --git a/lib/presentation/widgets/tiles/custom_radio_list_tile.dart b/lib/presentation/widgets/tiles/custom_radio_list_tile.dart index 2d8dc7a..2b8e855 100644 --- a/lib/presentation/widgets/tiles/custom_radio_list_tile.dart +++ b/lib/presentation/widgets/tiles/custom_radio_list_tile.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class CustomRadioListTile extends StatelessWidget { /// A custom radio list tile widget that encapsulates a [Radio] button with additional styling and functionality. diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart index c035a04..d662918 100644 --- a/lib/presentation/widgets/tiles/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart'; class GroupTile extends StatefulWidget { /// A tile widget that displays information about a group, including its name and members. diff --git a/lib/presentation/widgets/tiles/info_tile.dart b/lib/presentation/widgets/tiles/info_tile.dart index 78d7f28..fdbd88c 100644 --- a/lib/presentation/widgets/tiles/info_tile.dart +++ b/lib/presentation/widgets/tiles/info_tile.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class InfoTile extends StatefulWidget { /// A tile widget that displays a title with an icon and some content below it. diff --git a/lib/presentation/widgets/tiles/license_tile.dart b/lib/presentation/widgets/tiles/license_tile.dart index 33e5a45..9289ed5 100644 --- a/lib/presentation/widgets/tiles/license_tile.dart +++ b/lib/presentation/widgets/tiles/license_tile.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart'; +import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; +import 'package:tallee/presentation/widgets/colored_icon_container.dart'; class LicenseTile extends StatelessWidget { /// A tile widget that displays information about a software package license. diff --git a/lib/presentation/widgets/tiles/match_tile.dart b/lib/presentation/widgets/tiles/match_tile.dart index e1365c1..ab65e5d 100644 --- a/lib/presentation/widgets/tiles/match_tile.dart +++ b/lib/presentation/widgets/tiles/match_tile.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; import 'package:intl/intl.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart'; class MatchTile extends StatefulWidget { /// A tile widget that displays information about a match, including its name, diff --git a/lib/presentation/widgets/tiles/quick_info_tile.dart b/lib/presentation/widgets/tiles/quick_info_tile.dart index 4d6ef2e..5646fa5 100644 --- a/lib/presentation/widgets/tiles/quick_info_tile.dart +++ b/lib/presentation/widgets/tiles/quick_info_tile.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class QuickInfoTile extends StatefulWidget { /// A tile widget that displays a title with an icon and a numeric value below it. diff --git a/lib/presentation/widgets/tiles/settings_list_tile.dart b/lib/presentation/widgets/tiles/settings_list_tile.dart index d4bc6dc..de805cd 100644 --- a/lib/presentation/widgets/tiles/settings_list_tile.dart +++ b/lib/presentation/widgets/tiles/settings_list_tile.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/presentation/widgets/colored_icon_container.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/presentation/widgets/colored_icon_container.dart'; class SettingsListTile extends StatelessWidget { /// A customizable settings list tile widget that displays an icon, title, and an optional suffix widget. diff --git a/lib/presentation/widgets/tiles/statistics_tile.dart b/lib/presentation/widgets/tiles/statistics_tile.dart index 2ac0dfd..bc2f7b6 100644 --- a/lib/presentation/widgets/tiles/statistics_tile.dart +++ b/lib/presentation/widgets/tiles/statistics_tile.dart @@ -1,8 +1,8 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:game_tracker/l10n/generated/app_localizations.dart'; -import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; +import 'package:tallee/l10n/generated/app_localizations.dart'; +import 'package:tallee/presentation/widgets/tiles/info_tile.dart'; class StatisticsTile extends StatelessWidget { /// A tile widget that displays statistical data using horizontal bars. diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart index e468e95..2b29d41 100644 --- a/lib/presentation/widgets/tiles/text_icon_list_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class TextIconListTile extends StatelessWidget { /// A list tile widget that displays text with an optional icon button. diff --git a/lib/presentation/widgets/tiles/text_icon_tile.dart b/lib/presentation/widgets/tiles/text_icon_tile.dart index 90c32b7..f98e0a7 100644 --- a/lib/presentation/widgets/tiles/text_icon_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_tile.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class TextIconTile extends StatelessWidget { /// A tile widget that displays text with an optional icon that can be tapped. diff --git a/lib/presentation/widgets/tiles/title_description_list_tile.dart b/lib/presentation/widgets/tiles/title_description_list_tile.dart index a963d16..9dc8f33 100644 --- a/lib/presentation/widgets/tiles/title_description_list_tile.dart +++ b/lib/presentation/widgets/tiles/title_description_list_tile.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; +import 'package:tallee/core/custom_theme.dart'; class TitleDescriptionListTile extends StatelessWidget { /// A list tile widget that displays a title and description, with optional highlighting and badge. diff --git a/lib/services/data_transfer_service.dart b/lib/services/data_transfer_service.dart index 8767c59..5863d87 100644 --- a/lib/services/data_transfer_service.dart +++ b/lib/services/data_transfer_service.dart @@ -4,13 +4,13 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; import 'package:json_schema/json_schema.dart'; import 'package:provider/provider.dart'; +import 'package:tallee/core/enums.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; class DataTransferService { /// Deletes all data from the database. @@ -34,22 +34,28 @@ class DataTransferService { 'players': players.map((p) => p.toJson()).toList(), 'groups': groups - .map((g) => { - 'id': g.id, - 'name': g.name, - 'createdAt': g.createdAt.toIso8601String(), - 'memberIds': (g.members).map((m) => m.id).toList(), - }).toList(), + .map( + (g) => { + 'id': g.id, + 'name': g.name, + 'createdAt': g.createdAt.toIso8601String(), + 'memberIds': (g.members).map((m) => m.id).toList(), + }, + ) + .toList(), 'matches': matches - .map((m) => { - 'id': m.id, - 'name': m.name, - 'createdAt': m.createdAt.toIso8601String(), - 'groupId': m.group?.id, - 'playerIds': (m.players ?? []).map((p) => p.id).toList(), - 'winnerId': m.winner?.id, - }).toList(), + .map( + (m) => { + 'id': m.id, + 'name': m.name, + 'createdAt': m.createdAt.toIso8601String(), + 'groupId': m.group?.id, + 'playerIds': (m.players ?? []).map((p) => p.id).toList(), + 'winnerId': m.winner?.id, + }, + ) + .toList(), }; return json.encode(jsonMap); @@ -62,7 +68,7 @@ class DataTransferService { /// [fileName] The desired name for the exported file (without extension). static Future exportData( String jsonString, - String fileName + String fileName, ) async { try { final bytes = Uint8List.fromList(utf8.encode(jsonString)); @@ -76,7 +82,6 @@ class DataTransferService { } else { return ExportResult.success; } - } catch (e, stack) { print('[exportData] $e'); print(stack); @@ -104,11 +109,15 @@ class DataTransferService { final isValid = await _validateJsonSchema(jsonString); if (!isValid) return ImportResult.invalidSchema; - final Map decoded = json.decode(jsonString) as Map; + final Map decoded = + json.decode(jsonString) as Map; - final List playersJson = (decoded['players'] as List?) ?? []; - final List groupsJson = (decoded['groups'] as List?) ?? []; - final List matchesJson = (decoded['matches'] as List?) ?? []; + final List playersJson = + (decoded['players'] as List?) ?? []; + final List groupsJson = + (decoded['groups'] as List?) ?? []; + final List matchesJson = + (decoded['matches'] as List?) ?? []; // Players final List importedPlayers = playersJson @@ -122,7 +131,8 @@ class DataTransferService { // Groups final List importedGroups = groupsJson.map((g) { final map = g as Map; - final memberIds = (map['memberIds'] as List? ?? []).cast(); + final memberIds = (map['memberIds'] as List? ?? []) + .cast(); final members = memberIds .map((id) => playerById[id]) @@ -146,7 +156,8 @@ class DataTransferService { final map = m as Map; final String? groupId = map['groupId'] as String?; - final List playerIds = (map['playerIds'] as List? ?? []).cast(); + final List playerIds = + (map['playerIds'] as List? ?? []).cast(); final String? winnerId = map['winnerId'] as String?; final group = (groupId == null) ? null : groupById[groupId]; @@ -212,4 +223,4 @@ class DataTransferService { return false; } } -} \ No newline at end of file +} diff --git a/pubspec.yaml b/pubspec.yaml index c22d107..50b32b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ -name: game_tracker -description: "Game Tracking App for Card Games" +name: tallee +description: "Tracking App for Card Games" publish_to: 'none' version: 0.0.11+239 diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart index 0ec2cfc..5a6ad25 100644 --- a/test/db_tests/game_test.dart +++ b/test/db_tests/game_test.dart @@ -2,10 +2,10 @@ import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; void main() { late AppDatabase database; diff --git a/test/db_tests/group_match_test.dart b/test/db_tests/group_match_test.dart index 7d812bd..8c5e6e4 100644 --- a/test/db_tests/group_match_test.dart +++ b/test/db_tests/group_match_test.dart @@ -2,10 +2,10 @@ import 'package:clock/clock.dart'; import 'package:drift/drift.dart' hide isNotNull; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; void main() { late AppDatabase database; diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index 5104c65..d87edf3 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -2,9 +2,9 @@ import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/player.dart'; void main() { late AppDatabase database; diff --git a/test/db_tests/player_group_test.dart b/test/db_tests/player_group_test.dart index 2783430..b4a87bc 100644 --- a/test/db_tests/player_group_test.dart +++ b/test/db_tests/player_group_test.dart @@ -2,9 +2,9 @@ import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/player.dart'; void main() { late AppDatabase database; diff --git a/test/db_tests/player_match_test.dart b/test/db_tests/player_match_test.dart index 8a4f569..393d0c0 100644 --- a/test/db_tests/player_match_test.dart +++ b/test/db_tests/player_match_test.dart @@ -2,10 +2,10 @@ import 'package:clock/clock.dart'; import 'package:drift/drift.dart' hide isNotNull; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/match.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/group.dart'; +import 'package:tallee/data/dto/match.dart'; +import 'package:tallee/data/dto/player.dart'; void main() { late AppDatabase database; diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart index 5bd10ad..c2a4547 100644 --- a/test/db_tests/player_test.dart +++ b/test/db_tests/player_test.dart @@ -2,8 +2,8 @@ import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/player.dart'; +import 'package:tallee/data/db/database.dart'; +import 'package:tallee/data/dto/player.dart'; void main() { late AppDatabase database; From ceade5cafdef3a0fcb7f62b6ae08bdfdfe45d5df Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Thu, 22 Jan 2026 22:34:36 +0100 Subject: [PATCH 63/64] Fixed ios laucn screen --- ios/Runner.xcodeproj/project.pbxproj | 4 ---- .../Contents.json | 0 .../LauncherIcon.imageset/Contents.json | 2 +- .../LauncherIcon.imageset/Logo-Rounded.png | Bin 47780 -> 0 bytes .../icon-transparent.png} | Bin .../LauncherIconOnly.imageset/Contents.json | 12 ------------ ios/Runner/Base.lproj/LaunchScreen.storyboard | 14 +++++++------- 7 files changed, 8 insertions(+), 24 deletions(-) rename ios/Runner/Assets.xcassets/{LauncherBackgroundColor.colorset => LauncherColor.colorset}/Contents.json (100%) delete mode 100644 ios/Runner/Assets.xcassets/LauncherIcon.imageset/Logo-Rounded.png rename ios/Runner/Assets.xcassets/{LauncherIconOnly.imageset/Icon-Transparent.png => LauncherIcon.imageset/icon-transparent.png} (100%) delete mode 100644 ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d556582..27638af 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -277,14 +277,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; diff --git a/ios/Runner/Assets.xcassets/LauncherBackgroundColor.colorset/Contents.json b/ios/Runner/Assets.xcassets/LauncherColor.colorset/Contents.json similarity index 100% rename from ios/Runner/Assets.xcassets/LauncherBackgroundColor.colorset/Contents.json rename to ios/Runner/Assets.xcassets/LauncherColor.colorset/Contents.json diff --git a/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json index f17420d..06ddd98 100644 --- a/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json +++ b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Logo-Rounded.png", + "filename" : "icon-transparent.png", "idiom" : "universal" } ], diff --git a/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Logo-Rounded.png b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/Logo-Rounded.png deleted file mode 100644 index a89cc4300729678537a32bb57a10597fd1e47f7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47780 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æK}$}4 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 diff --git a/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Icon-Transparent.png b/ios/Runner/Assets.xcassets/LauncherIcon.imageset/icon-transparent.png similarity index 100% rename from ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Icon-Transparent.png rename to ios/Runner/Assets.xcassets/LauncherIcon.imageset/icon-transparent.png diff --git a/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json b/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json deleted file mode 100644 index 2002cdd..0000000 --- a/ios/Runner/Assets.xcassets/LauncherIconOnly.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "Icon-Transparent.png", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard index a64dcfb..28d0ddf 100644 --- a/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -20,10 +20,6 @@ - - - - + + + + - + @@ -43,8 +43,8 @@ - - + + From 2b7941202a51c28714ff510047a837b070e8e0bf Mon Sep 17 00:00:00 2001 From: "Gitea Actions [bot]" Date: Fri, 23 Jan 2026 12:31:09 +0000 Subject: [PATCH 64/64] Updated version number [skip ci] --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 50b32b7..dd01e83 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: tallee description: "Tracking App for Card Games" publish_to: 'none' -version: 0.0.11+239 +version: 0.0.12+240 environment: sdk: ^3.8.1