From dfe99a85a180581bda877a4f0fd1b9a657cdbe2e Mon Sep 17 00:00:00 2001 From: tikaiz Date: Fri, 13 Mar 2026 15:25:44 +0100 Subject: [PATCH] Styling of Tournament list and detail page --- docs/prompts.md | 7 +- .../lib/pages/tournament_detail_page.dart | 102 ++++++++++-------- .../widgets/available_tournament_list.dart | 97 ++++++++++++----- 3 files changed, 133 insertions(+), 73 deletions(-) diff --git a/docs/prompts.md b/docs/prompts.md index 305490a..7bd58ad 100644 --- a/docs/prompts.md +++ b/docs/prompts.md @@ -173,4 +173,9 @@ Folgende Dateien wurden in diesem Prompt verändert: - Always require the full amount of teams for initializing the bracket. Folgende Dateien wurden in diesem Prompt verändert: - backend_splatournament_manager/src/app.ts - - frontend_splatournament_manager/lib/pages/tournament_bracket_page.dart \ No newline at end of file + - frontend_splatournament_manager/lib/pages/tournament_bracket_page.dart + +- Style the tournament list and detail page to look closer to the rest of the app. +Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/widgets/available_tournament_list.dart + - frontend_splatournament_manager/lib/pages/tournament_detail_page.dart \ No newline at end of file diff --git a/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart b/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart index f3450a5..bf4b4e2 100644 --- a/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart +++ b/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart @@ -243,46 +243,50 @@ class _TournamentTeamsWidgetState extends State { ); } return ListView.builder( + padding: const EdgeInsets.fromLTRB(16, 4, 16, 16), itemCount: teams.length, itemBuilder: (context, index) { final team = teams[index]; - return ListTile( - leading: CircleAvatar(child: Text(team.tag)), - title: Text(team.name), - subtitle: team.description.isNotEmpty - ? Text(team.description) - : null, - trailing: IconButton( - icon: Icon( - Icons.remove_circle_outline, - color: Colors.red, - ), - onPressed: () async { - try { - await Provider.of( - context, - listen: false, - ).removeTeamFromTournament( - widget.tournament.id, - team.id, - ); - setState(() { - _teamsFuture = Provider.of( + return Card( + margin: const EdgeInsets.only(bottom: 12), + child: ListTile( + leading: CircleAvatar(child: Text(team.tag)), + title: Text(team.name), + subtitle: team.description.isNotEmpty + ? Text(team.description) + : null, + trailing: IconButton( + icon: const Icon( + Icons.remove_circle_outline, + color: Colors.red, + ), + onPressed: () async { + try { + await Provider.of( context, listen: false, - ).getTeamsByTournament(widget.tournament.id); - }); - } catch (e) { - if (!context.mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Team konnte nicht entfernt werden: ${e.toString().replaceFirst('Exception: ', '')}', + ).removeTeamFromTournament( + widget.tournament.id, + team.id, + ); + setState(() { + _teamsFuture = Provider.of( + context, + listen: false, + ).getTeamsByTournament(widget.tournament.id); + }); + } catch (e) { + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Team konnte nicht entfernt werden: ${e.toString().replaceFirst('Exception: ', '')}', + ), ), - ), - ); - } - }, + ); + } + }, + ), ), ); }, @@ -379,26 +383,34 @@ class DetailHeader extends StatelessWidget { @override Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; return SizedBox( - height: 350, + height: 250, width: double.maxFinite, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadiusDirectional.vertical( - bottom: Radius.circular(8), + borderRadius: const BorderRadiusDirectional.vertical( + bottom: Radius.circular(16), ), - image: DecorationImage( - fit: BoxFit.cover, - //TODO: Replace with proper image - image: NetworkImage( - "https://flutter.dev/assets/image_1.w635.f71cbb614cd16a40bfb87e128278227c.png", - ), + gradient: LinearGradient( + colors: [ + colorScheme.primaryContainer, + colorScheme.secondaryContainer, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), ), - padding: EdgeInsets.fromLTRB(16, 0, 0, 12), + padding: const EdgeInsets.fromLTRB(16, 0, 16, 6), child: Column( - verticalDirection: VerticalDirection.up, children: [ + const SizedBox(height: 80), + Icon( + Icons.emoji_events, + size: 116, + color: colorScheme.onPrimaryContainer.withValues(alpha: 0.7), + ), + Spacer(), Row( children: [ InputChip( diff --git a/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart b/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart index cbd8375..7785f58 100644 --- a/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart +++ b/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart @@ -9,22 +9,24 @@ class AvailableTournamentList extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.fromLTRB(24, 0, 24, 0), - child: Column( - children: [ - const Row(children: [Text('Verfügbare Turniere')]), - SizedBox( - width: double.infinity, - height: 350, - child: Consumer( - builder: (context, provider, _) { - return TournamentListFutureBuilder(provider: provider); - }, - ), + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.fromLTRB(16, 8, 16, 4), + child: Text( + 'Verfügbare Turniere', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), - ], - ), + ), + Expanded( + child: Consumer( + builder: (context, provider, _) { + return TournamentListFutureBuilder(provider: provider); + }, + ), + ), + ], ); } } @@ -58,6 +60,7 @@ class TournamentListFutureBuilder extends StatelessWidget { } return ListView.builder( + padding: const EdgeInsets.fromLTRB(16, 4, 16, 16), shrinkWrap: false, itemCount: list.length, itemBuilder: (context, index) { @@ -70,6 +73,15 @@ class TournamentListFutureBuilder extends StatelessWidget { } } +String _fmtDate(String iso) { + try { + final d = DateTime.parse(iso); + return '${d.day.toString().padLeft(2, '0')}.${d.month.toString().padLeft(2, '0')}.${d.year}'; + } catch (_) { + return iso; + } +} + class TournamentListItem extends StatelessWidget { final Tournament tournament; @@ -77,19 +89,50 @@ class TournamentListItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( - contentPadding: EdgeInsets.all(0), - leading: Icon(Icons.abc), - title: Text(tournament.name), - subtitle: Text(tournament.description), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => TournamentDetailPage(tournament: tournament), + final dateRange = + '${_fmtDate(tournament.registrationStartDate)} – ${_fmtDate(tournament.registrationEndDate)}'; + return Card( + margin: const EdgeInsets.only(bottom: 12), + child: InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + TournamentDetailPage(tournament: tournament), + ), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + children: [ + CircleAvatar( + child: const Icon(Icons.emoji_events), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + tournament.name, + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 4), + Text( + '${tournament.currentTeamAmount}/${tournament.maxTeamAmount} Teams\n$dateRange', + style: const TextStyle(fontSize: 13), + ), + ], + ), + ), + const Icon(Icons.chevron_right), + ], ), - ); - }, + ), + ), ); } }