I'm trying to switch to Navigator 2.0 following the example at https://github.com/carloshwa/flutter-example/tree/navigator_2 adapting it to my code.
As in the example, I have a class AppState extends ChangeNotifier
which RouterDelegate
listens to
AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>() {
appState.addListener(notifyListeners);
print('appState.addListener(notifyListeners) called');
}
to build the correct page
pages: [MaterialPage(child: WebPageMainLayout(appState: appState,))],
where WebPageMainLayout
adds a ConstrainedBox
with WebsitePageDisplay
as its child.
WebsitePageDisplay
has a Column
.
First Column
's widget is NavigationBar
from which buttons AppState
's selectedPage
gets set
void _handlePageTapped(String selected) {
print('selected tapped is $selected');
appState.selectedPage = selected;
}
...
NavigationBarButton(
title: AppLocalizations.instance.text('For retailers'),
navigationPath: RetailersLandingRoute,
onPressed: () {},
onTapped: _handlePageTapped,
),
So once set it notifies his listeners (RouterDelegate).
The second Column
's widget is the actual page to show returned from AppState
's selectedWidget
getter.
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
NavigationBar(),
Expanded(
child: widget.appState.selectedWidget,
)
],
);
The problem is that when a button is pressed the second widget (from AppState
's getter) is not swapped, dough I get the correct prints from _handlePageTapped
(eg. `/retailers from the above code)
I'm not sure if it's the RouterDelegate that dough, it gets notified of the changes in AppState
, doesn't rebuild the Navigator
with the new page, or I'm just implementing a wrong logic as I'm new to ChangeNotifier and Navigator 2.0 seems a bit over-complicated.
When the page first loads up I see the set of prints I setup from parseRouteInformation
, currentConfiguration
, restoreRouteInformation
, setNewRoutePath' first with no value ( as I don't have a
/route ) but then with the correct
/cyclists` value.
AppRouteInformationParser.parseRouteInformation called for /
AppRouteInformationParser uri is /
AppRouteInformationParser.urlSegment switch: /
RouterDelegate.currentConfiguration appState.selectedPage is
AppRouteInformationParser.restoreRouteInformation called for configuration
RouterDelegate.setNewRoutePath configuration is Configuration {unknown: false, selectedPage: /cyclists}
AppState setting selectedPage to /cyclists
RouterDelegate.currentConfiguration appState.selectedPage is /cyclists
AppRouteInformationParser.restoreRouteInformation called for configuration /cyclists
restoreRouteInformation RouteInformation.location: /cyclists
RouterDelegate.currentConfiguration appState.selectedPage is /cyclists
AppRouteInformationParser.restoreRouteInformation called for configuration /cyclists
restoreRouteInformation RouteInformation.location: /cyclists
RouterDelegate.currentConfiguration appState.selectedPage is /cyclists
AppRouteInformationParser.restoreRouteInformation called for configuration /cyclists
restoreRouteInformation RouteInformation.location: /cyclists
but when I press a NavigationBar
's button I only get the _handlePageTapped
print.
Also changing Url in chrome doesn't work..
Can you spot what I'm doing wrong?? As always many thanks for your help.
class AppState extends ChangeNotifier {
String _selectedPage;
AppState() : _selectedPage = '';
String get selectedPage => _selectedPage;
// works
Widget get selectedWidget {
switch (selectedPage) {
case CyclistsLandingRoute:
return CyclistLanding();
break;
case RetailersLandingRoute:
return RetailerLanding();
break;
case MapRoute:
return CityMap();
break;
case AboutRoute:
return AboutUs();
break;
case TermsOfServiceRoute:
return TermsOfService();
break;
case PrivacyPolicyRoute:
return PrivacyPolicy();
break;
// case PrivacySettingsRoute:
// return PrivacyPolicySettings();
// break;
case CommunityGuidelinesRoute:
return CommunityGuidelines();
break;
case LegalNoticeRoute:
return LegalNotice();
break;
default:
return CyclistLanding();
}
}
set selectedPage(String page) {
print('AppState setting selectedPage to $page');
_selectedPage = page;
notifyListeners();
}
}
class AppRouterDelegate extends RouterDelegate<Configuration>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<Configuration> {
final GlobalKey<NavigatorState> navigatorKey;
AppState appState = AppState();
AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>() {
appState.addListener(notifyListeners);
print('appState.addListener(notifyListeners) called');
}
@override
Configuration get currentConfiguration {
print(
'RouterDelegate.currentConfiguration appState.selectedPage is ${appState.selectedPage}');
switch (appState.selectedPage) {
case CyclistsLandingRoute:
return Configuration.cyclists(appState.selectedPage);
break;
case RetailersLandingRoute:
return Configuration.retailers(appState.selectedPage);
break;
case MapRoute:
return Configuration.map(appState.selectedPage);
break;
case AboutRoute:
return Configuration.about(appState.selectedPage);
case TermsOfServiceRoute:
return Configuration.termsOfService(appState.selectedPage);
case PrivacyPolicyRoute:
return Configuration.privacyPolicy(appState.selectedPage);
break;
// case PrivacySettingsRoute:
// return Configuration.privacySettings();
// break;
case CommunityGuidelinesRoute:
return Configuration.communityGuidelines(appState.selectedPage);
break;
case LegalNoticeRoute:
return Configuration.legalNotice(appState.selectedPage);
break;
default:
return Configuration.cyclists(appState.selectedPage);
}
}
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: [
MaterialPage(
child: WebPageMainLayout(
appState: appState,
))
],
onPopPage: (route, result) {
if (!route.didPop(result)) return false;
if (appState.selectedPage != null) {
appState.selectedPage = null;
notifyListeners();
}
// show404 = false;
notifyListeners();
return true;
},
);
}
@override
Future<void> setNewRoutePath(Configuration configuration) async {
print(
'RouterDelegate.setNewRoutePath configuration is ${configuration.toString()}');
if (configuration.isUnknown) {
// show404 = true;
appState.selectedPage = null;
notifyListeners();
return;
} else if (configuration.isCyclist) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isRetailer) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isMap) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isAbout) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isTermsOfService) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isPrivacyPolicy) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isPrivacySettings) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isCommunityGuidelines) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
} else if (configuration.isLegalNotice) {
appState.selectedPage = configuration.selectedPage;
notifyListeners();
return;
}
return;
}
}
class Configuration {
final bool unknown;
final String selectedPage;
Configuration.cyclists(this.selectedPage) : unknown = false;
Configuration.retailers(this.selectedPage) : unknown = false;
Configuration.map(this.selectedPage) : unknown = false;
Configuration.about(this.selectedPage) : unknown = false;
Configuration.termsOfService(this.selectedPage) : unknown = false;
Configuration.privacyPolicy(this.selectedPage) : unknown = false;
Configuration.privacySettings(this.selectedPage) : unknown = false;
Configuration.communityGuidelines(this.selectedPage) : unknown = false;
Configuration.legalNotice(this.selectedPage) : unknown = false;
// bool get isHome => unknown == false;
bool get isCyclist =>
selectedPage == CyclistsLandingRoute; //unknown == false;
bool get isRetailer =>
selectedPage == RetailersLandingRoute; //unknown == false;
bool get isMap => selectedPage == MapRoute; //unknown == true;
bool get isAbout => selectedPage == AboutRoute; //unknown == false;
bool get isTermsOfService =>
selectedPage == TermsOfServiceRoute; //unknown == false;
bool get isPrivacyPolicy =>
selectedPage == PrivacyPolicyRoute; //unknown == false;
bool get isPrivacySettings =>
selectedPage == PrivacySettingsRoute; //unknown == false;
bool get isCommunityGuidelines =>
selectedPage == CommunityGuidelinesRoute; //unknown == false;
bool get isLegalNotice =>
selectedPage == LegalNoticeRoute; //unknown == false;
bool get isUnknown => unknown == true;
@override
String toString() =>
'Configuration {unknown: $unknown, selectedPage: $selectedPage}';
}
class AppRouteInformationParser extends RouteInformationParser<Configuration> {
@override
Future<Configuration> parseRouteInformation(
RouteInformation routeInformation) async {
print(
'AppRouteInformationParser.parseRouteInformation called for ${routeInformation.location}');
final Uri uri = Uri.parse(routeInformation.location);
print('AppRouteInformationParser uri is $uri');
switch (routeInformation.location) {
case '/':
print('AppRouteInformationParser.urlSegment switch: /');
return Configuration.cyclists(CyclistsLandingRoute);
break;
case CyclistsLandingRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: cyclists');
return Configuration.cyclists(CyclistsLandingRoute);
break;
case RetailersLandingRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: retailers');
return Configuration.retailers(RetailersLandingRoute);
break;
case MapRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: map');
return Configuration.map(MapRoute);
break;
case AboutRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: about');
return Configuration.about(AboutRoute);
break;
case TermsOfServiceRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: terms-of-service');
return Configuration.termsOfService(TermsOfServiceRoute);
break;
case PrivacyPolicyRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: privacy-policy');
return Configuration.privacyPolicy(PrivacyPolicyRoute);
break;
case PrivacySettingsRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: privacy-settings');
return Configuration.privacySettings(PrivacySettingsRoute);
break;
case CommunityGuidelinesRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: community-guidelines');
return Configuration.communityGuidelines(CommunityGuidelinesRoute);
break;
case LegalNoticeRoute:
print(
'AppRouteInformationParser.routeInformation.location switch case: legal-notice');
return Configuration.legalNotice(LegalNoticeRoute);
break;
default:
print('AppRouteInformationParser.routeInformation.location: home');
return Configuration.cyclists(CyclistsLandingRoute);
// return Configuration.home();
}
}
@override
RouteInformation restoreRouteInformation(Configuration configuration) {
print(
'AppRouteInformationParser.restoreRouteInformation called for configuration ${configuration.selectedPage}');
RouteInformation information = RouteInformation(location: '/cyclists');
// if (configuration.isHome) {
// information = RouteInformation(location: '/');
// } else
if (configuration.isCyclist) {
print('restoreRouteInformation RouteInformation.location: /cyclists');
information = RouteInformation(location: '/cyclists');
} else if (configuration.isRetailer) {
print('restoreRouteInformation RouteInformation.location: /retailers');
information = RouteInformation(location: '/retailers');
} else if (configuration.isMap) {
print('restoreRouteInformation RouteInformation.location: /map');
information = RouteInformation(location: '/map');
} else if (configuration.isAbout) {
print('restoreRouteInformation RouteInformation.location: /about');
information = RouteInformation(location: '/about');
} else if (configuration.isTermsOfService) {
print(
'restoreRouteInformation RouteInformation.location: /terms-of-service');
information = RouteInformation(location: '/terms-of-service');
} else if (configuration.isPrivacyPolicy) {
print(
'restoreRouteInformation RouteInformation.location: /privacy-policy');
information = RouteInformation(location: '/privacy-policy');
} else if (configuration.isPrivacySettings) {
print(
'restoreRouteInformation RouteInformation.location: /privacy-settings');
information = RouteInformation(location: '/privacy-settings');
} else if (configuration.isCommunityGuidelines) {
print(
'restoreRouteInformation RouteInformation.location: /community-guidelines');
information = RouteInformation(location: '/community-guidelines');
} else if (configuration.isLegalNotice) {
print('restoreRouteInformation RouteInformation.location: /legal-notice');
information = RouteInformation(location: '/legal-notice');
}
// else if (configuration.isUnknown) {
// information = RouteInformation(location: '/unknown');
// }
return information;
}
}
Finally found out where I was mistaking..
I was instantiating a new AppState
in some widgets (NavigationBar
) instead of passing the one from RouterDelegate..
Once corrected, it works as expected.
I guess that focussing on the new Navigator 2.0 system made my brain go novice lol.