From 79249c418d8c20d0e748be770904ddac7bbd06ed Mon Sep 17 00:00:00 2001 From: Connor Frank Date: Mon, 1 Apr 2024 23:45:43 -0400 Subject: Themes, contexts, lots of changes --- README.md | 14 +----- lib/main.dart | 35 ++++++++++++- lib/main_menu.dart | 136 +++++++++++++++++++++++++++------------------------ lib/scorekeeper.dart | 29 ++++++++--- 4 files changed, 129 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 73539dd..3aa8dc0 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,5 @@ Mini Golf Scores -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## Ideas for Improvement +- Add course templates (automatically populate holes with par values) \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index e19de54..39a7f05 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,9 +16,40 @@ class MiniGolfScoreApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp( + return MaterialApp( + theme: ThemeData( + brightness: Brightness.light, + primarySwatch: Colors.blue, // Example primary color for light theme + scaffoldBackgroundColor: Colors.white, // Light mode background color + // Define other theme properties for light mode + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, // Button color for light mode + foregroundColor: Colors.black, // Text color for light mode + ), + ), + ), + darkTheme: ThemeData( + brightness: Brightness.dark, + primarySwatch: Colors.blueGrey, // Example primary color for dark theme + scaffoldBackgroundColor: Colors.black, // Dark mode background color + textTheme: const TextTheme( + bodyLarge: TextStyle(color: Colors.white), + bodyMedium: TextStyle(color: Colors.white), + bodySmall: TextStyle(color: Colors.white), + // Add other text styles as needed + ), + // Define other theme properties for dark mode + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blueGrey, // Button color for dark mode + foregroundColor: Colors.white, // Text color for dark mode + ), + ), + ), + themeMode: ThemeMode.system, // Use the system theme setting (light/dark) title: 'Mini Golf Score App', - home: MainMenu(), + home: const MainMenu(), ); } } diff --git a/lib/main_menu.dart b/lib/main_menu.dart index 30bd84b..7cd29c6 100644 --- a/lib/main_menu.dart +++ b/lib/main_menu.dart @@ -9,21 +9,21 @@ class MainMenu extends StatelessWidget { const MainMenu({super.key}); void _showLoadGameDialog(BuildContext context) async { + final localContext = context; final prefs = await SharedPreferences.getInstance(); final gameKeys = prefs.getKeys() .where((key) => key.startsWith('game_')) .toList(); if (gameKeys.isEmpty) { - // No games found, show a SnackBar instead - ScaffoldMessenger.of(context).showSnackBar( + ScaffoldMessenger.of(localContext).showSnackBar( const SnackBar(content: Text('No saved games found.')), ); return; } showDialog( - context: context, + context: localContext, builder: (context) { return AlertDialog( title: const Text('Select a Game to Load'), @@ -34,7 +34,7 @@ class MainMenu extends StatelessWidget { title: Text(key.substring(5).substring(0, 16).replaceAll( "T", " ")), onTap: () { - _loadGame(context, key); + _loadGame(localContext, key); }, ); }).toList(), @@ -46,16 +46,16 @@ class MainMenu extends StatelessWidget { } Future _loadGame(BuildContext context, String gameKey) async { + final localContext = context; final prefs = await SharedPreferences.getInstance(); final gameDataJson = prefs.getString(gameKey); if (gameDataJson != null) { final gameData = jsonDecode(gameDataJson); - // Assuming gameData structure. Convert data types as necessary. - Navigator.of(context).pop(); // Close the selection dialog + Navigator.of(localContext).pop(); // Close the selection dialog Navigator.push( - context, + localContext, MaterialPageRoute( - builder: (context) => + builder: (localContext) => ScoreKeeper( isNewGame: false, playerNames: List.from(gameData['playerNames']), @@ -70,8 +70,65 @@ class MainMenu extends StatelessWidget { } } + void showAboutDialog(BuildContext context) async { + final localContext = context; + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + String version = packageInfo.version; + + showDialog( + context: localContext, + builder: (BuildContext localContext) { + return AlertDialog( + title: const Text('About'), + content: SingleChildScrollView( + child: ListBody( + children: [ + const Text('Mini Golf Scorekeeper App'), + const Text('Made by Connor Frank'), + const Text('Princeton NJ'), + const Text(''), + Text('Version: $version'), // Display app version + const Text(''), + const Text('Mini Golf Scores Copyright (C) 2024 Connor Frank'), + const Text('This program comes with ABSOLUTELY NO WARRANTY.'), + const Text('This is free software, and you are welcome to redistribute it under certain conditions.'), + const Text('View \'Licenses\' in main menu for details.'), + // Add more about info here + ], + ), + ), + actions: [ + TextButton( + child: const Text('Contact Me'), + onPressed: () async { + Uri link = Uri(scheme: 'mailto', + path: 'conjfrnk+minigolf@gmail.com', + query: 'subject=Mini Golf Scores App', + ); + if (await canLaunchUrl(link)) { + await launchUrl(link); + } else { + ScaffoldMessenger.of(localContext).showSnackBar( + const SnackBar(content: Text('Could not launch email client')), + ); + } + }, + ), + TextButton( + child: const Text('OK'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + @override Widget build(BuildContext context) { + final localContext = context; return Scaffold( appBar: AppBar( title: const Text('Mini Golf Main Menu'), @@ -85,9 +142,9 @@ class MainMenu extends StatelessWidget { child: const Text('Start New Game'), onPressed: () { Navigator.push( - context, + localContext, MaterialPageRoute( - builder: (context) => const ScoreKeeper(isNewGame: true)), + builder: (localContext) => const ScoreKeeper(isNewGame: true)), ); }, ), @@ -95,7 +152,7 @@ class MainMenu extends StatelessWidget { // Space between the buttons ElevatedButton( child: const Text('Load Game'), - onPressed: () => _showLoadGameDialog(context), + onPressed: () => _showLoadGameDialog(localContext), ), const Spacer(), // This will push the bottom content to the bottom of the screen @@ -106,43 +163,8 @@ class MainMenu extends StatelessWidget { children: [ // About Button ElevatedButton( - onPressed: () async { - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - String version = packageInfo.version; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('About'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Mini Golf Scorekeeper App'), - const Text('Made by Connor Frank'), - const Text('Princeton NJ'), - const Text(''), - Text('Version: $version'), // Display app version - const Text(''), - const Text('Mini Golf Scores Copyright (C) 2024 Connor Frank'), - const Text('This program comes with ABSOLUTELY NO WARRANTY.'), - const Text('This is free software, and you are welcome to redistribute it under certain conditions.'), - const Text('View \'Licenses\' in main menu for details.'), - // Add more about info here - ], - ), - ), - actions: [ - TextButton( - child: const Text('OK'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); + onPressed: () { + showAboutDialog(localContext); }, child: const Text('About'), ), @@ -153,7 +175,7 @@ class MainMenu extends StatelessWidget { String version = packageInfo.version; // Action for License button showLicensePage( - context: context, + context: localContext, applicationName: 'Mini Golf Scores', applicationVersion: version, applicationLegalese: '© 2024 Connor Frank' @@ -170,7 +192,7 @@ class MainMenu extends StatelessWidget { if (await canLaunchUrl(link)) { await launchUrl(link); } else { - ScaffoldMessenger.of(context).showSnackBar( + ScaffoldMessenger.of(localContext).showSnackBar( const SnackBar(content: Text('Could not open GitHub')), ); } @@ -178,20 +200,6 @@ class MainMenu extends StatelessWidget { child: const Text( 'GitHub'), // You can use an Icon instead: Icon(Icons.link) ), - ElevatedButton( - onPressed: () async { - Uri link = Uri(scheme: 'mailto', - path: 'conjfrnk+minigolf@gmail.com'); - if (await canLaunchUrl(link)) { - await launchUrl(link); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Could not open GitHub')), - ); - } - }, - child: const Text('Contact'), - ), ], ), const SizedBox(height: 20), diff --git a/lib/scorekeeper.dart b/lib/scorekeeper.dart index b523466..ba6a068 100644 --- a/lib/scorekeeper.dart +++ b/lib/scorekeeper.dart @@ -94,6 +94,12 @@ class ScoreKeeperState extends State { ); } + Future _saveGameIfUnsaved() async { + if (!widget.isNewGame) { + await _saveGame(); + } + } + Future _saveGame() async { final prefs = await SharedPreferences.getInstance(); final String timestamp = gameCreationTime.toIso8601String(); @@ -319,8 +325,8 @@ class ScoreKeeperState extends State { } return ListTile( - title: Text('Hole $holeNumber'), - subtitle: Text(scoreText), + title: Text('Hole $holeNumber', style: Theme.of(context).textTheme.bodyMedium), + subtitle: Text(scoreText, style: Theme.of(context).textTheme.bodySmall), onTap: () => _showHoleDetailsDialog(holeNumber), ); } @@ -375,6 +381,13 @@ class ScoreKeeperState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + _saveGameIfUnsaved(); // Call your save game method + Navigator.of(context).pop(); // Navigate back after saving + }, + ), title: const Text('Mini Golf Score Keeper'), actions: [ IconButton( @@ -432,7 +445,7 @@ class ScoreKeeperState extends State { ), ), bottomNavigationBar: Container( - color: Colors.blueGrey[100], + color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[850] : Colors.blueGrey[100], height: 60.0, child: SingleChildScrollView( scrollDirection: Axis.horizontal, @@ -444,10 +457,12 @@ class ScoreKeeperState extends State { onTap: () => _showPlayerRankings(context), child: Container( padding: const EdgeInsets.all(10), - color: Colors.blueGrey[100], child: Text( 'Total Par: ${pars.values.fold(0, (prev, par) => prev + par)}', - style: const TextStyle(fontSize: 16), + style: TextStyle( + fontSize: 16, + color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black, // White or black text based on theme + ), ), ), ), @@ -468,8 +483,8 @@ class ScoreKeeperState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(name), - Text('Score: $totalScore'), + Text(name, style: Theme.of(context).textTheme.bodySmall), + Text('Score: $totalScore', style: Theme.of(context).textTheme.bodySmall), ], ), ); -- cgit v1.2.3