Unverified Commit 4fa5fe5f authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Remove nullOk from Scaffold.of and ScaffoldMessenger.of, create maybeOf for both (#68908)

parent e5f7726c
...@@ -487,11 +487,11 @@ class _AppBarState extends State<AppBar> { ...@@ -487,11 +487,11 @@ class _AppBarState extends State<AppBar> {
static const Color _defaultShadowColor = Color(0xFF000000); static const Color _defaultShadowColor = Color(0xFF000000);
void _handleDrawerButton() { void _handleDrawerButton() {
Scaffold.of(context)!.openDrawer(); Scaffold.of(context).openDrawer();
} }
void _handleDrawerButtonEnd() { void _handleDrawerButtonEnd() {
Scaffold.of(context)!.openEndDrawer(); Scaffold.of(context).openEndDrawer();
} }
@override @override
...@@ -500,7 +500,7 @@ class _AppBarState extends State<AppBar> { ...@@ -500,7 +500,7 @@ class _AppBarState extends State<AppBar> {
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
final ThemeData? theme = Theme.of(context); final ThemeData? theme = Theme.of(context);
final AppBarTheme appBarTheme = AppBarTheme.of(context); final AppBarTheme appBarTheme = AppBarTheme.of(context);
final ScaffoldState? scaffold = Scaffold.of(context, nullOk: true); final ScaffoldState? scaffold = Scaffold.maybeOf(context);
final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context); final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context);
final bool hasDrawer = scaffold?.hasDrawer ?? false; final bool hasDrawer = scaffold?.hasDrawer ?? false;
......
...@@ -737,7 +737,7 @@ PersistentBottomSheetController<T> showBottomSheet<T>({ ...@@ -737,7 +737,7 @@ PersistentBottomSheetController<T> showBottomSheet<T>({
assert(builder != null); assert(builder != null);
assert(debugCheckHasScaffold(context)); assert(debugCheckHasScaffold(context));
return Scaffold.of(context)!.showBottomSheet<T>( return Scaffold.of(context).showBottomSheet<T>(
builder, builder,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
elevation: elevation, elevation: elevation,
......
...@@ -204,16 +204,34 @@ class ScaffoldMessenger extends StatefulWidget { ...@@ -204,16 +204,34 @@ class ScaffoldMessenger extends StatefulWidget {
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
/// ///
/// If there is no [ScaffoldMessenger] in scope, then this will return null. /// If there is no [ScaffoldMessenger] in scope, then this will assert in
/// debug mode, and throw an exception in release mode.
///
/// See also: /// See also:
/// ///
/// * [maybeOf], which is a similar function but will return null instead of
/// throwing if there is no [ScaffoldMessenger] ancestor.
/// * [debugCheckHasScaffoldMessenger], which asserts that the given context /// * [debugCheckHasScaffoldMessenger], which asserts that the given context
/// has a [ScaffoldMessenger] ancestor. /// has a [ScaffoldMessenger] ancestor.
static ScaffoldMessengerState? of(BuildContext context, { bool nullOk = false }) { static ScaffoldMessengerState of(BuildContext context) {
assert(nullOk != null);
assert(context != null); assert(context != null);
assert(debugCheckHasScaffoldMessenger(context));
final _ScaffoldMessengerScope scope = context.dependOnInheritedWidgetOfExactType<_ScaffoldMessengerScope>()!;
return scope._scaffoldMessengerState;
}
assert(nullOk || debugCheckHasScaffoldMessenger(context)); /// The state from the closest instance of this class that encloses the given
/// context, if any.
///
/// Will return null if a [ScaffoldMessenger] is not found in the given context.
///
/// See also:
///
/// * [of], which is a similar function, except that it will throw an
/// exception if a [ScaffoldMessenger] is not found in the given context.
static ScaffoldMessengerState? maybeOf(BuildContext context) {
assert(context != null);
final _ScaffoldMessengerScope? scope = context.dependOnInheritedWidgetOfExactType<_ScaffoldMessengerScope>(); final _ScaffoldMessengerScope? scope = context.dependOnInheritedWidgetOfExactType<_ScaffoldMessengerScope>();
return scope?._scaffoldMessengerState; return scope?._scaffoldMessengerState;
...@@ -1755,7 +1773,11 @@ class Scaffold extends StatefulWidget { ...@@ -1755,7 +1773,11 @@ class Scaffold extends StatefulWidget {
/// By default, the drag gesture is enabled. /// By default, the drag gesture is enabled.
final bool endDrawerEnableOpenDragGesture; final bool endDrawerEnableOpenDragGesture;
/// The state from the closest instance of this class that encloses the given context. /// Finds the [ScaffoldState] from the closest instance of this class that
/// encloses the given context.
///
/// If no instance of this class encloses the given context, will cause an
/// assert in debug mode, and throw an exception in release mode.
/// ///
/// {@tool dartpad --template=freeform} /// {@tool dartpad --template=freeform}
/// Typical usage of the [Scaffold.of] function is to call it from within the /// Typical usage of the [Scaffold.of] function is to call it from within the
...@@ -1892,12 +1914,11 @@ class Scaffold extends StatefulWidget { ...@@ -1892,12 +1914,11 @@ class Scaffold extends StatefulWidget {
/// [ScaffoldState] rather than using the [Scaffold.of] function. /// [ScaffoldState] rather than using the [Scaffold.of] function.
/// ///
/// If there is no [Scaffold] in scope, then this will throw an exception. /// If there is no [Scaffold] in scope, then this will throw an exception.
/// To return null if there is no [Scaffold], then pass `nullOk: true`. /// To return null if there is no [Scaffold], use [maybeOf] instead.
static ScaffoldState? of(BuildContext context, { bool nullOk = false }) { static ScaffoldState of(BuildContext context) {
assert(nullOk != null);
assert(context != null); assert(context != null);
final ScaffoldState? result = context.findAncestorStateOfType<ScaffoldState>(); final ScaffoldState? result = context.findAncestorStateOfType<ScaffoldState>();
if (nullOk || result != null) if (result != null)
return result; return result;
throw FlutterError.fromParts(<DiagnosticsNode>[ throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary( ErrorSummary(
...@@ -1927,6 +1948,22 @@ class Scaffold extends StatefulWidget { ...@@ -1927,6 +1948,22 @@ class Scaffold extends StatefulWidget {
]); ]);
} }
/// Finds the [ScaffoldState] from the closest instance of this class that
/// encloses the given context.
///
/// If no instance of this class encloses the given context, will return null.
/// To throw an exception instead, use [of] instead of this function.
///
/// See also:
///
/// * [of], a similar function to this one that throws if no instance
/// encloses the given context. Also includes some sample code in its
/// documentation.
static ScaffoldState? maybeOf(BuildContext context) {
assert(context != null);
return context.findAncestorStateOfType<ScaffoldState>();
}
/// Returns a [ValueListenable] for the [ScaffoldGeometry] for the closest /// Returns a [ValueListenable] for the [ScaffoldGeometry] for the closest
/// [Scaffold] ancestor of the given context. /// [Scaffold] ancestor of the given context.
/// ///
...@@ -2714,7 +2751,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin { ...@@ -2714,7 +2751,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
void didChangeDependencies() { void didChangeDependencies() {
// nullOk is valid here since both the Scaffold and ScaffoldMessenger are // nullOk is valid here since both the Scaffold and ScaffoldMessenger are
// currently available for managing SnackBars. // currently available for managing SnackBars.
final ScaffoldMessengerState? _currentScaffoldMessenger = ScaffoldMessenger.of(context, nullOk: true); final ScaffoldMessengerState? _currentScaffoldMessenger = ScaffoldMessenger.maybeOf(context);
// If our ScaffoldMessenger has changed, unregister with the old one first. // If our ScaffoldMessenger has changed, unregister with the old one first.
if (_scaffoldMessenger != null && if (_scaffoldMessenger != null &&
(_currentScaffoldMessenger == null || _scaffoldMessenger != _currentScaffoldMessenger)) { (_currentScaffoldMessenger == null || _scaffoldMessenger != _currentScaffoldMessenger)) {
...@@ -3304,7 +3341,7 @@ class _StandardBottomSheetState extends State<_StandardBottomSheet> { ...@@ -3304,7 +3341,7 @@ class _StandardBottomSheetState extends State<_StandardBottomSheet> {
bool extentChanged(DraggableScrollableNotification notification) { bool extentChanged(DraggableScrollableNotification notification) {
final double extentRemaining = 1.0 - notification.extent; final double extentRemaining = 1.0 - notification.extent;
final ScaffoldState scaffold = Scaffold.of(context)!; final ScaffoldState scaffold = Scaffold.of(context);
if (extentRemaining < _kBottomSheetDominatesPercentage) { if (extentRemaining < _kBottomSheetDominatesPercentage) {
scaffold._floatingActionButtonVisibilityValue = extentRemaining * _kBottomSheetDominatesPercentage * 10; scaffold._floatingActionButtonVisibilityValue = extentRemaining * _kBottomSheetDominatesPercentage * 10;
scaffold.showBodyScrim(true, math.max( scaffold.showBodyScrim(true, math.max(
......
...@@ -123,7 +123,7 @@ class _SnackBarActionState extends State<SnackBarAction> { ...@@ -123,7 +123,7 @@ class _SnackBarActionState extends State<SnackBarAction> {
_haveTriggeredAction = true; _haveTriggeredAction = true;
}); });
widget.onPressed(); widget.onPressed();
Scaffold.of(context)!.hideCurrentSnackBar(reason: SnackBarClosedReason.action); Scaffold.of(context).hideCurrentSnackBar(reason: SnackBarClosedReason.action);
} }
@override @override
...@@ -529,14 +529,14 @@ class _SnackBarState extends State<SnackBar> { ...@@ -529,14 +529,14 @@ class _SnackBarState extends State<SnackBar> {
container: true, container: true,
liveRegion: true, liveRegion: true,
onDismiss: () { onDismiss: () {
Scaffold.of(context)!.removeCurrentSnackBar(reason: SnackBarClosedReason.dismiss); Scaffold.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.dismiss);
}, },
child: Dismissible( child: Dismissible(
key: const Key('dismissible'), key: const Key('dismissible'),
direction: DismissDirection.down, direction: DismissDirection.down,
resizeDuration: null, resizeDuration: null,
onDismissed: (DismissDirection direction) { onDismissed: (DismissDirection direction) {
Scaffold.of(context)!.removeCurrentSnackBar(reason: SnackBarClosedReason.swipe); Scaffold.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.swipe);
}, },
child: snackBar, child: snackBar,
), ),
......
...@@ -647,7 +647,7 @@ void main() { ...@@ -647,7 +647,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return FloatingActionButton( return FloatingActionButton(
onPressed: () { onPressed: () {
ScaffoldMessenger.of(context)!.showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Snacky!')), const SnackBar(content: Text('Snacky!')),
); );
}, },
......
...@@ -355,7 +355,7 @@ void main() { ...@@ -355,7 +355,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Scaffold.of(context)!.showBottomSheet<void>((BuildContext context) { Scaffold.of(context).showBottomSheet<void>((BuildContext context) {
return Container( return Container(
key: sheetKey, key: sheetKey,
color: Colors.blue[500], color: Colors.blue[500],
...@@ -1900,7 +1900,7 @@ void main() { ...@@ -1900,7 +1900,7 @@ void main() {
MaterialApp( MaterialApp(
home: Builder( home: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
Scaffold.of(context)!.showBottomSheet<void>((BuildContext context) { Scaffold.of(context).showBottomSheet<void>((BuildContext context) {
return Container(); return Container();
}); });
return Container(); return Container();
...@@ -2033,7 +2033,7 @@ void main() { ...@@ -2033,7 +2033,7 @@ void main() {
}); });
}); });
testWidgets('ScaffoldMessenger.of can return null', (WidgetTester tester) async { testWidgets('ScaffoldMessenger.maybeOf can return null if not found', (WidgetTester tester) async {
ScaffoldMessengerState? scaffoldMessenger; ScaffoldMessengerState? scaffoldMessenger;
const Key tapTarget = Key('tap-target'); const Key tapTarget = Key('tap-target');
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
...@@ -2045,7 +2045,7 @@ void main() { ...@@ -2045,7 +2045,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
scaffoldMessenger = ScaffoldMessenger.of(context, nullOk: true); scaffoldMessenger = ScaffoldMessenger.maybeOf(context);
}, },
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: Container( child: Container(
...@@ -2064,7 +2064,7 @@ void main() { ...@@ -2064,7 +2064,7 @@ void main() {
expect(scaffoldMessenger, isNull); expect(scaffoldMessenger, isNull);
}); });
testWidgets('ScaffoldMessenger.of will assert if !nullOk', (WidgetTester tester) async { testWidgets('ScaffoldMessenger.of will assert if not found', (WidgetTester tester) async {
const Key tapTarget = Key('tap-target'); const Key tapTarget = Key('tap-target');
final List<dynamic> exceptions = <dynamic>[]; final List<dynamic> exceptions = <dynamic>[];
......
...@@ -71,7 +71,7 @@ void main() { ...@@ -71,7 +71,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
ScaffoldMessenger.of(context)!.showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text(text), content: const Text(text),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
action: SnackBarAction(label: 'ACTION', onPressed: () {}), action: SnackBarAction(label: 'ACTION', onPressed: () {}),
...@@ -109,7 +109,7 @@ void main() { ...@@ -109,7 +109,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
ScaffoldMessenger.of(context)!.showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text(text), content: const Text(text),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
action: SnackBarAction(label: action, onPressed: () {}), action: SnackBarAction(label: action, onPressed: () {}),
...@@ -153,7 +153,7 @@ void main() { ...@@ -153,7 +153,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
ScaffoldMessenger.of(context)!.showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
elevation: elevation, elevation: elevation,
shape: shape, shape: shape,
...@@ -200,7 +200,7 @@ void main() { ...@@ -200,7 +200,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
ScaffoldMessenger.of(context)!.showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text('I am a snack bar.'), content: const Text('I am a snack bar.'),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
action: SnackBarAction(label: 'ACTION', onPressed: () {}), action: SnackBarAction(label: 'ACTION', onPressed: () {}),
...@@ -242,7 +242,7 @@ void main() { ...@@ -242,7 +242,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
ScaffoldMessenger.of(context)!.showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text('I am a snack bar.'), content: const Text('I am a snack bar.'),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
action: SnackBarAction(label: 'ACTION', onPressed: () {}), action: SnackBarAction(label: 'ACTION', onPressed: () {}),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment