Skip to content

[flutter_adaptive_scaffold] Go router sample for AdaptiveScaffold - #7452

Merged
auto-submit[bot] merged 19 commits into
flutter:mainfrom
martijn00:go_router
Sep 4, 2024
Merged

[flutter_adaptive_scaffold] Go router sample for AdaptiveScaffold#7452
auto-submit[bot] merged 19 commits into
flutter:mainfrom
martijn00:go_router

Conversation

@martijn00

@martijn00martijn00 commented Aug 20, 2024

Copy link
Copy Markdown
Contributor

This implements a sample of using GoRouter with AdaptiveScaffold. It also helps testing advanced adaptive scenarios.

List which issues are fixed by this PR. You must list at least one issue.

flutter/flutter#129850

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@chunhtai can you have a look at this one too?

Comment threadpackages/flutter_adaptive_scaffold/example/lib/go_router_demo.dart Outdated
Comment threadpackages/flutter_adaptive_scaffold/example/pubspec.yaml Outdated

@gspencergooggspencergoog left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

32384589-a60f0e74-c078-11e7-9bc1-e5b5287aea9d

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@Renzo-Olivares can you have a look?

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@hanskokx could you pitch in with your research findings on this sample?

@hanskokx

hanskokx commented Aug 29, 2024

Copy link
Copy Markdown

From my experience, AdaptiveScaffold works optimally when paired with AdaptiveLayout. However, there is an issue in flutter_adaptive_scaffold version 0.2.x where the leadingExtendedNavRail does not show up (I've been meaning to file a bug on this). Below is the approach I've utilized in production over the last few years:

classMainAppextendsStatelessWidget {
constMainApp({super.key});
@overrideWidgetbuild(BuildContext context) {
returnMaterialApp.router(
routeInformationProvider:AppRouter.router.routeInformationProvider,
routeInformationParser:AppRouter.router.routeInformationParser,
routerDelegate:AppRouter.router.routerDelegate,
),
);
}
}
enumAppRoute {
root("/", isProtected:false),
home("/splash", isProtected:false),
home("/welcome", isProtected:false),
home("/login", isProtected:false),
home("/register", isProtected:false),
home("/home"),
;
finalString path;
finalbool isProtected;
constAppRoute(this.path, {this.isProtected =true});
}
classAppRouter {
staticfinal router =GoRouter(
errorBuilder: (context, state) =>constErrorScreen(),
navigatorKey:GlobalKey<NavigatorState>(debugLabel:"root"),
initialLocation:AppRoute.splash.path,
debugLogDiagnostics: kDebugMode,
redirect: (BuildContext context, GoRouterState state) {
finalbool routeIsProtected =AppRoute.values.any(
(AppRoute route) =>
state.uri.toString().contains(route.path) && route.isProtected,
);
finalbool unauthenticated =AuthenticationService.I.status ==AuthenticationStatus.unauthenticated;
if (unauthenticated && routeIsProtected) {
return state.namedLocation(
AppRoute.welcome.name,
queryParameters:<String, String>{"from": state.uri.toString()},
);
}
returnnull;
},
routes:<RouteBase>[
GoRoute(
path:AppRoute.root.path,
redirect: (_, __) =>AppRoute.home.path,
),
GoRoute(
name:AppRoute.splash.name,
path:AppRoute.splash.path,
pageBuilder: (context, state) =>MaterialPage(
key: state.pageKey,
child:SplashScreen(),
);
),
// * WelcomeGoRoute(
name:AppRoute.welcome.name,
path:AppRoute.welcome.path,
pageBuilder: (context, state) {
returnMaterialPage(
key: state.pageKey,
child:constWelcomeScreen(),
);
},
routes: [
// LoginGoRoute(
name:AppRoute.login.name,
path:AppRoute.login.path,
builder: (context, state) =>LoginScreen();
routes: [
// Forgot passwordGoRoute(
name:AppRoute.forgotPassword.name,
path:AppRoute.forgotPassword.path,
builder: (context, state) =>AppScaffold(
key: state.pageKey,
body:constForgotPasswordScreen(),
);
),
],
),
// RegisterGoRoute(
name:AppRoute.register.name,
path:AppRoute.register.path,
builder: (context, state) =>constRegisterScreen();
),
],
),
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) =>AppScaffoldShell(
navigationShell: navigationShell,
),
branches:<StatefulShellBranch>[
// Home branchStatefulShellBranch(
initialLocation:AppRoute.home.path,
navigatorKey:GlobalKey<NavigatorState>(debugLabel:"home"),
routes: [
GoRoute(
name:AppRoute.home.name,
path:AppRoute.home.path,
pageBuilder: (context, state) {
returnNoTransitionPage(
child:AppScaffold(
key: state.pageKey,
body:HomeScreen(
key:GlobalKey(debugLabel:"Home Screen"),
),
),
);
},
),
],
),
],
),
],
);
}
extensionLandscapeExtensiononBuildContext {
boolget isLandscape =>MediaQuery.of(this).orientation ==Orientation.landscape ||
layoutSize !=LayoutSize.small;
LayoutSizeget layoutSize {
if (Breakpoints.large.isActive(this)) {
returnLayoutSize.large;
} elseif (Breakpoints.medium.isActive(this)) {
returnLayoutSize.medium;
} else {
returnLayoutSize.small;
}
}
}
enumLayoutSize { small, medium, large }
classAppScaffoldextendsStatelessWidget {
finalWidget body;
finalWidget? secondaryBody;
constAppScaffold({
requiredthis.body,
Key? key,
this.secondaryBody,
}) :super(key: key ??constValueKey("ScaffoldWithNestedNavigation"));
@overrideWidgetbuild(BuildContext context) {
returnAdaptiveLayout(
internalAnimations:false,
body:SlotLayout(
config:<Breakpoint, SlotLayoutConfig>{
Breakpoints.small:SlotLayout.from(
key:constKey("Body Small"),
builder: (context) {
finalWidget child = secondaryBody ?? body;
return context.isLandscape ?SafeArea(child: child) : child;
},
),
Breakpoints.mediumAndUp:SlotLayout.from(
key:constKey("Body Medium and Up"),
builder: (context) => context.isLandscape ?SafeArea(child: body) : body;
),
},
secondaryBody:SlotLayout(
config:<Breakpoint, SlotLayoutConfig>{
Breakpoints.small:SlotLayout.from(
key:constKey("Body Small"),
builder:null,
),
Breakpoints.mediumAndUp:SlotLayout.from(
key:constKey("Body Medium"),
builder: (context) => secondaryBody,
),
},
),
),
);
}
}
classAppScaffoldShellextendsStatelessWidget {
finalStatefulNavigationShell navigationShell;
constAppScaffoldShell({
requiredthis.navigationShell,
Key? key,
}) :super(key: key ??constValueKey("ScaffoldWithNestedNavigation"));
@overrideWidgetbuild(BuildContext context) {
returnAdaptiveScaffold(
selectedIndex: navigationShell.currentIndex,
onSelectedIndexChange: onNavigationEvent,
destinations: [
NavigationDestination(...),
NavigationDestination(...),
NavigationDestination(...),
],
body: (_) => navigationShell,
);
}
voidonNavigationEvent(int index) {
navigationShell.goBranch(
index,
initialLocation: index == navigationShell.currentIndex,
);
}
}

