From e7db3873f079ab9c8663d5e976247d451790dcf8 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Sat, 9 May 2020 19:21:39 +0530 Subject: [PATCH 01/12] Added support for returning value from popped route --- .../animations/lib/src/open_container.dart | 30 ++++++++----- .../animations/test/open_container_test.dart | 44 +++++++++---------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index 12b06d7e922f..37ac311a5c31 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -51,11 +51,13 @@ enum ContainerTransitionType { /// /// * [Transitions with animated containers](https://material.io/design/motion/choreography.html#transformation) /// in the Material spec. -class OpenContainer extends StatefulWidget { +class OpenContainer extends StatefulWidget { /// Creates an [OpenContainer]. /// /// All arguments except for [key] must not be null. The arguments - /// [closedBuilder] and [closedBuilder] are required. + /// [openBuilder] and [closedBuilder] are required. + /// `T` refers to the type of data returned by the route, + /// which can be accessed in the `onClosed` function. const OpenContainer({ Key key, this.closedColor = Colors.white, @@ -167,7 +169,15 @@ class OpenContainer extends StatefulWidget { final ShapeBorder openShape; /// Called when the container was popped and has returned to the closed state. - final VoidCallback onClosed; + /// The return value from the popped screen is passed to this function as an + /// argument. + /// + /// ``` + /// onClosed: (DataType data) { + /// ... + /// } + /// ``` + final Function(T) onClosed; /// Called to obtain the child for the container in the closed state. /// @@ -218,10 +228,10 @@ class OpenContainer extends StatefulWidget { final bool useRootNavigator; @override - _OpenContainerState createState() => _OpenContainerState(); + _OpenContainerState createState() => _OpenContainerState(); } -class _OpenContainerState extends State { +class _OpenContainerState extends State> { // Key used in [_OpenContainerRoute] to hide the widget returned by // [OpenContainer.openBuilder] in the source route while the container is // opening/open. A copy of that widget is included in the @@ -235,8 +245,8 @@ class _OpenContainerState extends State { final GlobalKey _closedBuilderKey = GlobalKey(); Future openContainer() async { - await Navigator.of(context, rootNavigator: widget.useRootNavigator) - .push(_OpenContainerRoute( + final T data = await Navigator.of(context, rootNavigator: widget.useRootNavigator) + .push(_OpenContainerRoute( closedColor: widget.closedColor, openColor: widget.openColor, closedElevation: widget.closedElevation, @@ -251,7 +261,7 @@ class _OpenContainerState extends State { transitionType: widget.transitionType, )); if (widget.onClosed != null) { - widget.onClosed(); + widget.onClosed(data); } } @@ -347,7 +357,7 @@ class _HideableState extends State<_Hideable> { } } -class _OpenContainerRoute extends ModalRoute { +class _OpenContainerRoute extends ModalRoute { _OpenContainerRoute({ @required this.closedColor, @required this.openColor, @@ -580,7 +590,7 @@ class _OpenContainerRoute extends ModalRoute { } @override - bool didPop(void result) { + bool didPop(T result) { _takeMeasurements( navigatorContext: subtreeContext, delayForSourceRoute: true, diff --git a/packages/animations/test/open_container_test.dart b/packages/animations/test/open_container_test.dart index bd0fb3975ebb..b9eb41e16a55 100644 --- a/packages/animations/test/open_container_test.dart +++ b/packages/animations/test/open_container_test.dart @@ -19,7 +19,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -192,7 +192,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -361,7 +361,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -535,7 +535,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -708,7 +708,7 @@ void main() { (WidgetTester tester) async { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( tappable: false, closedBuilder: (BuildContext context, VoidCallback _) { return const Text('Closed'); @@ -732,7 +732,7 @@ void main() { VoidCallback open, close; await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( tappable: false, closedBuilder: (BuildContext context, VoidCallback action) { open = action; @@ -767,7 +767,7 @@ void main() { testWidgets('open widget keeps state', (WidgetTester tester) async { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -806,7 +806,7 @@ void main() { VoidCallback open; await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { open = action; return Switch( @@ -855,7 +855,7 @@ void main() { testWidgets('closes to the right location when src position has changed', (WidgetTester tester) async { - final Widget openContainer = OpenContainer( + final Widget openContainer = OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return Container( height: 100, @@ -917,7 +917,7 @@ void main() { testWidgets('src changes size while open', (WidgetTester tester) async { final Widget openContainer = _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const _SizableContainer( initialSize: 100, @@ -989,7 +989,7 @@ void main() { (WidgetTester tester) async { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -1040,7 +1040,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -1098,7 +1098,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -1130,7 +1130,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( transitionDuration: const Duration(seconds: 2), closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); @@ -1178,7 +1178,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedShape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), @@ -1251,7 +1251,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -1319,7 +1319,7 @@ void main() { cacheExtent: 0, controller: controller, itemBuilder: (BuildContext context, int index) { - return OpenContainer( + return OpenContainer( closedBuilder: (BuildContext context, VoidCallback _) { return SizedBox( height: 100, @@ -1392,7 +1392,7 @@ void main() { cacheExtent: 0, controller: controller, itemBuilder: (BuildContext context, int index) { - return OpenContainer( + return OpenContainer( closedBuilder: (BuildContext context, VoidCallback _) { return SizedBox( height: 100, @@ -1485,8 +1485,8 @@ void main() { testWidgets('onClosed callback is called when container has closed', (WidgetTester tester) async { bool hasClosed = false; - final Widget openContainer = OpenContainer( - onClosed: () { + final Widget openContainer = OpenContainer( + onClosed: (dynamic _) { hasClosed = true; }, closedBuilder: (BuildContext context, VoidCallback action) { @@ -1540,7 +1540,7 @@ void main() { settings: route, builder: (BuildContext context) { return Container( - child: OpenContainer( + child: OpenContainer( useRootNavigator: useRootNavigator, closedBuilder: (BuildContext context, _) { return const Text('Closed'); @@ -1709,7 +1709,7 @@ class __RemoveOpenContainerExampleState Widget build(BuildContext context) { return removeOpenContainerWidget ? const Text('Container has been removed') - : OpenContainer( + : OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) => Column( children: [ From b999469b47dd017eaea2dcc4d892bcca15f2f089 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Sat, 9 May 2020 19:23:36 +0530 Subject: [PATCH 02/12] Example for `onClosed` added --- .../example/lib/container_transition.dart | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/animations/example/lib/container_transition.dart b/packages/animations/example/lib/container_transition.dart index 867ace0958b2..57e4a6d1b4a7 100644 --- a/packages/animations/example/lib/container_transition.dart +++ b/packages/animations/example/lib/container_transition.dart @@ -102,7 +102,10 @@ class _OpenContainerTransformDemoState @override Widget build(BuildContext context) { + final GlobalKey scaffoldKey = GlobalKey(); + return Scaffold( + key: scaffoldKey, appBar: AppBar( title: const Text('Container transform'), actions: [ @@ -200,10 +203,17 @@ class _OpenContainerTransformDemoState ), const SizedBox(height: 16.0), ...List.generate(10, (int index) { - return OpenContainer( + return OpenContainer( transitionType: _transitionType, openBuilder: (BuildContext _, VoidCallback openContainer) { - return _DetailsPage(); + return const _DetailsPage(includeMarkAsDoneBtn: true); + }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) { + scaffoldKey.currentState.showSnackBar( + const SnackBar(content: Text('Marked as done!')) + ); + } }, tappable: false, closedShape: const RoundedRectangleBorder(), @@ -223,10 +233,10 @@ class _OpenContainerTransformDemoState }), ], ), - floatingActionButton: OpenContainer( + floatingActionButton: OpenContainer( transitionType: _transitionType, openBuilder: (BuildContext context, VoidCallback _) { - return _DetailsPage(); + return const _DetailsPage(); }, closedElevation: 6.0, closedShape: const RoundedRectangleBorder( @@ -263,10 +273,10 @@ class _OpenContainerWrapper extends StatelessWidget { @override Widget build(BuildContext context) { - return OpenContainer( + return OpenContainer( transitionType: transitionType, openBuilder: (BuildContext context, VoidCallback _) { - return _DetailsPage(); + return const _DetailsPage(); }, tappable: false, closedBuilder: closedBuilder, @@ -453,10 +463,26 @@ class _InkWellOverlay extends StatelessWidget { } class _DetailsPage extends StatelessWidget { + const _DetailsPage({ + this.includeMarkAsDoneBtn = false + }); + + final bool includeMarkAsDoneBtn; + @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Details page')), + appBar: AppBar( + title: const Text('Details page'), + actions: [ + includeMarkAsDoneBtn ? + IconButton( + icon: const Icon(Icons.done), + onPressed: () => Navigator.pop(context, true), + tooltip: 'Mark as done', + ) : Container() + ], + ), body: ListView( children: [ Container( From b30c0946299f0b06e302f7fca8dbee69bb5112d8 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Sat, 9 May 2020 20:56:05 +0530 Subject: [PATCH 03/12] Formatted dart files --- .../example/lib/container_transition.dart | 22 +++++++++---------- .../animations/lib/src/open_container.dart | 7 +++--- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/animations/example/lib/container_transition.dart b/packages/animations/example/lib/container_transition.dart index 57e4a6d1b4a7..b83278af0f4f 100644 --- a/packages/animations/example/lib/container_transition.dart +++ b/packages/animations/example/lib/container_transition.dart @@ -103,7 +103,7 @@ class _OpenContainerTransformDemoState @override Widget build(BuildContext context) { final GlobalKey scaffoldKey = GlobalKey(); - + return Scaffold( key: scaffoldKey, appBar: AppBar( @@ -211,8 +211,7 @@ class _OpenContainerTransformDemoState onClosed: (bool isMarkedAsDone) { if (isMarkedAsDone) { scaffoldKey.currentState.showSnackBar( - const SnackBar(content: Text('Marked as done!')) - ); + const SnackBar(content: Text('Marked as done!'))); } }, tappable: false, @@ -463,9 +462,7 @@ class _InkWellOverlay extends StatelessWidget { } class _DetailsPage extends StatelessWidget { - const _DetailsPage({ - this.includeMarkAsDoneBtn = false - }); + const _DetailsPage({this.includeMarkAsDoneBtn = false}); final bool includeMarkAsDoneBtn; @@ -475,12 +472,13 @@ class _DetailsPage extends StatelessWidget { appBar: AppBar( title: const Text('Details page'), actions: [ - includeMarkAsDoneBtn ? - IconButton( - icon: const Icon(Icons.done), - onPressed: () => Navigator.pop(context, true), - tooltip: 'Mark as done', - ) : Container() + includeMarkAsDoneBtn + ? IconButton( + icon: const Icon(Icons.done), + onPressed: () => Navigator.pop(context, true), + tooltip: 'Mark as done', + ) + : Container() ], ), body: ListView( diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index 37ac311a5c31..342b1a8ac941 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -171,7 +171,7 @@ class OpenContainer extends StatefulWidget { /// Called when the container was popped and has returned to the closed state. /// The return value from the popped screen is passed to this function as an /// argument. - /// + /// /// ``` /// onClosed: (DataType data) { /// ... @@ -245,8 +245,9 @@ class _OpenContainerState extends State> { final GlobalKey _closedBuilderKey = GlobalKey(); Future openContainer() async { - final T data = await Navigator.of(context, rootNavigator: widget.useRootNavigator) - .push(_OpenContainerRoute( + final T data = + await Navigator.of(context, rootNavigator: widget.useRootNavigator) + .push(_OpenContainerRoute( closedColor: widget.closedColor, openColor: widget.openColor, closedElevation: widget.closedElevation, From e8cb98f68930fc717d00b237570c79f104caf479 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Sat, 16 May 2020 13:16:14 +0530 Subject: [PATCH 04/12] Updated `open_container.dart` - typedef for `onClosed` callback - Fixed documentation - Added `@optionalTypeArgs` --- .../animations/lib/src/open_container.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index 342b1a8ac941..608640d1acaf 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -29,6 +29,10 @@ enum ContainerTransitionType { fadeThrough, } +/// Callback function which is called when the [OpenContainer] +/// is closed. +typedef onClosedCallback = void Function(S data); + /// A container that grows to fill the screen to reveal new content when tapped. /// /// While the container is closed, it shows the [Widget] returned by @@ -44,6 +48,9 @@ enum ContainerTransitionType { /// closed to open and vice versa the widgets returned by the [openBuilder] and /// [closedBuilder] exist in the tree at the same time. Therefore, the widgets /// returned by these builders cannot include the same global key. +/// +/// `T` refers to the type of data returned by the route when the container +/// is closed. This value can be accessed in the `onClosed` function. /// // TODO(goderbauer): Add example animations and sample code. /// @@ -51,13 +58,12 @@ enum ContainerTransitionType { /// /// * [Transitions with animated containers](https://material.io/design/motion/choreography.html#transformation) /// in the Material spec. +@optionalTypeArgs class OpenContainer extends StatefulWidget { /// Creates an [OpenContainer]. /// /// All arguments except for [key] must not be null. The arguments /// [openBuilder] and [closedBuilder] are required. - /// `T` refers to the type of data returned by the route, - /// which can be accessed in the `onClosed` function. const OpenContainer({ Key key, this.closedColor = Colors.white, @@ -171,13 +177,7 @@ class OpenContainer extends StatefulWidget { /// Called when the container was popped and has returned to the closed state. /// The return value from the popped screen is passed to this function as an /// argument. - /// - /// ``` - /// onClosed: (DataType data) { - /// ... - /// } - /// ``` - final Function(T) onClosed; + final onClosedCallback onClosed; /// Called to obtain the child for the container in the closed state. /// From e5f7686f25293a62c300924d35f404cb3881089a Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Sat, 16 May 2020 13:20:36 +0530 Subject: [PATCH 05/12] Added test for `onClosed` with popped route value --- .../animations/test/open_container_test.dart | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/animations/test/open_container_test.dart b/packages/animations/test/open_container_test.dart index b9eb41e16a55..9ea8196921db 100644 --- a/packages/animations/test/open_container_test.dart +++ b/packages/animations/test/open_container_test.dart @@ -1525,6 +1525,50 @@ void main() { expect(hasClosed, isTrue); }); + testWidgets( + 'onClosed callback receives popped value when container has closed', + (WidgetTester tester) async { + bool value = false; + final Widget openContainer = OpenContainer( + onClosed: (bool poppedValue) { + value = poppedValue; + }, + closedBuilder: (BuildContext context, VoidCallback action) { + return GestureDetector( + onTap: action, + child: const Text('Closed'), + ); + }, + openBuilder: (BuildContext context, VoidCallback action) { + return GestureDetector( + onTap: () => Navigator.pop(context, true), + child: const Text('Open'), + ); + }, + ); + + await tester.pumpWidget( + _boilerplate(child: openContainer), + ); + + expect(find.text('Open'), findsNothing); + expect(find.text('Closed'), findsOneWidget); + expect(value, isFalse); + + await tester.tap(find.text('Closed')); + await tester.pumpAndSettle(); + + expect(find.text('Open'), findsOneWidget); + expect(find.text('Closed'), findsNothing); + + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + + expect(find.text('Open'), findsNothing); + expect(find.text('Closed'), findsOneWidget); + expect(value, isTrue); + }); + Widget _createRootNavigatorTest({ @required Key appKey, @required Key nestedNavigatorKey, From 7a04bbf6425baaf889a00a44abfd087b6028bd25 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Sat, 16 May 2020 13:40:39 +0530 Subject: [PATCH 06/12] Updated `container_transition.dart` - Moved `GlobalKey` from build method - Added `onClosed` parameter in `_OpenContainerWrapper` - Display number of times "Marked as done" was pressed - Removed `includeMarkAsDoneBtn` from `_DetailsPage` - Fixed formatting --- .../example/lib/container_transition.dart | 125 +++++++++++++++--- 1 file changed, 105 insertions(+), 20 deletions(-) diff --git a/packages/animations/example/lib/container_transition.dart b/packages/animations/example/lib/container_transition.dart index b83278af0f4f..2cc894322b54 100644 --- a/packages/animations/example/lib/container_transition.dart +++ b/packages/animations/example/lib/container_transition.dart @@ -49,6 +49,10 @@ class OpenContainerTransformDemo extends StatefulWidget { class _OpenContainerTransformDemoState extends State { ContainerTransitionType _transitionType = ContainerTransitionType.fade; + final GlobalKey scaffoldKey = GlobalKey(); + + static int doneCounter = 0; + final ValueKey counterKey = ValueKey(doneCounter); void _showSettingsBottomModalSheet(BuildContext context) { showModalBottomSheet( @@ -102,8 +106,6 @@ class _OpenContainerTransformDemoState @override Widget build(BuildContext context) { - final GlobalKey scaffoldKey = GlobalKey(); - return Scaffold( key: scaffoldKey, appBar: AppBar( @@ -120,11 +122,50 @@ class _OpenContainerTransformDemoState body: ListView( padding: const EdgeInsets.all(8.0), children: [ + Container( + key: counterKey, + padding: const EdgeInsets.symmetric( + vertical: 15.0, + horizontal: 10.0, + ), + margin: const EdgeInsets.only(bottom: 10.0), + decoration: BoxDecoration( + color: Colors.purple[100], + borderRadius: BorderRadius.circular(5.0), + ), + child: Row( + children: [ + const Padding( + padding: EdgeInsets.only(right: 10.0), + child: Icon(Icons.done), + ), + RichText( + text: TextSpan( + style: const TextStyle(fontSize: 18.0, color: Colors.black), + children: [ + const TextSpan(text: 'Marked as done '), + TextSpan( + text: '$doneCounter', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + const TextSpan(text: ' times'), + ], + ), + ), + ], + ), + ), _OpenContainerWrapper( transitionType: _transitionType, closedBuilder: (BuildContext _, VoidCallback openContainer) { return _ExampleCard(openContainer: openContainer); }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, ), const SizedBox(height: 16.0), _OpenContainerWrapper( @@ -132,6 +173,12 @@ class _OpenContainerTransformDemoState closedBuilder: (BuildContext _, VoidCallback openContainer) { return _ExampleSingleTile(openContainer: openContainer); }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, ), const SizedBox(height: 16.0), Row( @@ -145,6 +192,12 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary text', ); }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, ), ), const SizedBox(width: 8.0), @@ -157,6 +210,12 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary text', ); }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, ), ), ], @@ -173,6 +232,12 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary', ); }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, ), ), const SizedBox(width: 8.0), @@ -185,6 +250,12 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary', ); }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, ), ), const SizedBox(width: 8.0), @@ -197,6 +268,12 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary', ); }, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, ), ), ], @@ -206,12 +283,17 @@ class _OpenContainerTransformDemoState return OpenContainer( transitionType: _transitionType, openBuilder: (BuildContext _, VoidCallback openContainer) { - return const _DetailsPage(includeMarkAsDoneBtn: true); + return _DetailsPage(); }, onClosed: (bool isMarkedAsDone) { if (isMarkedAsDone) { - scaffoldKey.currentState.showSnackBar( - const SnackBar(content: Text('Marked as done!'))); + scaffoldKey.currentState.showSnackBar(const SnackBar( + content: Text('Marked as done!'), + )); + + setState(() { + doneCounter++; + }); } }, tappable: false, @@ -232,10 +314,10 @@ class _OpenContainerTransformDemoState }), ], ), - floatingActionButton: OpenContainer( + floatingActionButton: OpenContainer( transitionType: _transitionType, openBuilder: (BuildContext context, VoidCallback _) { - return const _DetailsPage(); + return _DetailsPage(); }, closedElevation: 6.0, closedShape: const RoundedRectangleBorder( @@ -244,6 +326,12 @@ class _OpenContainerTransformDemoState ), ), closedColor: Theme.of(context).colorScheme.secondary, + onClosed: (bool isMarkedAsDone) { + if (isMarkedAsDone) + setState(() { + doneCounter++; + }); + }, closedBuilder: (BuildContext context, VoidCallback openContainer) { return SizedBox( height: _fabDimension, @@ -265,18 +353,21 @@ class _OpenContainerWrapper extends StatelessWidget { const _OpenContainerWrapper({ this.closedBuilder, this.transitionType, + this.onClosed, }); final OpenContainerBuilder closedBuilder; final ContainerTransitionType transitionType; + final onClosedCallback onClosed; @override Widget build(BuildContext context) { - return OpenContainer( + return OpenContainer( transitionType: transitionType, openBuilder: (BuildContext context, VoidCallback _) { - return const _DetailsPage(); + return _DetailsPage(); }, + onClosed: onClosed, tappable: false, closedBuilder: closedBuilder, ); @@ -462,23 +553,17 @@ class _InkWellOverlay extends StatelessWidget { } class _DetailsPage extends StatelessWidget { - const _DetailsPage({this.includeMarkAsDoneBtn = false}); - - final bool includeMarkAsDoneBtn; - @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Details page'), actions: [ - includeMarkAsDoneBtn - ? IconButton( - icon: const Icon(Icons.done), - onPressed: () => Navigator.pop(context, true), - tooltip: 'Mark as done', - ) - : Container() + IconButton( + icon: const Icon(Icons.done), + onPressed: () => Navigator.pop(context, true), + tooltip: 'Mark as done', + ) ], ), body: ListView( From 73b1bddb66ea11bbf1b92c268590da7120430684 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Sat, 16 May 2020 13:41:29 +0530 Subject: [PATCH 07/12] Removed trailing whitespace in open_container.dart --- packages/animations/lib/src/open_container.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index 608640d1acaf..c191520a4040 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -48,7 +48,7 @@ typedef onClosedCallback = void Function(S data); /// closed to open and vice versa the widgets returned by the [openBuilder] and /// [closedBuilder] exist in the tree at the same time. Therefore, the widgets /// returned by these builders cannot include the same global key. -/// +/// /// `T` refers to the type of data returned by the route when the container /// is closed. This value can be accessed in the `onClosed` function. /// From 74e4c2293767dfc6fb31d8d014b9cfb7eca53594 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Tue, 19 May 2020 16:29:21 +0530 Subject: [PATCH 08/12] Updated open_container.dart - Replaced `onClosedCallback` to `ClosedCallback` - Updated type argument for OpenContainer: `T extends Object` --- packages/animations/lib/src/open_container.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index c191520a4040..feccdf11ab7c 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -31,7 +31,7 @@ enum ContainerTransitionType { /// Callback function which is called when the [OpenContainer] /// is closed. -typedef onClosedCallback = void Function(S data); +typedef ClosedCallback = void Function(S data); /// A container that grows to fill the screen to reveal new content when tapped. /// @@ -59,7 +59,7 @@ typedef onClosedCallback = void Function(S data); /// * [Transitions with animated containers](https://material.io/design/motion/choreography.html#transformation) /// in the Material spec. @optionalTypeArgs -class OpenContainer extends StatefulWidget { +class OpenContainer extends StatefulWidget { /// Creates an [OpenContainer]. /// /// All arguments except for [key] must not be null. The arguments @@ -175,9 +175,10 @@ class OpenContainer extends StatefulWidget { final ShapeBorder openShape; /// Called when the container was popped and has returned to the closed state. + /// /// The return value from the popped screen is passed to this function as an /// argument. - final onClosedCallback onClosed; + final ClosedCallback onClosed; /// Called to obtain the child for the container in the closed state. /// From 0dd18c8a3c057d5c3086ddcf297d4e1670f6d001 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Tue, 19 May 2020 16:44:53 +0530 Subject: [PATCH 09/12] Updated container_transition.dart - Added instance method to show snackbar when "Mark as done" is pressed - Removed "Mark as done" counter & corresponding container from scrollview - Added `onClosed` in `_OpenContainerWrapper` - Added `includeMarkAsDoneButton` in `_DetailsPage` --- .../example/lib/container_transition.dart | 135 ++++-------------- 1 file changed, 31 insertions(+), 104 deletions(-) diff --git a/packages/animations/example/lib/container_transition.dart b/packages/animations/example/lib/container_transition.dart index 2cc894322b54..155b5a4eec55 100644 --- a/packages/animations/example/lib/container_transition.dart +++ b/packages/animations/example/lib/container_transition.dart @@ -51,8 +51,12 @@ class _OpenContainerTransformDemoState ContainerTransitionType _transitionType = ContainerTransitionType.fade; final GlobalKey scaffoldKey = GlobalKey(); - static int doneCounter = 0; - final ValueKey counterKey = ValueKey(doneCounter); + void _showMarkedAsDoneSnackbar(bool isMarkedAsDone) { + if (isMarkedAsDone ?? false) + scaffoldKey.currentState.showSnackBar(const SnackBar( + content: Text('Marked as done!'), + )); + } void _showSettingsBottomModalSheet(BuildContext context) { showModalBottomSheet( @@ -122,50 +126,12 @@ class _OpenContainerTransformDemoState body: ListView( padding: const EdgeInsets.all(8.0), children: [ - Container( - key: counterKey, - padding: const EdgeInsets.symmetric( - vertical: 15.0, - horizontal: 10.0, - ), - margin: const EdgeInsets.only(bottom: 10.0), - decoration: BoxDecoration( - color: Colors.purple[100], - borderRadius: BorderRadius.circular(5.0), - ), - child: Row( - children: [ - const Padding( - padding: EdgeInsets.only(right: 10.0), - child: Icon(Icons.done), - ), - RichText( - text: TextSpan( - style: const TextStyle(fontSize: 18.0, color: Colors.black), - children: [ - const TextSpan(text: 'Marked as done '), - TextSpan( - text: '$doneCounter', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - const TextSpan(text: ' times'), - ], - ), - ), - ], - ), - ), _OpenContainerWrapper( transitionType: _transitionType, closedBuilder: (BuildContext _, VoidCallback openContainer) { return _ExampleCard(openContainer: openContainer); }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, + onClosed: _showMarkedAsDoneSnackbar, ), const SizedBox(height: 16.0), _OpenContainerWrapper( @@ -173,12 +139,7 @@ class _OpenContainerTransformDemoState closedBuilder: (BuildContext _, VoidCallback openContainer) { return _ExampleSingleTile(openContainer: openContainer); }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, + onClosed: _showMarkedAsDoneSnackbar, ), const SizedBox(height: 16.0), Row( @@ -192,12 +153,7 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary text', ); }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, + onClosed: _showMarkedAsDoneSnackbar, ), ), const SizedBox(width: 8.0), @@ -210,12 +166,7 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary text', ); }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, + onClosed: _showMarkedAsDoneSnackbar, ), ), ], @@ -232,12 +183,7 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary', ); }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, + onClosed: _showMarkedAsDoneSnackbar, ), ), const SizedBox(width: 8.0), @@ -250,12 +196,7 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary', ); }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, + onClosed: _showMarkedAsDoneSnackbar, ), ), const SizedBox(width: 8.0), @@ -268,12 +209,7 @@ class _OpenContainerTransformDemoState subtitle: 'Secondary', ); }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, + onClosed: _showMarkedAsDoneSnackbar, ), ), ], @@ -283,19 +219,9 @@ class _OpenContainerTransformDemoState return OpenContainer( transitionType: _transitionType, openBuilder: (BuildContext _, VoidCallback openContainer) { - return _DetailsPage(); - }, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) { - scaffoldKey.currentState.showSnackBar(const SnackBar( - content: Text('Marked as done!'), - )); - - setState(() { - doneCounter++; - }); - } + return const _DetailsPage(); }, + onClosed: _showMarkedAsDoneSnackbar, tappable: false, closedShape: const RoundedRectangleBorder(), closedElevation: 0.0, @@ -314,10 +240,12 @@ class _OpenContainerTransformDemoState }), ], ), - floatingActionButton: OpenContainer( + floatingActionButton: OpenContainer( transitionType: _transitionType, openBuilder: (BuildContext context, VoidCallback _) { - return _DetailsPage(); + return const _DetailsPage( + includeMarkAsDoneButton: false, + ); }, closedElevation: 6.0, closedShape: const RoundedRectangleBorder( @@ -326,12 +254,6 @@ class _OpenContainerTransformDemoState ), ), closedColor: Theme.of(context).colorScheme.secondary, - onClosed: (bool isMarkedAsDone) { - if (isMarkedAsDone) - setState(() { - doneCounter++; - }); - }, closedBuilder: (BuildContext context, VoidCallback openContainer) { return SizedBox( height: _fabDimension, @@ -358,14 +280,14 @@ class _OpenContainerWrapper extends StatelessWidget { final OpenContainerBuilder closedBuilder; final ContainerTransitionType transitionType; - final onClosedCallback onClosed; + final ClosedCallback onClosed; @override Widget build(BuildContext context) { return OpenContainer( transitionType: transitionType, openBuilder: (BuildContext context, VoidCallback _) { - return _DetailsPage(); + return const _DetailsPage(); }, onClosed: onClosed, tappable: false, @@ -553,17 +475,22 @@ class _InkWellOverlay extends StatelessWidget { } class _DetailsPage extends StatelessWidget { + const _DetailsPage({this.includeMarkAsDoneButton = true}); + + final bool includeMarkAsDoneButton; + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Details page'), actions: [ - IconButton( - icon: const Icon(Icons.done), - onPressed: () => Navigator.pop(context, true), - tooltip: 'Mark as done', - ) + if (includeMarkAsDoneButton) + IconButton( + icon: const Icon(Icons.done), + onPressed: () => Navigator.pop(context, true), + tooltip: 'Mark as done', + ) ], ), body: ListView( From 5b6e371614660c1d68ce2c9cc7aa1bd3dba13c37 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Tue, 19 May 2020 17:40:41 +0530 Subject: [PATCH 10/12] Updated open_container_test.dart Removed all unnecessary type arguments for `OpenContainer` --- .../animations/test/open_container_test.dart | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/animations/test/open_container_test.dart b/packages/animations/test/open_container_test.dart index 9ea8196921db..46d3c50a2adb 100644 --- a/packages/animations/test/open_container_test.dart +++ b/packages/animations/test/open_container_test.dart @@ -19,7 +19,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -192,7 +192,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -361,7 +361,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -535,7 +535,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -708,7 +708,7 @@ void main() { (WidgetTester tester) async { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( tappable: false, closedBuilder: (BuildContext context, VoidCallback _) { return const Text('Closed'); @@ -732,7 +732,7 @@ void main() { VoidCallback open, close; await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( tappable: false, closedBuilder: (BuildContext context, VoidCallback action) { open = action; @@ -767,7 +767,7 @@ void main() { testWidgets('open widget keeps state', (WidgetTester tester) async { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -806,7 +806,7 @@ void main() { VoidCallback open; await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { open = action; return Switch( @@ -855,7 +855,7 @@ void main() { testWidgets('closes to the right location when src position has changed', (WidgetTester tester) async { - final Widget openContainer = OpenContainer( + final Widget openContainer = OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return Container( height: 100, @@ -917,7 +917,7 @@ void main() { testWidgets('src changes size while open', (WidgetTester tester) async { final Widget openContainer = _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const _SizableContainer( initialSize: 100, @@ -989,7 +989,7 @@ void main() { (WidgetTester tester) async { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -1040,7 +1040,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -1098,7 +1098,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); }, @@ -1130,7 +1130,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( transitionDuration: const Duration(seconds: 2), closedBuilder: (BuildContext context, VoidCallback action) { return const Text('Closed'); @@ -1178,7 +1178,7 @@ void main() { height: 400, child: _boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedShape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), @@ -1251,7 +1251,7 @@ void main() { await tester.pumpWidget(_boilerplate( child: Center( - child: OpenContainer( + child: OpenContainer( closedColor: Colors.green, openColor: Colors.blue, closedElevation: 4.0, @@ -1319,7 +1319,7 @@ void main() { cacheExtent: 0, controller: controller, itemBuilder: (BuildContext context, int index) { - return OpenContainer( + return OpenContainer( closedBuilder: (BuildContext context, VoidCallback _) { return SizedBox( height: 100, @@ -1392,7 +1392,7 @@ void main() { cacheExtent: 0, controller: controller, itemBuilder: (BuildContext context, int index) { - return OpenContainer( + return OpenContainer( closedBuilder: (BuildContext context, VoidCallback _) { return SizedBox( height: 100, @@ -1485,7 +1485,7 @@ void main() { testWidgets('onClosed callback is called when container has closed', (WidgetTester tester) async { bool hasClosed = false; - final Widget openContainer = OpenContainer( + final Widget openContainer = OpenContainer( onClosed: (dynamic _) { hasClosed = true; }, @@ -1584,7 +1584,7 @@ void main() { settings: route, builder: (BuildContext context) { return Container( - child: OpenContainer( + child: OpenContainer( useRootNavigator: useRootNavigator, closedBuilder: (BuildContext context, _) { return const Text('Closed'); @@ -1753,7 +1753,7 @@ class __RemoveOpenContainerExampleState Widget build(BuildContext context) { return removeOpenContainerWidget ? const Text('Container has been removed') - : OpenContainer( + : OpenContainer( closedBuilder: (BuildContext context, VoidCallback action) => Column( children: [ From 0d70facb7e49ca16f34d8ae1a7f3bc3fd7fbb3f8 Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Thu, 21 May 2020 10:52:17 +0530 Subject: [PATCH 11/12] Updated open_container.dart `action` callback in openBuilder accepts return value which is provided to `onClosed` --- .../animations/lib/src/open_container.dart | 37 +++++++++++++------ .../animations/test/open_container_test.dart | 5 ++- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index feccdf11ab7c..347e69c0228f 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -5,13 +5,28 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; -/// Signature for a function that creates a [Widget] to be used within an +/// Signature for `action` callback function provided to [OpenContainer.openBuilder]. +/// +/// Parameter `returnValue` is the value which will be provided to [OpenContainer.onClosed] +/// when `action` is called. +typedef CloseContainerActionCallback = void Function({S returnValue}); + +/// Signature for a function that creates a [Widget] in open state within an /// [OpenContainer]. /// /// The `action` callback provided to [OpenContainer.openBuilder] can be used -/// to close the container. The `action` callback provided to -/// [OpenContainer.closedBuilder] can be used to open the container again. -typedef OpenContainerBuilder = Widget Function( +/// to close the container. +typedef OpenContainerBuilder = Widget Function( + BuildContext context, + CloseContainerActionCallback action, +); + +/// Signature for a function that creates a [Widget] in closed state within an +/// [OpenContainer]. +/// +/// The `action` callback provided to [OpenContainer.closedBuilder] can be used +/// to open the container. +typedef CloseContainerBuilder = Widget Function( BuildContext context, VoidCallback action, ); @@ -175,7 +190,7 @@ class OpenContainer extends StatefulWidget { final ShapeBorder openShape; /// Called when the container was popped and has returned to the closed state. - /// + /// /// The return value from the popped screen is passed to this function as an /// argument. final ClosedCallback onClosed; @@ -188,7 +203,7 @@ class OpenContainer extends StatefulWidget { /// /// The `action` callback provided to the builder can be called to open the /// container. - final OpenContainerBuilder closedBuilder; + final CloseContainerBuilder closedBuilder; /// Called to obtain the child for the container in the open state. /// @@ -198,7 +213,7 @@ class OpenContainer extends StatefulWidget { /// /// The `action` callback provided to the builder can be called to close the /// container. - final OpenContainerBuilder openBuilder; + final OpenContainerBuilder openBuilder; /// Whether the entire closed container can be tapped to open it. /// @@ -513,8 +528,8 @@ class _OpenContainerRoute extends ModalRoute { final Color openColor; final double openElevation; final ShapeBorder openShape; - final OpenContainerBuilder closedBuilder; - final OpenContainerBuilder openBuilder; + final CloseContainerBuilder closedBuilder; + final OpenContainerBuilder openBuilder; // See [_OpenContainerState._hideableKey]. final GlobalKey<_HideableState> hideableKey; @@ -670,8 +685,8 @@ class _OpenContainerRoute extends ModalRoute { return wasInProgress && isInProgress; } - void closeContainer() { - Navigator.of(subtreeContext).pop(); + void closeContainer({T returnValue}) { + Navigator.of(subtreeContext).pop(returnValue); } @override diff --git a/packages/animations/test/open_container_test.dart b/packages/animations/test/open_container_test.dart index 46d3c50a2adb..110b916b90a0 100644 --- a/packages/animations/test/open_container_test.dart +++ b/packages/animations/test/open_container_test.dart @@ -1539,9 +1539,10 @@ void main() { child: const Text('Closed'), ); }, - openBuilder: (BuildContext context, VoidCallback action) { + openBuilder: + (BuildContext context, CloseContainerActionCallback action) { return GestureDetector( - onTap: () => Navigator.pop(context, true), + onTap: () => action(returnValue: true), child: const Text('Open'), ); }, From 5265f21e61325329009af5f2c8d6878a609ed67f Mon Sep 17 00:00:00 2001 From: "Melvin. L. Abraham" Date: Wed, 27 May 2020 11:30:07 +0530 Subject: [PATCH 12/12] Updated open_container.dart - Added note of caution in `onClosed` documentation for `null` value - Minor formatting change --- packages/animations/lib/src/open_container.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index 7a46e19e3b06..b244668f1764 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -78,11 +78,7 @@ class OpenContainer extends StatefulWidget { /// Creates an [OpenContainer]. /// /// All arguments except for [key] must not be null. The arguments -<<<<<<< HEAD /// [openBuilder] and [closedBuilder] are required. -======= - /// [closedBuilder] and [openBuilder] are required. ->>>>>>> upstream/master const OpenContainer({ Key key, this.closedColor = Colors.white, @@ -197,6 +193,9 @@ class OpenContainer extends StatefulWidget { /// /// The return value from the popped screen is passed to this function as an /// argument. + /// + /// If no value is returned via [Navigator.pop] or [OpenContainer.openBuilder.action], + /// `null` will be returned by default. final ClosedCallback onClosed; /// Called to obtain the child for the container in the closed state. @@ -265,9 +264,10 @@ class _OpenContainerState extends State> { final GlobalKey _closedBuilderKey = GlobalKey(); Future openContainer() async { - final T data = - await Navigator.of(context, rootNavigator: widget.useRootNavigator) - .push(_OpenContainerRoute( + final T data = await Navigator.of( + context, + rootNavigator: widget.useRootNavigator, + ).push(_OpenContainerRoute( closedColor: widget.closedColor, openColor: widget.openColor, closedElevation: widget.closedElevation,