From 9466109b82bcebbbbd119f7e8b497881f546c2c5 Mon Sep 17 00:00:00 2001 From: YumNumm Date: Thu, 20 Jul 2023 01:10:49 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20modal=E3=81=A8EEW=E3=81=AE=E3=82=B5?= =?UTF-8?q?=E3=82=A4=E3=82=BA=E8=AA=BF=E6=95=B4=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/view_model/map_viewmodel.dart | 27 +++- .../sheet/sheet_floating_action_buttons.dart | 14 +- lib/feature/home/view/home_view.dart | 138 ++++++++++-------- .../home/viewmodel/home_viewmodel.dart | 31 +++- 4 files changed, 130 insertions(+), 80 deletions(-) diff --git a/lib/core/component/map/view_model/map_viewmodel.dart b/lib/core/component/map/view_model/map_viewmodel.dart index 3a690a3a9..00fd05ef2 100644 --- a/lib/core/component/map/view_model/map_viewmodel.dart +++ b/lib/core/component/map/view_model/map_viewmodel.dart @@ -31,7 +31,7 @@ class MapViewModel extends _$MapViewModel { late AnimationController _scaleController; late AnimationController _globalPointAndZoomLevelController; - final double _interactionEndFrictionCoefficient = 0.0000135; + static const double _interactionEndFrictionCoefficient = 0.0000135; _GestureType? _gestureType; @@ -43,6 +43,9 @@ class MapViewModel extends _$MapViewModel { const LatLng(30, 128.8), ); + /// POI適用後に移動したかどうか + bool _isMarkedAsMoved = false; + /// デフォルトの表示領域に戻す void reset() => _currencPoi = ( const LatLng(45.8, 145.1), @@ -59,13 +62,27 @@ class MapViewModel extends _$MapViewModel { state.fitBoundsByGlobalPoints([points.$1, points.$2], _renderBox!.size); } + Future animatedApplyBoundsIfNeeded({ + Duration duration = const Duration(milliseconds: 500), + Curve curve = Curves.easeOutCirc, + EdgeInsetsGeometry padding = EdgeInsets.zero, + }) async => + switch (_isMarkedAsMoved) { + false => animatedApplyBounds( + duration: duration, + curve: curve, + padding: padding, + ), + true => {}, + }; + Future animatedApplyBounds({ Duration duration = const Duration(milliseconds: 500), Curve curve = Curves.easeOutCirc, EdgeInsetsGeometry padding = EdgeInsets.zero, }) { if (_renderBox == null) { - return Future.value(); + throw Exception('MapController is not initialized.'); } final points = _currencPoi.toGlobalPoints(); return animatedBoundsByGlobalPoints( @@ -97,9 +114,7 @@ class MapViewModel extends _$MapViewModel { ); } - void setBoundsByGlobalPoints(GlobalPoint $1, GlobalPoint $2) { - applyBounds(); - } + void resetMarkAsMoved() => _isMarkedAsMoved = false; /// The minimum velocity for a touch to consider that touch to trigger a fling /// gesture. @@ -188,6 +203,7 @@ class MapViewModel extends _$MapViewModel { } void handleScaleUpdate(ScaleUpdateDetails details) { + _isMarkedAsMoved = true; if (_gestureType == _GestureType.pan) { // ジェスチャーが最初に開始されたとき、2本の指で行うジェスチャーでも、 // スケールや回転に変化がない場合がある。 @@ -533,7 +549,6 @@ class MapViewModel extends _$MapViewModel { _renderBox = renderBox; } - void registerAnimationControllers({ required AnimationController moveController, required AnimationController scaleController, diff --git a/lib/core/component/sheet/sheet_floating_action_buttons.dart b/lib/core/component/sheet/sheet_floating_action_buttons.dart index db84e6afd..8a0aee352 100644 --- a/lib/core/component/sheet/sheet_floating_action_buttons.dart +++ b/lib/core/component/sheet/sheet_floating_action_buttons.dart @@ -20,18 +20,16 @@ class SheetFloatingActionButtons extends HookWidget { final SheetController controller; @override Widget build(BuildContext context) { - final mediaQuery = useMemoized( - () => MediaQuery.of(context), - [context], - ); - final height = mediaQuery.size.height - - (mediaQuery.padding.top + mediaQuery.padding.bottom) - - kToolbarHeight; + final size = MediaQuery.sizeOf(context); + final padding = MediaQuery.paddingOf(context); + final height = + size.height - (padding.top + padding.bottom) - kToolbarHeight; return AnimatedBuilder( animation: controller.animation, builder: (BuildContext context, Widget? child) { return Positioned( - right: 0, + right: padding.right, + left: padding.left, bottom: height * controller.animation.value, child: Container( margin: const EdgeInsets.all(10), diff --git a/lib/feature/home/view/home_view.dart b/lib/feature/home/view/home_view.dart index e6d92f0ba..d6ba14061 100644 --- a/lib/feature/home/view/home_view.dart +++ b/lib/feature/home/view/home_view.dart @@ -22,7 +22,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:lat_lng/lat_lng.dart'; +import 'package:sheet/src/sheet.dart'; import 'package:talker_flutter/talker_flutter.dart'; class HomeView extends HookConsumerWidget { @@ -86,42 +86,35 @@ class _HomeBodyWidget extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final vm = ref.watch(homeViewModelProvider); - final brightness = MediaQuery.of(context).platformBrightness; final moveController = useAnimationController(); final scaleController = useAnimationController(); final globalPointAndZoomLevelController = useAnimationController(); // * mapViewModelへWidgetの各情報を登録しながら 初期化 + void init() { + // Widgetのサイズを登録 + final renderBox = mapKey.currentContext!.findRenderObject()! as RenderBox; + ref.read(mapViewModelProvider(mapKey).notifier) + ..registerRenderBox( + renderBox, + ) + ..registerAnimationControllers( + moveController: moveController, + scaleController: scaleController, + globalPointAndZoomLevelController: globalPointAndZoomLevelController, + ) + ..resetMarkAsMoved() + ..applyBounds(); + } + useEffect( () { - WidgetsBinding.instance.endOfFrame.then((_) { - // Widgetのサイズを登録 - final renderBox = - mapKey.currentContext!.findRenderObject()! as RenderBox; - ref.read(mapViewModelProvider(mapKey).notifier) - ..registerRenderBox( - renderBox, - ) - ..registerAnimationControllers( - moveController: moveController, - scaleController: scaleController, - globalPointAndZoomLevelController: - globalPointAndZoomLevelController, - ) - ..fitBounds([ - const LatLng(45.8, 145.1), - const LatLng(30, 128.8), - ]) - ..applyBounds(); - }); + WidgetsBinding.instance.endOfFrame.then((_) => init()); return null; }, - [mapKey], + [], ); final sheetController = vm.sheetController; - final mediaQuery = useMemoized( - () => MediaQuery.of(context), - [context], - ); + final mediaQuery = MediaQuery.of(context); useEffect( () { @@ -137,7 +130,7 @@ class _HomeBodyWidget extends HookConsumerWidget { (isDark ? MapColorScheme.dark() : MapColorScheme.light()) .backgroundColor; - return Stack( + final child = Stack( children: [ // background color Container( @@ -175,15 +168,18 @@ class _HomeBodyWidget extends HookConsumerWidget { final height = mediaQuery.size.height - (mediaQuery.padding.top + mediaQuery.padding.bottom) - kToolbarHeight; - ref - .read(mapViewModelProvider(mapKey).notifier) - .animatedApplyBounds( - padding: const EdgeInsets.all(8).add( - EdgeInsets.only( - bottom: height * sheetController.animation.value, - ), + ref.read(mapViewModelProvider(mapKey).notifier) + ..resetMarkAsMoved() + ..animatedApplyBounds( + padding: const EdgeInsets.all(8).add( + EdgeInsets.only( + bottom: switch (sheetController.animation.value) { + < 0.3 => height * sheetController.animation.value, + _ => height * 0.3, + }, ), - ); + ), + ); }, elevation: 4, child: const Icon(Icons.home), @@ -191,29 +187,55 @@ class _HomeBodyWidget extends HookConsumerWidget { ], ), // Sheet - RepaintBoundary( - child: BasicModalSheet( - controller: sheetController, - children: [ - const EewWidgets(), - const SheetStatusWidget(), - const EarthquakeHistorySheetWidget(), - ListTile( - title: const Text('強震モニタ設定'), - leading: const Icon(Icons.settings), - onTap: () => context.push(const KmoniRoute().location), - ), - ListTile( - title: const Text('震度配色設定'), - leading: const Icon(Icons.color_lens), - onTap: () => - context.push(const ColorSchemeConfigRoute().location), - ), - const DebugWidget(), - ], - ), - ), + _Sheet(sheetController: sheetController), ], ); + + return NotificationListener( + onNotification: (notification) { + WidgetsBinding.instance.endOfFrame.then( + (_) => ref.read(mapViewModelProvider(mapKey).notifier) + ..resetMarkAsMoved() + ..applyBounds(), + ); + return false; + }, + child: SizeChangedLayoutNotifier( + child: child, + ), + ); + } +} + +class _Sheet extends StatelessWidget { + const _Sheet({ + required this.sheetController, + }); + + final SheetController sheetController; + + @override + Widget build(BuildContext context) { + return RepaintBoundary( + child: BasicModalSheet( + controller: sheetController, + children: [ + const EewWidgets(), + const SheetStatusWidget(), + const EarthquakeHistorySheetWidget(), + ListTile( + title: const Text('強震モニタ設定'), + leading: const Icon(Icons.settings), + onTap: () => context.push(const KmoniRoute().location), + ), + ListTile( + title: const Text('震度配色設定'), + leading: const Icon(Icons.color_lens), + onTap: () => context.push(const ColorSchemeConfigRoute().location), + ), + const DebugWidget(), + ], + ), + ); } } diff --git a/lib/feature/home/viewmodel/home_viewmodel.dart b/lib/feature/home/viewmodel/home_viewmodel.dart index 5b01dddf3..3578c5912 100644 --- a/lib/feature/home/viewmodel/home_viewmodel.dart +++ b/lib/feature/home/viewmodel/home_viewmodel.dart @@ -20,43 +20,58 @@ class HomeViewModel { } final HomeViewModelRef ref; - final mapKey = GlobalKey(debugLabel: 'HomeView'); + final mapKey = const GlobalObjectKey(MapViewModel); double height = 0; SheetController sheetController = SheetController(); + int _lastEstimatedIntensityChangedEewsLength = -1; + void onEstimatedIntensityChanged( List points, ) { final filtered = _getTargets(points); + // EEWの要素数が変化したかチェック + final length = ref.read(eewTelegramProvider).length; + if (_lastEstimatedIntensityChangedEewsLength != length) { + _lastEstimatedIntensityChangedEewsLength = length; + ref.read(mapViewModelProvider(mapKey).notifier).resetMarkAsMoved(); + } if (filtered == null) { - _resetPoC(); - ref.read(MapViewModelProvider(mapKey).notifier).animatedApplyBounds( + ref + .read(mapViewModelProvider(mapKey).notifier) + .animatedApplyBoundsIfNeeded( padding: const EdgeInsets.all(8).add( EdgeInsets.only( - bottom: height * sheetController.animation.value, + bottom: switch (sheetController.animation.value) { + < 0.3 => height * sheetController.animation.value, + _ => height * 0.3, + }, ), ), ); return; } // 表示領域を変える - ref.read(MapViewModelProvider(mapKey).notifier) + ref.read(mapViewModelProvider(mapKey).notifier) ..setBounds( filtered, ) - ..animatedApplyBounds( + ..animatedApplyBoundsIfNeeded( padding: const EdgeInsets.all(8).add( EdgeInsets.only( - bottom: height * sheetController.animation.value, + bottom: switch (sheetController.animation.value) { + < 0.3 => height * sheetController.animation.value, + _ => height * 0.3, + }, ), ), ); } void _resetPoC() { - ref.read(MapViewModelProvider(mapKey).notifier).reset(); + ref.read(mapViewModelProvider(mapKey).notifier).reset(); } /// 震度1以上の観測点のうち、震度が最大~最大-1の観測点を含むLatLngの配列を返す