Add generic type for result in PopScope#139164
Add generic type for result in PopScope#139164auto-submit[bot] merged 7 commits intoflutter:masterfrom
Conversation
There was a problem hiding this comment.
I added this since we added to popScope, but I am not sure if there is a use case for result in NavigatorPopHandler.
There was a problem hiding this comment.
I decide to revert this change, I cant think of a reasonable way this can be used.
|
This will be a breaking change. will prepare the doc once this is approved |
|
will reopen once I am back from vacation |
|
internal test failures are expected, the code needs to be migrated |
justinmc
left a comment
There was a problem hiding this comment.
Thanks again for jumping in to help with this so quick after returning from leave!
This looks good, I probably should have done this in the first place. I'm struggling to picture exactly how the types should be used though. Maybe it would be worth adding an example (pop_scope.1.dart).
Consider the pop_scope.0.dart example. If I modify it so that the second page contains a Form that is returned as a result, the type parameters kind of confuse me:
pop_scope.0.dart modified to include a result value
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This sample demonstrates showing a confirmation dialog before navigating
// away from a page.
import 'package:flutter/material.dart';
void main() => runApp(const NavigatorPopHandlerApp());
class NavigatorPopHandlerApp extends StatelessWidget {
const NavigatorPopHandlerApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/home',
onGenerateRoute: (RouteSettings settings) {
return switch (settings.name) {
'/two' => MaterialPageRoute<FormData>(
builder: (BuildContext context) => const _PageTwo(),
),
_ => MaterialPageRoute(
builder: (BuildContext context) => const _HomePage(),
),
};
},
);
}
}
class _HomePage extends StatefulWidget {
const _HomePage();
@override
State<_HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
FormData? _formData;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Page One'),
if (_formData != null)
Text('Hello ${_formData!.name}, whose favorite food is ${_formData!.favoriteFood}.'),
TextButton(
onPressed: () async {
final FormData formData =
await Navigator.of(context).pushNamed<FormData?>('/two')
?? const FormData();
if (formData != _formData) {
setState(() {
_formData = formData;
});
}
},
child: const Text('Next page'),
),
],
),
),
);
}
}
class _PageTwo extends StatefulWidget {
const _PageTwo();
@override
State<_PageTwo> createState() => _PageTwoState();
}
class _PageTwoState extends State<_PageTwo> {
FormData _formData = const FormData();
/// Shows a dialog and resolves to true when the user has indicated that they
/// want to pop.
///
/// A return value of null indicates a desire not to pop, such as when the
/// user has dismissed the modal without tapping a button.
Future<bool?> _showBackDialog() {
return showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Are you sure?'),
content: const Text(
'Are you sure you want to leave this page?',
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Nevermind'),
onPressed: () {
Navigator.pop(context, false);
},
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Leave'),
onPressed: () {
Navigator.pop(context, true);
},
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Page Two'),
Form(
child: Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your name.',
),
onChanged: (String value) {
_formData = _formData.copyWith(
name: value,
);
},
),
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your favorite food.',
),
onChanged: (String value) {
_formData = _formData.copyWith(
favoriteFood: value,
);
},
),
],
),
),
// If this type is `Object?`, then it crashes because it doesn't
// match the type of the MaterialPageRoute.
PopScope<FormData>(
canPop: false,
onPopInvoked: (bool didPop, dynamic result) async {
if (didPop) {
return;
}
final bool shouldPop = await _showBackDialog() ?? false;
if (context.mounted && shouldPop) {
Navigator.pop(context, _formData);
}
},
child: TextButton(
onPressed: () async {
final bool shouldPop = await _showBackDialog() ?? false;
if (context.mounted && shouldPop) {
Navigator.pop(context, _formData);
}
},
child: const Text('Go back'),
),
),
],
),
),
);
}
}
class FormData {
const FormData({
this.name = '',
this.favoriteFood = '',
});
final String name;
final String favoriteFood;
FormData copyWith({String? name, String? favoriteFood}) {
return FormData(
name: name ?? this.name,
favoriteFood: favoriteFood ?? this.favoriteFood,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is FormData
&& other.name == name
&& other.favoriteFood == favoriteFood;
}
@override
int get hashCode => Object.hash(name, favoriteFood);
}My confusion comes from the fact that the result type of the dialog (bool) is different from the result type of the route (FormData). Is that example a good demonstration of this PR or am I using it wrong?
There was a problem hiding this comment.
Avoid underscore here and below. I guess this is less important in an integration test but still might help to write out the parameter.
There was a problem hiding this comment.
Is it possible to make this void? Not sure if it's better but just curious.
There was a problem hiding this comment.
this should match the Route generic type in line 1233. I am not sure if both can be void or not, I will have to investigate a bit more
There was a problem hiding this comment.
Pointing out some underscores in this test here and below as well.
There was a problem hiding this comment.
I wonder if people will want NavigatorPopHandler itself to have a type parameter, which is passed to PopScope here? I guess it's probably best to save that for another PR if/when it's needed.
There was a problem hiding this comment.
That was what i did before, but I can't think of a reason you need to access result in NavigatorPopHandler
There was a problem hiding this comment.
If I understand correctly, NavigatorPopHandler is for handling system back gesture, which won't have any result
There was a problem hiding this comment.
You're right, it shouldn't ever be necessary to set that as far as I can tell.
|
@justinmc Details// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This sample demonstrates showing a confirmation dialog before navigating
// away from a page.
import 'package:flutter/material.dart';
void main() => runApp(const NavigatorPopHandlerApp());
class NavigatorPopHandlerApp extends StatelessWidget {
const NavigatorPopHandlerApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/home',
onGenerateRoute: (RouteSettings settings) {
return switch (settings.name) {
'/two' => MaterialPageRoute<FormData>(
builder: (BuildContext context) => const _PageTwo(),
),
_ => MaterialPageRoute(
builder: (BuildContext context) => const _HomePage(),
),
};
},
);
}
}
class _HomePage extends StatefulWidget {
const _HomePage();
@override
State<_HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
FormData? _formData;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Page One'),
if (_formData != null)
Text('Hello ${_formData!.name}, whose favorite food is ${_formData!.favoriteFood}.'),
TextButton(
onPressed: () async {
final FormData formData =
await Navigator.of(context).pushNamed<FormData?>('/two')
?? const FormData();
if (formData != _formData) {
setState(() {
_formData = formData;
});
}
},
child: const Text('Next page'),
),
],
),
),
);
}
}
// This is a PopScope wrapper over _PageTwoBody
class _PageTwo extends StatelessWidget {
const _PageTwo();
Future<bool?> _showBackDialog(BuildContext context) {
return showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Are you sure?'),
content: const Text(
'Are you sure you want to leave this page?',
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Nevermind'),
onPressed: () {
Navigator.pop(context, false);
},
),
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Leave'),
onPressed: () {
Navigator.pop(context, true);
},
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return PopScope<FormData>(
canPop: false,
// We need result here because we don't know what `_PageTwoBody` pop the
// page with
onPopInvoked: (bool didPop, FormData? result) async {
if (didPop) {
return;
}
final bool shouldPop = await _showBackDialog(context) ?? false;
if (context.mounted && shouldPop) {
Navigator.pop(context, result);
}
},
child: const _PageTwoBody(),
);
}
}
class _PageTwoBody extends StatefulWidget {
const _PageTwoBody();
@override
State<_PageTwoBody> createState() => _PageTwoBodyState();
}
class _PageTwoBodyState extends State<_PageTwoBody> {
FormData _formData = const FormData();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Page Two'),
Form(
child: Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your name.',
),
onChanged: (String value) {
_formData = _formData.copyWith(
name: value,
);
},
),
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your favorite food.',
),
onChanged: (String value) {
_formData = _formData.copyWith(
favoriteFood: value,
);
},
),
],
),
),
// If this type is `Object?`, then it crashes because it doesn't
// match the type of the MaterialPageRoute.
TextButton(
onPressed: () async {
Navigator.maybePop(context, _formData);
},
child: const Text('Go back'),
),
],
),
),
);
}
}
class FormData {
const FormData({
this.name = '',
this.favoriteFood = '',
});
final String name;
final String favoriteFood;
FormData copyWith({String? name, String? favoriteFood}) {
return FormData(
name: name ?? this.name,
favoriteFood: favoriteFood ?? this.favoriteFood,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is FormData
&& other.name == name
&& other.favoriteFood == favoriteFood;
}
@override
int get hashCode => Object.hash(name, favoriteFood);
}The crash when you use |
There was a problem hiding this comment.
Nit: Too much whitespace here.
There was a problem hiding this comment.
Nit: Can you document what the T parameter means? Maybe something like this, based on MaterialPageRoute's docs:
The type parameter
Trepresents the return type of the route in which this widget appears. This result can be supplied as the route is popped from the stack with [Navigator.pop] by providing the optionalresultargument. It will be passed into [onPopInvoked] as theresultargument with the specified type.
|
some update, I am migrating internal code. |
|
A reason for requesting a revert of flutter/flutter/139164 could |
|
Reason for revert: hard breaking change |
This reverts commit 7ee05a0.
Reverts: #139164 Initiated by: chunhtai Reason for reverting: hard breaking change Original PR Author: chunhtai Reviewed By: {justinmc} This change reverts the following previous change: Adds a generic type and pop result to popscope and its friend. The use cases are to be able to capture the result when the pop is called. migration guide: flutter/website#9872
flutter/flutter@fb110b9...98685a0 2024-04-19 [email protected] Replace CocoaPods deprecated `exists?` with `exist?` (flutter/flutter#147056) 2024-04-19 [email protected] Roll Flutter Engine from 4ed7a2d6aed9 to 7fafbbf17c02 (2 revisions) (flutter/flutter#147046) 2024-04-19 [email protected] Roll Flutter Engine from 25d773ea90c4 to 4ed7a2d6aed9 (3 revisions) (flutter/flutter#147038) 2024-04-19 [email protected] Update link branches to `main` (continued) (flutter/flutter#146985) 2024-04-19 [email protected] Roll Flutter Engine from b6234dd1984e to 25d773ea90c4 (1 revision) (flutter/flutter#147035) 2024-04-19 [email protected] Roll Flutter Engine from ff471881e90a to b6234dd1984e (2 revisions) (flutter/flutter#147029) 2024-04-19 [email protected] Roll Flutter Engine from 442d14a7e840 to ff471881e90a (1 revision) (flutter/flutter#147025) 2024-04-19 [email protected] Roll Flutter Engine from 6e4a15d31769 to 442d14a7e840 (2 revisions) (flutter/flutter#147023) 2024-04-19 [email protected] Opt out users from GA3 if opted out of GA4 (flutter/flutter#146453) 2024-04-19 [email protected] Roll Flutter Engine from 61bf47d129bb to 6e4a15d31769 (1 revision) (flutter/flutter#147022) 2024-04-18 [email protected] Roll Flutter Engine from 13a6ce419664 to 61bf47d129bb (4 revisions) (flutter/flutter#147017) 2024-04-18 [email protected] Add a breadcrumb for the pub autoroller (flutter/flutter#146786) 2024-04-18 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Add generic type for result in PopScope (#139164)" (flutter/flutter#147015) 2024-04-18 [email protected] Redundant message fix (flutter/flutter#143978) 2024-04-18 [email protected] Clean up flutterRoot (flutter/flutter#147010) 2024-04-18 49699333+dependabot[bot]@users.noreply.github.com Bump actions/upload-artifact from 4.3.1 to 4.3.2 (flutter/flutter#147011) 2024-04-18 [email protected] Add Swift Package Manager as new opt-in feature for iOS and macOS (flutter/flutter#146256) 2024-04-18 [email protected] Refactor framework coverage tests (flutter/flutter#146210) 2024-04-18 [email protected] Roll Flutter Engine from 46ff024bff10 to 13a6ce419664 (3 revisions) (flutter/flutter#147006) 2024-04-18 [email protected] Changing the renderer on the web target should change its build key. (flutter/flutter#147003) 2024-04-18 [email protected] Roll Flutter Engine from 6abfa565a9f9 to 46ff024bff10 (1 revision) (flutter/flutter#147005) 2024-04-18 [email protected] Add generic type for result in PopScope (flutter/flutter#139164) 2024-04-18 [email protected] Roll Flutter Engine from aa6f7411c219 to 6abfa565a9f9 (1 revision) (flutter/flutter#147002) 2024-04-18 [email protected] [tools] Make SnapshotType.platform non-nullable (flutter/flutter#146958) 2024-04-18 [email protected] Roll Flutter Engine from b8e802515b5a to aa6f7411c219 (1 revision) (flutter/flutter#146996) 2024-04-18 [email protected] Roll Flutter Engine from 2c3e9c8bfce6 to b8e802515b5a (2 revisions) (flutter/flutter#146993) 2024-04-18 [email protected] Roll Packages from d39830e to 0e3809d (9 revisions) (flutter/flutter#146992) 2024-04-18 [email protected] Fix memory leaks in navigation rail (flutter/flutter#146988) 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 Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: 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
Adds a generic type and pop result to popscope and its friend. The use cases are to be able to capture the result when the pop is called. migration guide: flutter/website#9872
…lutter#147015) Reverts: flutter#139164 Initiated by: chunhtai Reason for reverting: hard breaking change Original PR Author: chunhtai Reviewed By: {justinmc} This change reverts the following previous change: Adds a generic type and pop result to popscope and its friend. The use cases are to be able to capture the result when the pop is called. migration guide: flutter/website#9872
)" (flutter#147015)" This reverts commit bb4c9b3.
waiting for flutter/flutter#139164 ## Presubmit checklist - [ ] This PR doesn’t contain automatically generated corrections (Grammarly or similar). - [ ] This PR follows the [Google Developer Documentation Style Guidelines](https://developers.google.com/style) — for example, it doesn’t use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first person). - [ ] This PR uses [semantic line breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks) of 80 characters or fewer. --------- Co-authored-by: Shams Zakhour (ignore Sfshaza) <[email protected]>
waiting for flutter/flutter#139164 ## Presubmit checklist - [ ] This PR doesn’t contain automatically generated corrections (Grammarly or similar). - [ ] This PR follows the [Google Developer Documentation Style Guidelines](https://developers.google.com/style) — for example, it doesn’t use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first person). - [ ] This PR uses [semantic line breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks) of 80 characters or fewer. --------- Co-authored-by: Shams Zakhour (ignore Sfshaza) <[email protected]>
flutter/flutter@fb110b9...98685a0 2024-04-19 [email protected] Replace CocoaPods deprecated `exists?` with `exist?` (flutter/flutter#147056) 2024-04-19 [email protected] Roll Flutter Engine from 4ed7a2d6aed9 to 7fafbbf17c02 (2 revisions) (flutter/flutter#147046) 2024-04-19 [email protected] Roll Flutter Engine from 25d773ea90c4 to 4ed7a2d6aed9 (3 revisions) (flutter/flutter#147038) 2024-04-19 [email protected] Update link branches to `main` (continued) (flutter/flutter#146985) 2024-04-19 [email protected] Roll Flutter Engine from b6234dd1984e to 25d773ea90c4 (1 revision) (flutter/flutter#147035) 2024-04-19 [email protected] Roll Flutter Engine from ff471881e90a to b6234dd1984e (2 revisions) (flutter/flutter#147029) 2024-04-19 [email protected] Roll Flutter Engine from 442d14a7e840 to ff471881e90a (1 revision) (flutter/flutter#147025) 2024-04-19 [email protected] Roll Flutter Engine from 6e4a15d31769 to 442d14a7e840 (2 revisions) (flutter/flutter#147023) 2024-04-19 [email protected] Opt out users from GA3 if opted out of GA4 (flutter/flutter#146453) 2024-04-19 [email protected] Roll Flutter Engine from 61bf47d129bb to 6e4a15d31769 (1 revision) (flutter/flutter#147022) 2024-04-18 [email protected] Roll Flutter Engine from 13a6ce419664 to 61bf47d129bb (4 revisions) (flutter/flutter#147017) 2024-04-18 [email protected] Add a breadcrumb for the pub autoroller (flutter/flutter#146786) 2024-04-18 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Add generic type for result in PopScope (#139164)" (flutter/flutter#147015) 2024-04-18 [email protected] Redundant message fix (flutter/flutter#143978) 2024-04-18 [email protected] Clean up flutterRoot (flutter/flutter#147010) 2024-04-18 49699333+dependabot[bot]@users.noreply.github.com Bump actions/upload-artifact from 4.3.1 to 4.3.2 (flutter/flutter#147011) 2024-04-18 [email protected] Add Swift Package Manager as new opt-in feature for iOS and macOS (flutter/flutter#146256) 2024-04-18 [email protected] Refactor framework coverage tests (flutter/flutter#146210) 2024-04-18 [email protected] Roll Flutter Engine from 46ff024bff10 to 13a6ce419664 (3 revisions) (flutter/flutter#147006) 2024-04-18 [email protected] Changing the renderer on the web target should change its build key. (flutter/flutter#147003) 2024-04-18 [email protected] Roll Flutter Engine from 6abfa565a9f9 to 46ff024bff10 (1 revision) (flutter/flutter#147005) 2024-04-18 [email protected] Add generic type for result in PopScope (flutter/flutter#139164) 2024-04-18 [email protected] Roll Flutter Engine from aa6f7411c219 to 6abfa565a9f9 (1 revision) (flutter/flutter#147002) 2024-04-18 [email protected] [tools] Make SnapshotType.platform non-nullable (flutter/flutter#146958) 2024-04-18 [email protected] Roll Flutter Engine from b8e802515b5a to aa6f7411c219 (1 revision) (flutter/flutter#146996) 2024-04-18 [email protected] Roll Flutter Engine from 2c3e9c8bfce6 to b8e802515b5a (2 revisions) (flutter/flutter#146993) 2024-04-18 [email protected] Roll Packages from d39830e to 0e3809d (9 revisions) (flutter/flutter#146992) 2024-04-18 [email protected] Fix memory leaks in navigation rail (flutter/flutter#146988) 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 Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: 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
Adds a generic type and pop result to popscope and its friend.
The use cases are to be able to capture the result when the pop is called.
migration guide: flutter/website#9872
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.