From 2c16803ca79919c5107fbafac597eb358e484ece Mon Sep 17 00:00:00 2001 From: Elliot Nash Date: Mon, 12 Aug 2024 16:57:26 -0700 Subject: [PATCH 1/8] Remove platform widgets --- README.md | 2 +- assets/icons/compass.png | Bin 0 -> 4071 bytes assets/{icons => svg_icons}/blank_pin.svg | 0 lib/consts.dart | 4 +- lib/main.dart | 83 ++------- lib/page/common/alert_banner.dart | 30 +--- .../common/animated_app_bar_scaffold.dart | 107 ----------- lib/page/common/confirmation.dart | 16 +- lib/page/common/hazard_modal_base.dart | 168 +++++++----------- lib/page/common/permissions_dialog.dart | 15 +- lib/page/common/platform_fab.dart | 59 +----- lib/page/common/platform_pill.dart | 19 +- lib/page/common/test_location_too_far.dart | 30 ++-- lib/page/home_page.dart | 25 +-- lib/page/home_page/map_compass.dart | 46 +---- lib/page/home_page/map_fabs.dart | 61 ++----- .../home_page/map_page/hazard_info_popup.dart | 19 +- lib/page/home_page/panel_page.dart | 38 ++-- .../home_page/panel_page/hazard_image.dart | 6 +- .../panel_page/trail_elevation_graph.dart | 5 +- .../panel_page/trail_hazards_widget.dart | 73 ++++---- lib/page/home_page/panel_page/trail_info.dart | 2 +- .../settings_page/button_setting_widget.dart | 13 +- .../selection_setting_widget.dart | 21 +-- .../settings_page/settings_page_scaffold.dart | 23 ++- lib/page/settings_page/settings_section.dart | 25 +-- .../settings_page/toggle_setting_widget.dart | 15 +- linux/flutter/generated_plugin_registrant.cc | 4 - linux/flutter/generated_plugins.cmake | 1 - macos/Flutter/GeneratedPluginRegistrant.swift | 2 - pubspec.lock | 18 +- pubspec.yaml | 10 +- .../flutter/generated_plugin_registrant.cc | 3 - windows/flutter/generated_plugins.cmake | 1 - 34 files changed, 249 insertions(+), 695 deletions(-) create mode 100644 assets/icons/compass.png rename assets/{icons => svg_icons}/blank_pin.svg (100%) delete mode 100644 lib/page/common/animated_app_bar_scaffold.dart diff --git a/README.md b/README.md index 318894f..31fa344 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ rendered icon, and [background.png](assets/icon/background.png) and [foreground.png](assets/icon/foreground.png) are separated bg/fg layers (used by android adaptive icons). -Custom icon symbols go in the [assets/icons](assets/icons) directory (svgs only). The icons are +Custom icon symbols go in the [assets/icons](assets/svg_icons) directory (svgs only). The icons are loaded in flutter using a font file. To generate the font file and the dart icon class, run: ```bash diff --git a/assets/icons/compass.png b/assets/icons/compass.png new file mode 100644 index 0000000000000000000000000000000000000000..860c3bcdcf4829dd09ce455416a88f54db763327 GIT binary patch literal 4071 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 with WidgetsBindingObserver { )); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - // PlatformProvider is flutter_platform_widgets' provider, allowing us - // to use widgets that render in the style of the device's platform. - // Eg. cupertino on ios, and material 3 on android - return PlatformProvider( - initialPlatform: kDebugMode ? kPlatformOverride : null, - builder: (context) { - return _theme( - builder: (context) => PlatformApp( - title: 'Forest Park Reports', - home: HomeScreen(key: homeKey), - ), - ); - }, - ); - } - - // here we build the apps theme - Widget _theme({required Widget Function(BuildContext context) builder}) { - // DynamicColorBuilder allows us to get the system theme on android, macos, and windows. - // On android the colorScheme will be the material you color palette, - // on macos and windows, this will be derived from the system accent color. - final materialLightTheme = ThemeData.from( - colorScheme: ColorScheme.fromSeed( - seedColor: kMaterialAppPrimaryColor, - brightness: Brightness.light, - ) - ); - final materialDarkTheme = ThemeData.from( - colorScheme: ColorScheme.fromSeed( - seedColor: kMaterialAppPrimaryColor, - brightness: Brightness.dark, - ) - ); - - // Cupertino themes - final lightDefaultCupertinoTheme = CupertinoThemeData(brightness: Brightness.light, primaryColor: kCupertinoAppPrimaryColor); - final cupertinoLightTheme = MaterialBasedCupertinoThemeData( - materialTheme: materialLightTheme.copyWith( - cupertinoOverrideTheme: CupertinoThemeData( + final lightTheme = ThemeData.from( + colorScheme: ColorScheme.fromSeed( + seedColor: kMaterialAppPrimaryColor, brightness: Brightness.light, - barBackgroundColor: lightDefaultCupertinoTheme.barBackgroundColor, - primaryColor: kCupertinoAppPrimaryColor, - textTheme: CupertinoTextThemeData( - navActionTextStyle: lightDefaultCupertinoTheme.textTheme.navActionTextStyle.copyWith(color: kCupertinoAppPrimaryColor) - ), - ), - ), + dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot, + ) ); - final darkDefaultCupertinoTheme = CupertinoThemeData(brightness: Brightness.dark, primaryColor: kCupertinoAppPrimaryColor); - final cupertinoDarkTheme = MaterialBasedCupertinoThemeData( - materialTheme: materialDarkTheme.copyWith( - cupertinoOverrideTheme: CupertinoThemeData( + final darkTheme = ThemeData.from( + colorScheme: ColorScheme.fromSeed( + seedColor: kMaterialAppPrimaryColor, brightness: Brightness.dark, - primaryColor: kCupertinoAppPrimaryColor, - barBackgroundColor: darkDefaultCupertinoTheme.barBackgroundColor, - textTheme: CupertinoTextThemeData( - navActionTextStyle: darkDefaultCupertinoTheme.textTheme.navActionTextStyle.copyWith(color: kCupertinoAppPrimaryColor) - ), - ), - ), + dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot, + ) ); - return PlatformTheme( - themeMode: ref.watch(settingsProvider.select((s) => s.colorTheme)).value, - materialLightTheme: materialLightTheme, - materialDarkTheme: materialDarkTheme, - cupertinoLightTheme: cupertinoLightTheme, - cupertinoDarkTheme: cupertinoDarkTheme, - builder: builder, + return MaterialApp( + title: 'Trail Eyes', + theme: lightTheme, + darkTheme: darkTheme, + home: HomeScreen(key: homeKey), ); } } diff --git a/lib/page/common/alert_banner.dart b/lib/page/common/alert_banner.dart index b8ed45e..959e1d0 100644 --- a/lib/page/common/alert_banner.dart +++ b/lib/page/common/alert_banner.dart @@ -1,7 +1,5 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/physics.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/consts.dart'; import 'package:forest_park_reports/main.dart'; import 'package:forest_park_reports/util/outline_box_shadow.dart'; @@ -153,7 +151,7 @@ class _AlertBannerState extends State<_AlertBanner> with SingleTickerProviderSta } } -class _AlertBannerBackground extends PlatformWidgetBase { +class _AlertBannerBackground extends StatelessWidget { final Widget child; const _AlertBannerBackground({ @@ -162,31 +160,7 @@ class _AlertBannerBackground extends PlatformWidgetBase { }); @override - Widget createCupertinoWidget(BuildContext context) { - return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(kCupertinoAlertCornerRadius), - boxShadow: [ - OutlineBoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 4, - ), - ], - ), - child: CupertinoPopupSurface( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: kFabPadding, - vertical: kFabPadding, - ), - child: child, - ), - ), - ); - } - - @override - Widget createMaterialWidget(BuildContext context) { + Widget build(BuildContext context) { return Card( child: Padding( padding: const EdgeInsets.symmetric( diff --git a/lib/page/common/animated_app_bar_scaffold.dart b/lib/page/common/animated_app_bar_scaffold.dart deleted file mode 100644 index 2356a00..0000000 --- a/lib/page/common/animated_app_bar_scaffold.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; - -/// An animated platform app bar that changes color when scrolled. -/// -/// Renders a [CupertinoNavigationBar] on iOS and a [AppBar] on Android. -class AnimatedAppBarScaffold extends StatefulWidget { - /// The child [Widget]. - final Widget body; - /// Scroll controller of body scrollview. - /// - /// Used to know when to change color. - final ScrollController scrollController; - /// App bar title. - final String title; - /// Previous page title; shown next to back button on iOS. - final String? previousPageTitle; - const AnimatedAppBarScaffold({super.key, required this.body, required this.scrollController, required this.title, this.previousPageTitle}); - - @override - State createState() => _AnimatedAppBarScaffoldState(); -} - -class _AnimatedAppBarScaffoldState extends State with TickerProviderStateMixin { - late final AnimationController _animationController; - Animation? _barColorTween; - Animation? _separatorColorTween; - - @override - void initState() { - super.initState(); - - _animationController = AnimationController(vsync: this, duration: Duration.zero); - // Called whenever we scroll. - widget.scrollController.addListener(scrollListener); - } - - Color get _background => isCupertino(context) - ? CupertinoDynamicColor.resolve(CupertinoColors.systemGroupedBackground, context) - : Theme.of(context).scaffoldBackgroundColor; - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - - final barColor = isCupertino(context) - ? CupertinoTheme.of(context).barBackgroundColor.withAlpha(150) - : Theme.of(context).colorScheme.surface; - - _barColorTween = ColorTween( - begin: _background, - end: barColor, - ).animate(_animationController); - _separatorColorTween = ColorTween( - begin: _background, - end: CupertinoDynamicColor.resolve(CupertinoColors.separator, context).withAlpha(150), - ).animate(_animationController); - } - - @override - void dispose() { - widget.scrollController.removeListener(scrollListener); - - super.dispose(); - } - - void scrollListener() { - // We want to progress the animation smoothly as we transition to scrolling - // Therefore the first 12 pixels are the transition zone. - // How far we are down in these pixels should be how much we animate. - double a = (widget.scrollController.offset/kScrollTransition).clamp(0, 1); - _animationController.animateTo(a); - } - - @override - Widget build(BuildContext context) { - final titleStyle = isCupertino(context) - ? CupertinoTheme.of(context).textTheme.navTitleTextStyle.copyWith(fontSize: 20) - : null; - - return AnimatedBuilder( - animation: _animationController, - builder: (context, child) => PlatformScaffold( - appBar: PlatformAppBar( - title: Text(widget.title, style: titleStyle), - backgroundColor: _barColorTween!.value, - cupertino: (context, _) => CupertinoNavigationBarData( - previousPageTitle: widget.previousPageTitle, - border: Border( - bottom: BorderSide( - color: _separatorColorTween!.value ?? _background, - width: 0.0, // 0.0 means one physical pixel - ), - ), - ), - ), - backgroundColor: _background, - body: child - ), - child: widget.body, - ); - } -} - -/// How many pixels the app bar animation is done over. -const double kScrollTransition = 12; diff --git a/lib/page/common/confirmation.dart b/lib/page/common/confirmation.dart index 35d19cc..adc21b1 100644 --- a/lib/page/common/confirmation.dart +++ b/lib/page/common/confirmation.dart @@ -1,5 +1,5 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; + +import 'package:flutter/material.dart'; /// Holds information for showing a confirmation dialog. class ConfirmationInfo { @@ -21,20 +21,20 @@ class ConfirmationInfo { } Future showConfirmationDialog(BuildContext context, ConfirmationInfo confirmation) async { - return await showPlatformDialog( + return await showDialog( context: context, - builder: (context) => PlatformAlertDialog( + builder: (context) => AlertDialog( title: Text(confirmation.title), content: Text(confirmation.content), actions: [ - PlatformDialogAction( - child: PlatformText(confirmation.negative), + TextButton( + child: Text(confirmation.negative), onPressed: () { Navigator.of(context).pop(false); }, ), - PlatformDialogAction( - child: PlatformText(confirmation.affirmative), + TextButton( + child: Text(confirmation.affirmative), onPressed: () { Navigator.of(context).pop(true); }, diff --git a/lib/page/common/hazard_modal_base.dart b/lib/page/common/hazard_modal_base.dart index 65bb7c0..a6c6928 100644 --- a/lib/page/common/hazard_modal_base.dart +++ b/lib/page/common/hazard_modal_base.dart @@ -1,9 +1,7 @@ import 'dart:async'; import 'dart:io'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/consts.dart'; import 'package:forest_park_reports/page/common/permissions_dialog.dart'; import 'package:forest_park_reports/page/home_page/panel_page.dart'; @@ -73,18 +71,18 @@ class _HazardModalState extends ConsumerState> { return; } - showPlatformDialog(context: context, builder: (_) => PlatformAlertDialog( + showDialog(context: context, builder: (_) => AlertDialog( title: const Text('No photo submitted'), content: const Text('Are you sure you\'d like to submit this hazard without a photo?'), actions: [ - PlatformDialogAction( - child: PlatformText('Cancel'), + TextButton( + child: const Text('Cancel'), onPressed: () { Navigator.pop(context); }, ), - PlatformDialogAction( - child: PlatformText('Yes'), + TextButton( + child: const Text('Yes'), onPressed: () { Navigator.pop(context); _submit(); @@ -112,13 +110,9 @@ class _HazardModalState extends ConsumerState> { Widget build(BuildContext context) { final theme = Theme.of(context); return Panel( - child: PlatformWidgetBuilder( - cupertino: (_, child, __) => child, - material: (_, child, __) => Material( - color: Colors.transparent, - child: child - ), - child: SizedBox( + child: Material( + color: Colors.transparent, + child: SizedBox( height: 500, // height: PanelValues.snapHeight(context), child: Stack( @@ -131,111 +125,76 @@ class _HazardModalState extends ConsumerState> { padding: const EdgeInsets.only(left: 16, top: 10), child: Text( widget.title, - style: isCupertino(context) - ? CupertinoTheme.of(context).textTheme.navTitleTextStyle.copyWith(fontSize: 28) - : theme.textTheme.titleLarge!.copyWith(fontSize: 28), + style: theme.textTheme.titleLarge!.copyWith(fontSize: 28), ), ), - + if (widget.options != null) Padding( padding: const EdgeInsets.only(left: 12, right: 12, top: 12), - child: PlatformWidget( - cupertino: (context, _) => CupertinoSlidingSegmentedControl( - groupValue: _selectedOption, - onValueChanged: (dynamic value) => setState(() { - _selectedOption = value; - }), - children: widget.options!, - ), - - material: (context, _) => SizedBox( - height: 40, - child: SegmentedButton( - emptySelectionAllowed: true, - showSelectedIcon: false, - selected: { - if (_selectedOption != null) - _selectedOption - }, - onSelectionChanged: (selection) { - if (selection.length == 1) { - setState(() => _selectedOption = selection.first); - } - }, - segments: [ - for (final option in widget.options!.entries) - ButtonSegment( - value: option.key, - label: Padding( + child: SizedBox( + height: 40, + child: SegmentedButton( + emptySelectionAllowed: true, + showSelectedIcon: false, + selected: { + if (_selectedOption != null) + _selectedOption + }, + onSelectionChanged: (selection) { + if (selection.length == 1) { + setState(() => _selectedOption = selection.first); + } + }, + segments: [ + for (final option in widget.options!.entries) + ButtonSegment( + value: option.key, + label: Padding( padding: const EdgeInsets.only(bottom: 8), child: option.value - ), ), - ] - ), + ), + ], ), ), ), Expanded( - child: Padding( - padding: const EdgeInsets.only(left:12, right: 12, top: 8), - child: ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(isCupertino(context) ? 8 : 18)), - child: PlatformWidgetBuilder( - cupertino: (context, child, _) => CupertinoButton( - padding: EdgeInsets.zero, - onPressed: _cameraSelect, - color: CupertinoDynamicColor.resolve(CupertinoColors.quaternarySystemFill, context), - child: child!, - ), - material: (context, child, _) => FilledButton( - style: ButtonStyle( - shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(isCupertino(context) ? 8 : 18))), - backgroundColor: WidgetStatePropertyAll(theme.colorScheme.surfaceContainer), - padding: const WidgetStatePropertyAll(EdgeInsets.only()) - ), - onPressed: null, - child: InkWell( - onTap: _cameraSelect, - child: child) - , - ), - child: ConstrainedBox( - constraints: const BoxConstraints.expand(), - child: _image == null ? Icon( - CupertinoIcons.camera, - color: isCupertino(context) - ? CupertinoTheme.of(context).primaryColor - : theme.colorScheme.primary - ) : Image.file( - File(_image!.path), - fit: BoxFit.cover, - ), + child: Padding( + padding: const EdgeInsets.only(left:12, right: 12, top: 8), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(18)), + child: FilledButton( + style: ButtonStyle( + shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(18))), + backgroundColor: WidgetStatePropertyAll(theme.colorScheme.surfaceContainer), + padding: const WidgetStatePropertyAll(EdgeInsets.only()) + ), + onPressed: null, + child: InkWell( + onTap: _cameraSelect, + child: ConstrainedBox( + constraints: const BoxConstraints.expand(), + child: _image == null ? Icon( + Icons.camera_alt_rounded, + color: theme.colorScheme.primary, + ) : Image.file( + File(_image!.path), + fit: BoxFit.cover, + ), + ), + ), ), ), - ), - ) + ) ), Padding( padding: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 28), - child: PlatformWidget( - cupertino: (context, _) => CupertinoButton( - color: CupertinoTheme.of(context).primaryColor, - onPressed: (widget.options != null && _selectedOption == null) || _inProgress + child: FilledButton( + onPressed: (widget.options != null && _selectedOption == null) || _inProgress ? null : _onSubmit, - child: Text( - 'Submit', - style: CupertinoTheme.of(context).textTheme.textStyle, - ), - ), - material: (context, _) => FilledButton( - onPressed: (widget.options != null && _selectedOption == null) || _inProgress - ? null - : _onSubmit, - child: const Text('Submit'), - ), + child: const Text('Submit'), ), ), SizedBox(height: MediaQuery.of(context).viewPadding.bottom), @@ -248,15 +207,12 @@ class _HazardModalState extends ConsumerState> { child: SizedBox( width: 24, height: 24, - child: CupertinoButton( - padding: EdgeInsets.zero, - borderRadius: const BorderRadius.all(Radius.circular(100)), - color: CupertinoDynamicColor.resolve(CupertinoColors.secondarySystemFill, context), + child: IconButton( onPressed: _close, - child: Icon( + icon: const Icon( Icons.close_rounded, size: 20, - color: CupertinoDynamicColor.resolve(CupertinoColors.systemGrey, context), + // color: CupertinoDynamicColor.resolve(CupertinoColors.systemGrey, context), ), ), ), diff --git a/lib/page/common/permissions_dialog.dart b/lib/page/common/permissions_dialog.dart index 10338f6..8683c63 100644 --- a/lib/page/common/permissions_dialog.dart +++ b/lib/page/common/permissions_dialog.dart @@ -1,21 +1,20 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; /// UI to request location showMissingPermissionDialog(BuildContext context, String title, String message) { - showPlatformDialog( + showDialog( context: context, - builder: (context) => PlatformAlertDialog( + builder: (context) => AlertDialog( title: Text(title), content: Text(message), actions: [ - PlatformDialogAction( - child: PlatformText("Cancel"), + TextButton( + child: const Text("Cancel"), onPressed: () => Navigator.pop(context), ), - PlatformDialogAction( - child: PlatformText("Go To Settings"), + TextButton( + child: const Text("Go To Settings"), onPressed: () { Geolocator.openAppSettings(); Navigator.pop(context); diff --git a/lib/page/common/platform_fab.dart b/lib/page/common/platform_fab.dart index 1436236..462fd69 100644 --- a/lib/page/common/platform_fab.dart +++ b/lib/page/common/platform_fab.dart @@ -1,10 +1,4 @@ -import 'dart:ui'; - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; -import 'package:forest_park_reports/util/outline_box_shadow.dart'; - /// A generic floating action button that automatically customizes to the current platform based on provided themes class PlatformFAB extends StatelessWidget { @@ -22,52 +16,13 @@ class PlatformFAB extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - return PlatformWidget( - cupertino: (context, _) { - const fabRadius = BorderRadius.all(Radius.circular(8)); - // Reduce blur before opacity - final double sigma = 15 * Curves.easeIn.transform((opacity*1.5 - 0.5).clamp(0, 1)); - final shadowColor = Colors.black.withOpacity(0.26*opacity); - return Container( - decoration: BoxDecoration( - borderRadius: fabRadius, - boxShadow: [ - OutlineBoxShadow( - color: shadowColor, - blurRadius: 4, - ), - ], - ), - child: ClipRRect( - borderRadius: fabRadius, - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: sigma, sigmaY: sigma), - child: SizedBox( - width: 50, - height: 50, - child: Opacity( - opacity: opacity, - child: CupertinoButton( - padding: EdgeInsets.zero, - color: CupertinoDynamicColor.resolve(CupertinoColors.secondarySystemBackground, context).withAlpha(210), - pressedOpacity: 0.9, - onPressed: onPressed, - child: child - ), - ), - ), - ), - ), - ); - }, - material: (_, __) => Opacity( - opacity: opacity, - child: FloatingActionButton( - heroTag: heroTag, - backgroundColor: theme.colorScheme.surface, - onPressed: onPressed, - child: child, - ), + return Opacity( + opacity: opacity, + child: FloatingActionButton( + heroTag: heroTag, + backgroundColor: theme.colorScheme.surface, + onPressed: onPressed, + child: child, ), ); } diff --git a/lib/page/common/platform_pill.dart b/lib/page/common/platform_pill.dart index f233379..46ee9dd 100644 --- a/lib/page/common/platform_pill.dart +++ b/lib/page/common/platform_pill.dart @@ -1,29 +1,22 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; /// A pill that indicates draggability of the main panel -class PlatformPill extends StatelessWidget { - const PlatformPill({super.key}); +class PanelPill extends StatelessWidget { + const PanelPill({super.key}); @override Widget build(BuildContext context) { - final isIos = isCupertino(context); - final theme = Theme.of(context); return Align( alignment: Alignment.topCenter, child: Container( - margin: EdgeInsets.symmetric( - vertical: isIos ? 5 : 10 + margin: const EdgeInsets.symmetric( + vertical: 10 ), - width: isIos ? 35 : 26, + width: 26, height: 5, decoration: BoxDecoration( - color: isIos - ? CupertinoDynamicColor.resolve(CupertinoColors.systemGrey2, context) - : theme.colorScheme.onSurface, + color: Theme.of(context).colorScheme.onSurface, borderRadius: const BorderRadius.all(Radius.circular(12.0))), ), ); } - } diff --git a/lib/page/common/test_location_too_far.dart b/lib/page/common/test_location_too_far.dart index 784de58..0861bc0 100644 --- a/lib/page/common/test_location_too_far.dart +++ b/lib/page/common/test_location_too_far.dart @@ -1,8 +1,7 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/provider/location_provider.dart'; import 'package:forest_park_reports/util/extensions.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -76,25 +75,26 @@ Future testLocationTooFarDynamic(BuildContext context, WidgetRef ref, { Future _badLocationAlert(BuildContext context, String title, String? content, String acceptText, bool overrideEnabled, String overrideText) { final continueCompleter = Completer(); - showPlatformDialog(context: context, builder: (context) => PlatformAlertDialog( - title: PlatformText(title), - content: (content == null) ? null : PlatformText(content), + showDialog(context: context, builder: (context) => AlertDialog( + title: Text(title), + content: (content == null) ? null : Text(content), actions: [ - PlatformDialogAction( - onPressed: () { - Navigator.pop(context); - continueCompleter.complete(false); - }, - child: PlatformText(acceptText) + TextButton( + onPressed: () { + Navigator.pop(context); + continueCompleter.complete(false); + }, + child: Text(acceptText) ), - if (overrideEnabled) PlatformDialogAction( + if (overrideEnabled) + TextButton( onPressed: () { Navigator.pop(context); continueCompleter.complete(true); }, - child: PlatformText(overrideText) - ), + child: Text(overrideText) + ), ], )); return continueCompleter.future; -} \ No newline at end of file +} diff --git a/lib/page/home_page.dart b/lib/page/home_page.dart index 7c720fa..f6e90aa 100644 --- a/lib/page/home_page.dart +++ b/lib/page/home_page.dart @@ -1,6 +1,5 @@ import 'dart:math'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; @@ -12,7 +11,6 @@ import 'package:forest_park_reports/page/common/platform_fab.dart'; import 'package:forest_park_reports/page/settings_page.dart'; import 'package:forest_park_reports/provider/panel_position_provider.dart'; import 'package:forest_park_reports/page/common/statusbar_blur.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/page/home_page/map_fabs.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:forest_park_reports/page/home_page/map_page.dart'; @@ -43,7 +41,7 @@ class _HomeScreenState extends State { // make the height of the panel when open 80% of the screen final theme = Theme.of(context); - return PlatformScaffold( + return Scaffold( body: Stack( alignment: Alignment.topCenter, children: [ @@ -120,24 +118,14 @@ class _HomeScreenState extends State { heroTag: "settings_fab", onPressed: () async { Navigator.of(context).push( - platformPageRoute( - context: context, + MaterialPageRoute( builder: (_) => const SettingsPage(), ), ); }, - child: PlatformWidget( - cupertino: (_, __) => Icon( - // Fix for bug in cupertino_icons package, should be CupertinoIcons.location - CupertinoIcons.gear, - color: View.of(context).platformDispatcher.platformBrightness == Brightness.light - ? CupertinoColors.systemGrey.highContrastColor - : CupertinoColors.systemGrey.darkHighContrastColor - ), - material: (_, __) => Icon( - Icons.settings, - color: theme.colorScheme.onSurface, - ), + child: Icon( + Icons.settings, + color: theme.colorScheme.onSurface, ), ); } @@ -162,8 +150,7 @@ class _HomeScreenState extends State { ), ), // status bar blur - if (isCupertino(context)) - const StatusBarBlur(), + const StatusBarBlur(), ], ), ); diff --git a/lib/page/home_page/map_compass.dart b/lib/page/home_page/map_compass.dart index 24f51fb..d4fcc1e 100644 --- a/lib/page/home_page/map_compass.dart +++ b/lib/page/home_page/map_compass.dart @@ -1,7 +1,5 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/provider/map_position_provider.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:latlong2/latlong.dart'; @@ -89,25 +87,17 @@ class _MapCompassState extends ConsumerState with TickerProviderStat children: [ Transform.rotate( angle: degToRadian(camera.rotation + widget.rotationOffset), - child: widget.icon ?? PlatformWidget( - cupertino: (_, __) => SizedBox(height: 50, child: Image(image: Theme.of(context).brightness == Brightness.light - ? const AssetImage("assets/image/cupertino_compass.png") - : const AssetImage("assets/image/cupertino_compass_dark.png"))), - material: (_, __) => Transform.rotate( - angle: degToRadian(-45.0), - child: Stack( - alignment: Alignment.center, - children: [ - const Icon(CupertinoIcons.compass, color: Colors.red, size: 50), - Icon(CupertinoIcons.compass_fill, color: theme.colorScheme.surface, size: 50), - Icon(CupertinoIcons.circle, color: theme.colorScheme.surface, size: 52), - ], - ), + child: widget.icon ?? Transform.rotate( + angle: degToRadian(135.0), + child: Stack( + alignment: Alignment.center, + children: [ + Icon(Icons.circle, color: theme.colorScheme.surface, size: 48), + Image.asset('assets/icons/compass.png', width: 20), + ], ), ), ), - // Show cardinal dir letter if default iOS compass or if custom compass and showCardDir enabled - if (widget.icon == null && isCupertino(context) || widget.icon != null && widget.showCardDir) cardDirText(camera, context) ] ), onPressed: @@ -117,26 +107,6 @@ class _MapCompassState extends ConsumerState with TickerProviderStat ); } - Widget cardDirText(MapCamera camera, BuildContext context) { - // Shift camera rotation, clamp from 0 to 360, - // then perform integer division based on 90 degree chunks - int dir = ((camera.rotation + 45) % 360) ~/ 90; - - String letter = - dir == 0 ? 'N' : - dir == 1 ? 'W' : - dir == 2 ? 'S' : - 'E'; - Brightness mode = View.of(context).platformDispatcher.platformBrightness; - Color color = isCupertino(context) ? - mode == Brightness.light - ? CupertinoColors.systemGrey.highContrastColor - : CupertinoColors.systemGrey.darkHighContrastColor - : Theme.of(context).colorScheme.onSurface; - - return Text(letter, style: TextStyle(color: color, fontSize: 20), textAlign: TextAlign.center); - } - void _resetRotation(MapCamera camera) { // current rotation of the map final rotation = camera.rotation; diff --git a/lib/page/home_page/map_fabs.dart b/lib/page/home_page/map_fabs.dart index 60ec5c8..cc3e492 100644 --- a/lib/page/home_page/map_fabs.dart +++ b/lib/page/home_page/map_fabs.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:forest_park_reports/page/common/platform_fab.dart'; import 'package:forest_park_reports/provider/location_provider.dart'; @@ -6,7 +5,6 @@ import 'package:forest_park_reports/provider/align_position_provider.dart'; import 'package:forest_park_reports/util/extensions.dart'; import 'package:forest_park_reports/page/common/permissions_dialog.dart'; import 'package:forest_park_reports/page/common/hazard_add_modal.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; /// The floating action buttons used on the map page. Holds the location and add hazard [PlatformFAB]. @@ -25,23 +23,15 @@ class MapFabs extends ConsumerWidget { Consumer( builder: (context, ref, child) { return PlatformFAB( - heroTag: "add_hazard_fab", - opacity: opacity, - onPressed: () async { - createHazardAddModal(context); - }, - child: PlatformWidget( - cupertino: (_, __) => Icon( - CupertinoIcons.add, - color: View.of(context).platformDispatcher.platformBrightness == Brightness.light - ? CupertinoColors.systemGrey.highContrastColor - : CupertinoColors.systemGrey.darkHighContrastColor - ), - material: (_, __) => Icon( - Icons.add, - color: theme.colorScheme.onSurface, - ), - ) + heroTag: "add_hazard_fab", + opacity: opacity, + onPressed: () async { + createHazardAddModal(context); + }, + child: Icon( + Icons.add, + color: theme.colorScheme.onSurface, + ), ); } ), @@ -74,30 +64,15 @@ class MapFabs extends ConsumerWidget { ); } }, - child: PlatformWidget( - cupertino: (_, __) => Icon( - switch (followOnLocationTarget) { - AlignPositionTargetState.currentLocation => - CupertinoIcons.location_fill, - AlignPositionTargetState.none => - CupertinoIcons.location, - AlignPositionTargetState.forestPark => - Icons.park, - }, - color: View.of(context).platformDispatcher.platformBrightness == Brightness.light - ? CupertinoColors.systemGrey.highContrastColor - : CupertinoColors.systemGrey.darkHighContrastColor - ), - material: (_, __) => Icon( - followOnLocationTarget == AlignPositionTargetState.forestPark - ? Icons.park - : followOnLocationTarget == AlignPositionTargetState.currentLocation - ? Icons.my_location - : Icons.location_searching, - color: followOnLocationTarget == AlignPositionTargetState.none - ? theme.colorScheme.onSurface - : theme.colorScheme.primary, - ), + child: Icon( + followOnLocationTarget == AlignPositionTargetState.forestPark + ? Icons.park + : followOnLocationTarget == AlignPositionTargetState.currentLocation + ? Icons.my_location + : Icons.location_searching, + color: followOnLocationTarget == AlignPositionTargetState.none + ? theme.colorScheme.onSurface + : theme.colorScheme.primary, ), ); } diff --git a/lib/page/home_page/map_page/hazard_info_popup.dart b/lib/page/home_page/map_page/hazard_info_popup.dart index d3e37c0..3b50672 100644 --- a/lib/page/home_page/map_page/hazard_info_popup.dart +++ b/lib/page/home_page/map_page/hazard_info_popup.dart @@ -1,7 +1,4 @@ -import 'dart:ui'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/model/hazard.dart'; import 'package:forest_park_reports/util/outline_box_shadow.dart'; @@ -26,18 +23,8 @@ class HazardInfoPopup extends StatelessWidget { ), child: ClipRRect( borderRadius: radius, - child: PlatformWidgetBuilder( - cupertino: (context, child, _) => BackdropFilter( - filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50), - child: Container( - color: CupertinoDynamicColor.resolve(CupertinoColors.secondarySystemBackground, context).withAlpha(210), - child: child, - ), - ), - material: (_, child, __) => Container( - color: theme.colorScheme.surface, - child: child, - ), + child: Container( + color: theme.colorScheme.surface, child: IntrinsicWidth( child: Column( mainAxisSize: MainAxisSize.min, @@ -63,4 +50,4 @@ class HazardInfoPopup extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/page/home_page/panel_page.dart b/lib/page/home_page/panel_page.dart index 1de39b7..2eb27ca 100644 --- a/lib/page/home_page/panel_page.dart +++ b/lib/page/home_page/panel_page.dart @@ -1,9 +1,6 @@ import 'dart:math'; -import 'dart:ui'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/page/common/hazard_update_modal.dart'; import 'package:forest_park_reports/provider/panel_position_provider.dart'; import 'package:forest_park_reports/util/panel_values.dart'; @@ -57,16 +54,15 @@ class PanelPage extends ConsumerWidget { Expanded( child: Padding( padding: const EdgeInsets.only(left: 20, right: 10), - child: PlatformTextButton( + child: TextButton( onPressed: () async { ref.read(panelPositionProvider.notifier).move(PanelState.COLLAPSED); await createHazardUpdateModal(context, selectedHazard, false); ref.read(panelPositionProvider.notifier).move(PanelState.SNAPPED); }, - padding: EdgeInsets.zero, - child: const Text( + child: Text( "Report Cleared", - style: TextStyle(color: CupertinoColors.systemGreen), + style: TextStyle(color: Theme.of(context).colorScheme.primary), ), ), ), @@ -74,16 +70,15 @@ class PanelPage extends ConsumerWidget { Expanded( child: Padding( padding: const EdgeInsets.only(left: 10, right: 20), - child: PlatformTextButton( + child: TextButton( onPressed: () async { ref.read(panelPositionProvider.notifier).move(PanelState.COLLAPSED); await createHazardUpdateModal(context, selectedHazard, true); ref.read(panelPositionProvider.notifier).move(PanelState.SNAPPED); }, - padding: EdgeInsets.zero, - child: const Text( + child: Text( "Report Present", - style: TextStyle(color: CupertinoColors.destructiveRed), + style: TextStyle(color: Theme.of(context).colorScheme.error), ), ), ), @@ -183,7 +178,7 @@ class Panel extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - final panelRadius = BorderRadius.vertical(top: Radius.circular(isCupertino(context) ? 8 : 18)); + const panelRadius = BorderRadius.vertical(top: Radius.circular(18)); return MediaQuery.removePadding( context: context, removeTop: true, @@ -192,9 +187,9 @@ class Panel extends StatelessWidget { child: Padding( padding: const EdgeInsets.only(top: 8), child: Container( - decoration: BoxDecoration( + decoration: const BoxDecoration( borderRadius: panelRadius, - boxShadow: const [ + boxShadow: [ OutlineBoxShadow( color: Colors.black26, blurRadius: 4, @@ -203,18 +198,9 @@ class Panel extends StatelessWidget { ), child: ClipRRect( borderRadius: panelRadius, - child: PlatformWidget( - cupertino: (context, _) => BackdropFilter( - filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50), - child: Container( - color: CupertinoDynamicColor.resolve(CupertinoColors.secondarySystemBackground, context).withAlpha(210), - child: child, - ), - ), - material: (_, __) => Container( - color: theme.colorScheme.surface, - child: child, - ) + child:Container( + color: theme.colorScheme.surface, + child: child, ), ), ), diff --git a/lib/page/home_page/panel_page/hazard_image.dart b/lib/page/home_page/panel_page/hazard_image.dart index e2df40d..da1e789 100644 --- a/lib/page/home_page/panel_page/hazard_image.dart +++ b/lib/page/home_page/panel_page/hazard_image.dart @@ -1,7 +1,5 @@ import 'package:blurhash_ffi/blurhash_ffi.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/page/common/fade_in_widget.dart'; import 'package:forest_park_reports/provider/hazard_photo_provider.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -40,8 +38,8 @@ class HazardImage extends ConsumerWidget { ), ) else - Center( - child: PlatformCircularProgressIndicator(), + const Center( + child: CircularProgressIndicator(), ), ], ); diff --git a/lib/page/home_page/panel_page/trail_elevation_graph.dart b/lib/page/home_page/panel_page/trail_elevation_graph.dart index b1f0dc0..2fb7ebe 100644 --- a/lib/page/home_page/panel_page/trail_elevation_graph.dart +++ b/lib/page/home_page/panel_page/trail_elevation_graph.dart @@ -2,7 +2,6 @@ import 'dart:math'; import 'package:collection/collection.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/consts.dart'; import 'package:forest_park_reports/provider/hazard_provider.dart'; import 'package:forest_park_reports/provider/map_cursor_provider.dart'; @@ -24,8 +23,8 @@ class TrailElevationGraph extends ConsumerWidget { }); Widget _loading() { - return Center( - child: PlatformCircularProgressIndicator() + return const Center( + child: CircularProgressIndicator() ); } diff --git a/lib/page/home_page/panel_page/trail_hazards_widget.dart b/lib/page/home_page/panel_page/trail_hazards_widget.dart index 759f44f..515bd10 100644 --- a/lib/page/home_page/panel_page/trail_hazards_widget.dart +++ b/lib/page/home_page/panel_page/trail_hazards_widget.dart @@ -1,6 +1,5 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/model/hazard.dart'; import 'package:forest_park_reports/page/home_page/panel_page/hazard_image.dart'; import 'package:forest_park_reports/provider/hazard_provider.dart'; @@ -45,8 +44,8 @@ class TrailHazardsWidget extends ConsumerWidget { HazardInfoWidget( hazard: hazard, )).toList(), - ) : Center( - child: PlatformCircularProgressIndicator(), + ) : const Center( + child: CircularProgressIndicator(), ), ), ), @@ -65,13 +64,13 @@ class HazardInfoWidget extends ConsumerWidget { final hazardUpdates = ref.watch(hazardUpdatesProvider(hazard.uuid)).valueOrNull; final lastImage = hazardUpdates?.lastImage; final lastBlurHash = hazardUpdates?.lastBlurHash; - return PlatformTextButton( + return Padding( padding: const EdgeInsets.only(left: 12, right: 8, top: 8, bottom: 8), - onPressed: () { - ref.read(selectedRelationProvider.notifier).deselect(); - ref.read(selectedHazardProvider.notifier).selectAndMove(hazard); - }, - material: (_, __) => MaterialTextButtonData( + child: TextButton( + onPressed: () { + ref.read(selectedRelationProvider.notifier).deselect(); + ref.read(selectedHazardProvider.notifier).selectAndMove(hazard); + }, style: ButtonStyle( shape: WidgetStateProperty.all( RoundedRectangleBorder( @@ -79,35 +78,35 @@ class HazardInfoWidget extends ConsumerWidget { ), ), ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - hazard.hazard.displayName, - style: theme.textTheme.titleLarge, - ), - Text( - hazard.timeString(), - style: theme.textTheme.titleMedium - ) - ], - ), - if (lastImage != null) - SizedBox( - height: 80, - child: AspectRatio( - aspectRatio: 4/3, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(8)), - child: HazardImage(lastImage, blurHash: lastBlurHash), - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + hazard.hazard.displayName, + style: theme.textTheme.titleLarge, + ), + Text( + hazard.timeString(), + style: theme.textTheme.titleMedium ) - ) - ], + ], + ), + if (lastImage != null) + SizedBox( + height: 80, + child: AspectRatio( + aspectRatio: 4/3, + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: HazardImage(lastImage, blurHash: lastBlurHash), + ), + ) + ) + ], + ), ), ); } diff --git a/lib/page/home_page/panel_page/trail_info.dart b/lib/page/home_page/panel_page/trail_info.dart index 780470e..4e060ec 100644 --- a/lib/page/home_page/panel_page/trail_info.dart +++ b/lib/page/home_page/panel_page/trail_info.dart @@ -37,7 +37,7 @@ class _TrailInfoWidgetState extends State { children: [ const Align( alignment: Alignment.topCenter, - child: PlatformPill(), + child: PanelPill(), ), Align( alignment: Alignment.centerLeft, diff --git a/lib/page/settings_page/button_setting_widget.dart b/lib/page/settings_page/button_setting_widget.dart index 82ea070..2dd8a18 100644 --- a/lib/page/settings_page/button_setting_widget.dart +++ b/lib/page/settings_page/button_setting_widget.dart @@ -1,5 +1,6 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; import 'package:forest_park_reports/page/common/confirmation.dart'; /// Styles for [ButtonSettingWidget]. @@ -37,13 +38,13 @@ class ButtonSettingWidget extends StatelessWidget { Widget build(BuildContext context) { final textStyle = switch(buttonStyle) { ButtonSettingStyle.none => null, - ButtonSettingStyle.danger => CupertinoTheme.of(context).textTheme.actionTextStyle.copyWith( - color: CupertinoDynamicColor.resolve(CupertinoColors.destructiveRed, context), + ButtonSettingStyle.danger => TextStyle( + color: Theme.of(context).colorScheme.error, ), - ButtonSettingStyle.button => CupertinoTheme.of(context).textTheme.actionTextStyle, + ButtonSettingStyle.button => null, }; - return PlatformListTile( + return ListTile( title: Text( name, style: textStyle diff --git a/lib/page/settings_page/selection_setting_widget.dart b/lib/page/settings_page/selection_setting_widget.dart index f735ccd..fbf1757 100644 --- a/lib/page/settings_page/selection_setting_widget.dart +++ b/lib/page/settings_page/selection_setting_widget.dart @@ -1,5 +1,4 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:flutter/material.dart'; import 'package:forest_park_reports/model/settings.dart'; import 'package:forest_park_reports/page/settings_page/settings_page_scaffold.dart'; @@ -22,16 +21,13 @@ class SelectionSettingWidget extends StatelessWidget @override Widget build(BuildContext context) { - return PlatformListTile( + return ListTile( title: Text(name), - trailing: const CupertinoListTileChevron(), - cupertino: (_, __) => CupertinoListTileData( - additionalInfo: Text(selectedOption.displayName), - ), + // TODO: material alternative - trailing: const CupertinoListTileChevron(), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () async { await Navigator.of(context).push( - platformPageRoute( - context: context, + MaterialPageRoute( builder: (context) => _SelectionSettingWidgetPage( name: name, pageTitle: pageTitle, @@ -81,7 +77,7 @@ class _SelectionSettingWidgetPageState extends State<_SelectionSettingWidgetPage SettingsSection( children: [ for (final option in widget.options) - PlatformListTile( + ListTile( title: Text(option.displayName), onTap: () async { final delay = Future.delayed(const Duration(milliseconds: 100)); @@ -91,9 +87,8 @@ class _SelectionSettingWidgetPageState extends State<_SelectionSettingWidgetPage }); await delay; }, - trailing: option == selected ? Icon( - CupertinoIcons.checkmark, - size: CupertinoTheme.of(context).textTheme.textStyle.fontSize, + trailing: option == selected ? const Icon( + Icons.check_rounded, ) : null, ), ], diff --git a/lib/page/settings_page/settings_page_scaffold.dart b/lib/page/settings_page/settings_page_scaffold.dart index 0d005cc..ab2c791 100644 --- a/lib/page/settings_page/settings_page_scaffold.dart +++ b/lib/page/settings_page/settings_page_scaffold.dart @@ -1,5 +1,5 @@ import 'package:flutter/cupertino.dart'; -import 'package:forest_park_reports/page/common/animated_app_bar_scaffold.dart'; +import 'package:flutter/material.dart'; import 'package:forest_park_reports/page/settings_page/settings_section.dart'; @@ -30,17 +30,16 @@ class _SettingsPageScaffoldState extends State { @override Widget build(BuildContext context) { - return AnimatedAppBarScaffold( - // Pass the scroll controller to AnimatedAppBarScaffold so it knows when to show and hide. - scrollController: _scrollController, - title: widget.title, - previousPageTitle: widget.previousPageTitle, - body: ListView( - // Allows bouncing even when content doesn't fill up the screen - physics: const AlwaysScrollableScrollPhysics(), - controller: _scrollController, - children: widget.children - ), + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: ListView( + // Allows bouncing even when content doesn't fill up the screen + physics: const AlwaysScrollableScrollPhysics(), + controller: _scrollController, + children: widget.children + ), ); } } diff --git a/lib/page/settings_page/settings_section.dart b/lib/page/settings_page/settings_section.dart index c270591..5224058 100644 --- a/lib/page/settings_page/settings_section.dart +++ b/lib/page/settings_page/settings_section.dart @@ -1,10 +1,8 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:forest_park_reports/page/settings_page/settings_page_scaffold.dart'; /// A Settings group using [CupertinoListSection.insetGrouped()] on iOS and Material style dividers on Android. -class SettingsSection extends PlatformWidgetBase { +class SettingsSection extends StatelessWidget { /// The children; these should be settings tiles (but are not required to be). final List children; /// The label/heading displayed at the beginning of the group. Rendered in caps on iOS. @@ -12,26 +10,7 @@ class SettingsSection extends PlatformWidgetBase { const SettingsSection({super.key, required this.children, this.label}); @override - Widget createCupertinoWidget(BuildContext context) { - return CupertinoListSection.insetGrouped( - backgroundColor: CupertinoDynamicColor.resolve(CupertinoColors.systemGroupedBackground, context), - header: label != null - ? Padding( - padding: const EdgeInsets.only(left: 20), - child: Text( - label!.toUpperCase(), - style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( - fontSize: 14, - color: CupertinoDynamicColor.resolve(kHeaderFooterColor, context), - ), - ), - ) : null, - children: children, - ); - } - - @override - Widget createMaterialWidget(BuildContext context) { + Widget build(BuildContext context) { return Column( children: [ if (label != null) diff --git a/lib/page/settings_page/toggle_setting_widget.dart b/lib/page/settings_page/toggle_setting_widget.dart index 4b9ad85..6c7c774 100644 --- a/lib/page/settings_page/toggle_setting_widget.dart +++ b/lib/page/settings_page/toggle_setting_widget.dart @@ -1,6 +1,4 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; /// A settings widget for boolean options. class ToggleSettingWidget extends StatelessWidget { @@ -19,15 +17,12 @@ class ToggleSettingWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return PlatformListTile( - material: (_, __) => MaterialListTileData( - // Allow clicking the entire tile on Android. - onTap: () { - onChanged(!value); - } - ), + return ListTile( title: Text(name), - trailing: PlatformSwitch( + onTap: () { + onChanged(!value); + }, + trailing: Switch( value: value, onChanged: onChanged, ), diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 9c6bbeb..30f72f7 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,15 +6,11 @@ #include "generated_plugin_registrant.h" -#include #include #include #include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) dynamic_color_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); - dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 19746ce..4aa4488 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - dynamic_color file_selector_linux objectbox_flutter_libs sqlite3_flutter_libs diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 0bc992a..12b0052 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,7 +5,6 @@ import FlutterMacOS import Foundation -import dynamic_color import file_selector_macos import geolocator_apple import objectbox_flutter_libs @@ -14,7 +13,6 @@ import shared_preferences_foundation import sqlite3_flutter_libs func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) ObjectboxFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "ObjectboxFlutterLibsPlugin")) diff --git a/pubspec.lock b/pubspec.lock index e19f75b..c56686b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -226,7 +226,7 @@ packages: source: hosted version: "3.0.3" cupertino_icons: - dependency: "direct main" + dependency: transitive description: name: cupertino_icons sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 @@ -297,14 +297,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.18.0" - dynamic_color: - dependency: "direct main" - description: - name: dynamic_color - sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d - url: "https://pub.dev" - source: hosted - version: "1.7.0" equatable: dependency: transitive description: @@ -478,14 +470,6 @@ packages: url: "https://pub.dev" source: hosted version: "9.1.0" - flutter_platform_widgets: - dependency: "direct main" - description: - name: flutter_platform_widgets - sha256: "1a52147c03f0265b4f64d607f05ccfce5b2390224c6d40435ebc212f23576fff" - url: "https://pub.dev" - source: hosted - version: "7.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d05c805..0a73acf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,12 +32,6 @@ dependencies: meta: ^1.12.0 collection: ^1.17.1 intl: ^0.19.0 - dynamic_color: ^1.7.0 - # dynamic_color: - # git: - # url: https://github.com/hasali19/material-foundation-flutter-packages.git - # path: packages/dynamic_color - cupertino_icons: ^1.0.5 latlong2: ^0.9.0 geolocator: ^12.0.0 hooks_riverpod: ^2.3.6 @@ -45,7 +39,6 @@ dependencies: sliding_up_panel2: git: url: https://github.com/trilliumlab/sliding_up_panel.git - flutter_platform_widgets: ^7.0.0 dio: ^5.2.1+1 path: ^1.8.3 path_provider: ^2.0.15 @@ -103,6 +96,7 @@ flutter: - asset: assets/fonts/trail_eyes_icons.otf assets: - assets/image/ + - assets/icons/ - .env icons_launcher: @@ -119,7 +113,7 @@ icons_launcher: # Generate icon class with `dart run icon_font_generator:generator` icon_font: - input_svg_dir: "assets/icons/" + input_svg_dir: "assets/svg_icons/" output_font_file: "assets/fonts/trail_eyes_icons.otf" output_class_file: "lib/util/trail_eyes_icons.dart" class_name: "TrailEyesIcons" diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index edab2c4..34f3d70 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,15 +6,12 @@ #include "generated_plugin_registrant.h" -#include #include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { - DynamicColorPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); GeolocatorWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 9a57451..9d3a42a 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - dynamic_color file_selector_windows geolocator_windows objectbox_flutter_libs From 76158d3dc9264c18a038c5874559554eec77eca7 Mon Sep 17 00:00:00 2001 From: Elliot Nash Date: Mon, 12 Aug 2024 17:17:36 -0700 Subject: [PATCH 2/8] Remove cupertino imports + use material modals --- lib/consts.dart | 8 - lib/model/hazard_type.dart | 5 +- lib/page/common/hazard_add_modal.dart | 74 ++++--- lib/page/common/hazard_modal_base.dart | 191 +++++++++--------- lib/page/common/hazard_update_modal.dart | 73 ++++--- lib/page/home_page/map_page.dart | 1 - .../map_page/hazard_marker_layer.dart | 5 +- .../map_page/trail_polyline_layer.dart | 8 +- .../home_page/panel_page/hazard_info.dart | 7 +- lib/page/settings_page.dart | 1 - .../settings_page/settings_page_scaffold.dart | 11 - lib/provider/hazard_photo_provider.dart | 2 +- lib/provider/hazard_provider.dart | 13 +- lib/util/image_extensions.dart | 2 +- lib/util/offline_uploader.dart | 2 +- lib/util/outline_box_shadow.dart | 2 +- lib/util/panel_values.dart | 2 +- 17 files changed, 180 insertions(+), 227 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index 750fbac..5914d31 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:forest_park_reports/model/camera_position.dart'; @@ -18,7 +17,6 @@ const kPlatformOverride = TargetPlatform.android; // const kPlatformOverride = TargetPlatform.iOS; final kMaterialAppPrimaryColor = Colors.green.shade700; -final kCupertinoAppPrimaryColor = CupertinoColors.systemGreen.highContrastColor; // Allows a user to submit hazards and updates without appropriate proximity. const bool kLocationOverrideEnabled = true; @@ -58,9 +56,3 @@ const kBackgroundRequestPortName = "backgroundRequestPort"; // Uuid generator const kUuidGen = Uuid(); - -// Colors -const kDialogColor = CupertinoDynamicColor.withBrightness( - color: Color(0xCCF2F2F2), - darkColor: Color(0xBF1E1E1E), -); diff --git a/lib/model/hazard_type.dart b/lib/model/hazard_type.dart index 642149d..9b9aad4 100644 --- a/lib/model/hazard_type.dart +++ b/lib/model/hazard_type.dart @@ -1,10 +1,9 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; enum HazardType { - tree("Fallen Tree", CupertinoIcons.tree), + tree("Fallen Tree", Icons.park_outlined), flood("Flooded Trail", Icons.flood_rounded), - other("Other Hazard", CupertinoIcons.question_diamond_fill); + other("Other Hazard", Icons.help_outline_outlined); const HazardType(this.displayName, this.icon); final String displayName; diff --git a/lib/page/common/hazard_add_modal.dart b/lib/page/common/hazard_add_modal.dart index 1440ed6..aba96e4 100644 --- a/lib/page/common/hazard_add_modal.dart +++ b/lib/page/common/hazard_add_modal.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:forest_park_reports/consts.dart'; import 'package:forest_park_reports/model/hazard_type.dart'; import 'package:forest_park_reports/page/common/hazard_modal_base.dart'; @@ -15,49 +15,43 @@ import 'package:latlong2/latlong.dart'; /// The additional modal with the ui for reporting a trail hazard createHazardAddModal(BuildContext context) async { - await showCupertinoModalPopup( + await showModalBottomSheet( context: context, builder: (context) { - return Dismissible( - direction: DismissDirection.down, - key: const Key('key'), - onDismissed: (_) => Navigator.of(context).pop(), - child: HazardModal( - title: "Report New Hazard", - options: { - for (final type in HazardType.values) - type: Text("${type.name[0].toUpperCase()}${type.name.substring(1)}",) - }, - onSubmit: (context, ref, image, uuid, hazardType) async { + return HazardModal( + title: "Report New Hazard", + options: { + for (final type in HazardType.values) + type: Text("${type.name[0].toUpperCase()}${type.name.substring(1)}",) + }, + onSubmit: (context, ref, image, uuid, hazardType) async { + if (!await testLocationTooFarDynamic(context, ref, + tolerance: kAddLocationTolerance, + actionLocationGetter: (context, ref, loc) { + var completer = Completer(); + ref.read(trailsProvider.notifier).snapLocation(loc).then( + (result) => completer.complete(result.location)); + return completer.future; + }, + title: "Too far from trail", + content: "Reports must be made on a marked Forest Park trail", + overrideEnabled: kLocationOverrideEnabled)) { + return false; + } + // The above check ensured the location already has a value (testLocationTooFarDynamic) + final location = ref.read(locationProvider).requireValue; + var snappedLoc = await ref.read(trailsProvider.notifier).snapLocation(location.latLng()!); - if (!await testLocationTooFarDynamic(context, ref, - tolerance: kAddLocationTolerance, - actionLocationGetter: (context, ref, loc) { - var completer = Completer(); - ref.read(trailsProvider.notifier).snapLocation(loc).then( - (result) => completer.complete(result.location)); - return completer.future; - }, - title: "Too far from trail", - content: "Reports must be made on a marked Forest Park trail", - overrideEnabled: kLocationOverrideEnabled)) { - return false; - } - // The above check ensured the location already has a value (testLocationTooFarDynamic) - final location = ref.read(locationProvider).requireValue; - var snappedLoc = await ref.read(trailsProvider.notifier).snapLocation(location.latLng()!); + final activeHazardNotifier = ref.read(activeHazardProvider.notifier); - final activeHazardNotifier = ref.read(activeHazardProvider.notifier); - - activeHazardNotifier.createHazard( - uuid: uuid, - hazard: hazardType!, - location: snappedLoc.location, - imageFile: image - ); - return true; - }, - ), + activeHazardNotifier.createHazard( + uuid: uuid, + hazard: hazardType!, + location: snappedLoc.location, + imageFile: image + ); + return true; + }, ); } ); diff --git a/lib/page/common/hazard_modal_base.dart b/lib/page/common/hazard_modal_base.dart index a6c6928..cf62e61 100644 --- a/lib/page/common/hazard_modal_base.dart +++ b/lib/page/common/hazard_modal_base.dart @@ -109,118 +109,109 @@ class _HazardModalState extends ConsumerState> { @override Widget build(BuildContext context) { final theme = Theme.of(context); - return Panel( - child: Material( - color: Colors.transparent, - child: SizedBox( - height: 500, - // height: PanelValues.snapHeight(context), - child: Stack( - fit: StackFit.expand, + return SizedBox( + height: 500, + // height: PanelValues.snapHeight(context), + child: Stack( + fit: StackFit.expand, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16, top: 10), - child: Text( - widget.title, - style: theme.textTheme.titleLarge!.copyWith(fontSize: 28), - ), - ), + Padding( + padding: const EdgeInsets.only(left: 16, top: 10), + child: Text( + widget.title, + style: theme.textTheme.titleLarge!.copyWith(fontSize: 28), + ), + ), - if (widget.options != null) Padding( - padding: const EdgeInsets.only(left: 12, right: 12, top: 12), - child: SizedBox( - height: 40, - child: SegmentedButton( - emptySelectionAllowed: true, - showSelectedIcon: false, - selected: { - if (_selectedOption != null) - _selectedOption - }, - onSelectionChanged: (selection) { - if (selection.length == 1) { - setState(() => _selectedOption = selection.first); - } - }, - segments: [ - for (final option in widget.options!.entries) - ButtonSegment( - value: option.key, - label: Padding( - padding: const EdgeInsets.only(bottom: 8), - child: option.value - ), - ), - ], - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left:12, right: 12, top: 8), - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(18)), - child: FilledButton( - style: ButtonStyle( - shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(18))), - backgroundColor: WidgetStatePropertyAll(theme.colorScheme.surfaceContainer), - padding: const WidgetStatePropertyAll(EdgeInsets.only()) - ), - onPressed: null, - child: InkWell( - onTap: _cameraSelect, - child: ConstrainedBox( - constraints: const BoxConstraints.expand(), - child: _image == null ? Icon( - Icons.camera_alt_rounded, - color: theme.colorScheme.primary, - ) : Image.file( - File(_image!.path), - fit: BoxFit.cover, - ), - ), - ), + if (widget.options != null) Padding( + padding: const EdgeInsets.only(left: 12, right: 12, top: 12), + child: SizedBox( + height: 40, + child: SegmentedButton( + emptySelectionAllowed: true, + showSelectedIcon: false, + selected: { + if (_selectedOption != null) + _selectedOption + }, + onSelectionChanged: (selection) { + if (selection.length == 1) { + setState(() => _selectedOption = selection.first); + } + }, + segments: [ + for (final option in widget.options!.entries) + ButtonSegment( + value: option.key, + label: Padding( + padding: const EdgeInsets.only(bottom: 8), + child: option.value ), ), - ) - ), - - Padding( - padding: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 28), - child: FilledButton( - onPressed: (widget.options != null && _selectedOption == null) || _inProgress - ? null - : _onSubmit, - child: const Text('Submit'), - ), + ], ), - SizedBox(height: MediaQuery.of(context).viewPadding.bottom), - ], + ), ), - Align( - alignment: Alignment.topRight, - child: Padding( - padding: const EdgeInsets.all(14), - child: SizedBox( - width: 24, - height: 24, - child: IconButton( - onPressed: _close, - icon: const Icon( - Icons.close_rounded, - size: 20, - // color: CupertinoDynamicColor.resolve(CupertinoColors.systemGrey, context), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left:12, right: 12, top: 8), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(18)), + child: FilledButton( + style: ButtonStyle( + shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(18))), + backgroundColor: WidgetStatePropertyAll(theme.colorScheme.surfaceContainer), + padding: const WidgetStatePropertyAll(EdgeInsets.only()) + ), + onPressed: null, + child: InkWell( + onTap: _cameraSelect, + child: ConstrainedBox( + constraints: const BoxConstraints.expand(), + child: _image == null ? Icon( + Icons.camera_alt_rounded, + color: theme.colorScheme.primary, + ) : Image.file( + File(_image!.path), + fit: BoxFit.cover, + ), + ), + ), ), ), - ), + ) + ), + + Padding( + padding: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 28), + child: FilledButton( + onPressed: (widget.options != null && _selectedOption == null) || _inProgress + ? null + : _onSubmit, + child: const Text('Submit'), ), ), + SizedBox(height: MediaQuery.of(context).viewPadding.bottom), ], ), - ), + Align( + alignment: Alignment.topRight, + child: Padding( + padding: const EdgeInsets.all(2), + child: IconButton( + onPressed: _close, + icon: const Icon( + Icons.close_rounded, + // size: 20, + // color: CupertinoDynamicColor.resolve(CupertinoColors.systemGrey, context), + ), + ), + ), + ), + ], ), ); } diff --git a/lib/page/common/hazard_update_modal.dart b/lib/page/common/hazard_update_modal.dart index e5becc2..ca22d24 100644 --- a/lib/page/common/hazard_update_modal.dart +++ b/lib/page/common/hazard_update_modal.dart @@ -1,4 +1,4 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:forest_park_reports/consts.dart'; import 'package:forest_park_reports/model/hazard.dart'; import 'package:forest_park_reports/page/common/confirmation.dart'; @@ -10,47 +10,42 @@ import 'package:latlong2/latlong.dart'; /// The additional modal with the ui for reporting a trail hazard createHazardUpdateModal(BuildContext context, HazardModel selectedHazard, bool isPresent) async { - await showCupertinoModalPopup( + await showModalBottomSheet( context: context, builder: (context) { - return Dismissible( - direction: DismissDirection.down, - key: const Key('key'), - onDismissed: (_) => Navigator.of(context).pop(), - child: HazardModal( - title: "Update Hazard", - options: const { - false: Text("Cleared", style: TextStyle(color: CupertinoColors.systemGreen)), - true: Text("Present", style: TextStyle(color: CupertinoColors.destructiveRed)), - }, - initialOption: isPresent, - onSubmit: (context, ref, image, updateUuid, hazardType) async { - if (!await showConfirmationDialog(context, ConfirmationInfo( - title: "Report hazard ${isPresent ? "present" : "cleared"}?", - content: "Please make sure the hazard is ${isPresent ? "still present" : "gone"}.", - affirmative: "Yes" - ))) { - return false; - } - - if (context.mounted && !await testLocationTooFar(context, ref, - tolerance: kUpdateLocationTolerance, - actionLocation: LatLng(selectedHazard.location.latitude, selectedHazard.location.longitude), - title: "Too far from hazard", - content: "Hazard updates must be made in proximity to the hazard", - overrideEnabled: kLocationOverrideEnabled)) { - return false; - } + return HazardModal( + title: "Update Hazard", + options: const { + false: Text("Cleared", style: TextStyle(color: Colors.green)), + true: Text("Present", style: TextStyle(color: Colors.red)), + }, + initialOption: isPresent, + onSubmit: (context, ref, image, updateUuid, hazardType) async { + if (!await showConfirmationDialog(context, ConfirmationInfo( + title: "Report hazard ${isPresent ? "present" : "cleared"}?", + content: "Please make sure the hazard is ${isPresent ? "still present" : "gone"}.", + affirmative: "Yes" + ))) { + return false; + } - ref.read(activeHazardProvider.notifier).updateHazard( - uuid: updateUuid, - hazard: selectedHazard.uuid, - active: isPresent, - imageFile: image, - ); - return true; - }, - ), + if (context.mounted && !await testLocationTooFar(context, ref, + tolerance: kUpdateLocationTolerance, + actionLocation: LatLng(selectedHazard.location.latitude, selectedHazard.location.longitude), + title: "Too far from hazard", + content: "Hazard updates must be made in proximity to the hazard", + overrideEnabled: kLocationOverrideEnabled)) { + return false; + } + + ref.read(activeHazardProvider.notifier).updateHazard( + uuid: updateUuid, + hazard: selectedHazard.uuid, + active: isPresent, + imageFile: image, + ); + return true; + }, ); } ); diff --git a/lib/page/home_page/map_page.dart b/lib/page/home_page/map_page.dart index cb3f2e7..416d937 100644 --- a/lib/page/home_page/map_page.dart +++ b/lib/page/home_page/map_page.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:forest_park_reports/provider/map_position_provider.dart'; import 'package:http/io_client.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map_animations/flutter_map_animations.dart'; diff --git a/lib/page/home_page/map_page/hazard_marker_layer.dart b/lib/page/home_page/map_page/hazard_marker_layer.dart index 54c507f..1355761 100644 --- a/lib/page/home_page/map_page/hazard_marker_layer.dart +++ b/lib/page/home_page/map_page/hazard_marker_layer.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map_animations/flutter_map_animations.dart'; @@ -50,8 +49,8 @@ class HazardMarkerLayer extends ConsumerWidget { child: MapIcon( Icons.fmd_bad_rounded, color: hazard.offline - ? CupertinoColors.systemGrey - : CupertinoColors.destructiveRed, + ? Colors.grey + : Colors.red, ), ) ); diff --git a/lib/page/home_page/map_page/trail_polyline_layer.dart b/lib/page/home_page/map_page/trail_polyline_layer.dart index f8d5a6e..c0ffb2b 100644 --- a/lib/page/home_page/map_page/trail_polyline_layer.dart +++ b/lib/page/home_page/map_page/trail_polyline_layer.dart @@ -1,5 +1,5 @@ import 'package:collection/collection.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:forest_park_reports/model/relation.dart'; import 'package:forest_park_reports/provider/hazard_provider.dart'; @@ -71,14 +71,14 @@ class TrailPolylineLayer extends ConsumerWidget { hitValue: trail.id, points: trail.geometry, strokeWidth: 1.0, - borderColor: CupertinoColors.activeGreen.withAlpha(80), + borderColor: Colors.green.withAlpha(80), borderStrokeWidth: 8.0, - color: CupertinoColors.activeGreen, + color: Colors.green, ) : Polyline( hitValue: trail.id, points: trail.geometry, strokeWidth: 1.0, - color: CupertinoColors.activeOrange, + color: Colors.orange, ); }).whereNotNull().toList()..sort((a, b) { // sorts the list to have selected polylines at the top diff --git a/lib/page/home_page/panel_page/hazard_info.dart b/lib/page/home_page/panel_page/hazard_info.dart index f8e0caa..9aeec7d 100644 --- a/lib/page/home_page/panel_page/hazard_info.dart +++ b/lib/page/home_page/panel_page/hazard_info.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:forest_park_reports/model/hazard_update.dart'; @@ -25,10 +24,10 @@ class UpdateInfoWidget extends StatelessWidget { decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(2.5)), color: update.offline - ? CupertinoDynamicColor.resolve(CupertinoColors.systemGrey, context) + ? Colors.grey : update.active - ? CupertinoDynamicColor.resolve(CupertinoColors.destructiveRed, context) - : CupertinoDynamicColor.resolve(CupertinoColors.systemGreen, context), + ? Colors.red + : Colors.green, ), height: kImageHeight, width: 5, diff --git a/lib/page/settings_page.dart b/lib/page/settings_page.dart index 2657d54..1388995 100644 --- a/lib/page/settings_page.dart +++ b/lib/page/settings_page.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_uploader/flutter_uploader.dart'; import 'package:forest_park_reports/consts.dart'; diff --git a/lib/page/settings_page/settings_page_scaffold.dart b/lib/page/settings_page/settings_page_scaffold.dart index ab2c791..5ecb8d6 100644 --- a/lib/page/settings_page/settings_page_scaffold.dart +++ b/lib/page/settings_page/settings_page_scaffold.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:forest_park_reports/page/settings_page/settings_section.dart'; @@ -46,13 +45,3 @@ class _SettingsPageScaffoldState extends State { /// The margin from the side of the screen for settings tiles on Android. const double kAndroidSettingsMargin = 16; -const kHeaderFooterColor = CupertinoDynamicColor( - color: Color.fromRGBO(108, 108, 108, 1.0), - darkColor: Color.fromRGBO(142, 142, 146, 1.0), - highContrastColor: Color.fromRGBO(74, 74, 77, 1.0), - darkHighContrastColor: Color.fromRGBO(176, 176, 183, 1.0), - elevatedColor: Color.fromRGBO(108, 108, 108, 1.0), - darkElevatedColor: Color.fromRGBO(142, 142, 146, 1.0), - highContrastElevatedColor: Color.fromRGBO(108, 108, 108, 1.0), - darkHighContrastElevatedColor: Color.fromRGBO(142, 142, 146, 1.0), -); diff --git a/lib/provider/hazard_photo_provider.dart b/lib/provider/hazard_photo_provider.dart index 123ed06..0729ce5 100644 --- a/lib/provider/hazard_photo_provider.dart +++ b/lib/provider/hazard_photo_provider.dart @@ -1,6 +1,6 @@ import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:forest_park_reports/consts.dart'; import 'package:forest_park_reports/provider/dio_provider.dart'; diff --git a/lib/provider/hazard_provider.dart b/lib/provider/hazard_provider.dart index b1949db..d6fe1c2 100644 --- a/lib/provider/hazard_provider.dart +++ b/lib/provider/hazard_provider.dart @@ -1,10 +1,7 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; import 'package:forest_park_reports/consts.dart'; -import 'package:forest_park_reports/main.dart'; import 'package:forest_park_reports/model/hazard_new_response.dart'; import 'package:forest_park_reports/model/hazard_type.dart'; import 'package:forest_park_reports/model/queued_request.dart'; @@ -83,7 +80,7 @@ class ActiveHazard extends _$ActiveHazard { showAlertBanner( key: Key(uuid), child: const Text("Your report has been queued", key: Key("Your report has been queued")), - color: CupertinoDynamicColor.resolve(CupertinoColors.systemGrey, homeKey.currentContext!), + color: Colors.grey, ); // If we're passed an image, decode it. @@ -139,7 +136,7 @@ class ActiveHazard extends _$ActiveHazard { showAlertBanner( key: Key(response.hazard.uuid), child: const Text("Report uploaded successfully", key: Key("Report uploaded successfully")), - color: CupertinoDynamicColor.resolve(CupertinoColors.activeGreen, homeKey.currentContext!), + color: Colors.green, ); _addHazard(response.hazard); @@ -174,7 +171,7 @@ class ActiveHazard extends _$ActiveHazard { showAlertBanner( key: Key(uuid), child: const Text("Your report has been queued", key: Key("Your report has been queued")), - color: CupertinoDynamicColor.resolve(CupertinoColors.systemGrey, homeKey.currentContext!), + color: Colors.green, ); // If we're passed an image, decode it. @@ -240,7 +237,7 @@ class ActiveHazard extends _$ActiveHazard { showAlertBanner( key: Key(hazardUpdate.uuid), child: const Text("Report uploaded successfully", key: Key("Report uploaded successfully")), - color: CupertinoDynamicColor.resolve(CupertinoColors.activeGreen, homeKey.currentContext!), + color: Colors.green, ); // Add new update to hazard updates diff --git a/lib/util/image_extensions.dart b/lib/util/image_extensions.dart index a751e12..a5285da 100644 --- a/lib/util/image_extensions.dart +++ b/lib/util/image_extensions.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'package:blurhash_ffi/blurhash.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:image/image.dart' as img; extension CompressImage on img.Image { diff --git a/lib/util/offline_uploader.dart b/lib/util/offline_uploader.dart index 7ae932c..9dd0aff 100644 --- a/lib/util/offline_uploader.dart +++ b/lib/util/offline_uploader.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'dart:isolate'; import 'dart:ui'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:forest_park_reports/consts.dart'; import 'package:forest_park_reports/main.dart'; import 'package:forest_park_reports/model/hazard_new_response.dart'; diff --git a/lib/util/outline_box_shadow.dart b/lib/util/outline_box_shadow.dart index 08c5661..9d1227e 100644 --- a/lib/util/outline_box_shadow.dart +++ b/lib/util/outline_box_shadow.dart @@ -1,4 +1,4 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; class OutlineBoxShadow extends BoxShadow { const OutlineBoxShadow({ diff --git a/lib/util/panel_values.dart b/lib/util/panel_values.dart index dccfc8d..85221e3 100644 --- a/lib/util/panel_values.dart +++ b/lib/util/panel_values.dart @@ -1,4 +1,4 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; /// An assortment of calculated values regarding the panel class PanelValues { From 6e3aa7b97fa2702f3010cf9e90afdb1a71a46ff6 Mon Sep 17 00:00:00 2001 From: Elliot Nash Date: Mon, 12 Aug 2024 17:22:19 -0700 Subject: [PATCH 3/8] Remove platform override --- lib/consts.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index 5914d31..34e172e 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -10,12 +10,6 @@ const kApiUrl = "https://forestpark.cecs.pdx.edu/staging/v1"; // const kApiUrl = "http://192.168.0.247:8000"; // const kApiUrl = "http://localhost:8000/"; -// This is for development only. -// TODO Maybe move this over to the settings page or only set on debug -// const kPlatformOverride = null; -const kPlatformOverride = TargetPlatform.android; -// const kPlatformOverride = TargetPlatform.iOS; - final kMaterialAppPrimaryColor = Colors.green.shade700; // Allows a user to submit hazards and updates without appropriate proximity. From ad79f1a69239e3078787beed4a0f3a6ca334b210 Mon Sep 17 00:00:00 2001 From: Elliot Nash Date: Mon, 12 Aug 2024 18:55:20 -0700 Subject: [PATCH 4/8] Fix color theme setting --- lib/main.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index a37b67b..beb87c4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:forest_park_reports/provider/settings_provider.dart'; import 'package:forest_park_reports/util/offline_uploader.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:forest_park_reports/consts.dart'; @@ -90,6 +91,7 @@ class _AppState extends ConsumerState with WidgetsBindingObserver { return MaterialApp( title: 'Trail Eyes', + themeMode: ref.watch(settingsProvider.select((s) => s.colorTheme)).value, theme: lightTheme, darkTheme: darkTheme, home: HomeScreen(key: homeKey), From fe3b5736d22042485d386d7079327770bf60f43d Mon Sep 17 00:00:00 2001 From: Elliot Nash Date: Tue, 13 Aug 2024 10:23:37 -0700 Subject: [PATCH 5/8] Fade status bar blur --- lib/page/common/statusbar_blur.dart | 33 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/lib/page/common/statusbar_blur.dart b/lib/page/common/statusbar_blur.dart index e52a90d..6d6f331 100644 --- a/lib/page/common/statusbar_blur.dart +++ b/lib/page/common/statusbar_blur.dart @@ -2,21 +2,38 @@ import 'dart:ui'; import 'package:flutter/widgets.dart'; +const kBlurSteps = 6; +const double kMaxSigma = 4; +const double kOverlap = 4; + /// Blurs the top status bar (used for iOS devices) class StatusBarBlur extends StatelessWidget { const StatusBarBlur({super.key}); @override Widget build(BuildContext context) { + final height = MediaQuery.of(context).viewPadding.top; + final stepHeight = height/kBlurSteps; + return Align( alignment: Alignment.topCenter, - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), - child: Container( - height: MediaQuery.of(context).viewPadding.top, - ), - ), - ), + child: Stack( + children: [ + for (int i = 0; i < kBlurSteps; ++i) + Positioned( + top: i * stepHeight, + left: 0, + right: 0, + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: (1-(i.toDouble()/kBlurSteps))*kMaxSigma, sigmaY: (1-(i.toDouble()/kBlurSteps))*kMaxSigma), + child: Container( + height: stepHeight + kOverlap, + ), + ), + ), + ), + ], + ) ); } } From 0f91121e18599683314f3eb0069db5661c4302f3 Mon Sep 17 00:00:00 2001 From: Elliot Nash Date: Tue, 13 Aug 2024 10:28:05 -0700 Subject: [PATCH 6/8] Cleanup statusbar blur --- lib/page/common/statusbar_blur.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/page/common/statusbar_blur.dart b/lib/page/common/statusbar_blur.dart index 6d6f331..509ac0f 100644 --- a/lib/page/common/statusbar_blur.dart +++ b/lib/page/common/statusbar_blur.dart @@ -18,20 +18,20 @@ class StatusBarBlur extends StatelessWidget { alignment: Alignment.topCenter, child: Stack( children: [ - for (int i = 0; i < kBlurSteps; ++i) - Positioned( + for (int i = 0; i < kBlurSteps; ++i) () { + final sigma = (1-(i.toDouble()/kBlurSteps))*kMaxSigma; + return Positioned( top: i * stepHeight, left: 0, right: 0, child: ClipRect( child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: (1-(i.toDouble()/kBlurSteps))*kMaxSigma, sigmaY: (1-(i.toDouble()/kBlurSteps))*kMaxSigma), - child: Container( - height: stepHeight + kOverlap, - ), + filter: ImageFilter.blur(sigmaX: sigma, sigmaY: sigma), + child: Container(height: stepHeight + kOverlap), ), ), - ), + ); + }() ], ) ); From cbb95da9330daff1b432830d24506f4a4f8a2a5c Mon Sep 17 00:00:00 2001 From: Brayden F <113265535+DigitalFork@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:21:26 -0700 Subject: [PATCH 7/8] Change compass colors (visibility) and ColorScheme --- assets/icons/compass.png | Bin 4071 -> 4769 bytes lib/main.dart | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/icons/compass.png b/assets/icons/compass.png index 860c3bcdcf4829dd09ce455416a88f54db763327..471315f512d2fade33a6a99837fff1787f9ffac0 100644 GIT binary patch literal 4769 zcma)Ai93|t`#-Z_Y#9{ULdx=HZ)_DNgv1a+G)C5;>`V5UY}pE_EGeU8-=*GcLtg5& zD^jwhvhV9)mf!S#|AF6gUC;GA_vd`>?L6nX?{l3b3ycvrhcE{Kfcvtsfh7PC<|_ms zSecI-0VVE#q(Dm}Jy6vzy1*3R9v96n0#KXANxjL!l-d1^uLlBfq~p&G`QTgP3ILz_ zWrK^>p^hsPJddnLqS)3CCztD%tCkfdK8j!OP;tEjvUC+|I62NpOOPfMq6sU~XB1_3ItG%bF^7jD{KBU-?iywna6I z@Tsi2+YBhrPM+=>!f&hib3>s(0!+T}tzRZ9gghH+;n|I4zRgkO1gx3h3;~ zV$b>)Pe~F1_*mO&PnBF(gENP;RR8gslGz9#HP+4O<<5#iffJ(n(o}oJJ&v4+i)*p( z<{Sk7sKkhmL<0mM)`X?dE8G~aaZ9OdQOaPVckwxIr98Vox<_Btkz7j>CbHDmm&aQ{A;mdwZD%6P>?#OaB#w%CY}E-W0LK6j2W7EBeQmF z4+a70oT@Ev%#F(32&%<(&Rk}JMsG~R2n5&< z7LFC`0l;M-Pjz=^TonpzHR16rn5eT?tgeuMS?Y@fB+=@z^Qqd-ONXMnEeD*`H6Ap# z^AF!@UkXe-d2~0;tC<3eC8N`GZC9|Z)7;^8td=yEARzH-*elKCHxIQX2E|pmJGbCu zv$Tx=jmSM<##F%1iTm)3D$nwT&WQjBma-@^(~*+(A%vxo!U6}B{_@?tMe)8J5h&Q6 zRyZK}l1j@k?!o=ZHUghe$_VgL&ib%|#gWG3atW11VI%-rp=4K!zk5ay3DSA3BXCT_ zr(~DDzBQa5BmqdclHI$A$^)i1im3G=S`tV^PQDmjeqvw88N9(nI||0`aX>)3eghAV zr+((zPACiS#p zis2Ss_#B-0!eZs|X|o+cKL@|g#Q6NkrrYw-$2o!k$9h@ItkF%+>ige#Y>duC8(Ybd zVCi;V4IgG~9aI933|R<=>Rs+C-~Ai=#*vSzyReP7Zj4Ep%Rcqb`wuI14bmgC`D_s6 zN$ZH05@1@?I-)-B=I%k*Q1W-rzmCDtXp5Em(r!C~>o>M@>?jIPTHXu?7Y*q>xCMD-EGG93#M5Lii=u9#1CJ=R0TOxJCM++%m4-EPD>9BwM5&L}c`*)!1h z>)sIwPTpe1GeQv5-O6oiAQpTae4^EJsWE?)UaW^8{)GfW!c*bRxd|{mM0Rm!-IV43 zSZzN?Bh9H%+;+4~NqDd2;yH3bfoctV_FXoPm0;e{>w2GGJGl&sHXod+-=Dk4mVTFN zV9v{ZHU`s%F!82`A%SOj@Fe%lF4prcqZA31kbvB!kzmFhHS!t^)))+0#Kh;1?by(F zvqi6{4|is#&`2m!9o{C9gr$YwB#*1<;vub=6Ec{Vb&G8CLFukF!!@72WZSB|M^U7aSFl@U=GS)+k`|&+6ub=*u0Q>h8+)^;QN)oXh zmj>OtxiasMo6U-!bN?Z{?9$<^G8Purk`lQ6F=M-g@K3&EG$vpB`{7(8JAKVvKtY{x zVIEjs&}E1;Q2D}l%)j7drad~vO#_U;q8?lNjFI3`njG2qDlPL>2y}9W=jkYS_8|Lf z2b(L`PzP$cUJx;&o`H--o4lt0`NJa&>0>Y>IbjS9PJOd&nD>d!D5II%(0jwx-__}r zb*{DdK-46`!=t-FsV@p5=1p~fuGHg z&9o>q*9<-X6LN6{vDYil*$^NQiSt7T=8f6XUW1jKvaVHMMLzLC ziQgTr?O~%c>S+1Yt}7Sdcxbu{0#ub0W4o0?Ov5*MpWuY&H68{UzEni_^y#K;K-Le> z*!2Aplq)Ap3U+(Kr+I$DNHeY-9Kt3tzOF*|hYQ062RkbipOuq|S>WMcjFn82=9S`l z=qz1}yTL68Ea%ixzEe+n91=F*!Vt=bc_6#$BW9$(V35q=S*RY5W5u`Z bb%kbZ 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 with WidgetsBindingObserver { colorScheme: ColorScheme.fromSeed( seedColor: kMaterialAppPrimaryColor, brightness: Brightness.light, - dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot, + dynamicSchemeVariant: DynamicSchemeVariant.rainbow, ) ); final darkTheme = ThemeData.from( colorScheme: ColorScheme.fromSeed( seedColor: kMaterialAppPrimaryColor, brightness: Brightness.dark, - dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot, + dynamicSchemeVariant: DynamicSchemeVariant.rainbow, ) ); From 263f421530572ff6080fff26daa4527de9f66d48 Mon Sep 17 00:00:00 2001 From: Brayden F <113265535+DigitalFork@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:28:44 -0700 Subject: [PATCH 8/8] Make compass center transparent --- assets/icons/compass.png | Bin 4769 -> 8404 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/icons/compass.png b/assets/icons/compass.png index 471315f512d2fade33a6a99837fff1787f9ffac0..05f8f82a23af7a04ffba58816716c9a425f4c056 100644 GIT binary patch literal 8404 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 Sd&lT`V5UY}pE_EGeU8-=*GcLtg5& zD^jwhvhV9)mf!S#|AF6gUC;GA_vd`>?L6nX?{l3b3ycvrhcE{Kfcvtsfh7PC<|_ms zSecI-0VVE#q(Dm}Jy6vzy1*3R9v96n0#KXANxjL!l-d1^uLlBfq~p&G`QTgP3ILz_ zWrK^>p^hsPJddnLqS)3CCztD%tCkfdK8j!OP;tEjvUC+|I62NpOOPfMq6sU~XB1_3ItG%bF^7jD{KBU-?iywna6I z@Tsi2+YBhrPM+=>!f&hib3>s(0!+T}tzRZ9gghH+;n|I4zRgkO1gx3h3;~ zV$b>)Pe~F1_*mO&PnBF(gENP;RR8gslGz9#HP+4O<<5#iffJ(n(o}oJJ&v4+i)*p( z<{Sk7sKkhmL<0mM)`X?dE8G~aaZ9OdQOaPVckwxIr98Vox<_Btkz7j>CbHDmm&aQ{A;mdwZD%6P>?#OaB#w%CY}E-W0LK6j2W7EBeQmF z4+a70oT@Ev%#F(32&%<(&Rk}JMsG~R2n5&< z7LFC`0l;M-Pjz=^TonpzHR16rn5eT?tgeuMS?Y@fB+=@z^Qqd-ONXMnEeD*`H6Ap# z^AF!@UkXe-d2~0;tC<3eC8N`GZC9|Z)7;^8td=yEARzH-*elKCHxIQX2E|pmJGbCu zv$Tx=jmSM<##F%1iTm)3D$nwT&WQjBma-@^(~*+(A%vxo!U6}B{_@?tMe)8J5h&Q6 zRyZK}l1j@k?!o=ZHUghe$_VgL&ib%|#gWG3atW11VI%-rp=4K!zk5ay3DSA3BXCT_ zr(~DDzBQa5BmqdclHI$A$^)i1im3G=S`tV^PQDmjeqvw88N9(nI||0`aX>)3eghAV zr+((zPACiS#p zis2Ss_#B-0!eZs|X|o+cKL@|g#Q6NkrrYw-$2o!k$9h@ItkF%+>ige#Y>duC8(Ybd zVCi;V4IgG~9aI933|R<=>Rs+C-~Ai=#*vSzyReP7Zj4Ep%Rcqb`wuI14bmgC`D_s6 zN$ZH05@1@?I-)-B=I%k*Q1W-rzmCDtXp5Em(r!C~>o>M@>?jIPTHXu?7Y*q>xCMD-EGG93#M5Lii=u9#1CJ=R0TOxJCM++%m4-EPD>9BwM5&L}c`*)!1h z>)sIwPTpe1GeQv5-O6oiAQpTae4^EJsWE?)UaW^8{)GfW!c*bRxd|{mM0Rm!-IV43 zSZzN?Bh9H%+;+4~NqDd2;yH3bfoctV_FXoPm0;e{>w2GGJGl&sHXod+-=Dk4mVTFN zV9v{ZHU`s%F!82`A%SOj@Fe%lF4prcqZA31kbvB!kzmFhHS!t^)))+0#Kh;1?by(F zvqi6{4|is#&`2m!9o{C9gr$YwB#*1<;vub=6Ec{Vb&G8CLFukF!!@72WZSB|M^U7aSFl@U=GS)+k`|&+6ub=*u0Q>h8+)^;QN)oXh zmj>OtxiasMo6U-!bN?Z{?9$<^G8Purk`lQ6F=M-g@K3&EG$vpB`{7(8JAKVvKtY{x zVIEjs&}E1;Q2D}l%)j7drad~vO#_U;q8?lNjFI3`njG2qDlPL>2y}9W=jkYS_8|Lf z2b(L`PzP$cUJx;&o`H--o4lt0`NJa&>0>Y>IbjS9PJOd&nD>d!D5II%(0jwx-__}r zb*{DdK-46`!=t-FsV@p5=1p~fuGHg z&9o>q*9<-X6LN6{vDYil*$^NQiSt7T=8f6XUW1jKvaVHMMLzLC ziQgTr?O~%c>S+1Yt}7Sdcxbu{0#ub0W4o0?Ov5*MpWuY&H68{UzEni_^y#K;K-Le> z*!2Aplq)Ap3U+(Kr+I$DNHeY-9Kt3tzOF*|hYQ062RkbipOuq|S>WMcjFn82=9S`l z=qz1}yTL68Ea%ixzEe+n91=F*!Vt=bc_6#$BW9$(V35q=S*RY5W5u`Z bb%kbZ zWR*?#qONC$RBzqJA{W(TxxQjEGj^)5AgIDwyNq1cm^0$7w|p_Ac%`9t2yc`KkxVyNVbKAXFpahJ>cwOA@)8coEY`T!!LGwtiHwLxn4q@ zM&;iz%b3pvjFfhwRF~iD?7UPC;wQ|1ppndd30Z%4TD<29*~t`8BPO2VrUe(u$FXeE9>BVvSD~E0`e{- z;oFj#FN4J!HeGu9&i&tlZsm+(%FNoifK+KOi-LnJWe*YV`$gWM_rPxei?W_P9IbLn z3W+?YY%6-39%b?!Bx)}D(06{fXxYkbydiOn!(-y#d}efVy?PX6op57Y_Va9s$-WA$=bIi} zpTPEF{j~#q-zCun_Y=h)l@7^bZkWBmvb6~kbhsPbH$s~H!xd8QQC88-mCw{1)ya1@ zIKOnwW$z5vx3~yxJSNC+-^CvT)wVc-6dC`WPI$0Xr#}*0vE*k}vxZ#PEh}G;J&&3z zny)0K+d?ojF43u8dF=VLd;(9ti7 z6B9^@;5;O9(-&#N)>gjdL-~tLqS+#KRAkv+!JOXbxTvAvEc-%G5BWnz&Ax`_Zyc03 zM&-E6Y=p!FW#Fa(;rU-9#4{Rj{FGXi#6I%2>~{!P$85e$z&N|pmXetXYg><+hQe>b z+jLJ>k=S-CRq$UEM54|PBQGWqro+$QH3A@;{_^r{>`VA<%;K*3{o z_@Q5^JrDUJz`y{*aHXXGGegfx`NrmRw40`)h$_*2U-_rhPE(Ub{(3(c5J6<_5P&)EirA@>ksK~rVq;mCa_;WZ|tF1&UW&> zd8Vlx(&d69?1-m*a!H4MVgpC0%J$2d?>TuCziv^KvyZ!EtzU|`_gGIp1-ej4Q$lkOV;vN2A771=c^|B2b7(d=@o{@64;z`jB z{S*Qs$`@N5hCe^B!fqcuB)QH!C=a3gob8i5#T<*=z!~cg>Q~5YUT1Dwvtl2KwXId# zsns((l4EYnn6uFp8Er@;d-bfac z%XuBVfU%CaW-JII+~w&Z{&$u-P%QfeV`oeonUUJ+nNokYT*Zx3AA2(zU+(c*JhXY*W4BDp0Qykrv0X&; zkWBrq@BZn&i~677ZL2x9)rt#VVULQCN30_{jQK$cy&$=P`;3mt;fgKcQlN6&(Lenu z-!vzBrmYDT??f7l6@?J{$mmY{EhWnOCXKOkD>t^ikfMsjQ7yd|nR{nWJG7IUlP!j3COts1^-DNCM5luImNq-d|cH1E-UkzBo5g9h_uGU9Dd z!g8E22wl^?RcjUhQux+h^E$i_QpaZxmb0T)Dy7b2el(M}3&!;O;{}-cdGZ_GRO=-y z={_&iLifk<0dpmKy?^}!a&TVJdYC2$CzRI&i00XB{Y;EymY-=^d4#oWK5RNgS5JRB zMQ7iSOFkN5IW5*El0^vnJ-?eNg7;Dtjb|y~Y-W(AuAh z4-KDUnl3zw2gl#+%albODvm3PoDyJ)o0GZ^-b3Bs0>GiXx+%=`dy)sfOhohn#Dqg0 zpepILMV~fDt0p&=&!E^WOe7#RHy7@h%$@lD&D3h7U@TT0%1(^^JUhkjKl1`+amVsb@mo8Zr;Dwp#n5<0ZF_rU zdU*XRH)`9V`>Gw2wXnH^1^K!#1@DK=CBIeIH46kEAvhTN_>=aBYt6hGCne z`wzc)D`^j3N`nvwpqxb4f#FIy@$b>jhH1~H!Yf>7cE39w#P{NkL;t_0FMoK)`MT)h XwZrk&*?4EKKfvWn7=tQ3r