Uh oh!
There was an error while loading. Please reload this page.
[flutter_adaptive_scaffold] Go router sample for AdaptiveScaffold - #7452
Conversation
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. |
65ec0be to
0e11e4aComparemartijn00
commented
Aug 21, 2024
@chunhtai can you have a look at this one too? |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
martijn00
commented
Aug 27, 2024
@Renzo-Olivares can you have a look? |
Uh oh!
There was an error while loading. Please reload this page.
martijn00
commented
Aug 29, 2024
@hanskokx could you pitch in with your research findings on this sample? |
From my experience, 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
commented
Aug 29, 2024
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
commented
Aug 30, 2024
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.mov0.2.2.mov
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.
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
commented
Aug 30, 2024
@hanskokx I think you are correct this is a bug. Probably in this code: I have to look into that to figure out where it is. |
martijn00
commented
Aug 30, 2024
@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 |
hanskokx
commented
Aug 30, 2024
@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
commented
Aug 30, 2024
hanskokx
commented
Aug 30, 2024
I wonder if you are a prophet 😅. #7300 (comment) |
martijn00
commented
Aug 30, 2024
Yeah i agree a new issue is better. I'll look into adding a test for this case. |
martijn00
commented
Aug 30, 2024
martijn00
commented
Aug 30, 2024
@gspencergoog can you add: "override: no changelog needed" label. |
…app_router.dart Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com>
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
…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
…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

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
dart format.)[shared_preferences]pubspec.yamlwith an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.CHANGELOG.mdto add a description of the change, following repository CHANGELOG style, or this PR is exempt from CHANGELOG changes.///).If you need help, consider asking for advice on the #hackers-new channel on Discord.