You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
showDialog() and push() cause a crash if pop() was called on the previous window before the opening animation was completed
Environment
name: untitled2description: "A new Flutter project."publish_to: 'none'version: 1.0.0+1environment:sdk: '>=3.4.3 <4.0.0'dependencies:flutter:sdk: fluttercupertino_icons: ^1.0.6flutter_modular: ^6.3.4dev_dependencies:flutter_test:sdk: flutterflutter_lints: ^3.0.0flutter:uses-material-design: true
To Reproduce
You need to do a pushNamed to a screen, then do a pop() on that screen until the animation is complete, then immediately call showDialog() or push(). This results in the following error:
======== Exception caught by widgets library =======================================================
The following StateError was thrown building Builder:
Bad state: Future already completed
The relevant error-causing widget was:
MaterialApp MaterialApp:file:///Users/gleb.klimov/StudioProjects/untitled2/lib/main.dart:25:26
When the exception was thrown, this was the stack:
#1 Route.didComplete (package:flutter/src/widgets/navigator.dart:425:19)
#2 _RouteEntry.handleComplete (package:flutter/src/widgets/navigator.dart:3083:11)
#3 NavigatorState._flushHistoryUpdates (package:flutter/src/widgets/navigator.dart:4294:17)
#4 NavigatorState._updatePages (package:flutter/src/widgets/navigator.dart:4198:5)
This is because Navigator:didComplete is called 3 times after these actions, and the third time calling _popCompleter.complete() results in an error because it was already called the first time:
I/flutter ( 8768): Navigator:didComplete, _popCompleter is called with null, settings: /second, isCompleted: false
I/flutter ( 8768): Navigator:didComplete, _popCompleter is called with null, settings: null, isCompleted: false
I/flutter ( 8768): Navigator:didComplete, _popCompleter is called with null, settings: /second, isCompleted: true
Code for reproducing:
import'package:flutter/material.dart';
import'package:flutter_modular/flutter_modular.dart';
voidmain() =>runApp(constMyApp());
classAppModuleextendsModule {
staticconst route ="/";
@overridevoidroutes(RouteManager r) {
r.redirect('/', to:'/first');
r.child('/first', child: (context) =>constFirstPage());
r.child('/second', child: (context) =>constSecondPage());
r.child('/third', child: (context) =>constThirdPage());
}
}
classMyAppextendsStatelessWidget {
constMyApp({super.key});
@overrideWidgetbuild(BuildContext context) {
returnModularApp(
module:AppModule(),
child:MaterialApp.router(
title:'Flutter Demo',
theme:ThemeData(
colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),
useMaterial3:true,
),
routerConfig:Modular.routerConfig,
),
);
}
}
classFirstPageextendsStatelessWidget {
constFirstPage({super.key});
@overrideWidgetbuild(BuildContext context) {
returnScaffold(
appBar:AppBar(title:constText('First page')),
body:Column(
children: [
constCenter(child:Text('This is the first page')),
OutlinedButton(onPressed: () =>_testCase1(context), child:constText('Navigate to the second page and show a dialog')),
OutlinedButton(onPressed: () =>_testCase3(context), child:constText('Navigate to the second page and then to the third using push()')),
],
),
);
}
void_testCase1(BuildContext context) {
Modular.to.pushNamed('/second').then((value) {
showDialog(context: context, builder: (context) =>_getAlertDialog());
});
}
void_testCase3(BuildContext context) {
Modular.to.pushNamed('/second').then((value) {
Modular.to.push(MaterialPageRoute(builder: (context) =>constThirdPage()));
});
}
Widget_getAlertDialog() {
returnAlertDialog(
title:constText('You most likely won\'t see this dialog.'),
actions: [
TextButton(
onPressed: () =>Modular.to.pop(),
child:constText('Close'),
)
],
);
}
}
classSecondPageextendsStatefulWidget {
constSecondPage({super.key});
@overrideState<SecondPage> createState() =>_SecondPageState();
}
class_SecondPageStateextendsState<SecondPage> {
@overridevoidinitState() {
// do pop() before finishing the animationFuture.delayed(constDuration(milliseconds:80)).then((value) =>Modular.to.pop());
super.initState();
}
@overrideWidgetbuild(BuildContext context) {
returnScaffold(appBar:AppBar(title:constText('Second page')));
}
}
classThirdPageextendsStatelessWidget {
constThirdPage({super.key});
@overrideWidgetbuild(BuildContext context) {
returnScaffold(
appBar:AppBar(title:constText('Third page')),
body:constCenter(
child:Text('This is the third page'),
),
);
}
}
Screenshots
The text was updated successfully, but these errors were encountered:
I'd like to check with Contributors: does anyone understand what the problem is and how difficult it is to fix? As a result of this bug, we have no way to upgrade to the new version of modular (the old version has a workaround). Maybe someone could suggest a rough plan to fix the problem so that I can countertribute with less time-consuming code study?
Describe the bug
showDialog() and push() cause a crash if pop() was called on the previous window before the opening animation was completed
Environment
To Reproduce
You need to do a pushNamed to a screen, then do a pop() on that screen until the animation is complete, then immediately call showDialog() or push(). This results in the following error:
This is because Navigator:didComplete is called 3 times after these actions, and the third time calling _popCompleter.complete() results in an error because it was already called the first time:
Code for reproducing:
Screenshots

The text was updated successfully, but these errors were encountered: