diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 141af77..cf6288a 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -5,6 +5,7 @@ import 'package:game_tracker/presentation/widgets/quick_create_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; import 'package:game_tracker/presentation/widgets/tiles/quick_info_tile.dart'; import 'package:provider/provider.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class HomeView extends StatefulWidget { const HomeView({super.key}); @@ -16,6 +17,7 @@ class HomeView extends StatefulWidget { class _HomeViewState extends State { late Future _gameCountFuture; late Future _groupCountFuture; + bool isLoading = true; @override initState() { @@ -23,120 +25,165 @@ class _HomeViewState extends State { final db = Provider.of(context, listen: false); _gameCountFuture = db.gameDao.getGameCount(); _groupCountFuture = db.groupDao.getGroupCount(); + + Future.wait([_gameCountFuture, _groupCountFuture]).then((_) async { + await Future.delayed(const Duration(milliseconds: 50)); + if (mounted) { + setState(() { + isLoading = false; + }); + } + }); } @override Widget build(BuildContext context) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - return SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FutureBuilder( - future: _gameCountFuture, - builder: (context, snapshot) { - final int count = (snapshot.hasData) ? snapshot.data! : 0; - return QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: 'Games', - icon: Icons.groups_rounded, - value: count, - ); - }, - ), - SizedBox(width: constraints.maxWidth * 0.05), - FutureBuilder( - future: _groupCountFuture, - builder: (context, snapshot) { - final int count = - (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) - ? snapshot.data! - : 0; - return QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: 'Groups', - icon: Icons.groups_rounded, - value: count, - ); - }, - ), - ], - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: InfoTile( - width: constraints.maxWidth * 0.95, - title: 'Recent Games', - icon: Icons.timer, - content: const Padding( - padding: EdgeInsets.symmetric(horizontal: 40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GameTile( - gameTitle: 'Gamenight', - gameType: 'Cabo', - ruleset: 'Lowest Points', - players: '5 Players', - winner: 'Leonard', - ), - Padding( - padding: EdgeInsets.symmetric(vertical: 8.0), - child: Divider(), - ), - GameTile( - gameTitle: 'Schoolbreak', - gameType: 'Uno', - ruleset: 'Highest Points', - players: 'The Gang', - winner: 'Lina', - ), - SizedBox(height: 8), - ], - ), - ), - ), - ), - InfoTile( - width: constraints.maxWidth * 0.95, - title: 'Quick Create', - icon: Icons.add_box_rounded, - content: Column( - spacing: 8, + return Skeletonizer( + effect: PulseEffect( + from: Colors.grey[800]!, + to: Colors.grey[600]!, + duration: const Duration(milliseconds: 800), + ), + enabled: isLoading, + enableSwitchAnimation: true, + switchAnimationConfig: const SwitchAnimationConfig( + duration: Duration(milliseconds: 200), + switchInCurve: Curves.linear, + switchOutCurve: Curves.linear, + transitionBuilder: AnimatedSwitcher.defaultTransitionBuilder, + layoutBuilder: AnimatedSwitcher.defaultLayoutBuilder, + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton(text: 'Category 1', onPressed: () {}), - QuickCreateButton(text: 'Category 2', onPressed: () {}), - ], + FutureBuilder( + future: _gameCountFuture, + builder: (context, snapshot) { + final int count = (snapshot.hasData) + ? snapshot.data! + : 0; + return QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: 'Games', + icon: Icons.groups_rounded, + value: count, + ); + }, ), - 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(width: constraints.maxWidth * 0.05), + FutureBuilder( + future: _groupCountFuture, + builder: (context, snapshot) { + final int count = + (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) + ? snapshot.data! + : 0; + return QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: 'Groups', + icon: Icons.groups_rounded, + value: count, + ); + }, ), ], ), - ), - ], + Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: InfoTile( + width: constraints.maxWidth * 0.95, + title: 'Recent Games', + icon: Icons.timer, + content: const Padding( + padding: EdgeInsets.symmetric(horizontal: 40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GameTile( + gameTitle: 'Gamenight', + gameType: 'Cabo', + ruleset: 'Lowest Points', + players: '5 Players', + winner: 'Leonard', + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Divider(), + ), + GameTile( + gameTitle: 'Schoolbreak', + gameType: 'Uno', + ruleset: 'Highest Points', + players: 'The Gang', + winner: 'Lina', + ), + SizedBox(height: 8), + ], + ), + ), + ), + ), + InfoTile( + width: constraints.maxWidth * 0.95, + title: 'Quick Create', + icon: Icons.add_box_rounded, + content: Column( + spacing: 8, + 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: () {}, + ), + ], + ), + ], + ), + ), + ], + ), ), ); }, diff --git a/lib/presentation/widgets/game_tile.dart b/lib/presentation/widgets/game_tile.dart index c79a6b7..fcd2f65 100644 --- a/lib/presentation/widgets/game_tile.dart +++ b/lib/presentation/widgets/game_tile.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class GameTile extends StatefulWidget { final String gameTitle; @@ -48,9 +49,11 @@ class _GameTileState extends State { borderRadius: BorderRadius.circular(4), color: CustomTheme.primaryColor, ), - child: Text( - widget.ruleset, - style: const TextStyle(fontWeight: FontWeight.bold), + child: Skeleton.ignore( + child: Text( + widget.ruleset, + style: const TextStyle(fontWeight: FontWeight.bold), + ), ), ), Center( @@ -68,19 +71,21 @@ class _GameTileState extends State { borderRadius: BorderRadius.circular(4), color: Colors.yellow.shade300, ), - 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, + 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, + ), ), - ), - ], + ], + ), ), ), ),