From 29d071da5d35022299c1797ebc6956d3d83fa653 Mon Sep 17 00:00:00 2001 From: TechAurelian Date: Wed, 17 Apr 2024 12:54:24 +0300 Subject: [PATCH] Fix the new Material 3 app theme + Fix Flutter lint issues --- lib/common/app_strings.dart | 4 +-- lib/main.dart | 21 +++++++++------- lib/models/counter.dart | 21 +++------------- lib/screens/home.dart | 2 +- lib/screens/settings_screen.dart | 4 +-- lib/utils/utils.dart | 42 ++++++++++---------------------- lib/widgets/color_list_tile.dart | 15 ++++-------- lib/widgets/counter_display.dart | 9 ++++--- lib/widgets/counters_drawer.dart | 8 +++--- 9 files changed, 47 insertions(+), 79 deletions(-) diff --git a/lib/common/app_strings.dart b/lib/common/app_strings.dart index 9e20190..0962073 100644 --- a/lib/common/app_strings.dart +++ b/lib/common/app_strings.dart @@ -15,8 +15,8 @@ class AppStrings { static const String drawerTitle = appName; static const String settingsItemTitle = 'Settings'; static const String helpItemTitle = 'Online Help'; - static const String rateItemTitle = 'Rate or review'; - static const String viewSourceItemTitle = 'View app source'; + static const String rateItemTitle = 'Rate App'; + static const String viewSourceItemTitle = 'View Source Code'; static const Map menuActions = { MenuAction.reset: 'Reset counter', diff --git a/lib/main.dart b/lib/main.dart index fd34112..b6a8bf7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'common/app_strings.dart'; import 'screens/home.dart'; -import 'utils/utils.dart'; void main() { runApp(const CountersApp()); @@ -14,21 +13,25 @@ void main() { /// The app widget. class CountersApp extends StatelessWidget { - const CountersApp({Key? key}) : super(key: key); + const CountersApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: AppStrings.appName, - theme: ThemeData( - brightness: Brightness.light, - primarySwatch: Colors.white.createMaterialColor(), - textButtonTheme: TextButtonThemeData( - style: TextButton.styleFrom(foregroundColor: Colors.black), + + // A black and white theme to go with the app's colored counters + theme: ThemeData.from( + colorScheme: ColorScheme.light( + primary: Colors.black, + surface: Colors.white, + onSurface: Colors.black, + surfaceTint: Colors.white, + primaryContainer: Colors.white, + onPrimaryContainer: Colors.black, + outlineVariant: Colors.grey.shade200, ), - visualDensity: VisualDensity.adaptivePlatformDensity, - typography: Typography.material2018(), ), home: const HomeScreen(), ); diff --git a/lib/models/counter.dart b/lib/models/counter.dart index 65881c7..1bae222 100644 --- a/lib/models/counter.dart +++ b/lib/models/counter.dart @@ -2,9 +2,6 @@ // Licensed under the MIT License. See LICENSE in the project root for license information. // @author TechAurelian (https://techaurelian.com) -// cSpell:ignore endregion - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -17,8 +14,6 @@ class Counter { /// Creates a counter of the specified [type]. Counter(this.type); - //#region Counter value - /// The counter value. int _value = 0; @@ -46,12 +41,8 @@ class Counter { _setValue(0); } - //#endregion - - //#region Persistent storage - /// Returns the persistent storage key for each counter type. - static String _counterKey(CounterType type) => '${describeEnum(type)}_counter'; + static String _counterKey(CounterType type) => '${type.name}_counter'; /// Saves the counter value to persistent storage. Future _saveValue() async { @@ -64,10 +55,6 @@ class Counter { _value = preferences.getInt(_counterKey(type)) ?? 0; } - //#endregion - - //#region Counter type, color, name - /// The counter type. final CounterType type; @@ -82,8 +69,8 @@ class Counter { /// Returns the name of the specified counter type (e.g. "Black Counter"). static String nameOf(CounterType type) { - final String name = describeEnum(type); - return '${name.substring(0, 1).toUpperCase()}${name.substring(1).toLowerCase()} Counter'; + final String name = type.name; + return '${name[0].toUpperCase()}${name.substring(1).toLowerCase()} Counter'; } /// A map with the corresponding [Color] value for each counter type. @@ -100,8 +87,6 @@ class Counter { CounterType.orange: Colors.orange, CounterType.grey: Colors.grey, }; - -//#endregion } /// Provides a map of counters for each counter type, and keeps a reference to the current counter. diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 8f000ae..59f4c64 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -20,7 +20,7 @@ enum MenuAction { reset, share } /// The app home screen widget. class HomeScreen extends StatefulWidget { - const HomeScreen({Key? key}) : super(key: key); + const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index a2238fc..5aa96b4 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -9,9 +9,9 @@ import '../common/app_strings.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({ - Key? key, + super.key, required this.appSettings, - }) : super(key: key); + }); final AppSettings appSettings; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 4546bd1..a1e46b6 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -3,6 +3,7 @@ // @author TechAurelian (https://techaurelian.com) import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -16,44 +17,27 @@ String toDecimalString(BuildContext context, int number) { /// /// Shows an error [SnackBar] if there is no support for launching the URL. Future launchUrlExternal(BuildContext context, String url) async { - if (!await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication)) { - showSnackBar(context, 'Failed to open $url'); + try { + await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication); + } on PlatformException catch (e) { + if (!context.mounted) return; + showSnackBar(context, 'Failed to open $url: ${e.message}'); } } /// Shows a [SnackBar] with the specified [text] at the bottom of the specified scaffold. void showSnackBar(BuildContext context, String text) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(text), - ), - ); + ScaffoldMessenger.of(context) + ..removeCurrentSnackBar() + ..showSnackBar(SnackBar(content: Text(text))); } /// Utility Color extension methods. extension ColorX on Color { /// Returns the contrast color for this color. - Color contrastOf() => - ThemeData.estimateBrightnessForColor(this) == Brightness.light ? Colors.black : Colors.white; - - /// Creates a material color from any ARGB color value. - MaterialColor createMaterialColor() { - List strengths = [.05]; - Map swatch = {}; - final int r = red, g = green, b = blue; - - for (int i = 1; i < 10; i++) { - strengths.add(0.1 * i); - } - for (var strength in strengths) { - final double ds = 0.5 - strength; - swatch[(strength * 1000).round()] = Color.fromRGBO( - r + ((ds < 0 ? r : (255 - r)) * ds).round(), - g + ((ds < 0 ? g : (255 - g)) * ds).round(), - b + ((ds < 0 ? b : (255 - b)) * ds).round(), - 1, - ); - } - return MaterialColor(value, swatch); + Color contrastOf() { + return ThemeData.estimateBrightnessForColor(this) == Brightness.light + ? Colors.black + : Colors.white; } } diff --git a/lib/widgets/color_list_tile.dart b/lib/widgets/color_list_tile.dart index 449350b..4d26fba 100644 --- a/lib/widgets/color_list_tile.dart +++ b/lib/widgets/color_list_tile.dart @@ -10,13 +10,13 @@ class ColorListTile extends StatelessWidget { /// /// The [color] and [title] parameters must not be null. const ColorListTile({ - Key? key, + super.key, required this.color, required this.title, required this.subtitle, this.selected = false, this.onTap, - }) : super(key: key); + }); /// The ARGB color value to fill the circular color swatch. final Color color; @@ -43,10 +43,6 @@ class ColorListTile extends StatelessWidget { color: color, border: color == Colors.white ? Border.all() : null, ), - // title: Text( - // title, - // style: TextStyle(color: Theme.of(context).textTheme.bodyText1!.color), - // ), title: Text(title), subtitle: Text(subtitle), onTap: onTap, @@ -61,12 +57,11 @@ class _ColorFilledCircle extends StatelessWidget { /// /// The [color] parameter must not be null. const _ColorFilledCircle({ - Key? key, + super.key, // ignore: unused_element required this.color, - // ignore: unused_element - this.diameter = 40.0, + this.diameter = 40.0, // ignore: unused_element this.border, - }) : super(key: key); + }); /// The color with which to fill the circle. final Color color; diff --git a/lib/widgets/counter_display.dart b/lib/widgets/counter_display.dart index d4612a7..ed7947a 100644 --- a/lib/widgets/counter_display.dart +++ b/lib/widgets/counter_display.dart @@ -10,11 +10,11 @@ import '../utils/utils.dart'; class CounterDisplay extends StatelessWidget { /// Creates a counter display widget. const CounterDisplay({ - Key? key, + super.key, required this.value, required this.color, this.isPortrait = true, - }) : super(key: key); + }); /// The color with which to fill the counter container. final Color color; @@ -27,8 +27,9 @@ class CounterDisplay extends StatelessWidget { @override Widget build(BuildContext context) { - final TextStyle? counterStyle = - isPortrait ? Theme.of(context).textTheme.headline1 : Theme.of(context).textTheme.headline2; + final TextStyle? counterStyle = isPortrait + ? Theme.of(context).textTheme.displayLarge + : Theme.of(context).textTheme.displayMedium; return Container( alignment: Alignment.center, diff --git a/lib/widgets/counters_drawer.dart b/lib/widgets/counters_drawer.dart index b074b92..5126c53 100644 --- a/lib/widgets/counters_drawer.dart +++ b/lib/widgets/counters_drawer.dart @@ -16,12 +16,12 @@ enum DrawerExtraActions { settings, help, rate, viewSource } class CountersDrawer extends StatelessWidget { /// Creates a counters drawer widget. const CountersDrawer({ - Key? key, + super.key, required this.title, required this.counters, required this.onSelected, this.onExtraSelected, - }) : super(key: key); + }); /// The title of the drawer displayed in the drawer header. final String title; @@ -63,7 +63,7 @@ class CountersDrawer extends StatelessWidget { onTap: () => _onExtraActionTap(context, DrawerExtraActions.help), ), ListTile( - leading: const Icon(Icons.code), + leading: const Icon(Icons.flutter_dash), title: const Text(AppStrings.viewSourceItemTitle), onTap: () => _onExtraActionTap(context, DrawerExtraActions.viewSource), ), @@ -86,7 +86,7 @@ class CountersDrawer extends StatelessWidget { child: DrawerHeader( child: Text( title, - style: Theme.of(context).textTheme.headline6, + style: Theme.of(context).textTheme.titleLarge, ), ), );