From 54896396790915e17667656b8b5985290f0846c5 Mon Sep 17 00:00:00 2001 From: Koji Wakamiya Date: Fri, 7 Apr 2023 01:00:51 +0900 Subject: [PATCH 1/3] Add go_router_builder and ShellRoute --- lib/view/home/history/history_widget.dart | 12 +- lib/view/home/home_screen.dart | 243 ++++++++--------- .../home/simple/simple_search_screen.dart | 41 ++- lib/view/router.dart | 247 ++++++++++++------ lib/view/router.g.dart | 202 +++++++++++++- lib/view/router_key.dart | 4 + .../search/search_meeting_detail_screen.dart | 14 +- .../search/search_meeting_summary_screen.dart | 14 +- lib/view/search/search_speech_screen.dart | 71 ++--- lib/view/status/issue_detail_screen.dart | 14 +- lib/view/status/speech_detail_screen.dart | 14 +- pubspec.lock | 16 ++ pubspec.yaml | 1 + 13 files changed, 583 insertions(+), 310 deletions(-) create mode 100644 lib/view/router_key.dart diff --git a/lib/view/home/history/history_widget.dart b/lib/view/home/history/history_widget.dart index ba64a57..f7fe4bc 100644 --- a/lib/view/home/history/history_widget.dart +++ b/lib/view/home/history/history_widget.dart @@ -3,10 +3,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_kokkai_gijiroku/model/entity/memo_result.dart'; import 'package:flutter_kokkai_gijiroku/model/entity/search_params.dart'; import 'package:flutter_kokkai_gijiroku/model/hive/search_history.dart'; -import 'package:flutter_kokkai_gijiroku/view/search/search_speech_screen.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/memo_edit_dialog.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/search_params_list.dart'; -import 'package:go_router/go_router.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:intl/intl.dart'; @@ -49,12 +48,9 @@ class HistoryWidget extends ConsumerWidget { clipBehavior: Clip.hardEdge, child: InkWell( onTap: () { - context.pushNamed( - SearchSpeechScreen.screenName, - queryParams: { - 'q': history.params.uriQuery, - }, - ); + SearchSpeechRoute( + q: history.params.uriQuery, + ).push(context); }, child: Padding( padding: const EdgeInsets.all(16), diff --git a/lib/view/home/home_screen.dart b/lib/view/home/home_screen.dart index df774a5..1ed0356 100644 --- a/lib/view/home/home_screen.dart +++ b/lib/view/home/home_screen.dart @@ -3,135 +3,100 @@ import 'package:flutter/material.dart'; import 'package:flutter_kokkai_gijiroku/model/entity/search_params.dart'; import 'package:flutter_kokkai_gijiroku/model/entity/search_state.dart'; import 'package:flutter_kokkai_gijiroku/presenter/search_state_manager.dart'; -import 'package:flutter_kokkai_gijiroku/view/home/full/full_search_screen.dart'; -import 'package:flutter_kokkai_gijiroku/view/home/history/history_widget.dart'; -import 'package:flutter_kokkai_gijiroku/view/home/simple/simple_search_screen.dart'; -import 'package:flutter_kokkai_gijiroku/view/search/search_meeting_detail_screen.dart'; -import 'package:flutter_kokkai_gijiroku/view/search/search_meeting_summary_screen.dart'; -import 'package:flutter_kokkai_gijiroku/view/search/search_speech_screen.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:flutter_kokkai_gijiroku/view/search_mode.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/home_app_bar_action.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; enum HomeMode { - simple('/', 'homeScreenSimple'), - full('/full', 'homeScreenFull'), - history('/history', 'homeScreenHistory'); + simple('/'), + full('/full'), + history('/history'); final String path; - final String name; - const HomeMode(this.path, this.name); + const HomeMode(this.path); } class HomeScreen extends ConsumerWidget { const HomeScreen({ super.key, - required this.mode, + required this.child, }); - final HomeMode mode; + final Widget child; - int get index => HomeMode.values.indexOf(mode); + /// get current HomeMode from path + HomeMode _getHomeMode(BuildContext context) { + final path = GoRouter.of(context).location; + return HomeMode.values.firstWhere( + (e) => path.startsWith(e.path), + orElse: () => HomeMode.simple, + ); + } @override Widget build(BuildContext context, WidgetRef ref) { final screenSize = MediaQuery.of(context).breakpointScreenSize; + final mode = _getHomeMode(context); + final index = HomeMode.values.indexOf(mode); - final Widget body; final FloatingActionButton? actionButton; - switch (mode) { case HomeMode.simple: - body = SimpleSearchWidget( - submitAction: () { + actionButton = null; + break; + case HomeMode.full: + actionButton = FloatingActionButton.extended( + label: const Text('検索'), + icon: const Icon(Icons.search_outlined), + tooltip: '検索', + onPressed: () { final state = ref.read(searchStateManagerProvider); - final text = state.any; - if (text.isEmpty) { + if (state.from != null && + state.until != null && + state.from!.isAfter(state.until!)) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('日付の指定が不正です'), + ), + ); + return; + } + if (state.any.isEmpty && + state.speaker.isEmpty && + state.nameOfMeeting.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('検索語を入力してください'), + content: Text('検索語/会議名/発言者名のいずれかを入力してください'), ), ); return; } - context.pushNamed( - SearchSpeechScreen.screenName, - queryParams: { - 'q': SearchParams( - any: text, - ).uriQuery, - }, - ); + switch (state.mode) { + case SearchMode.meetingDetail: + SearchMeetingDetailRoute( + q: state.fullParams.uriQuery, + ).push(context); + break; + case SearchMode.meetingSummary: + SearchMeetingSummaryRoute( + q: state.fullParams.uriQuery, + ).push(context); + break; + case SearchMode.speech: + SearchSpeechRoute( + q: state.fullParams.uriQuery, + ).push(context); + break; + } }, ); - actionButton = null; - break; - case HomeMode.full: - action() { - final state = ref.read(searchStateManagerProvider); - - if (state.from != null && - state.until != null && - state.from!.isAfter(state.until!)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('日付の指定が不正です'), - ), - ); - return; - } - if (state.any.isEmpty && - state.speaker.isEmpty && - state.nameOfMeeting.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('検索語/会議名/発言者名のいずれかを入力してください'), - ), - ); - return; - } - - switch (state.mode) { - case SearchMode.meetingDetail: - context.pushNamed( - SearchMeetingDetailScreen.screenName, - queryParams: { - 'q': state.fullParams.uriQuery, - }, - ); - break; - case SearchMode.meetingSummary: - context.pushNamed( - SearchMeetingSummaryScreen.screenName, - queryParams: { - 'q': state.fullParams.uriQuery, - }, - ); - break; - case SearchMode.speech: - context.pushNamed( - SearchSpeechScreen.screenName, - queryParams: { - 'q': state.fullParams.uriQuery, - }, - ); - break; - } - } - body = const FullSearchWidget(); - actionButton = FloatingActionButton.extended( - label: const Text('検索'), - icon: const Icon(Icons.search_outlined), - tooltip: '検索', - onPressed: action, - ); break; case HomeMode.history: - body = const HistoryWidget(); actionButton = null; break; } @@ -145,7 +110,7 @@ class HomeScreen extends ConsumerWidget { HomeAppBarAction(), ], ), - body: body, + body: child, floatingActionButton: actionButton, bottomNavigationBar: BottomNavigationBar( items: const [ @@ -174,48 +139,48 @@ class HomeScreen extends ConsumerWidget { }, ), ); - } else { - return Scaffold( - appBar: AppBar( - title: const Text('議事録検索'), - actions: const [ - HomeAppBarAction(), - ], - ), - body: Row( - children: [ - NavigationRail( - destinations: const [ - NavigationRailDestination( - icon: Icon(Icons.search), - label: Text('キーワード検索'), - ), - NavigationRailDestination( - icon: Icon(Icons.manage_search), - label: Text('条件検索'), - ), - NavigationRailDestination( - icon: Icon(Icons.history), - label: Text('検索履歴'), - ), - ], - selectedIndex: index, - onDestinationSelected: (index) { - _navigate( - context: context, - index: index, - ); - }, - ), - Expanded( - child: body, - ), - ], - ), - floatingActionButton: actionButton, - floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, - ); } + + return Scaffold( + appBar: AppBar( + title: const Text('議事録検索'), + actions: const [ + HomeAppBarAction(), + ], + ), + body: Row( + children: [ + NavigationRail( + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.search), + label: Text('キーワード検索'), + ), + NavigationRailDestination( + icon: Icon(Icons.manage_search), + label: Text('条件検索'), + ), + NavigationRailDestination( + icon: Icon(Icons.history), + label: Text('検索履歴'), + ), + ], + selectedIndex: index, + onDestinationSelected: (index) { + _navigate( + context: context, + index: index, + ); + }, + ), + Expanded( + child: child, + ), + ], + ), + floatingActionButton: actionButton, + floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, + ); } void _navigate({ @@ -223,6 +188,16 @@ class HomeScreen extends ConsumerWidget { required int index, }) { final mode = HomeMode.values[index]; - context.goNamed(mode.name); + switch (mode) { + case HomeMode.simple: + const SimpleRoute().go(context); + break; + case HomeMode.full: + const FullRoute().go(context); + break; + case HomeMode.history: + const HistoryRoute().go(context); + break; + } } } diff --git a/lib/view/home/simple/simple_search_screen.dart b/lib/view/home/simple/simple_search_screen.dart index d2de814..47d7220 100644 --- a/lib/view/home/simple/simple_search_screen.dart +++ b/lib/view/home/simple/simple_search_screen.dart @@ -1,17 +1,16 @@ import 'package:breakpoints_mq/breakpoints_mq.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_kokkai_gijiroku/model/entity/search_params.dart'; import 'package:flutter_kokkai_gijiroku/presenter/search_state_manager.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; class SimpleSearchWidget extends HookConsumerWidget { const SimpleSearchWidget({ super.key, - required this.submitAction, }); - final VoidCallback submitAction; - @override Widget build(BuildContext context, WidgetRef ref) { final any = ref.watch( @@ -35,7 +34,23 @@ class SimpleSearchWidget extends HookConsumerWidget { suffixIcon: IconButton( icon: const Icon(Icons.search), onPressed: () { - submitAction(); + final state = ref.read(searchStateManagerProvider); + final text = state.any; + + if (text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('検索語を入力してください'), + ), + ); + return; + } + + SearchSpeechRoute( + q: SearchParams( + any: text, + ).uriQuery, + ).push(context); }, ), ), @@ -43,7 +58,23 @@ class SimpleSearchWidget extends HookConsumerWidget { ref.read(searchStateManagerProvider.notifier).updateAny(value); }, onEditingComplete: () { - submitAction(); + final state = ref.read(searchStateManagerProvider); + final text = state.any; + + if (text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('検索語を入力してください'), + ), + ); + return; + } + + SearchSpeechRoute( + q: SearchParams( + any: text, + ).uriQuery, + ).push(context); }, ), ), diff --git a/lib/view/router.dart b/lib/view/router.dart index dcc5042..072fa3f 100644 --- a/lib/view/router.dart +++ b/lib/view/router.dart @@ -1,6 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_kokkai_gijiroku/model/entity/search_params.dart'; +import 'package:flutter_kokkai_gijiroku/view/home/full/full_search_screen.dart'; +import 'package:flutter_kokkai_gijiroku/view/home/history/history_widget.dart'; import 'package:flutter_kokkai_gijiroku/view/home/home_screen.dart'; +import 'package:flutter_kokkai_gijiroku/view/home/simple/simple_search_screen.dart'; +import 'package:flutter_kokkai_gijiroku/view/router_key.dart'; import 'package:flutter_kokkai_gijiroku/view/search/search_meeting_detail_screen.dart'; import 'package:flutter_kokkai_gijiroku/view/search/search_meeting_summary_screen.dart'; import 'package:flutter_kokkai_gijiroku/view/search/search_speech_screen.dart'; @@ -16,88 +20,173 @@ GoRouter router( RouterRef ref, ) => GoRouter( + navigatorKey: rootNavigatorKey, + routes: $appRoutes, + ); + +@TypedShellRoute( + routes: [ + TypedGoRoute( + path: '/', routes: [ - GoRoute( - path: HomeMode.simple.path, - name: HomeMode.simple.name, - pageBuilder: (context, state) => NoTransitionPage( - key: state.pageKey, - child: const HomeScreen( - mode: HomeMode.simple, - ), - ), - routes: [ - GoRoute( - path: 'search/detail', - name: SearchMeetingDetailScreen.screenName, - pageBuilder: (context, state) => MaterialPage( - key: state.pageKey, - child: SearchMeetingDetailScreen( - params: SearchParamsExt.fromUriQuery(state.queryParams['q']), - ), - ), - ), - GoRoute( - path: 'search/summary', - name: SearchMeetingSummaryScreen.screenName, - pageBuilder: (context, state) => MaterialPage( - key: state.pageKey, - child: SearchMeetingSummaryScreen( - params: SearchParamsExt.fromUriQuery(state.queryParams['q']), - ), - ), - ), - GoRoute( - path: 'search/speech', - name: SearchSpeechScreen.screenName, - pageBuilder: (context, state) => MaterialPage( - key: state.pageKey, - child: SearchSpeechScreen( - params: SearchParamsExt.fromUriQuery(state.queryParams['q']), - ), - ), - ), - GoRoute( - path: 'speech/:speechID', - name: SpeechDetailScreen.screenName, - pageBuilder: (context, state) => MaterialPage( - key: state.pageKey, - child: SpeechDetailScreen( - speechID: state.params['speechID']!, - ), - ), - ), - GoRoute( - path: 'issue/:issueID', - name: IssueDetailScreen.screenName, - pageBuilder: (context, state) => MaterialPage( - key: state.pageKey, - child: IssueDetailScreen( - issueID: state.params['issueID']!, - ), - ), - ), - ], + TypedGoRoute( + path: 'search/detail', + ), + TypedGoRoute( + path: 'search/summary', ), - GoRoute( - path: HomeMode.full.path, - name: HomeMode.full.name, - pageBuilder: (context, state) => NoTransitionPage( - key: state.pageKey, - child: const HomeScreen( - mode: HomeMode.full, - ), - ), + TypedGoRoute( + path: 'search/speech', ), - GoRoute( - path: HomeMode.history.path, - name: HomeMode.history.name, - pageBuilder: (context, state) => NoTransitionPage( - key: state.pageKey, - child: const HomeScreen( - mode: HomeMode.history, - ), - ), + TypedGoRoute( + path: 'speech/:speechID', + ), + TypedGoRoute( + path: 'issue/:issueID', ), ], + ), + TypedGoRoute( + path: '/full', + ), + TypedGoRoute( + path: '/history', + ), + ], +) +class HomeShellRoute extends ShellRouteData { + const HomeShellRoute(); + + static final $navigatorKey = shellNavigatorKey; + + @override + Widget builder(BuildContext context, GoRouterState state, Widget navigator) { + return HomeScreen( + child: navigator, + ); + } +} + +class SimpleRoute extends GoRouteData { + const SimpleRoute(); + + static final $navigatorKey = shellNavigatorKey; + + @override + Page buildPage(BuildContext context, GoRouterState state) { + return const NoTransitionPage( + child: SimpleSearchWidget(), + ); + } +} + +class FullRoute extends GoRouteData { + const FullRoute(); + + static final $navigatorKey = shellNavigatorKey; + + @override + Page buildPage(BuildContext context, GoRouterState state) { + return const NoTransitionPage( + child: FullSearchWidget(), + ); + } +} + +class HistoryRoute extends GoRouteData { + const HistoryRoute(); + + static final $navigatorKey = shellNavigatorKey; + + @override + Page buildPage(BuildContext context, GoRouterState state) { + return const NoTransitionPage( + child: HistoryWidget(), + ); + } +} + +class SearchMeetingDetailRoute extends GoRouteData { + const SearchMeetingDetailRoute({ + this.q = '', + }); + + static final $parentNavigatorKey = rootNavigatorKey; + + final String q; + + @override + Widget build(BuildContext context, GoRouterState state) { + return SearchMeetingDetailScreen( + params: SearchParamsExt.fromUriQuery(q), + ); + } +} + +class SearchMeetingSummaryRoute extends GoRouteData { + const SearchMeetingSummaryRoute({ + this.q = '', + }); + + static final $parentNavigatorKey = rootNavigatorKey; + + final String q; + + @override + Widget build(BuildContext context, GoRouterState state) { + return SearchMeetingSummaryScreen( + params: SearchParamsExt.fromUriQuery(q), + ); + } +} + +class SearchSpeechRoute extends GoRouteData { + const SearchSpeechRoute({ + this.q = '', + }); + + static final $parentNavigatorKey = rootNavigatorKey; + + final String q; + + @override + Widget build(BuildContext context, GoRouterState state) { + return SearchSpeechScreen( + params: SearchParamsExt.fromUriQuery(q), + ); + } +} + +class SpeechDetailRoute extends GoRouteData { + const SpeechDetailRoute({ + required this.speechID, + }); + + static final $parentNavigatorKey = rootNavigatorKey; + + final String speechID; + + @override + Widget build(BuildContext context, GoRouterState state) { + return SpeechDetailScreen( + speechID: speechID, + ); + } +} + +class IssueDetailRoute extends GoRouteData { + const IssueDetailRoute({ + required this.issueID, + }); + + static final $parentNavigatorKey = rootNavigatorKey; + + final String issueID; + + @override + Widget build(BuildContext context, GoRouterState state) { + return IssueDetailScreen( + issueID: issueID, ); + } +} diff --git a/lib/view/router.g.dart b/lib/view/router.g.dart index c9c01c5..1447bd2 100644 --- a/lib/view/router.g.dart +++ b/lib/view/router.g.dart @@ -2,11 +2,211 @@ part of 'router.dart'; +// ************************************************************************** +// GoRouterGenerator +// ************************************************************************** + +List get $appRoutes => [ + $homeShellRoute, + ]; + +RouteBase get $homeShellRoute => ShellRouteData.$route( + factory: $HomeShellRouteExtension._fromState, + navigatorKey: HomeShellRoute.$navigatorKey, + routes: [ + GoRouteData.$route( + path: '/', + factory: $SimpleRouteExtension._fromState, + routes: [ + GoRouteData.$route( + path: 'search/detail', + factory: $SearchMeetingDetailRouteExtension._fromState, + parentNavigatorKey: SearchMeetingDetailRoute.$parentNavigatorKey, + ), + GoRouteData.$route( + path: 'search/summary', + factory: $SearchMeetingSummaryRouteExtension._fromState, + parentNavigatorKey: SearchMeetingSummaryRoute.$parentNavigatorKey, + ), + GoRouteData.$route( + path: 'search/speech', + factory: $SearchSpeechRouteExtension._fromState, + parentNavigatorKey: SearchSpeechRoute.$parentNavigatorKey, + ), + GoRouteData.$route( + path: 'speech/:speechID', + factory: $SpeechDetailRouteExtension._fromState, + parentNavigatorKey: SpeechDetailRoute.$parentNavigatorKey, + ), + GoRouteData.$route( + path: 'issue/:issueID', + factory: $IssueDetailRouteExtension._fromState, + parentNavigatorKey: IssueDetailRoute.$parentNavigatorKey, + ), + ], + ), + GoRouteData.$route( + path: '/full', + factory: $FullRouteExtension._fromState, + ), + GoRouteData.$route( + path: '/history', + factory: $HistoryRouteExtension._fromState, + ), + ], + ); + +extension $HomeShellRouteExtension on HomeShellRoute { + static HomeShellRoute _fromState(GoRouterState state) => + const HomeShellRoute(); +} + +extension $SimpleRouteExtension on SimpleRoute { + static SimpleRoute _fromState(GoRouterState state) => const SimpleRoute(); + + String get location => GoRouteData.$location( + '/', + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + +extension $SearchMeetingDetailRouteExtension on SearchMeetingDetailRoute { + static SearchMeetingDetailRoute _fromState(GoRouterState state) => + SearchMeetingDetailRoute( + q: state.queryParams['q'] ?? '', + ); + + String get location => GoRouteData.$location( + '/search/detail', + queryParams: { + if (q != '') 'q': q, + }, + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + +extension $SearchMeetingSummaryRouteExtension on SearchMeetingSummaryRoute { + static SearchMeetingSummaryRoute _fromState(GoRouterState state) => + SearchMeetingSummaryRoute( + q: state.queryParams['q'] ?? '', + ); + + String get location => GoRouteData.$location( + '/search/summary', + queryParams: { + if (q != '') 'q': q, + }, + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + +extension $SearchSpeechRouteExtension on SearchSpeechRoute { + static SearchSpeechRoute _fromState(GoRouterState state) => SearchSpeechRoute( + q: state.queryParams['q'] ?? '', + ); + + String get location => GoRouteData.$location( + '/search/speech', + queryParams: { + if (q != '') 'q': q, + }, + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + +extension $SpeechDetailRouteExtension on SpeechDetailRoute { + static SpeechDetailRoute _fromState(GoRouterState state) => SpeechDetailRoute( + speechID: state.params['speechID']!, + ); + + String get location => GoRouteData.$location( + '/speech/${Uri.encodeComponent(speechID)}', + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + +extension $IssueDetailRouteExtension on IssueDetailRoute { + static IssueDetailRoute _fromState(GoRouterState state) => IssueDetailRoute( + issueID: state.params['issueID']!, + ); + + String get location => GoRouteData.$location( + '/issue/${Uri.encodeComponent(issueID)}', + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + +extension $FullRouteExtension on FullRoute { + static FullRoute _fromState(GoRouterState state) => const FullRoute(); + + String get location => GoRouteData.$location( + '/full', + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + +extension $HistoryRouteExtension on HistoryRoute { + static HistoryRoute _fromState(GoRouterState state) => const HistoryRoute(); + + String get location => GoRouteData.$location( + '/history', + ); + + void go(BuildContext context) => context.go(location); + + void push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); +} + // ************************************************************************** // RiverpodGenerator // ************************************************************************** -String _$routerHash() => r'6c5277bc5cce87991586c0707513f017790b7e27'; +String _$routerHash() => r'7a148586d383d01203f906b7c59e315d16a0eb57'; /// See also [router]. @ProviderFor(router) diff --git a/lib/view/router_key.dart b/lib/view/router_key.dart new file mode 100644 index 0000000..b841287 --- /dev/null +++ b/lib/view/router_key.dart @@ -0,0 +1,4 @@ +import 'package:flutter/material.dart'; + +final rootNavigatorKey = GlobalKey(); +final shellNavigatorKey = GlobalKey(); diff --git a/lib/view/search/search_meeting_detail_screen.dart b/lib/view/search/search_meeting_detail_screen.dart index 5d3c4fa..03affc2 100644 --- a/lib/view/search/search_meeting_detail_screen.dart +++ b/lib/view/search/search_meeting_detail_screen.dart @@ -5,12 +5,11 @@ import 'package:flutter_kokkai_gijiroku/model/entity/search_params.dart'; import 'package:flutter_kokkai_gijiroku/model/source/data_source_meeting_detail.dart'; import 'package:flutter_kokkai_gijiroku/presenter/api_presenter.dart'; import 'package:flutter_kokkai_gijiroku/utils/date_formatter.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:flutter_kokkai_gijiroku/view/search_mode.dart'; -import 'package:flutter_kokkai_gijiroku/view/status/speech_detail_screen.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_content.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_divider.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_options.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:over_bottom_sheet/over_bottom_sheet.dart'; import 'package:paging_view/paging_view.dart'; @@ -22,8 +21,6 @@ class SearchMeetingDetailScreen extends HookConsumerWidget { required this.params, }); - static String screenName = 'searchMeetingDetail'; - final SearchParams params; @override @@ -92,12 +89,9 @@ class SearchMeetingDetailScreen extends HookConsumerWidget { title: Text(record.speaker), subtitle: Text(record.speechID), onTap: () { - context.pushNamed( - SpeechDetailScreen.screenName, - params: { - 'speechID': record.speechID, - }, - ); + SpeechDetailRoute( + speechID: record.speechID, + ).push(context); }, ); }, diff --git a/lib/view/search/search_meeting_summary_screen.dart b/lib/view/search/search_meeting_summary_screen.dart index 118e590..77a4cd5 100644 --- a/lib/view/search/search_meeting_summary_screen.dart +++ b/lib/view/search/search_meeting_summary_screen.dart @@ -5,12 +5,11 @@ import 'package:flutter_kokkai_gijiroku/model/entity/search_params.dart'; import 'package:flutter_kokkai_gijiroku/model/source/data_source_meeting_summary.dart'; import 'package:flutter_kokkai_gijiroku/presenter/api_presenter.dart'; import 'package:flutter_kokkai_gijiroku/utils/date_formatter.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:flutter_kokkai_gijiroku/view/search_mode.dart'; -import 'package:flutter_kokkai_gijiroku/view/status/speech_detail_screen.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_content.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_divider.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_options.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:over_bottom_sheet/over_bottom_sheet.dart'; import 'package:paging_view/paging_view.dart'; @@ -22,8 +21,6 @@ class SearchMeetingSummaryScreen extends HookConsumerWidget { required this.params, }); - static String screenName = 'searchMeetingSummary'; - final SearchParams params; @override @@ -89,12 +86,9 @@ class SearchMeetingSummaryScreen extends HookConsumerWidget { title: Text(e.speaker), subtitle: Text(e.speechID), onTap: () { - context.pushNamed( - SpeechDetailScreen.screenName, - params: { - 'speechID': e.speechID, - }, - ); + SpeechDetailRoute( + speechID: e.speechID, + ).push(context); }, ); }, diff --git a/lib/view/search/search_speech_screen.dart b/lib/view/search/search_speech_screen.dart index 444288d..ea2afa9 100644 --- a/lib/view/search/search_speech_screen.dart +++ b/lib/view/search/search_speech_screen.dart @@ -5,12 +5,11 @@ import 'package:flutter_kokkai_gijiroku/model/entity/speech_record.dart'; import 'package:flutter_kokkai_gijiroku/model/source/data_source_speech.dart'; import 'package:flutter_kokkai_gijiroku/presenter/api_presenter.dart'; import 'package:flutter_kokkai_gijiroku/utils/date_formatter.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:flutter_kokkai_gijiroku/view/search_mode.dart'; -import 'package:flutter_kokkai_gijiroku/view/status/speech_detail_screen.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_content.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_divider.dart'; import 'package:flutter_kokkai_gijiroku/view/widget/bottom_sheet_options.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:over_bottom_sheet/over_bottom_sheet.dart'; import 'package:paging_view/paging_view.dart'; @@ -21,8 +20,6 @@ class SearchSpeechScreen extends ConsumerWidget { required this.params, }); - static String screenName = 'searchSpeech'; - final SearchParams params; @override @@ -76,12 +73,9 @@ class SearchSpeechScreen extends ConsumerWidget { overflow: TextOverflow.ellipsis, ), onTap: () { - context.pushNamed( - SpeechDetailScreen.screenName, - params: { - 'speechID': element.speechID, - }, - ); + SpeechDetailRoute( + speechID: element.speechID, + ).push(context); }, onLongPress: () { showDialog( @@ -93,54 +87,45 @@ class SearchSpeechScreen extends ConsumerWidget { SimpleDialogOption( child: const Text('この会議で絞り込み'), onPressed: () { - context.pushNamed( - SearchSpeechScreen.screenName, - queryParams: { - 'q': params - .copyWith( - issueID: element.issueID, - ) - .uriQuery, - }, - ); - Navigator.of(context).pop(); + + SearchSpeechRoute( + q: params + .copyWith( + issueID: element.issueID, + ) + .uriQuery, + ).push(context); }, ), if (element.speaker.isNotEmpty) SimpleDialogOption( child: const Text('発言者で絞り込み'), onPressed: () { - context.pushNamed( - SearchSpeechScreen.screenName, - queryParams: { - 'q': params - .copyWith( - speaker: element.speaker, - ) - .uriQuery, - }, - ); - Navigator.of(context).pop(); + + SearchSpeechRoute( + q: params + .copyWith( + speaker: element.speaker, + ) + .uriQuery, + ).push(context); }, ), if (element.speakerGroup.isNotEmpty) SimpleDialogOption( child: const Text('所属政党で絞り込み'), onPressed: () { - context.pushNamed( - SearchSpeechScreen.screenName, - queryParams: { - 'q': params - .copyWith( - speakerGroup: element.speakerGroup, - ) - .uriQuery, - }, - ); - Navigator.of(context).pop(); + + SearchSpeechRoute( + q: params + .copyWith( + speakerGroup: element.speakerGroup, + ) + .uriQuery, + ).push(context); }, ), ], diff --git a/lib/view/status/issue_detail_screen.dart b/lib/view/status/issue_detail_screen.dart index 5ae974d..eef375b 100644 --- a/lib/view/status/issue_detail_screen.dart +++ b/lib/view/status/issue_detail_screen.dart @@ -2,8 +2,7 @@ import 'package:breakpoints_mq/breakpoints_mq.dart'; import 'package:flutter/material.dart'; import 'package:flutter_kokkai_gijiroku/model/entity/speech_record.dart'; import 'package:flutter_kokkai_gijiroku/model/source/data_source_issue.dart'; -import 'package:flutter_kokkai_gijiroku/view/status/speech_detail_screen.dart'; -import 'package:go_router/go_router.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:paging_view/paging_view.dart'; @@ -13,8 +12,6 @@ class IssueDetailScreen extends ConsumerWidget { required this.issueID, }); - static String screenName = 'statusIssue'; - final String issueID; @override @@ -46,12 +43,9 @@ class IssueDetailScreen extends ConsumerWidget { ), ), onTap: () { - context.pushNamed( - SpeechDetailScreen.screenName, - params: { - 'speechID': element.speechID, - }, - ); + SpeechDetailRoute( + speechID: element.speechID, + ).go(context); }, ), initialLoadingWidget: const Center( diff --git a/lib/view/status/speech_detail_screen.dart b/lib/view/status/speech_detail_screen.dart index 89063d0..2d05a8a 100644 --- a/lib/view/status/speech_detail_screen.dart +++ b/lib/view/status/speech_detail_screen.dart @@ -2,9 +2,8 @@ import 'package:breakpoints_mq/breakpoints_mq.dart'; import 'package:flutter/material.dart'; import 'package:flutter_kokkai_gijiroku/presenter/api_presenter.dart'; import 'package:flutter_kokkai_gijiroku/utils/date_formatter.dart'; -import 'package:flutter_kokkai_gijiroku/view/status/issue_detail_screen.dart'; +import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:flutter_linkify/flutter_linkify.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -14,8 +13,6 @@ class SpeechDetailScreen extends ConsumerWidget { required this.speechID, }); - static String screenName = 'statusSpeech'; - final String speechID; @override @@ -103,12 +100,9 @@ class SpeechDetailScreen extends ConsumerWidget { minimumSize: const Size.fromHeight(48), ), onPressed: () { - context.pushNamed( - IssueDetailScreen.screenName, - params: { - 'issueID': data.issueID, - }, - ); + IssueDetailRoute( + issueID: data.issueID, + ).push(context); }, child: const Text('会議'), ), diff --git a/pubspec.lock b/pubspec.lock index 412b4cd..8a3abbc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -341,6 +341,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.5.5" + go_router_builder: + dependency: "direct dev" + description: + name: go_router_builder + sha256: d4006e511607d356f23b5dfc759473a25a641b49324174a662c9ba700a666985 + url: "https://pub.dev" + source: hosted + version: "1.2.0" google_fonts: dependency: "direct main" description: @@ -597,6 +605,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.5" + path_to_regexp: + dependency: transitive + description: + name: path_to_regexp + sha256: "169d78fbd55e61ea8873bcca545979f559d22238f66facdd7ef30870c7f53327" + url: "https://pub.dev" + source: hosted + version: "0.4.0" petitparser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fa58fe6..1c8208a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,6 +51,7 @@ dev_dependencies: json_serializable: ^6.0.0 riverpod_generator: ^2.0.0 hive_generator: ^2.0.0 + go_router_builder: ^1.0.0 flutter: uses-material-design: true From 4b383de69bf3b905ab15b0aa9270457c38620161 Mon Sep 17 00:00:00 2001 From: Koji Wakamiya Date: Fri, 7 Apr 2023 01:10:23 +0900 Subject: [PATCH 2/3] fix --- lib/view/home/full/full_search_screen.dart | 4 +- lib/view/home/history/history_widget.dart | 4 +- .../home/simple/simple_search_screen.dart | 63 +++++++------------ 3 files changed, 24 insertions(+), 47 deletions(-) diff --git a/lib/view/home/full/full_search_screen.dart b/lib/view/home/full/full_search_screen.dart index 9aa7c30..3350767 100644 --- a/lib/view/home/full/full_search_screen.dart +++ b/lib/view/home/full/full_search_screen.dart @@ -16,9 +16,7 @@ enum _Field { } class FullSearchWidget extends ConsumerWidget { - const FullSearchWidget({ - super.key, - }); + const FullSearchWidget({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/view/home/history/history_widget.dart b/lib/view/home/history/history_widget.dart index f7fe4bc..1cee7f9 100644 --- a/lib/view/home/history/history_widget.dart +++ b/lib/view/home/history/history_widget.dart @@ -11,9 +11,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:intl/intl.dart'; class HistoryWidget extends ConsumerWidget { - const HistoryWidget({ - super.key, - }); + const HistoryWidget({super.key}); DateFormat get _formatter => DateFormat.yMd().add_Hm(); diff --git a/lib/view/home/simple/simple_search_screen.dart b/lib/view/home/simple/simple_search_screen.dart index 47d7220..8359bbd 100644 --- a/lib/view/home/simple/simple_search_screen.dart +++ b/lib/view/home/simple/simple_search_screen.dart @@ -7,9 +7,7 @@ import 'package:flutter_kokkai_gijiroku/view/router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; class SimpleSearchWidget extends HookConsumerWidget { - const SimpleSearchWidget({ - super.key, - }); + const SimpleSearchWidget({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -21,6 +19,25 @@ class SimpleSearchWidget extends HookConsumerWidget { text: any, ), ); + searchAction() { + final state = ref.read(searchStateManagerProvider); + final text = state.any; + + if (text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('検索語を入力してください'), + ), + ); + return; + } + + SearchSpeechRoute( + q: SearchParams( + any: text, + ).uriQuery, + ).push(context); + } return BreakpointWidget( child: Center( @@ -33,49 +50,13 @@ class SimpleSearchWidget extends HookConsumerWidget { labelText: '検索語', suffixIcon: IconButton( icon: const Icon(Icons.search), - onPressed: () { - final state = ref.read(searchStateManagerProvider); - final text = state.any; - - if (text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('検索語を入力してください'), - ), - ); - return; - } - - SearchSpeechRoute( - q: SearchParams( - any: text, - ).uriQuery, - ).push(context); - }, + onPressed: searchAction, ), ), onChanged: (value) { ref.read(searchStateManagerProvider.notifier).updateAny(value); }, - onEditingComplete: () { - final state = ref.read(searchStateManagerProvider); - final text = state.any; - - if (text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('検索語を入力してください'), - ), - ); - return; - } - - SearchSpeechRoute( - q: SearchParams( - any: text, - ).uriQuery, - ).push(context); - }, + onEditingComplete: searchAction, ), ), ); From 5ff9f749ab731add787a1d4e5b7c9ad43708d015 Mon Sep 17 00:00:00 2001 From: Koji Wakamiya Date: Fri, 7 Apr 2023 01:16:35 +0900 Subject: [PATCH 3/3] fix --- lib/view/home/home_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/view/home/home_screen.dart b/lib/view/home/home_screen.dart index 1ed0356..11a7f4d 100644 --- a/lib/view/home/home_screen.dart +++ b/lib/view/home/home_screen.dart @@ -30,7 +30,7 @@ class HomeScreen extends ConsumerWidget { /// get current HomeMode from path HomeMode _getHomeMode(BuildContext context) { final path = GoRouter.of(context).location; - return HomeMode.values.firstWhere( + return HomeMode.values.lastWhere( (e) => path.startsWith(e.path), orElse: () => HomeMode.simple, );