From cc7faf477bd6892baba179e1ef6c1df8c7bb6320 Mon Sep 17 00:00:00 2001 From: tikaiz Date: Fri, 13 Mar 2026 14:56:39 +0100 Subject: [PATCH] reorganize the profile page, move My Teams from Homepage to profile add sign out button to popup menu in homepage --- docs/prompts.md | 23 +++- .../lib/pages/home_page.dart | 61 +++------ .../lib/pages/settings_page.dart | 31 ++--- .../lib/providers/team_provider.dart | 24 +++- .../lib/widgets/my_teams_widget.dart | 119 ++++++++---------- 5 files changed, 126 insertions(+), 132 deletions(-) diff --git a/docs/prompts.md b/docs/prompts.md index dcb0c61..4b9cd01 100644 --- a/docs/prompts.md +++ b/docs/prompts.md @@ -147,4 +147,25 @@ Folgende Dateien wurden in diesem Prompt verändert: - frontend_splatournament_manager/ios/Runner/Info.plist - frontend_splatournament_manager/linux/runner/my_application.cc - frontend_splatournament_manager/windows/runner/main.cpp - - frontend_splatournament_manager/windows/runner/Runner.rc \ No newline at end of file + - frontend_splatournament_manager/windows/runner/Runner.rc + +- Move the sign out button to the popup menu in the homescreen. +Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/pages/home_page.dart + - frontend_splatournament_manager/lib/pages/settings_page.dart + +- Move only the "Meine Teams" list to the settings menu, keep the "Alle Teams" list in the homescreen but get rid of the top tabbar. +Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/pages/home_page.dart + - frontend_splatournament_manager/lib/pages/settings_page.dart + - frontend_splatournament_manager/lib/widgets/my_teams_widget.dart + +- The member count isn't updated in both lists when joining and leaving a team. +Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/providers/team_provider.dart + - frontend_splatournament_manager/lib/widgets/my_teams_widget.dart + +- Rename the settings page to Profile +Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/pages/settings_page.dart + - frontend_splatournament_manager/lib/pages/home_page.dart \ No newline at end of file diff --git a/frontend_splatournament_manager/lib/pages/home_page.dart b/frontend_splatournament_manager/lib/pages/home_page.dart index 0327133..4873c34 100644 --- a/frontend_splatournament_manager/lib/pages/home_page.dart +++ b/frontend_splatournament_manager/lib/pages/home_page.dart @@ -3,10 +3,10 @@ import 'package:frontend_splatournament_manager/providers/tournament_provider.da import 'package:frontend_splatournament_manager/providers/team_provider.dart'; import 'package:frontend_splatournament_manager/widgets/available_tournament_list.dart'; import 'package:frontend_splatournament_manager/widgets/teams_list_widget.dart'; -import 'package:frontend_splatournament_manager/widgets/my_teams_widget.dart'; import 'package:frontend_splatournament_manager/widgets/my_tournaments_carousel.dart'; import 'package:frontend_splatournament_manager/pages/create_tournament_page.dart'; import 'package:frontend_splatournament_manager/pages/create_team_page.dart'; +import 'package:frontend_splatournament_manager/providers/auth_provider.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; @@ -17,48 +17,14 @@ class HomePage extends StatefulWidget { State createState() => _HomePageState(); } -class _HomePageState extends State - with SingleTickerProviderStateMixin { +class _HomePageState extends State { int _selectedIndex = 0; - late TabController _tabController; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 2, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } @override Widget build(BuildContext context) { - final appBarForeground = - Theme.of(context).appBarTheme.foregroundColor ?? - Theme.of(context).colorScheme.onSurface; - return Scaffold( appBar: AppBar( title: Text(_selectedIndex == 0 ? 'Turniere' : 'Teams'), - bottom: _selectedIndex == 1 - ? TabBar( - controller: _tabController, - labelColor: appBarForeground, - unselectedLabelColor: appBarForeground.withValues(alpha: 0.82), - indicatorColor: appBarForeground, - labelStyle: const TextStyle(fontWeight: FontWeight.w700), - unselectedLabelStyle: const TextStyle( - fontWeight: FontWeight.w500, - ), - tabs: const [ - Tab(text: 'Alle Teams'), - Tab(text: 'Meine Teams'), - ], - ) - : null, actions: [ IconButton( onPressed: () async { @@ -91,12 +57,24 @@ class _HomePageState extends State ), PopupMenuButton( onSelected: (value) { - context.go("/settings"); + if (value == 1) { + context.go("/settings"); + } else if (value == 2) { + Provider.of(context, listen: false).logout(); + context.go('/login'); + } }, offset: const Offset(0, 48), itemBuilder: (context) { return [ - const PopupMenuItem(value: 1, child: Text('Einstellungen')), + const PopupMenuItem(value: 1, child: Text('Profil')), + const PopupMenuItem( + value: 2, + child: Text( + 'Abmelden', + style: TextStyle(color: Colors.red), + ), + ), ]; }, ), @@ -112,11 +90,8 @@ class _HomePageState extends State const Expanded(child: AvailableTournamentList()), ], ), - // Teams View with tabs - TabBarView( - controller: _tabController, - children: const [TeamsListWidget(), MyTeamsWidget()], - ), + // Teams View + const TeamsListWidget(), ], ), bottomNavigationBar: BottomNavigationBar( diff --git a/frontend_splatournament_manager/lib/pages/settings_page.dart b/frontend_splatournament_manager/lib/pages/settings_page.dart index 6948343..7af6292 100644 --- a/frontend_splatournament_manager/lib/pages/settings_page.dart +++ b/frontend_splatournament_manager/lib/pages/settings_page.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:frontend_splatournament_manager/widgets/my_teams_widget.dart'; import 'package:frontend_splatournament_manager/widgets/theme_selector_widget.dart'; -import 'package:provider/provider.dart'; -import 'package:frontend_splatournament_manager/providers/auth_provider.dart'; -import 'package:go_router/go_router.dart'; import '../widgets/profile_widget.dart'; @@ -17,28 +15,23 @@ class _SettingsPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Einstellungen')), + appBar: AppBar(title: const Text('Profil')), body: Column( children: [ const SizedBox(height: 24), const ProfileWidget(), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - ThemeSelectorWidget(), - ListTile( - leading: const Icon(Icons.logout, color: Colors.red), - title: const Text( - 'Abmelden', - style: TextStyle(color: Colors.red), - ), - onTap: () { - Provider.of(context, listen: false).logout(); - context.go('/login'); - }, + ThemeSelectorWidget(), + const Padding( + padding: EdgeInsets.fromLTRB(16, 16, 16, 4), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'Meine Teams', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), - ], + ), ), + const Expanded(child: MyTeamsWidget()), ], ), ); diff --git a/frontend_splatournament_manager/lib/providers/team_provider.dart b/frontend_splatournament_manager/lib/providers/team_provider.dart index a60e691..d2ef31c 100644 --- a/frontend_splatournament_manager/lib/providers/team_provider.dart +++ b/frontend_splatournament_manager/lib/providers/team_provider.dart @@ -6,9 +6,12 @@ class TeamProvider extends ChangeNotifier { final TeamService _teamService = TeamService(); List _teams = []; + List _userTeams = []; Future>? _initialLoadFuture; + Future>? _userTeamsFuture; List get teams => _teams; + List get userTeams => _userTeams; Future> fetchAllTeams() async { _teams = await _teamService.getAllTeams(); @@ -26,6 +29,17 @@ class TeamProvider extends ChangeNotifier { return _initialLoadFuture!; } + Future> fetchUserTeams() async { + _userTeams = await _teamService.getUserTeams(); + notifyListeners(); + return _userTeams; + } + + Future> ensureUserTeamsLoaded() { + _userTeamsFuture ??= fetchUserTeams(); + return _userTeamsFuture!; + } + Future createTeam({ required String name, required String tag, @@ -77,11 +91,19 @@ class TeamProvider extends ChangeNotifier { Future joinTeam(int teamId) async { await _teamService.joinTeam(teamId); - notifyListeners(); + await _refreshMembership(); } Future leaveTeam(int teamId) async { await _teamService.leaveTeam(teamId); + await _refreshMembership(); + } + + Future _refreshMembership() async { + await Future.wait([ + _teamService.getAllTeams().then((t) => _teams = t), + _teamService.getUserTeams().then((t) => _userTeams = t), + ]); notifyListeners(); } diff --git a/frontend_splatournament_manager/lib/widgets/my_teams_widget.dart b/frontend_splatournament_manager/lib/widgets/my_teams_widget.dart index 87f49f6..7714d5b 100644 --- a/frontend_splatournament_manager/lib/widgets/my_teams_widget.dart +++ b/frontend_splatournament_manager/lib/widgets/my_teams_widget.dart @@ -3,71 +3,57 @@ import 'package:frontend_splatournament_manager/models/team.dart'; import 'package:frontend_splatournament_manager/providers/team_provider.dart'; import 'package:provider/provider.dart'; -class MyTeamsWidget extends StatefulWidget { +class MyTeamsWidget extends StatelessWidget { const MyTeamsWidget({super.key}); - @override - State createState() => _MyTeamsWidgetState(); -} - -class _MyTeamsWidgetState extends State { - late Future> _myTeamsFuture; - - @override - void initState() { - super.initState(); - _loadMyTeams(); - } - - void _loadMyTeams() { - _myTeamsFuture = Provider.of( - context, - listen: false, - ).getUserTeams(); - } - @override Widget build(BuildContext context) { - return FutureBuilder>( - future: _myTeamsFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } + return Consumer( + builder: (context, provider, _) { + return FutureBuilder>( + future: provider.ensureUserTeamsLoaded(), + builder: (context, snapshot) { + final teams = provider.userTeams; - if (snapshot.hasError) { - return Center( - child: Text( - 'Fehler: ${snapshot.error.toString().replaceFirst('Exception: ', '')}', - ), - ); - } + if (snapshot.connectionState == ConnectionState.waiting && + teams.isEmpty) { + return const Center(child: CircularProgressIndicator()); + } - final teams = snapshot.data ?? []; - if (teams.isEmpty) { - return const Center( - child: Text( - 'Du bist noch in keinem Team.\nTritt einem Team im Tab Alle Teams bei.', - ), - ); - } + if (snapshot.hasError && teams.isEmpty) { + return Center( + child: Text( + "Fehler: ${snapshot.error.toString().replaceFirst("Exception: ", "")}", + ), + ); + } - return ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: teams.length, - itemBuilder: (context, index) => _buildTeamCard(teams[index]), + if (teams.isEmpty) { + return const Center( + child: Text( + 'Du bist noch in keinem Team.\nTritt einem Team unter Teams bei.', + ), + ); + } + + return ListView.builder( + padding: const EdgeInsets.all(16), + itemCount: teams.length, + itemBuilder: (context, index) => + _buildTeamCard(context, teams[index]), + ); + }, ); }, ); } - Widget _buildTeamCard(Team team) { + Widget _buildTeamCard(BuildContext context, Team team) { final memberCountText = team.memberCount != null - ? '${team.memberCount}/4 Mitglieder' - : 'Keine Mitglieder'; - final description = team.description.isEmpty - ? 'Keine Beschreibung' - : team.description; + ? "${team.memberCount}/4 Mitglieder" + : "Keine Mitglieder"; + final description = + team.description.isEmpty ? "Keine Beschreibung" : team.description; return Card( margin: const EdgeInsets.only(bottom: 12), @@ -80,50 +66,47 @@ class _MyTeamsWidgetState extends State { ), trailing: IconButton( icon: const Icon(Icons.logout, color: Colors.red), - onPressed: () => _leaveTeam(team), + onPressed: () => _leaveTeam(context, team), ), ), ); } - Future _leaveTeam(Team team) async { + Future _leaveTeam(BuildContext context, Team team) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Team verlassen?'), + title: const Text("Team verlassen?"), content: Text('Soll "${team.name}" verlassen werden?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), - child: const Text('Abbrechen'), + child: const Text("Abbrechen"), ), TextButton( onPressed: () => Navigator.pop(context, true), - child: const Text('Verlassen', style: TextStyle(color: Colors.red)), + child: const Text("Verlassen", style: TextStyle(color: Colors.red)), ), ], ), ); - if (confirmed == true && mounted) { + if (confirmed == true && context.mounted) { try { - await Provider.of( - context, - listen: false, - ).leaveTeam(team.id); - if (mounted) { + await Provider.of(context, listen: false).leaveTeam( + team.id, + ); + if (context.mounted) { ScaffoldMessenger.of( context, - ).showSnackBar(const SnackBar(content: Text('Team verlassen'))); - _loadMyTeams(); - setState(() {}); + ).showSnackBar(const SnackBar(content: Text("Team verlassen"))); } } catch (e) { - if (mounted) { + if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - 'Fehler: ${e.toString().replaceFirst('Exception: ', '')}', + "Fehler: ${e.toString().replaceFirst("Exception: ", "")}", ), ), );