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
+}