Jaime Blasco
Committed by GitHub

Merge pull request #253 from LeGoffMael/fixMaintainState

fix: keep state in memory in ModalBottomSheetRoute
  1 +name: Runnable (stable)
  2 +
  3 +on:
  4 + push:
  5 + branches:
  6 + - main
  7 + - master
  8 + pull_request:
  9 + branches:
  10 + - main
  11 + - master
  12 +
  13 +jobs:
  14 + analyze:
  15 + name: Analyze on ${{ matrix.os }}
  16 + runs-on: ${{ matrix.os }}
  17 + strategy:
  18 + matrix:
  19 + os: [ ubuntu-latest ]
  20 + steps:
  21 + - uses: actions/checkout@v1
  22 + - uses: actions/setup-java@v1
  23 + with:
  24 + java-version: '11.x'
  25 + - uses: subosito/flutter-action@v2
  26 + with:
  27 + channel: 'stable'
  28 + - name: Log Dart/Flutter versions
  29 + run: |
  30 + dart --version
  31 + flutter --version
  32 + - name: Prepare dependencies
  33 + run: flutter pub get
  34 + - name: Analyse the repo
  35 + run: flutter analyze lib
  36 + - name: Run tests
  37 + run: flutter test
@@ -160,13 +160,13 @@ class ModalBottomSheetRoute<T> extends PageRoute<T> { @@ -160,13 +160,13 @@ class ModalBottomSheetRoute<T> extends PageRoute<T> {
160 160
161 @override 161 @override
162 bool get barrierDismissible => isDismissible; 162 bool get barrierDismissible => isDismissible;
163 - 163 +
164 @override 164 @override
165 - bool get maintainState => false; //idk but needed 165 + bool get maintainState => true; // keep in memory when not active (#252)
166 166
167 @override 167 @override
168 bool get opaque => false; //transparency 168 bool get opaque => false; //transparency
169 - 169 +
170 @override 170 @override
171 final String? barrierLabel; 171 final String? barrierLabel;
172 172
  1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter/material.dart';
1 import 'package:flutter_test/flutter_test.dart'; 3 import 'package:flutter_test/flutter_test.dart';
  4 +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
2 5
3 void main() { 6 void main() {
4 - test('adds one to input values', () {}); 7 + group(
  8 + 'Route.mainState are well-controlled by `mainState`',
  9 + () {
  10 + Future<void> testInitStateAndDispose(
  11 + WidgetTester tester,
  12 + Future<void> Function(BuildContext context, WidgetBuilder builder)
  13 + onPressed,
  14 + ) async {
  15 + int _initState = 0, _dispose = 0;
  16 + await _pumpWidget(
  17 + tester: tester,
  18 + onPressed: (context) => onPressed(
  19 + context,
  20 + (_) => _TestWidget(
  21 + onInitState: () => _initState++,
  22 + onDispose: () => _dispose++,
  23 + ),
  24 + ),
  25 + );
  26 + expect(_initState, 0);
  27 + await tester.tap(_textButtonWithText('Press me'));
  28 + await tester.pumpAndSettle();
  29 + expect(_initState, 1);
  30 + expect(_dispose, 0);
  31 + await tester.tap(_textButtonWithText('TestWidget push'));
  32 + await tester.pumpAndSettle();
  33 + expect(_initState, 1);
  34 + expect(_dispose, 0);
  35 + await tester.tap(_textButtonWithText('TestWidget pushed pop'));
  36 + await tester.pumpAndSettle();
  37 + expect(_initState, 1);
  38 + expect(_dispose, 0);
  39 + await tester.tap(_textButtonWithText('TestWidget pop'));
  40 + await tester.pumpAndSettle();
  41 + expect(_initState, 1);
  42 + expect(_dispose, 1);
  43 + }
  44 +
  45 + testWidgets('with showCupertinoModalBottomSheet', (tester) {
  46 + return testInitStateAndDispose(
  47 + tester,
  48 + (context, builder) => showCupertinoModalBottomSheet(
  49 + context: context,
  50 + builder: builder,
  51 + ),
  52 + );
  53 + });
  54 + testWidgets('with showMaterialModalBottomSheet', (tester) {
  55 + return testInitStateAndDispose(
  56 + tester,
  57 + (context, builder) => showMaterialModalBottomSheet(
  58 + context: context,
  59 + builder: builder,
  60 + ),
  61 + );
  62 + });
  63 + },
  64 + );
  65 +}
  66 +
  67 +Future<void> _pumpWidget({
  68 + required WidgetTester tester,
  69 + required void Function(BuildContext context) onPressed,
  70 +}) {
  71 + return tester.pumpWidget(
  72 + MaterialApp(
  73 + home: Builder(
  74 + builder: (context) => Scaffold(
  75 + body: Center(
  76 + child: TextButton(
  77 + onPressed: () => onPressed(context),
  78 + child: Text('Press me'),
  79 + ),
  80 + ),
  81 + ),
  82 + ),
  83 + ),
  84 + );
  85 +}
  86 +
  87 +Finder _textButtonWithText(String text) {
  88 + return find.widgetWithText(TextButton, text);
  89 +}
  90 +
  91 +class _TestWidget extends StatefulWidget {
  92 + const _TestWidget({
  93 + Key? key,
  94 + this.onInitState,
  95 + this.onDispose,
  96 + }) : super(key: key);
  97 +
  98 + final VoidCallback? onInitState;
  99 + final VoidCallback? onDispose;
  100 +
  101 + @override
  102 + State<_TestWidget> createState() => _TestWidgetState();
  103 +}
  104 +
  105 +class _TestWidgetState extends State<_TestWidget> {
  106 + @override
  107 + void initState() {
  108 + super.initState();
  109 + widget.onInitState?.call();
  110 + }
  111 +
  112 + @override
  113 + void dispose() {
  114 + widget.onDispose?.call();
  115 + super.dispose();
  116 + }
  117 +
  118 + @override
  119 + Widget build(BuildContext context) {
  120 + return Scaffold(
  121 + body: Column(
  122 + mainAxisAlignment: MainAxisAlignment.center,
  123 + children: [
  124 + TextButton(
  125 + onPressed: () => Navigator.of(context).push(
  126 + defaultPageRoute(
  127 + targetPlatform: Theme.of(context).platform,
  128 + builder: (context) => Scaffold(
  129 + body: Center(
  130 + child: TextButton(
  131 + onPressed: () => Navigator.of(context).pop(),
  132 + child: Text('TestWidget pushed pop'),
  133 + ),
  134 + ),
  135 + ),
  136 + ),
  137 + ),
  138 + child: Text('TestWidget push'),
  139 + ),
  140 + TextButton(
  141 + onPressed: () => Navigator.of(context).pop(),
  142 + child: Text('TestWidget pop'),
  143 + ),
  144 + ],
  145 + ),
  146 + );
  147 + }
  148 +}
  149 +
  150 +PageRoute<T> defaultPageRoute<T>({
  151 + required TargetPlatform targetPlatform,
  152 + required WidgetBuilder builder,
  153 + RouteSettings? settings,
  154 + bool maintainState = true,
  155 + bool fullscreenDialog = false,
  156 +}) {
  157 + switch (targetPlatform) {
  158 + case TargetPlatform.iOS:
  159 + case TargetPlatform.macOS:
  160 + return CupertinoPageRoute<T>(
  161 + builder: builder,
  162 + settings: settings,
  163 + maintainState: maintainState,
  164 + fullscreenDialog: fullscreenDialog,
  165 + );
  166 + default:
  167 + return MaterialPageRoute<T>(
  168 + builder: builder,
  169 + settings: settings,
  170 + maintainState: maintainState,
  171 + fullscreenDialog: fullscreenDialog,
  172 + );
  173 + }
5 } 174 }