diff --git a/frontend_splatournament_manager/lib/main.dart b/frontend_splatournament_manager/lib/main.dart index 162844f..d9d96c7 100644 --- a/frontend_splatournament_manager/lib/main.dart +++ b/frontend_splatournament_manager/lib/main.dart @@ -3,7 +3,8 @@ import 'package:frontend_splatournament_manager/pages/home_page.dart'; import 'package:frontend_splatournament_manager/pages/login_page.dart'; import 'package:frontend_splatournament_manager/pages/settings_page.dart'; import 'package:frontend_splatournament_manager/providers/auth_provider.dart'; -import 'package:frontend_splatournament_manager/state_provider.dart'; +import 'package:frontend_splatournament_manager/providers/theme_provider.dart'; +import 'package:frontend_splatournament_manager/providers/tournament_provider.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; @@ -11,7 +12,8 @@ void main() { runApp( MultiProvider( providers: [ - ChangeNotifierProvider(create: (_) => StateProvider()), + ChangeNotifierProvider(create: (_) => ThemeProvider()), + ChangeNotifierProvider(create: (_) => TournamentProvider()), ChangeNotifierProvider(create: (_) => AuthProvider()), ], child: const SplatournamentApp(), @@ -23,11 +25,11 @@ class SplatournamentApp extends StatelessWidget { const SplatournamentApp({super.key}); @override Widget build(BuildContext context) { - final stateProvider = Provider.of(context); + final themeProvider = Provider.of(context); return MaterialApp.router( title: 'Splatournament Manager', routerConfig: routes, - themeMode: stateProvider.theme, + themeMode: themeProvider.theme, theme: ThemeData( brightness: Brightness.light, primarySwatch: Colors.blue, diff --git a/frontend_splatournament_manager/lib/pages/home_page.dart b/frontend_splatournament_manager/lib/pages/home_page.dart index 257969d..b0f7113 100644 --- a/frontend_splatournament_manager/lib/pages/home_page.dart +++ b/frontend_splatournament_manager/lib/pages/home_page.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:frontend_splatournament_manager/state_provider.dart'; +import 'package:frontend_splatournament_manager/providers/tournament_provider.dart'; import 'package:frontend_splatournament_manager/widgets/available_tournament_list.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; @@ -13,16 +13,20 @@ class HomePage extends StatelessWidget { appBar: AppBar( title: Text("Splatournament"), actions: [ - Consumer( - builder: - (BuildContext context, StateProvider value, Widget? child) { - return IconButton( - onPressed: () { - value.notifyState(); - }, - icon: Icon(Icons.refresh), - ); - }, + IconButton( + onPressed: () async { + final tournamentProvider = + Provider.of(context, listen: false); + try { + await tournamentProvider.refreshAvailableTournaments(); + } catch (_) { + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Failed to refresh tournaments')), + ); + } + }, + icon: Icon(Icons.refresh), ), PopupMenuButton( onSelected: (value) { diff --git a/frontend_splatournament_manager/lib/providers/theme_provider.dart b/frontend_splatournament_manager/lib/providers/theme_provider.dart new file mode 100644 index 0000000..f456b50 --- /dev/null +++ b/frontend_splatournament_manager/lib/providers/theme_provider.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +class ThemeProvider extends ChangeNotifier { + ThemeMode _themeMode = ThemeMode.system; + + ThemeMode get theme => _themeMode; + + void setTheme(ThemeMode mode) { + _themeMode = mode; + notifyListeners(); + } +} \ No newline at end of file diff --git a/frontend_splatournament_manager/lib/providers/tournament_provider.dart b/frontend_splatournament_manager/lib/providers/tournament_provider.dart new file mode 100644 index 0000000..d18040e --- /dev/null +++ b/frontend_splatournament_manager/lib/providers/tournament_provider.dart @@ -0,0 +1,41 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:frontend_splatournament_manager/models/tournament.dart'; +import 'package:http/http.dart' as http; + +class TournamentProvider extends ChangeNotifier { + static const String baseUrl = "http://10.0.2.2:3000"; + + List _availableTournaments = []; + Future>? _initialLoadFuture; + + List get availableTournaments => _availableTournaments; + + Future> _fetchTournaments() async { + final response = await http.get(Uri.parse('$baseUrl/tournaments')); + if (response.statusCode != HttpStatus.ok) { + throw Exception('Failed to load tournaments (${response.statusCode})'); + } + + final List list = json.decode(response.body); + return list.map((json) => Tournament.fromJson(json)).toList(); + } + + Future> fetchAvailableTournaments() async { + _availableTournaments = await _fetchTournaments(); + notifyListeners(); + return _availableTournaments; + } + + Future> ensureTournamentsLoaded() { + _initialLoadFuture ??= fetchAvailableTournaments(); + return _initialLoadFuture!; + } + + Future> refreshAvailableTournaments() { + _initialLoadFuture = fetchAvailableTournaments(); + return _initialLoadFuture!; + } +} \ No newline at end of file diff --git a/frontend_splatournament_manager/lib/state_provider.dart b/frontend_splatournament_manager/lib/state_provider.dart deleted file mode 100644 index db3d3a0..0000000 --- a/frontend_splatournament_manager/lib/state_provider.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:frontend_splatournament_manager/models/tournament.dart'; -import 'package:http/http.dart' as http; - -class StateProvider extends ChangeNotifier { - static const String baseUrl = "http://10.0.2.2:3000"; - ThemeMode _themeMode = ThemeMode.system; - - ThemeMode get theme => _themeMode; - - void setTheme(ThemeMode mode) { - _themeMode = mode; - notifyListeners(); - } - List? _availableTournaments; - void notifyState(){ - notifyListeners(); - } - Future> fetchAvailableTournaments() async { - try { - var response = await http.get(Uri.parse('$baseUrl/tournaments')); - if (response.statusCode == 200) { - final List list = json.decode(response.body); - _availableTournaments = list.map((json) => Tournament.fromJson(json)).toList(); - return _availableTournaments!; - } - } catch (e) { - _availableTournaments = null; - return Future.error(e); - } - return[]; - } - List get availableTournaments => _availableTournaments ?? []; -} \ No newline at end of file diff --git a/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart b/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart index 4393e4f..9b0648f 100644 --- a/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart +++ b/frontend_splatournament_manager/lib/widgets/available_tournament_list.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:frontend_splatournament_manager/models/tournament.dart'; import 'package:frontend_splatournament_manager/pages/tournament_detail_page.dart'; -import 'package:frontend_splatournament_manager/state_provider.dart'; +import 'package:frontend_splatournament_manager/providers/tournament_provider.dart'; import 'package:provider/provider.dart'; class AvailableTournamentList extends StatelessWidget { @@ -17,13 +17,10 @@ class AvailableTournamentList extends StatelessWidget { SizedBox( width: double.infinity, height: 350, - child: Consumer( - builder: - ( - BuildContext context, - StateProvider provider, - Widget? child, - ) => TournamentListFutureBuilder(provider: provider), + child: Consumer( + builder: (context, provider, _) { + return TournamentListFutureBuilder(provider: provider); + }, ), ), ], @@ -33,22 +30,30 @@ class AvailableTournamentList extends StatelessWidget { } class TournamentListFutureBuilder extends StatelessWidget { - final StateProvider provider; + final TournamentProvider provider; const TournamentListFutureBuilder({super.key, required this.provider}); @override Widget build(BuildContext context) { - return FutureBuilder( - future: provider.fetchAvailableTournaments(), + return FutureBuilder>( + future: provider.ensureTournamentsLoaded(), builder: (context, snapshot) { - if (snapshot.hasError) { - return Center(child: Text('Error: ${snapshot.error}')); - } else if (!snapshot.hasData || - snapshot.connectionState == ConnectionState.waiting) { + final list = provider.availableTournaments; + print(list); + if (snapshot.connectionState == ConnectionState.waiting && + list.isEmpty) { return Center(child: CircularProgressIndicator()); } - var list = snapshot.data!; + + if (snapshot.hasError && list.isEmpty) { + return Center(child: Text('Error: ${snapshot.error}')); + } + + if (list.isEmpty) { + return Center(child: Text('No tournaments found')); + } + return ListView.builder( shrinkWrap: false, itemCount: list.length, @@ -85,4 +90,3 @@ class TournamentListItem extends StatelessWidget { ); } } - diff --git a/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart b/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart index 7513fe4..d7a0d25 100644 --- a/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart +++ b/frontend_splatournament_manager/lib/widgets/theme_selector_widget.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../state_provider.dart'; +import '../providers/theme_provider.dart'; class ThemeSelectorWidget extends StatelessWidget { ThemeSelectorWidget({super.key}); @@ -23,7 +23,7 @@ class ThemeSelectorWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final stateProvider = Provider.of(context); + final themeProvider = Provider.of(context); return Container( decoration: BoxDecoration(color: Theme.of(context).hoverColor, borderRadius: BorderRadius.circular(8)), padding: const EdgeInsets.all(8.0), @@ -37,10 +37,10 @@ class ThemeSelectorWidget extends StatelessWidget { child: DropdownButtonFormField( icon: Icon(Icons.color_lens), items: dropdownElements, - initialValue: stateProvider.theme, + initialValue: themeProvider.theme, onChanged: (value) { if (value == null) return; - stateProvider.setTheme(value); + themeProvider.setTheme(value); }, ), ),