diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 1e38808..a8b18c8 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -17,7 +17,10 @@ class CustomNavigationBar extends StatefulWidget { class _CustomNavigationBarState extends State with SingleTickerProviderStateMixin { + /// Currently selected tab index int currentIndex = 0; + + /// Key count to force rebuild of tab views int tabKeyCount = 0; @override @@ -119,12 +122,14 @@ class _CustomNavigationBarState extends State ); } + /// Handles tab tap events. Updates the current [index] state. void onTabTapped(int index) { setState(() { currentIndex = index; }); } + /// Returns the title of the current tab based on [currentIndex]. String _currentTabTitle(context) { final loc = AppLocalizations.of(context); switch (currentIndex) { 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 cba22ef..022a4b5 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 @@ -18,15 +18,17 @@ class CreateGroupView extends StatefulWidget { } class _CreateGroupViewState extends State { - final _groupNameController = TextEditingController(); late final AppDatabase db; + /// Controller for the group name input field + final _groupNameController = TextEditingController(); + + /// List of currently selected players List selectedPlayers = []; @override void initState() { super.initState(); - db = Provider.of(context, listen: false); _groupNameController.addListener(() { setState(() {}); 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 c641dde..57d05a4 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -21,7 +21,11 @@ class GroupsView extends StatefulWidget { class _GroupsViewState extends State { late final AppDatabase db; + + /// Loaded groups from the database late List loadedGroups; + + /// Loading state bool isLoading = true; List groups = List.filled( diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 072699e..170adb4 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -21,9 +21,17 @@ class HomeView extends StatefulWidget { 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( @@ -42,32 +50,7 @@ class _HomeViewState extends State { @override void initState() { super.initState(); - final db = Provider.of(context, listen: false); - Future.wait([ - db.matchDao.getMatchCount(), - db.groupDao.getGroupCount(), - db.matchDao.getAllMatches(), - Future.delayed(Constants.minimumSkeletonDuration), - ]).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 (loadedRecentMatches.length < 2) { - recentMatches.add( - Match(name: 'Dummy Match', winner: null, group: null, players: null), - ); - } - if (mounted) { - setState(() { - isLoading = false; - }); - } - }); + loadHomeViewData(); } @override @@ -230,6 +213,40 @@ class _HomeViewState extends State { ); } + /// Loads the data for the HomeView from the database. + /// This includes the match count, group count, and recent matches. + void loadHomeViewData() { + final db = Provider.of(context, listen: false); + Future.wait([ + db.matchDao.getMatchCount(), + db.groupDao.getGroupCount(), + db.matchDao.getAllMatches(), + Future.delayed(Constants.minimumSkeletonDuration), + ]).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 (loadedRecentMatches.length < 2) { + recentMatches.add( + Match(name: 'Dummy Match', winner: null, group: null, players: null), + ); + } + if (mounted) { + setState(() { + isLoading = false; + }); + } + }); + } + + /// Generates a text representation of the players in the match. + /// If the match has a group, it returns the group name and the number of additional players. + /// If there is no group, it returns the count of players. String _getPlayerText(Match game, context) { final loc = AppLocalizations.of(context); if (game.group == null) { 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 18e1e9d..01981e2 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 @@ -20,10 +20,12 @@ class ChooseGameView extends StatefulWidget { } class _ChooseGameViewState extends State { - late int selectedGameIndex; - + /// Controller for the search bar final TextEditingController searchBarController = TextEditingController(); + /// Currently selected game index + late int selectedGameIndex; + @override void initState() { selectedGameIndex = widget.initialGameIndex; 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 5101db6..011b819 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 @@ -136,8 +136,7 @@ class _ChooseGroupViewState extends State { ); } - /// Filters the groups based on the search query. - /// TODO: Maybe implement also targetting player names? + /// Filters the groups based on the search [query]. void filterGroups(String query) { setState(() { if (query.isEmpty) { 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 7a41417..73be471 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 @@ -19,6 +19,7 @@ class ChooseRulesetView extends StatefulWidget { } class _ChooseRulesetViewState extends State { + /// Currently selected ruleset index late int selectedRulesetIndex; @override 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 d3a23ae..775f29d 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 @@ -26,7 +26,6 @@ class CreateMatchView extends StatefulWidget { } class _CreateMatchViewState extends State { - /// Reference to the app database late final AppDatabase db; /// Controller for the match name input field 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 5c455f6..93ebbc6 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 @@ -18,8 +18,12 @@ class MatchResultView extends StatefulWidget { } class _MatchResultViewState extends State { - late final List allPlayers; late final AppDatabase db; + + /// List of all players who participated in the match + late final List allPlayers; + + /// Currently selected winner player Player? _selectedPlayer; @override @@ -132,6 +136,8 @@ class _MatchResultViewState extends State { ); } + /// Handles saving or removing the winner in the database + /// based on the current selection. Future _handleWinnerSaving() async { if (_selectedPlayer == null) { await db.matchDao.removeWinner(matchId: widget.match.id); @@ -144,6 +150,10 @@ class _MatchResultViewState extends State { widget.onWinnerChanged?.call(); } + /// Retrieves all players associated with the given [match]. + /// This includes players directly assigned to the match + /// as well as members of the group (if any). + /// The returned list is sorted alphabetically by player name. List getAllPlayers(Match match) { List players = []; 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 bea2f14..45b957f 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -28,6 +28,8 @@ class _MatchViewState extends State { late final AppDatabase db; bool isLoading = true; + /// Loaded matches from the database, + /// initially filled with skeleton matches List matches = List.filled( 4, Match( @@ -44,7 +46,6 @@ class _MatchViewState extends State { @override void initState() { super.initState(); - db = Provider.of(context, listen: false); loadGames(); } @@ -117,6 +118,7 @@ class _MatchViewState extends State { ); } + /// Loads the games from the database and sorts them by creation date. void loadGames() { Future.wait([ db.matchDao.getAllMatches(), diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index 1125118..a60b854 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -25,28 +25,7 @@ class _StatisticsViewState extends State { @override void initState() { super.initState(); - - final db = Provider.of(context, listen: false); - - Future.wait([ - db.matchDao.getAllMatches(), - db.playerDao.getAllPlayers(), - Future.delayed(Constants.minimumSkeletonDuration), - ]).then((results) async { - if (!mounted) return; - final matches = results[0] as List; - final players = results[1] as List; - winCounts = _calculateWinsForAllPlayers(matches, players, context); - matchCounts = _calculateMatchAmountsForAllPlayers( - matches, - players, - context, - ); - winRates = computeWinRatePercent(wins: winCounts, matches: matchCounts); - setState(() { - isLoading = false; - }); - }); + loadStatisticData(); } @override @@ -118,13 +97,43 @@ class _StatisticsViewState extends State { ); } + /// Loads matches and players from the database + /// and calculates statistics for each player + void loadStatisticData() { + final db = Provider.of(context, listen: false); + + Future.wait([ + db.matchDao.getAllMatches(), + db.playerDao.getAllPlayers(), + Future.delayed(Constants.minimumSkeletonDuration), + ]).then((results) async { + if (!mounted) return; + final matches = results[0] as List; + final players = results[1] as List; + winCounts = _calculateWinsForAllPlayers( + matches: matches, + players: players, + context: context, + ); + matchCounts = _calculateMatchAmountsForAllPlayers( + matches: matches, + players: players, + context: context, + ); + winRates = computeWinRatePercent(wins: winCounts, matches: matchCounts); + setState(() { + isLoading = false; + }); + }); + } + /// Calculates the number of wins for each player /// and returns a sorted list of tuples (playerName, winCount) - List<(String, int)> _calculateWinsForAllPlayers( - List matches, - List players, - BuildContext context, - ) { + List<(String, int)> _calculateWinsForAllPlayers({ + required List matches, + required List players, + required BuildContext context, + }) { List<(String, int)> winCounts = []; final loc = AppLocalizations.of(context); @@ -169,11 +178,11 @@ class _StatisticsViewState extends State { /// Calculates the number of matches played for each player /// and returns a sorted list of tuples (playerName, matchCount) - List<(String, int)> _calculateMatchAmountsForAllPlayers( - List matches, - List players, - BuildContext context, - ) { + List<(String, int)> _calculateMatchAmountsForAllPlayers({ + required List matches, + required List players, + required BuildContext context, + }) { List<(String, int)> matchCounts = []; final loc = AppLocalizations.of(context);