@martijn00

Copy link
Copy Markdown
ContributorAuthor

Thanks! I'm curious about the leadingExtendedNavRail bug. I'm working on new implementations that would make things easier. Currently the AdaptiveScaffold implementation is way to complicated.

https://docs.google.com/document/d/1DMFfGrHv_V1Je6_wrfyu0iY3ngJgn317OscfNbuRMRA/pub

Let me know if you have feedback on the doc.

@hanskokx

Copy link
Copy Markdown

Thanks! I'm curious about the leadingExtendedNavRail bug.

I've recorded the behavior I'm seeing in 0.1.12 vs 0.2.2. I haven't had time yet to dig into it and figure out what changed and/or what's broken. It's been on my todo list but I'm right at the end of this project and have needed to focus on getting it shipped.

0.1.12.mov
0.2.2.mov

I'm working on new implementations that would make things easier. Currently the AdaptiveScaffold implementation is way to complicated.

Yeah, that would be great! As you can see from the code I provided before, the true implementation requires far more work than is reasonable. (I even cut a bunch out of that example, such as where I'm disabling animations because they look wonky.) A more streamlined approach would be greatly appreciated.

https://docs.google.com/document/d/1DMFfGrHv_V1Je6_wrfyu0iY3ngJgn317OscfNbuRMRA/pub
Let me know if you have feedback on the doc.

It would be beneficial to have a feature that allows users to resize panes, possibly through a drag handle that becomes visible when tapping between panes. Naturally, this feature would be optional.

Adding panes dynamically would be a useful feature. Consider a list within a list scenario: the first pane displays a list of items, and upon selection, a second pane appears, showing further details and another list. Selecting an item from this secondary list could lead to a deeper list in a new pane or reveal more details about the item. By the third level, the initial pane could automatically hide to prevent screen clutter. (Feel free to disregard if this seems far-fetched.)

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@hanskokx I think you are correct this is a bug. Probably in this code:

final bool isHeightActive = isDesktop ||
orientation == Orientation.portrait ||
(orientation == Orientation.landscape && andUp
? isWidthActive || height >= lowerBoundHeight
: height >= lowerBoundHeight && height < upperBoundHeight);

I have to look into that to figure out where it is.

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@hanskokx because the device size is a width of 841 and a height of 668 it can't be active on mediumLarge because the height starts at 900 but cannot be active at medium because the width doesn't match. Therefor it falls back to standard which is not good in this situation.

I'm not sure yet how to handle this, but my feeling is the breakpoint to apply is mediumLarge. This could be done by lowering the height to maybe 480? The specs are just not very clear on this.

@hanskokx

Copy link
Copy Markdown

@martijn00 Do you know what PR/commit the behavior was changed in? That might provide some insights into why the change was made and illuminate a path forward.

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@hanskokx in this pr #7300

@hanskokx

Copy link
Copy Markdown

@hanskokx in this pr #7300

I wonder if you are a prophet 😅. #7300 (comment)
I agree that your work in refactoring into the Breakpoints enum is the best place to start looking. Perhaps we should spin up a new bug ticket and migrate the conversation there, to keep this PR focused on the sample?

@martijn00

Copy link
Copy Markdown
ContributorAuthor

Yeah i agree a new issue is better. I'll look into adding a test for this case.

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@hanskokx Here is a PR for it: #7549

@martijn00

Copy link
Copy Markdown
ContributorAuthor

@gspencergoog can you add: "override: no changelog needed" label.

@chunhtaichunhtai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@gspencergooggspencergoog added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 4, 2024
@auto-submit
auto-submitBot merged commit f408578 into flutter:mainSep 4, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 4, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 4, 2024
auto-submitBot pushed a commit to flutter/flutter that referenced this pull request Sep 4, 2024
flutter/packages@848d7e9...e93995a
2024-09-04 109111084+yaakovschectman@users.noreply.github.com [google_maps_flutter_android] Convert `JointType` to an enum (flutter/packages#7558)
2024-09-04 mhvdijk@gmail.com [flutter_adaptive_scaffold] Go router sample for AdaptiveScaffold (flutter/packages#7452)
2024-09-04 mhvdijk@gmail.com [flutter_adaptive_scaffold] Fix breakpoint not being active in certain cases like foldables (flutter/packages#7549)
2024-09-03 34871572+gmackall@users.noreply.github.com [google_sign_in_android] Downgrade Guava version from `33.3.0` to `32.0.1` (flutter/packages#7573)
2024-09-03 magder@google.com [google_maps_flutter] Remove unused MapKit imports from iOS example apps (flutter/packages#7522)
2024-09-03 10687576+bparrishMines@users.noreply.github.com [interactive_media_ads] Adds support for pausing and resuming Ad playback and skipping an Ad (flutter/packages#7285)
2024-09-03 34871572+gmackall@users.noreply.github.com [rfw] Upgrade missed example app (flutter/packages#7545)
2024-09-03 49699333+dependabot[bot]@users.noreply.github.com [video_player]: Bump exoplayer_version from 1.4.0 to 1.4.1 in /packages/video_player/video_player_android/android (flutter/packages#7564)
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human
is aware of the problem.
To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
creatorpiyush pushed a commit to creatorpiyush/packages that referenced this pull request Jun 10, 2026
…utter#7452)
This implements a sample of using GoRouter with AdaptiveScaffold. It also helps testing advanced adaptive scenarios.
*List which issues are fixed by this PR. You must list at least one issue.*
flutter/flutter#129850
bisor0627 pushed a commit to bisor0627/packages that referenced this pull request Jun 19, 2026
…utter#7452)
This implements a sample of using GoRouter with AdaptiveScaffold. It also helps testing advanced adaptive scenarios.
*List which issues are fixed by this PR. You must list at least one issue.*
flutter/flutter#129850
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmitMerge PR when tree becomes green via auto submit Appp: flutter_adaptive_scaffold

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@martijn00@hanskokx@gspencergoog@chunhtai