From bd56d97b6d10fdfda6e9291d1e9201e8c80cfdb1 Mon Sep 17 00:00:00 2001 From: tikaiz Date: Thu, 12 Mar 2026 11:45:59 +0100 Subject: [PATCH] added 2 themes --- docs/prompt.md | 14 ++ frontend_splatournament_manager/lib/main.dart | 18 +- .../lib/pages/home_page.dart | 28 +-- .../lib/pages/tournament_detail_page.dart | 43 +++-- .../lib/providers/theme_provider.dart | 159 +++++++++++++++--- .../lib/widgets/theme_selector_widget.dart | 39 +++-- 6 files changed, 225 insertions(+), 76 deletions(-) diff --git a/docs/prompt.md b/docs/prompt.md index 57fcce9..1381254 100644 --- a/docs/prompt.md +++ b/docs/prompt.md @@ -77,3 +77,17 @@ Folgende Dateien wurden in diesem Prompt verändert: - Show a placeholder in the carousel if no tournaments were found.

Folgende Dateien wurden in diesem Prompt verändert: - frontend_splatournament_manager/lib/widgets/my_tournaments_carousel.dart + +- Add 2 more themes that change the colors of the application, one light and one dark.

+Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/providers/theme_provider.dart + - frontend_splatournament_manager/lib/main.dart + - frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart + +- Make the background color of the tournament detail page semi-transparent and keep the title text legible.

+Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/pages/tournament_detail_page.dart + +- In the Teams view, fix the upper TabBar text so selected and non-selected labels are readable.

