forked from flutter/packages
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reland root predictive back (#132249)
Root predictive back (flutter/flutter#120385) was reverted in flutter/flutter#132167. This PR is an attempt to reland it. The reversion happened due to failed Google tests (b/295073110).
- Loading branch information
Showing
36 changed files
with
3,224 additions
and
297 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// 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. | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:flutter/services.dart'; | ||
|
||
/// This sample demonstrates showing a confirmation dialog when the user | ||
/// attempts to navigate away from a page with unsaved [Form] data. | ||
void main() => runApp(const FormApp()); | ||
|
||
class FormApp extends StatelessWidget { | ||
const FormApp({ | ||
super.key, | ||
}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return MaterialApp( | ||
home: Scaffold( | ||
appBar: AppBar( | ||
title: const Text('Confirmation Dialog Example'), | ||
), | ||
body: Center( | ||
child: _SaveableForm(), | ||
), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class _SaveableForm extends StatefulWidget { | ||
@override | ||
State<_SaveableForm> createState() => _SaveableFormState(); | ||
} | ||
|
||
class _SaveableFormState extends State<_SaveableForm> { | ||
final TextEditingController _controller = TextEditingController(); | ||
String _savedValue = ''; | ||
bool _isDirty = false; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_controller.addListener(_onChanged); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_controller.removeListener(_onChanged); | ||
super.dispose(); | ||
} | ||
|
||
void _onChanged() { | ||
final bool nextIsDirty = _savedValue != _controller.text; | ||
if (nextIsDirty == _isDirty) { | ||
return; | ||
} | ||
setState(() { | ||
_isDirty = nextIsDirty; | ||
}); | ||
} | ||
|
||
Future<void> _showDialog() async { | ||
final bool? shouldDiscard = await showDialog<bool>( | ||
context: context, | ||
builder: (BuildContext context) { | ||
return AlertDialog( | ||
title: const Text('Are you sure?'), | ||
content: const Text('Any unsaved changes will be lost!'), | ||
actions: <Widget>[ | ||
TextButton( | ||
child: const Text('Yes, discard my changes'), | ||
onPressed: () { | ||
Navigator.pop(context, true); | ||
}, | ||
), | ||
TextButton( | ||
child: const Text('No, continue editing'), | ||
onPressed: () { | ||
Navigator.pop(context, false); | ||
}, | ||
), | ||
], | ||
); | ||
}, | ||
); | ||
|
||
if (shouldDiscard ?? false) { | ||
// Since this is the root route, quit the app where possible by invoking | ||
// the SystemNavigator. If this wasn't the root route, then | ||
// Navigator.maybePop could be used instead. | ||
// See https://github.com/flutter/flutter/issues/11490 | ||
SystemNavigator.pop(); | ||
} | ||
} | ||
|
||
void _save(String? value) { | ||
setState(() { | ||
_savedValue = value ?? ''; | ||
}); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Center( | ||
child: Column( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
children: <Widget>[ | ||
const Text('If the field below is unsaved, a confirmation dialog will be shown on back.'), | ||
const SizedBox(height: 20.0), | ||
Form( | ||
canPop: !_isDirty, | ||
onPopInvoked: (bool didPop) { | ||
if (didPop) { | ||
return; | ||
} | ||
_showDialog(); | ||
}, | ||
autovalidateMode: AutovalidateMode.always, | ||
child: Column( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
children: <Widget>[ | ||
TextFormField( | ||
controller: _controller, | ||
onFieldSubmitted: (String? value) { | ||
_save(value); | ||
}, | ||
), | ||
TextButton( | ||
onPressed: () { | ||
_save(_controller.text); | ||
}, | ||
child: Row( | ||
children: <Widget>[ | ||
const Text('Save'), | ||
if (_controller.text.isNotEmpty) | ||
Icon( | ||
_isDirty ? Icons.warning : Icons.check, | ||
), | ||
], | ||
), | ||
), | ||
], | ||
), | ||
), | ||
TextButton( | ||
onPressed: () { | ||
if (_isDirty) { | ||
_showDialog(); | ||
return; | ||
} | ||
// Since this is the root route, quit the app where possible by | ||
// invoking the SystemNavigator. If this wasn't the root route, | ||
// then Navigator.maybePop could be used instead. | ||
// See https://github.com/flutter/flutter/issues/11490 | ||
SystemNavigator.pop(); | ||
}, | ||
child: const Text('Go back'), | ||
), | ||
], | ||
), | ||
); | ||
} | ||
} |
Oops, something went wrong.