Merge branch 'feature/1-homeview-erstellen' into development

This commit is contained in:
2025-11-11 21:10:31 +01:00
7 changed files with 347 additions and 20 deletions

View File

@@ -22,4 +22,13 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
final result = await query.getSingle();
return Game(id: result.id, name: result.name);
}
/// Retrieves the number of games in the database.
Future<int> getGameCount() async {
final count =
await (selectOnly(gameTable)..addColumns([gameTable.id.count()]))
.map((row) => row.read(gameTable.id.count()))
.getSingle();
return count ?? 0;
}
}

View File

@@ -56,4 +56,13 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
);
return rowsAffected > 0;
}
/// Retrieves the number of groups in the database.
Future<int> getGroupCount() async {
final count =
await (selectOnly(groupTable)..addColumns([groupTable.id.count()]))
.map((row) => row.read(groupTable.id.count()))
.getSingle();
return count ?? 0;
}
}

View File

@@ -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<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
late Future<int> _gameCountFuture;
late Future<int> _groupCountFuture;
@override
initState() {
super.initState();
final db = Provider.of<AppDatabase>(context, listen: false);
_gameCountFuture = db.gameDao.getGameCount();
_groupCountFuture = db.groupDao.getGroupCount();
}
@override
Widget build(BuildContext context) {
return const Column(
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FutureBuilder<int>(
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<int>(
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: [
QuickInfoTile(title: 'Games', icon: Icons.casino, value: 42),
QuickInfoTile(
title: 'Groups',
icon: Icons.groups_rounded,
value: 5,
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: () {}),
],
),
],
),
),
],
),
);
},
);
}
}

View File

@@ -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<GameTile> createState() => _GameTileState();
}
class _GameTileState extends State<GameTile> {
@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,
),
),
],
),
),
),
],
);
}
}

View File

@@ -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<QuickCreateButton> createState() => _QuickCreateButtonState();
}
class _QuickCreateButtonState extends State<QuickCreateButton> {
@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),
),
);
}
}

View File

@@ -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<InfoTile> createState() => _InfoTileState();
}
class _InfoTileState extends State<InfoTile> {
@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,
],
),
);
}
}

View File

@@ -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<QuickInfoTile> {
@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<QuickInfoTile> {
children: [
Row(
children: [
const Icon(Icons.casino),
Icon(widget.icon),
const SizedBox(width: 5),
Text(
widget.title,