7 Commits

Author SHA1 Message Date
4f0a1eec6d refactor
Some checks failed
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Failing after 2m6s
2025-12-21 19:50:34 +01:00
24b60bb18b added minimumSkeletonDuration constant and changed future logic 2025-12-21 19:46:59 +01:00
c8532adfde changed skeleton duration logic in statistics view and refactored 2025-12-21 15:52:02 +01:00
76186787e7 changed futurebuilder logic in player selection 2025-12-21 15:51:24 +01:00
f05114a99e removed futurebuilder logic in groups_view 2025-12-21 15:50:39 +01:00
d96494f608 Changed futurebuilder logic in groups_view 2025-12-21 15:50:24 +01:00
0eaf3d251b added constant minimumSkeletonDuration 2025-12-21 15:49:58 +01:00
7 changed files with 99 additions and 147 deletions

2
lib/core/constants.dart Normal file
View File

@@ -0,0 +1,2 @@
/// Minimum duration of all app skeletons
Duration minimumSkeletonDuration = Duration(milliseconds: 250);

View File

@@ -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/data/db/database.dart';
import 'package:game_tracker/data/dto/group.dart';
@@ -34,10 +35,10 @@ class _GroupsViewState extends State<GroupsView> {
void initState() {
super.initState();
db = Provider.of<AppDatabase>(context, listen: false);
_allGroupsFuture = Future.delayed(
const Duration(milliseconds: 250),
() => db.groupDao.getAllGroups(),
);
_allGroupsFuture = Future.wait([
db.groupDao.getAllGroups(),
Future.delayed(minimumSkeletonDuration),
]).then((results) => results[0] as List<Group>);
}
@override

View File

@@ -1,4 +1,5 @@
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/group.dart';
import 'package:game_tracker/data/dto/match.dart';
@@ -18,12 +19,10 @@ class HomeView extends StatefulWidget {
}
class _HomeViewState extends State<HomeView> {
late Future<int> _matchCountFuture;
late Future<int> _groupCountFuture;
late Future<List<Match>> _recentMatchesFuture;
bool isLoading = true;
late final List<Match> skeletonData = List.filled(
int matchCount = 0;
int groupCount = 0;
List<Match> recentMatches = List.filled(
2,
Match(
name: 'Skeleton Match',
@@ -39,19 +38,24 @@ class _HomeViewState extends State<HomeView> {
);
@override
initState() {
void initState() {
super.initState();
final db = Provider.of<AppDatabase>(context, listen: false);
_matchCountFuture = db.matchDao.getMatchCount();
_groupCountFuture = db.groupDao.getGroupCount();
_recentMatchesFuture = db.matchDao.getAllMatches();
Future.wait([
_matchCountFuture,
_groupCountFuture,
_recentMatchesFuture,
]).then((_) async {
await Future.delayed(const Duration(milliseconds: 250));
db.matchDao.getMatchCount(),
db.groupDao.getGroupCount(),
db.matchDao.getAllMatches(),
Future.delayed(minimumSkeletonDuration),
]).then((results) {
matchCount = results[0] as int;
groupCount = results[1] as int;
recentMatches = results[2] as List<Match>;
recentMatches =
(recentMatches..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
.take(2)
.toList();
if (mounted) {
setState(() {
isLoading = false;
@@ -73,38 +77,20 @@ class _HomeViewState extends State<HomeView> {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FutureBuilder<int>(
future: _matchCountFuture,
builder: (context, snapshot) {
final int count = (snapshot.hasData)
? snapshot.data!
: 0;
return QuickInfoTile(
QuickInfoTile(
width: constraints.maxWidth * 0.45,
height: constraints.maxHeight * 0.15,
title: 'Matches',
icon: Icons.groups_rounded,
value: count,
);
},
value: matchCount,
),
SizedBox(width: constraints.maxWidth * 0.05),
FutureBuilder<int>(
future: _groupCountFuture,
builder: (context, snapshot) {
final int count =
(snapshot.connectionState == ConnectionState.done &&
snapshot.hasData)
? snapshot.data!
: 0;
return QuickInfoTile(
QuickInfoTile(
width: constraints.maxWidth * 0.45,
height: constraints.maxHeight * 0.15,
title: 'Groups',
icon: Icons.groups_rounded,
value: count,
);
},
value: groupCount,
),
],
),
@@ -116,80 +102,48 @@ class _HomeViewState extends State<HomeView> {
icon: Icons.timer,
content: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
child: FutureBuilder(
future: _recentMatchesFuture,
builder:
(
BuildContext context,
AsyncSnapshot<List<Match>> snapshot,
) {
if (snapshot.hasError) {
return const Center(
heightFactor: 4,
child: Text(
'Error while loading recent matches.',
child: Visibility(
visible: !isLoading,
replacement: const Center(
heightFactor: 12,
child: Text('No recent games available.'),
),
);
}
final List<Match> matches =
(isLoading
? skeletonData
: (snapshot.data ?? [])
..sort(
(a, b) => b.createdAt.compareTo(
a.createdAt,
),
))
.take(2)
.toList();
if (matches.isNotEmpty) {
return Column(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MatchTile(
matchTitle: matches[0].name,
matchTitle: recentMatches[0].name,
game: 'Winner',
ruleset: 'Ruleset',
players: _getPlayerText(matches[0]),
winner: matches[0].winner == null
players: _getPlayerText(recentMatches[0]),
winner: recentMatches[0].winner == null
? 'Match in progress...'
: matches[0].winner!.name,
: recentMatches[0].winner!.name,
),
const Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
),
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Divider(),
),
if (matches.length > 1) ...[
if (recentMatches.length > 1) ...[
MatchTile(
matchTitle: matches[1].name,
matchTitle: recentMatches[1].name,
game: 'Winner',
ruleset: 'Ruleset',
players: _getPlayerText(matches[1]),
winner: matches[1].winner == null
players: _getPlayerText(recentMatches[1]),
winner: recentMatches[1].winner == null
? 'Game in progress...'
: matches[1].winner!.name,
: recentMatches[1].winner!.name,
),
const SizedBox(height: 8),
] else ...[
const Center(
heightFactor: 4,
child: Text(
'No second game available.',
),
child: Text('No second game available.'),
),
],
],
);
} else {
return const Center(
heightFactor: 12,
child: Text('No recent games available.'),
);
}
},
),
),
),
),
@@ -199,7 +153,6 @@ class _HomeViewState extends State<HomeView> {
title: 'Quick Create',
icon: Icons.add_box_rounded,
content: Column(
spacing: 8,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,

View File

@@ -28,12 +28,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
/// Reference to the app database
late final AppDatabase db;
/// Futures to load all groups and players from the database
late Future<List<Group>> _allGroupsFuture;
/// Future to load all players from the database
late Future<List<Player>> _allPlayersFuture;
/// Controller for the game name input field
final TextEditingController _gameNameController = TextEditingController();
@@ -107,10 +101,10 @@ class _CreateMatchViewState extends State<CreateMatchView> {
db = Provider.of<AppDatabase>(context, listen: false);
_allGroupsFuture = db.groupDao.getAllGroups();
_allPlayersFuture = db.playerDao.getAllPlayers();
Future.wait([_allGroupsFuture, _allPlayersFuture]).then((result) async {
Future.wait([
db.groupDao.getAllGroups(),
db.playerDao.getAllPlayers(),
]).then((result) async {
groupsList = result[0] as List<Group>;
playerList = result[1] as List<Player>;
});

View File

@@ -2,6 +2,7 @@ import 'dart:core' hide Match;
import 'package:flutter/cupertino.dart';
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/group.dart';
@@ -43,10 +44,10 @@ class _MatchViewState extends State<MatchView> {
void initState() {
super.initState();
db = Provider.of<AppDatabase>(context, listen: false);
_gameListFuture = Future.delayed(
const Duration(milliseconds: 250),
() => db.matchDao.getAllMatches(),
);
_gameListFuture = Future.wait([
db.matchDao.getAllMatches(),
Future.delayed(minimumSkeletonDuration),
]).then((results) => results[0] as List<Match>);
}
@override

View File

@@ -1,4 +1,5 @@
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';
@@ -14,8 +15,6 @@ class StatisticsView extends StatefulWidget {
}
class _StatisticsViewState extends State<StatisticsView> {
late Future<List<Match>> _matchesFuture;
late Future<List<Player>> _playersFuture;
List<(String, int)> winCounts = List.filled(6, ('Skeleton Player', 1));
List<(String, int)> matchCounts = List.filled(6, ('Skeleton Player', 1));
List<(String, double)> winRates = List.filled(6, ('Skeleton Player', 1));
@@ -25,11 +24,12 @@ class _StatisticsViewState extends State<StatisticsView> {
void initState() {
super.initState();
final db = Provider.of<AppDatabase>(context, listen: false);
_matchesFuture = db.matchDao.getAllMatches();
_playersFuture = db.playerDao.getAllPlayers();
Future.wait([_matchesFuture, _playersFuture]).then((results) async {
await Future.delayed(const Duration(milliseconds: 250));
Future.wait([
db.matchDao.getAllMatches(),
db.playerDao.getAllPlayers(),
Future.delayed(minimumSkeletonDuration),
]).then((results) async {
final matches = results[0] as List<Match>;
final players = results[1] as List<Player>;
winCounts = _calculateWinsForAllPlayers(matches, players);

View File

@@ -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/data/db/database.dart';
import 'package:game_tracker/data/dto/player.dart';
@@ -46,10 +47,10 @@ class _PlayerSelectionState extends State<PlayerSelection> {
}
void loadPlayerList() {
_allPlayersFuture = Future.delayed(
const Duration(milliseconds: 250),
() => db.playerDao.getAllPlayers(),
);
_allPlayersFuture = Future.wait([
db.playerDao.getAllPlayers(),
Future.delayed(minimumSkeletonDuration),
]).then((results) => results[0] as List<Player>);
suggestedPlayers = skeletonData;
_allPlayersFuture.then((loadedPlayers) {
setState(() {