From f2626bd5af97315cfc1591c3b2aae45e000d708e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 May 2026 13:42:39 +0200 Subject: [PATCH 01/12] Updated statistics view --- .../views/main_menu/statistics_view.dart | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index 98a8e1d..fc6de83 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -6,6 +6,7 @@ import 'package:tallee/data/models/match.dart'; import 'package:tallee/data/models/player.dart'; import 'package:tallee/l10n/generated/app_localizations.dart'; import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/tiles/quick_info_tile.dart'; import 'package:tallee/presentation/widgets/tiles/statistics_tile.dart'; import 'package:tallee/presentation/widgets/top_centered_message.dart'; @@ -18,6 +19,9 @@ class StatisticsView extends StatefulWidget { } class _StatisticsViewState extends State { + int matchCount = 0; + int groupCount = 0; + List<(Player, int)> winCounts = List.filled(6, ( Player(name: 'Skeleton Player'), 1, @@ -53,7 +57,27 @@ class _StatisticsViewState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ - SizedBox(height: constraints.maxHeight * 0.01), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: loc.matches, + icon: Icons.groups_rounded, + value: matchCount, + ), + SizedBox(width: constraints.maxWidth * 0.05), + QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: loc.groups, + icon: Icons.groups_rounded, + value: groupCount, + ), + ], + ), + SizedBox(height: constraints.maxHeight * 0.02), Visibility( visible: winCounts.isEmpty && @@ -115,11 +139,17 @@ class _StatisticsViewState extends State { Future.wait([ db.matchDao.getAllMatches(), db.playerDao.getAllPlayers(), + db.matchDao.getMatchCount(), + db.groupDao.getGroupCount(), Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) async { if (!mounted) return; + final matches = results[0] as List; final players = results[1] as List; + matchCount = results[2] as int; + groupCount = results[3] as int; + winCounts = _calculateWinsForAllPlayers( matches: matches, players: players, @@ -134,6 +164,7 @@ class _StatisticsViewState extends State { winCounts: winCounts, matchCounts: matchCounts, ); + setState(() { isLoading = false; }); From f8c6d3d0892aa0fb92a646015a9af96a10296206 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 May 2026 13:42:43 +0200 Subject: [PATCH 02/12] Deleted home view --- .../main_menu/custom_navigation_bar.dart | 17 +- .../views/main_menu/home_view.dart | 259 ------------------ 2 files changed, 4 insertions(+), 272 deletions(-) delete mode 100644 lib/presentation/views/main_menu/home_view.dart diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 16316ad..5e23077 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -3,7 +3,6 @@ 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/group_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'; @@ -31,7 +30,6 @@ class _CustomNavigationBarState extends State final loc = AppLocalizations.of(context); // Pretty ugly but works final List tabs = [ - KeyedSubtree(key: ValueKey('home_$tabKeyCount'), child: const HomeView()), KeyedSubtree( key: ValueKey('matches_$tabKeyCount'), child: const MatchView(), @@ -101,27 +99,20 @@ class _CustomNavigationBarState extends State 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, + index: 1, + isSelected: currentIndex == 1, icon: Icons.group_rounded, label: loc.groups, onTabTapped: onTabTapped, ), NavbarItem( - index: 3, - isSelected: currentIndex == 3, + index: 2, + isSelected: currentIndex == 2, icon: Icons.bar_chart_rounded, label: loc.statistics, onTabTapped: onTabTapped, diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart deleted file mode 100644 index 321f12b..0000000 --- a/lib/presentation/views/main_menu/home_view.dart +++ /dev/null @@ -1,259 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:tallee/core/adaptive_page_route.dart'; -import 'package:tallee/core/constants.dart'; -import 'package:tallee/core/enums.dart'; -import 'package:tallee/data/db/database.dart'; -import 'package:tallee/data/models/game.dart'; -import 'package:tallee/data/models/group.dart'; -import 'package:tallee/data/models/match.dart'; -import 'package:tallee/data/models/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, - /// recent matches, and quick create options. - const HomeView({super.key}); - - @override - State createState() => _HomeViewState(); -} - -class _HomeViewState extends State { - bool isLoading = true; - - /// Amount of matches in the database - int matchCount = 0; - - /// Amount of groups in the database - int groupCount = 0; - - /// Loaded recent matches from the database - List loadedRecentMatches = []; - - /// Recent matches to display, initially filled with skeleton matches - List recentMatches = List.filled( - 2, - Match( - name: 'Skeleton Match', - game: Game( - name: 'Skeleton Game', - ruleset: Ruleset.singleWinner, - description: 'This is a skeleton game description.', - color: GameColor.blue, - icon: '', - ), - group: Group( - name: 'Skeleton Group', - description: 'This is a skeleton group description.', - members: [ - Player( - name: - 'Skeleton Player 1' - '', - ), - Player( - name: - 'Skeleton Player 2' - '', - ), - ], - ), - notes: 'These are skeleton notes.', - players: [ - Player( - name: - 'Skeleton Player 1' - '', - ), - Player( - name: - 'Skeleton Player 2' - '', - ), - ], - ), - ); - - @override - void initState() { - super.initState(); - loadHomeViewData(); - } - - @override - Widget build(BuildContext context) { - final loc = AppLocalizations.of(context); - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return AppSkeleton( - fixLayoutBuilder: true, - enabled: isLoading, - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: loc.matches, - icon: Icons.groups_rounded, - value: matchCount, - ), - SizedBox(width: constraints.maxWidth * 0.05), - QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: loc.groups, - icon: Icons.groups_rounded, - value: groupCount, - ), - ], - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: InfoTile( - width: constraints.maxWidth * 0.95, - title: loc.recent_matches, - icon: Icons.history_rounded, - content: Column( - children: [ - if (recentMatches.isNotEmpty) - for (Match match in recentMatches) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 6.0, - ), - child: MatchTile( - compact: true, - width: constraints.maxWidth * 0.9, - match: match, - onTap: () async { - await Navigator.of(context).push( - adaptivePageRoute( - fullscreenDialog: true, - builder: (context) => - MatchResultView(match: match), - ), - ); - await loadRecentMatches(); - - setState(() { - print('loaded'); - }); - }, - ), - ) - else - Center( - heightFactor: 5, - child: Text(loc.no_recent_matches_available), - ), - ], - ), - ), - ), - Padding( - padding: EdgeInsets.zero, - child: InfoTile( - width: constraints.maxWidth * 0.95, - title: loc.quick_create, - icon: Icons.add_box_rounded, - content: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 1', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 2', - onPressed: () {}, - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 3', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 4', - onPressed: () {}, - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 5', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 6', - onPressed: () {}, - ), - ], - ), - ], - ), - ), - ), - SizedBox(height: MediaQuery.paddingOf(context).bottom), - ], - ), - ), - ); - }, - ); - } - - /// Loads the data for the HomeView from the database. - /// This includes the match count, group count, and recent matches. - Future loadHomeViewData() async { - final db = Provider.of(context, listen: false); - Future.wait([ - db.matchDao.getMatchCount(), - db.groupDao.getGroupCount(), - db.matchDao.getAllMatches(), - Future.delayed(Constants.MINIMUM_SKELETON_DURATION), - ]).then((results) { - matchCount = results[0] as int; - groupCount = results[1] as int; - loadedRecentMatches = results[2] as List; - recentMatches = - (loadedRecentMatches - ..sort((a, b) => b.createdAt.compareTo(a.createdAt))) - .take(2) - .toList(); - if (mounted) { - setState(() { - isLoading = false; - }); - } - }); - } - - Future loadRecentMatches() async { - final db = Provider.of(context, listen: false); - final matches = await db.matchDao.getAllMatches(); - recentMatches = - (matches..sort((a, b) => b.createdAt.compareTo(a.createdAt))) - .take(2) - .toList(); - } -} From 87ea5b47eedb1b757dae16c41f95959fcad97470 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 6 May 2026 20:34:55 +0200 Subject: [PATCH 03/12] Improved skeleton data --- .../views/main_menu/match_view/match_view.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) 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 2fb36e7..4f70347 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -10,6 +10,7 @@ import 'package:tallee/data/models/game.dart'; import 'package:tallee/data/models/group.dart'; import 'package:tallee/data/models/match.dart'; import 'package:tallee/data/models/player.dart'; +import 'package:tallee/data/models/score_entry.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_detail_view.dart'; @@ -30,8 +31,7 @@ class _MatchViewState extends State { late final AppDatabase db; bool isLoading = true; - /// Loaded matches from the database, - /// initially filled with skeleton matches + /// Loaded matches from the database, initially filled with skeleton matches List matches = List.filled( 4, Match( @@ -46,7 +46,15 @@ class _MatchViewState extends State { name: 'Group name', members: List.filled(5, Player(name: 'Player')), ), - players: [Player(name: 'Player')], + players: [ + Player(name: 'Player'), + Player(name: 'Player'), + Player(name: 'Player'), + Player(name: 'Player'), + Player(id: 'mvp_id', name: 'Player'), + ], + scores: {'mvp_id': ScoreEntry(score: 1)}, + endedAt: DateTime.now(), ), ); From 34a24c9dec9c5eb640d9276fd2cf9dd1e518e3ac Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Thu, 7 May 2026 20:39:01 +0200 Subject: [PATCH 04/12] Enhance navbar item animations --- lib/presentation/widgets/navbar_item.dart | 117 +++++++++++++--------- 1 file changed, 70 insertions(+), 47 deletions(-) diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index 17c055c..160c000 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -44,24 +44,49 @@ class _NavbarItemState extends State /// Scale animation for the icon when selected late Animation _scaleAnimation; + /// Color animation for the icon + late Animation _iconColorAnimation; + + /// Background color animation for the icon container + late Animation _bgColorAnimation; + + /// Font size animation for the label + late Animation _fontSizeAnimation; + + /// A simple double tween used to lerp between two font weights + late Animation _fontWeightT; + @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 300), vsync: this, + // Set initial value directly so the visual state matches widget.isSelected + value: widget.isSelected ? 1.0 : 0.0, ); - _scaleAnimation = Tween(begin: 1.0, end: 1.2).animate( - CurvedAnimation( - parent: _animationController, - curve: Curves.easeInOutBack, - ), + final curved = CurvedAnimation( + parent: _animationController, + curve: Curves.easeOut, ); - if (widget.isSelected) { - _animationController.forward(); - } + _scaleAnimation = Tween(begin: 1.0, end: 1.2).animate(curved); + + _iconColorAnimation = ColorTween( + begin: CustomTheme.navBarItemUnselectedColor, + end: CustomTheme.navBarItemSelectedColor, + ).animate(curved); + + _bgColorAnimation = ColorTween( + begin: Colors.transparent, + end: CustomTheme.primaryColor.withAlpha(50), + ).animate(curved); + + _fontSizeAnimation = Tween(begin: 11.0, end: 12.0).animate(curved); + + // drives font weight interpolation + _fontWeightT = Tween(begin: 0.0, end: 1.0).animate(curved); } // Retrigger animation on selection change @@ -83,46 +108,44 @@ class _NavbarItemState extends State behavior: HitTestBehavior.opaque, child: Padding( padding: const EdgeInsets.symmetric(vertical: 5.0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AnimatedContainer( - width: 50, - height: 50, - decoration: BoxDecoration( - color: widget.isSelected - ? CustomTheme.primaryColor.withAlpha(50) - : Colors.transparent, - borderRadius: const BorderRadius.all(Radius.circular(15)), - ), - duration: const Duration(milliseconds: 200), - child: ScaleTransition( - scale: widget.isSelected - ? _scaleAnimation - : const AlwaysStoppedAnimation(1.0), - child: Icon( - widget.icon, - color: widget.isSelected - ? CustomTheme.navBarItemSelectedColor - : CustomTheme.navBarItemUnselectedColor, - size: 32, + child: AnimatedBuilder( + animation: _animationController, + builder: (context, child) { + final iconColor = _iconColorAnimation.value!; + final bgColor = _bgColorAnimation.value!; + final fontSize = _fontSizeAnimation.value; + final fontWeight = FontWeight.lerp( + FontWeight.w500, + FontWeight.bold, + _fontWeightT.value, + ); + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: bgColor, + borderRadius: const BorderRadius.all(Radius.circular(15)), + ), + child: ScaleTransition( + scale: _scaleAnimation, + child: Icon(widget.icon, color: iconColor, size: 32), + ), ), - ), - ), - Text( - widget.label, - style: TextStyle( - color: widget.isSelected - ? CustomTheme.navBarItemSelectedColor - : CustomTheme.navBarItemUnselectedColor, - fontSize: widget.isSelected ? 12 : 11, - fontWeight: widget.isSelected - ? FontWeight.bold - : FontWeight.w500, - ), - ), - ], + Text( + widget.label, + style: TextStyle( + color: iconColor, + fontSize: fontSize, + fontWeight: fontWeight, + ), + ), + ], + ); + }, ), ), ), From 4dd794c08ffd2ef0f10618269d51fc367cae881c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 8 May 2026 18:02:00 +0200 Subject: [PATCH 05/12] Applied #212 fix --- lib/presentation/views/main_menu/statistics_view.dart | 4 ++-- lib/presentation/widgets/tiles/quick_info_tile.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index fc6de83..8659a2e 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -62,7 +62,7 @@ class _StatisticsViewState extends State { children: [ QuickInfoTile( width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, + height: constraints.maxHeight * 0.13, title: loc.matches, icon: Icons.groups_rounded, value: matchCount, @@ -70,7 +70,7 @@ class _StatisticsViewState extends State { SizedBox(width: constraints.maxWidth * 0.05), QuickInfoTile( width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, + height: constraints.maxHeight * 0.13, title: loc.groups, icon: Icons.groups_rounded, value: groupCount, diff --git a/lib/presentation/widgets/tiles/quick_info_tile.dart b/lib/presentation/widgets/tiles/quick_info_tile.dart index 5646fa5..79fa513 100644 --- a/lib/presentation/widgets/tiles/quick_info_tile.dart +++ b/lib/presentation/widgets/tiles/quick_info_tile.dart @@ -50,7 +50,7 @@ class _QuickInfoTileState extends State { width: widget.width ?? 180, decoration: CustomTheme.standardBoxDecoration, child: Column( - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ From 23f0c9c23e9a9f398d93c3532744608f66a24b5d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 May 2026 13:42:39 +0200 Subject: [PATCH 06/12] Updated statistics view --- .../views/main_menu/statistics_view.dart | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index 98a8e1d..fc6de83 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -6,6 +6,7 @@ import 'package:tallee/data/models/match.dart'; import 'package:tallee/data/models/player.dart'; import 'package:tallee/l10n/generated/app_localizations.dart'; import 'package:tallee/presentation/widgets/app_skeleton.dart'; +import 'package:tallee/presentation/widgets/tiles/quick_info_tile.dart'; import 'package:tallee/presentation/widgets/tiles/statistics_tile.dart'; import 'package:tallee/presentation/widgets/top_centered_message.dart'; @@ -18,6 +19,9 @@ class StatisticsView extends StatefulWidget { } class _StatisticsViewState extends State { + int matchCount = 0; + int groupCount = 0; + List<(Player, int)> winCounts = List.filled(6, ( Player(name: 'Skeleton Player'), 1, @@ -53,7 +57,27 @@ class _StatisticsViewState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ - SizedBox(height: constraints.maxHeight * 0.01), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: loc.matches, + icon: Icons.groups_rounded, + value: matchCount, + ), + SizedBox(width: constraints.maxWidth * 0.05), + QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: loc.groups, + icon: Icons.groups_rounded, + value: groupCount, + ), + ], + ), + SizedBox(height: constraints.maxHeight * 0.02), Visibility( visible: winCounts.isEmpty && @@ -115,11 +139,17 @@ class _StatisticsViewState extends State { Future.wait([ db.matchDao.getAllMatches(), db.playerDao.getAllPlayers(), + db.matchDao.getMatchCount(), + db.groupDao.getGroupCount(), Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) async { if (!mounted) return; + final matches = results[0] as List; final players = results[1] as List; + matchCount = results[2] as int; + groupCount = results[3] as int; + winCounts = _calculateWinsForAllPlayers( matches: matches, players: players, @@ -134,6 +164,7 @@ class _StatisticsViewState extends State { winCounts: winCounts, matchCounts: matchCounts, ); + setState(() { isLoading = false; }); From 284395bb77953e2e7a5678df77cdd8d1b4a0f66f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 5 May 2026 13:42:43 +0200 Subject: [PATCH 07/12] Deleted home view --- .../main_menu/custom_navigation_bar.dart | 17 +- .../views/main_menu/home_view.dart | 259 ------------------ 2 files changed, 4 insertions(+), 272 deletions(-) delete mode 100644 lib/presentation/views/main_menu/home_view.dart diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 16316ad..5e23077 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -3,7 +3,6 @@ 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/group_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'; @@ -31,7 +30,6 @@ class _CustomNavigationBarState extends State final loc = AppLocalizations.of(context); // Pretty ugly but works final List tabs = [ - KeyedSubtree(key: ValueKey('home_$tabKeyCount'), child: const HomeView()), KeyedSubtree( key: ValueKey('matches_$tabKeyCount'), child: const MatchView(), @@ -101,27 +99,20 @@ class _CustomNavigationBarState extends State 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, + index: 1, + isSelected: currentIndex == 1, icon: Icons.group_rounded, label: loc.groups, onTabTapped: onTabTapped, ), NavbarItem( - index: 3, - isSelected: currentIndex == 3, + index: 2, + isSelected: currentIndex == 2, icon: Icons.bar_chart_rounded, label: loc.statistics, onTabTapped: onTabTapped, diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart deleted file mode 100644 index 627db82..0000000 --- a/lib/presentation/views/main_menu/home_view.dart +++ /dev/null @@ -1,259 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:tallee/core/adaptive_page_route.dart'; -import 'package:tallee/core/constants.dart'; -import 'package:tallee/core/enums.dart'; -import 'package:tallee/data/db/database.dart'; -import 'package:tallee/data/models/game.dart'; -import 'package:tallee/data/models/group.dart'; -import 'package:tallee/data/models/match.dart'; -import 'package:tallee/data/models/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, - /// recent matches, and quick create options. - const HomeView({super.key}); - - @override - State createState() => _HomeViewState(); -} - -class _HomeViewState extends State { - bool isLoading = true; - - /// Amount of matches in the database - int matchCount = 0; - - /// Amount of groups in the database - int groupCount = 0; - - /// Loaded recent matches from the database - List loadedRecentMatches = []; - - /// Recent matches to display, initially filled with skeleton matches - List recentMatches = List.filled( - 2, - Match( - name: 'Skeleton Match', - game: Game( - name: 'Skeleton Game', - ruleset: Ruleset.singleWinner, - description: 'This is a skeleton game description.', - color: GameColor.blue, - icon: '', - ), - group: Group( - name: 'Skeleton Group', - description: 'This is a skeleton group description.', - members: [ - Player( - name: - 'Skeleton Player 1' - '', - ), - Player( - name: - 'Skeleton Player 2' - '', - ), - ], - ), - notes: 'These are skeleton notes.', - players: [ - Player( - name: - 'Skeleton Player 1' - '', - ), - Player( - name: - 'Skeleton Player 2' - '', - ), - ], - ), - ); - - @override - void initState() { - super.initState(); - loadHomeViewData(); - } - - @override - Widget build(BuildContext context) { - final loc = AppLocalizations.of(context); - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return AppSkeleton( - fixLayoutBuilder: true, - enabled: isLoading, - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.13, - title: loc.matches, - icon: Icons.groups_rounded, - value: matchCount, - ), - SizedBox(width: constraints.maxWidth * 0.05), - QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.13, - title: loc.groups, - icon: Icons.groups_rounded, - value: groupCount, - ), - ], - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: InfoTile( - width: constraints.maxWidth * 0.95, - title: loc.recent_matches, - icon: Icons.history_rounded, - content: Column( - children: [ - if (recentMatches.isNotEmpty) - for (Match match in recentMatches) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 6.0, - ), - child: MatchTile( - compact: true, - width: constraints.maxWidth * 0.9, - match: match, - onTap: () async { - await Navigator.of(context).push( - adaptivePageRoute( - fullscreenDialog: true, - builder: (context) => - MatchResultView(match: match), - ), - ); - await loadRecentMatches(); - - setState(() { - print('loaded'); - }); - }, - ), - ) - else - Center( - heightFactor: 5, - child: Text(loc.no_recent_matches_available), - ), - ], - ), - ), - ), - Padding( - padding: EdgeInsets.zero, - child: InfoTile( - width: constraints.maxWidth * 0.95, - title: loc.quick_create, - icon: Icons.add_box_rounded, - content: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 1', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 2', - onPressed: () {}, - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 3', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 4', - onPressed: () {}, - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 5', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 6', - onPressed: () {}, - ), - ], - ), - ], - ), - ), - ), - SizedBox(height: MediaQuery.paddingOf(context).bottom), - ], - ), - ), - ); - }, - ); - } - - /// Loads the data for the HomeView from the database. - /// This includes the match count, group count, and recent matches. - Future loadHomeViewData() async { - final db = Provider.of(context, listen: false); - Future.wait([ - db.matchDao.getMatchCount(), - db.groupDao.getGroupCount(), - db.matchDao.getAllMatches(), - Future.delayed(Constants.MINIMUM_SKELETON_DURATION), - ]).then((results) { - matchCount = results[0] as int; - groupCount = results[1] as int; - loadedRecentMatches = results[2] as List; - recentMatches = - (loadedRecentMatches - ..sort((a, b) => b.createdAt.compareTo(a.createdAt))) - .take(2) - .toList(); - if (mounted) { - setState(() { - isLoading = false; - }); - } - }); - } - - Future loadRecentMatches() async { - final db = Provider.of(context, listen: false); - final matches = await db.matchDao.getAllMatches(); - recentMatches = - (matches..sort((a, b) => b.createdAt.compareTo(a.createdAt))) - .take(2) - .toList(); - } -} From f6dccbfc76076793c2cd5facab7a17837011cd95 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 6 May 2026 20:34:55 +0200 Subject: [PATCH 08/12] Improved skeleton data --- .../views/main_menu/match_view/match_view.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) 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 2fb36e7..4f70347 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -10,6 +10,7 @@ import 'package:tallee/data/models/game.dart'; import 'package:tallee/data/models/group.dart'; import 'package:tallee/data/models/match.dart'; import 'package:tallee/data/models/player.dart'; +import 'package:tallee/data/models/score_entry.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_detail_view.dart'; @@ -30,8 +31,7 @@ class _MatchViewState extends State { late final AppDatabase db; bool isLoading = true; - /// Loaded matches from the database, - /// initially filled with skeleton matches + /// Loaded matches from the database, initially filled with skeleton matches List matches = List.filled( 4, Match( @@ -46,7 +46,15 @@ class _MatchViewState extends State { name: 'Group name', members: List.filled(5, Player(name: 'Player')), ), - players: [Player(name: 'Player')], + players: [ + Player(name: 'Player'), + Player(name: 'Player'), + Player(name: 'Player'), + Player(name: 'Player'), + Player(id: 'mvp_id', name: 'Player'), + ], + scores: {'mvp_id': ScoreEntry(score: 1)}, + endedAt: DateTime.now(), ), ); From cd7e61e2c73d6db315e2ba6f68058525ab26a4f6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 8 May 2026 18:02:00 +0200 Subject: [PATCH 09/12] Applied #212 fix --- lib/presentation/views/main_menu/statistics_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index fc6de83..8659a2e 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -62,7 +62,7 @@ class _StatisticsViewState extends State { children: [ QuickInfoTile( width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, + height: constraints.maxHeight * 0.13, title: loc.matches, icon: Icons.groups_rounded, value: matchCount, @@ -70,7 +70,7 @@ class _StatisticsViewState extends State { SizedBox(width: constraints.maxWidth * 0.05), QuickInfoTile( width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, + height: constraints.maxHeight * 0.13, title: loc.groups, icon: Icons.groups_rounded, value: groupCount, From 514b1c32e7a44ca8b5d6ecce0a652aab1c705958 Mon Sep 17 00:00:00 2001 From: "Gitea Actions [bot]" Date: Fri, 8 May 2026 16:52:14 +0000 Subject: [PATCH 10/12] Updated version number [skip ci] --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 7afeda4..283cbc2 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.25+259 +version: 0.0.26+260 environment: sdk: ^3.8.1 From 3494d397ed192f37e903b82abe153166d712afa1 Mon Sep 17 00:00:00 2001 From: "Gitea Actions [bot]" Date: Fri, 8 May 2026 16:52:55 +0000 Subject: [PATCH 11/12] Updated licenses [skip ci] --- .../views/main_menu/settings_view/licenses/oss_licenses.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 0876c07..a837a65 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 @@ -37676,12 +37676,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', ); -/// tallee 0.0.25+259 +/// tallee 0.0.26+260 const _tallee = Package( name: 'tallee', description: 'Tracking App for Card Games', authors: [], - version: '0.0.25+259', + version: '0.0.26+260', spdxIdentifiers: ['LGPL-3.0'], isMarkdown: false, isSdk: false, From 86a920e9340479858a0610eb519a2a4e6c509dc2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 8 May 2026 23:33:15 +0200 Subject: [PATCH 12/12] fix: tab title --- lib/presentation/views/main_menu/custom_navigation_bar.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 5e23077..bf6ded3 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -136,12 +136,10 @@ class _CustomNavigationBarState extends State final loc = AppLocalizations.of(context); switch (currentIndex) { case 0: - return loc.home; - case 1: return loc.matches; - case 2: + case 1: return loc.groups; - case 3: + case 2: return loc.statistics; default: return '';