diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index e59fae4..3b6529a 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -22,4 +22,13 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { final result = await query.getSingle(); return Game(id: result.id, name: result.name); } + + /// Retrieves the number of games in the database. + Future getGameCount() async { + final count = + await (selectOnly(gameTable)..addColumns([gameTable.id.count()])) + .map((row) => row.read(gameTable.id.count())) + .getSingle(); + return count ?? 0; + } } diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index c1932d3..7dc144d 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -56,4 +56,13 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { ); return rowsAffected > 0; } + + /// Retrieves the number of groups in the database. + Future getGroupCount() async { + final count = + await (selectOnly(groupTable)..addColumns([groupTable.id.count()])) + .map((row) => row.read(groupTable.id.count())) + .getSingle(); + return count ?? 0; + } } diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 1a95b27..42cb822 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -1,25 +1,145 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/presentation/widgets/quick_info_tile.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/presentation/widgets/game_tile.dart'; +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'; -class HomeView extends StatelessWidget { +class HomeView extends StatefulWidget { const HomeView({super.key}); + @override + State createState() => _HomeViewState(); +} + +class _HomeViewState extends State { + late Future _gameCountFuture; + late Future _groupCountFuture; + + @override + initState() { + super.initState(); + final db = Provider.of(context, listen: false); + _gameCountFuture = db.gameDao.getGameCount(); + _groupCountFuture = db.groupDao.getGroupCount(); + } + @override Widget build(BuildContext context) { - return const Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickInfoTile(title: 'Games', icon: Icons.casino, value: 42), - QuickInfoTile( - title: 'Groups', - icon: Icons.groups_rounded, - value: 5, - ), - ], - ), - ], + 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: 24.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 new file mode 100644 index 0000000..c79a6b7 --- /dev/null +++ b/lib/presentation/widgets/game_tile.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class GameTile extends StatefulWidget { + final String gameTitle; + final String gameType; + final String ruleset; + final String players; + final String winner; + + const GameTile({ + super.key, + required this.gameTitle, + required this.gameType, + required this.ruleset, + required this.players, + required this.winner, + }); + + @override + State createState() => _GameTileState(); +} + +class _GameTileState extends State { + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + widget.gameTitle, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + const SizedBox(width: 5), + Text( + widget.gameType, + 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: 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: 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/quick_create_button.dart b/lib/presentation/widgets/quick_create_button.dart new file mode 100644 index 0000000..3860f1c --- /dev/null +++ b/lib/presentation/widgets/quick_create_button.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class QuickCreateButton extends StatefulWidget { + final String text; + final VoidCallback? onPressed; + const QuickCreateButton({ + super.key, + required this.text, + required this.onPressed, + }); + + @override + State createState() => _QuickCreateButtonState(); +} + +class _QuickCreateButtonState extends State { + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: widget.onPressed, + style: ElevatedButton.styleFrom( + minimumSize: const Size(140, 45), + backgroundColor: CustomTheme.primaryColor, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + ), + child: Text( + widget.text, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + ); + } +} diff --git a/lib/presentation/widgets/tiles/info_tile.dart b/lib/presentation/widgets/tiles/info_tile.dart new file mode 100644 index 0000000..168262e --- /dev/null +++ b/lib/presentation/widgets/tiles/info_tile.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class InfoTile extends StatefulWidget { + final String title; + final IconData icon; + final Widget content; + final EdgeInsets? padding; + final double? height; + final double? width; + const InfoTile({ + super.key, + required this.title, + required this.icon, + required this.content, + this.padding, + this.height, + this.width, + }); + + @override + State createState() => _InfoTileState(); +} + +class _InfoTileState extends State { + @override + Widget build(BuildContext context) { + return Container( + padding: widget.padding ?? const EdgeInsets.all(12), + height: widget.height, + width: widget.width ?? 380, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: CustomTheme.boxColor, + border: Border.all(color: CustomTheme.boxBorder), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + children: [ + Icon(widget.icon), + const SizedBox(width: 5), + Text( + widget.title, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 10), + widget.content, + ], + ), + ); + } +} diff --git a/lib/presentation/widgets/quick_info_tile.dart b/lib/presentation/widgets/tiles/quick_info_tile.dart similarity index 82% rename from lib/presentation/widgets/quick_info_tile.dart rename to lib/presentation/widgets/tiles/quick_info_tile.dart index 69ab5c6..423b8d3 100644 --- a/lib/presentation/widgets/quick_info_tile.dart +++ b/lib/presentation/widgets/tiles/quick_info_tile.dart @@ -5,11 +5,17 @@ class QuickInfoTile extends StatefulWidget { final String title; final IconData icon; final int value; + final double? height; + final double? width; + final EdgeInsets? padding; const QuickInfoTile({ super.key, required this.title, required this.icon, required this.value, + this.height, + this.width, + this.padding, }); @override @@ -20,9 +26,9 @@ class _QuickInfoTileState extends State { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.all(12), - height: 110, - width: 180, + padding: widget.padding ?? const EdgeInsets.all(12), + height: widget.height ?? 110, + width: widget.width ?? 180, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: CustomTheme.boxColor, @@ -33,7 +39,7 @@ class _QuickInfoTileState extends State { children: [ Row( children: [ - const Icon(Icons.casino), + Icon(widget.icon), const SizedBox(width: 5), Text( widget.title,