+Folgende Dateien wurden in diesem Prompt verändert: + - frontend_splatournament_manager/lib/pages/home_page.dart diff --git a/frontend_splatournament_manager/lib/main.dart b/frontend_splatournament_manager/lib/main.dart index 2474631..3e01744 100644 --- a/frontend_splatournament_manager/lib/main.dart +++ b/frontend_splatournament_manager/lib/main.dart @@ -32,15 +32,9 @@ class SplatournamentApp extends StatelessWidget { return MaterialApp.router( title: 'Splatournament Manager', routerConfig: routes, - themeMode: themeProvider.theme, - theme: ThemeData( - brightness: Brightness.light, - primarySwatch: Colors.blue, - ), - darkTheme: ThemeData( - brightness: Brightness.dark, - primarySwatch: Colors.deepPurple, - ), + themeMode: themeProvider.themeMode, + theme: themeProvider.lightTheme, + darkTheme: themeProvider.darkTheme, ); } } @@ -50,10 +44,10 @@ final routes = GoRouter( redirect: (context, state) async { final authProvider = Provider.of(context, listen: false); await authProvider.checkAuthStatus(); - + final isLoggedIn = authProvider.isLoggedIn; final isGoingToLogin = state.matchedLocation == '/login'; - // redirect to login + // redirect to login if (!isLoggedIn && !isGoingToLogin) { return '/login'; } @@ -61,7 +55,7 @@ final routes = GoRouter( if (isLoggedIn && isGoingToLogin) { return '/'; } - + return null; }, routes: [ diff --git a/frontend_splatournament_manager/lib/pages/home_page.dart b/frontend_splatournament_manager/lib/pages/home_page.dart index 4436914..b1622a7 100644 --- a/frontend_splatournament_manager/lib/pages/home_page.dart +++ b/frontend_splatournament_manager/lib/pages/home_page.dart @@ -17,7 +17,8 @@ class HomePage extends StatefulWidget { State createState() => _HomePageState(); } -class _HomePageState extends State with SingleTickerProviderStateMixin { +class _HomePageState extends State + with SingleTickerProviderStateMixin { int _selectedIndex = 0; late TabController _tabController; @@ -35,12 +36,23 @@ class _HomePageState extends State with SingleTickerProviderStateMixin @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 ? "Tournaments" : "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: 'All Teams'), Tab(text: 'My Teams'), @@ -101,10 +113,7 @@ class _HomePageState extends State with SingleTickerProviderStateMixin // Teams View with tabs TabBarView( controller: _tabController, - children: const [ - TeamsListWidget(), - MyTeamsWidget(), - ], + children: const [TeamsListWidget(), MyTeamsWidget()], ), ], ), @@ -120,10 +129,7 @@ class _HomePageState extends State with SingleTickerProviderStateMixin icon: Icon(Icons.emoji_events), label: 'Tournaments', ), - BottomNavigationBarItem( - icon: Icon(Icons.groups), - label: 'Teams', - ), + BottomNavigationBarItem(icon: Icon(Icons.groups), label: 'Teams'), ], ), floatingActionButton: FloatingActionButton( @@ -138,9 +144,7 @@ class _HomePageState extends State with SingleTickerProviderStateMixin } else { Navigator.push( context, - MaterialPageRoute( - builder: (context) => const CreateTeamPage(), - ), + MaterialPageRoute(builder: (context) => const CreateTeamPage()), ); } }, diff --git a/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart b/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart index 0476543..d5f9f86 100644 --- a/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart +++ b/frontend_splatournament_manager/lib/pages/tournament_detail_page.dart @@ -18,15 +18,19 @@ class _TournamentDetailPageState extends State { void _showJoinTeamDialog(BuildContext context, int tournamentId) async { final teamProvider = Provider.of(context, listen: false); - + try { final teams = await teamProvider.getUserTeams(); - + if (!context.mounted) return; - + if (teams.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('You are not a member of any team. Join or create a team first!')), + const SnackBar( + content: Text( + 'You are not a member of any team. Join or create a team first!', + ), + ), ); return; } @@ -46,8 +50,8 @@ class _TournamentDetailPageState extends State { return ListTile( leading: CircleAvatar(child: Text(team.tag)), title: Text(team.name), - subtitle: team.description.isNotEmpty - ? Text(team.description) + subtitle: team.description.isNotEmpty + ? Text(team.description) : null, onTap: () => Navigator.pop(dialogContext, team), ); @@ -70,15 +74,15 @@ class _TournamentDetailPageState extends State { tournamentId, selectedTeam.id, ); - + if (!context.mounted) return; - + ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('${selectedTeam.name} joined the tournament!'), ), ); - + // Refresh teams list if currently showing if (isShowingTeams) { setState(() {}); @@ -87,25 +91,34 @@ class _TournamentDetailPageState extends State { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Failed to join: ${e.toString().replaceAll('Exception: ', '')}'), + content: Text( + 'Failed to join: ${e.toString().replaceAll('Exception: ', '')}', + ), ), ); } } } catch (e) { if (!context.mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Failed to load your teams: $e')), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Failed to load your teams: $e'))); } } @override Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + final appBarBackground = colorScheme.surface.withValues(alpha: 0.78); + return Scaffold( appBar: AppBar( - title: Text(widget.tournament.name, style: TextStyle(overflow: TextOverflow.ellipsis)), - backgroundColor: Theme.of(context).colorScheme.surface.withAlpha(180), + backgroundColor: appBarBackground, + foregroundColor: colorScheme.onSurface, + title: Text( + widget.tournament.name, + style: TextStyle(overflow: TextOverflow.ellipsis), + ), elevation: 3, actions: [ IconButton( diff --git a/frontend_splatournament_manager/lib/providers/theme_provider.dart b/frontend_splatournament_manager/lib/providers/theme_provider.dart index f3a1191..22c9cef 100644 --- a/frontend_splatournament_manager/lib/providers/theme_provider.dart +++ b/frontend_splatournament_manager/lib/providers/theme_provider.dart @@ -1,11 +1,50 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; -class ThemeProvider extends ChangeNotifier { - static const String _themeKey = 'theme_mode'; - ThemeMode _themeMode = ThemeMode.system; +enum AppThemeOption { lightBlue, darkPurple, lightMint, darkAmber, system } - ThemeMode get theme => _themeMode; +class ThemeProvider extends ChangeNotifier { + static const String _themeKey = 'theme_option'; + AppThemeOption _selectedTheme = AppThemeOption.system; + + AppThemeOption get selectedTheme => _selectedTheme; + + ThemeMode get themeMode { + switch (_selectedTheme) { + case AppThemeOption.lightBlue: + case AppThemeOption.lightMint: + return ThemeMode.light; + case AppThemeOption.darkPurple: + case AppThemeOption.darkAmber: + return ThemeMode.dark; + case AppThemeOption.system: + return ThemeMode.system; + } + } + + ThemeData get lightTheme { + switch (_selectedTheme) { + case AppThemeOption.lightMint: + return _mintLightTheme; + case AppThemeOption.lightBlue: + case AppThemeOption.darkPurple: + case AppThemeOption.darkAmber: + case AppThemeOption.system: + return _blueLightTheme; + } + } + + ThemeData get darkTheme { + switch (_selectedTheme) { + case AppThemeOption.darkAmber: + return _amberDarkTheme; + case AppThemeOption.lightBlue: + case AppThemeOption.darkPurple: + case AppThemeOption.lightMint: + case AppThemeOption.system: + return _purpleDarkTheme; + } + } ThemeProvider() { _loadTheme(); @@ -14,38 +53,116 @@ class ThemeProvider extends ChangeNotifier { Future _loadTheme() async { final prefs = await SharedPreferences.getInstance(); final themeName = prefs.getString(_themeKey) ?? 'system'; - _themeMode = _themeFromString(themeName); + _selectedTheme = _themeFromString(themeName); notifyListeners(); } - Future setTheme(ThemeMode mode) async { - _themeMode = mode; + Future setTheme(AppThemeOption option) async { + _selectedTheme = option; notifyListeners(); - + final prefs = await SharedPreferences.getInstance(); - await prefs.setString(_themeKey, _themeToString(mode)); + await prefs.setString(_themeKey, _themeToString(option)); } - String _themeToString(ThemeMode mode) { - switch (mode) { - case ThemeMode.light: - return 'light'; - case ThemeMode.dark: - return 'dark'; - case ThemeMode.system: + String _themeToString(AppThemeOption option) { + switch (option) { + case AppThemeOption.lightBlue: + return 'light_blue'; + case AppThemeOption.darkPurple: + return 'dark_purple'; + case AppThemeOption.lightMint: + return 'light_mint'; + case AppThemeOption.darkAmber: + return 'dark_amber'; + case AppThemeOption.system: return 'system'; } } - ThemeMode _themeFromString(String theme) { + AppThemeOption _themeFromString(String theme) { switch (theme) { case 'light': - return ThemeMode.light; + case 'light_blue': + return AppThemeOption.lightBlue; case 'dark': - return ThemeMode.dark; + case 'dark_purple': + return AppThemeOption.darkPurple; + case 'light_mint': + return AppThemeOption.lightMint; + case 'dark_amber': + return AppThemeOption.darkAmber; case 'system': default: - return ThemeMode.system; + return AppThemeOption.system; } } -} \ No newline at end of file + + ThemeData get _blueLightTheme { + final scheme = ColorScheme.fromSeed( + seedColor: Colors.blue, + brightness: Brightness.light, + ); + return ThemeData( + colorScheme: scheme, + useMaterial3: true, + appBarTheme: AppBarTheme( + backgroundColor: scheme.primary, + foregroundColor: scheme.onPrimary, + ), + ); + } + + ThemeData get _purpleDarkTheme { + final scheme = ColorScheme.fromSeed( + seedColor: Colors.deepPurple, + brightness: Brightness.dark, + ); + return ThemeData( + colorScheme: scheme, + useMaterial3: true, + appBarTheme: AppBarTheme( + backgroundColor: scheme.surface, + foregroundColor: scheme.onSurface, + ), + ); + } + + ThemeData get _mintLightTheme { + final scheme = ColorScheme.fromSeed( + seedColor: const Color(0xFF00897B), + brightness: Brightness.light, + ); + return ThemeData( + colorScheme: scheme, + useMaterial3: true, + appBarTheme: AppBarTheme( + backgroundColor: scheme.primary, + foregroundColor: scheme.onPrimary, + ), + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: scheme.secondary, + foregroundColor: scheme.onSecondary, + ), + ); + } + + ThemeData get _amberDarkTheme { + final scheme = ColorScheme.fromSeed( + seedColor: const Color(0xFFFF8F00), + brightness: Brightness.dark, + ); + return ThemeData( + colorScheme: scheme, + useMaterial3: true, + appBarTheme: AppBarTheme( + backgroundColor: scheme.surface, + foregroundColor: scheme.onSurface, + ), + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: scheme.primary, + foregroundColor: scheme.onPrimary, + ), + ); + } +} diff --git a/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart b/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart index d7a0d25..66c9523 100644 --- a/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart +++ b/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart @@ -6,26 +6,34 @@ import '../providers/theme_provider.dart'; class ThemeSelectorWidget extends StatelessWidget { ThemeSelectorWidget({super.key}); - final List dropdownElements = [ - DropdownMenuItem( - value: ThemeMode.light, - child: Text("Light"), + final List> dropdownElements = [ + const DropdownMenuItem( + value: AppThemeOption.lightBlue, + child: Text("Light Blue"), ), - DropdownMenuItem( - value: ThemeMode.dark, - child: Text("Dark"), + const DropdownMenuItem( + value: AppThemeOption.darkPurple, + child: Text("Dark Purple"), ), - DropdownMenuItem( - value: ThemeMode.system, - child: Text("System"), + const DropdownMenuItem( + value: AppThemeOption.lightMint, + child: Text("Light Mint"), ), + const DropdownMenuItem( + value: AppThemeOption.darkAmber, + child: Text("Dark Amber"), + ), + const DropdownMenuItem(value: AppThemeOption.system, child: Text("System")), ]; @override Widget build(BuildContext context) { final themeProvider = Provider.of(context); return Container( - decoration: BoxDecoration(color: Theme.of(context).hoverColor, borderRadius: BorderRadius.circular(8)), + decoration: BoxDecoration( + color: Theme.of(context).hoverColor, + borderRadius: BorderRadius.circular(8), + ), padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), child: Row( @@ -34,10 +42,10 @@ class ThemeSelectorWidget extends StatelessWidget { Text("Theme"), SizedBox( width: 250, - child: DropdownButtonFormField( - icon: Icon(Icons.color_lens), + child: DropdownButtonFormField( + icon: const Icon(Icons.color_lens), items: dropdownElements, - initialValue: themeProvider.theme, + initialValue: themeProvider.selectedTheme, onChanged: (value) { if (value == null) return; themeProvider.setTheme(value); @@ -48,5 +56,4 @@ class ThemeSelectorWidget extends StatelessWidget { ), ); } - -} \ No newline at end of file +}