@@ -80,6 +80,7 @@ class _ThemePickerButtonState extends material.State<ThemePickerButton> {
8080 material.ValueNotifier <bool >(false );
8181 bool _triggerHovered = false ;
8282 bool _closingWithExit = false ;
83+ int _exitGeneration = 0 ;
8384 String ? _previewThemeId;
8485 String ? _previewThemeLabel;
8586 QueryaTheme ? _previewTheme;
@@ -104,16 +105,25 @@ class _ThemePickerButtonState extends material.State<ThemePickerButton> {
104105 super .dispose ();
105106 }
106107
108+ void _cancelExit () {
109+ if (_closingWithExit) {
110+ _exitGeneration++ ;
111+ _closingWithExit = false ;
112+ _menuOpen.value = true ;
113+ }
114+ }
115+
107116 /// Plays exit fade-slide, then removes the [MenuAnchor] overlay (#499).
108117 Future <void > _closeWithExit () async {
109118 if (! _controller.isOpen || _closingWithExit) return ;
110119 _closingWithExit = true ;
111120 _menuOpen.value = false ;
121+ final gen = ++ _exitGeneration;
112122 final duration = context.motionDuration (QueryaMotion .standard);
113123 if (duration > QueryaMotion .instant) {
114124 await Future <void >.delayed (duration);
115125 }
116- if (! mounted) return ;
126+ if (! mounted || gen != _exitGeneration ) return ;
117127 if (_controller.isOpen) {
118128 _controller.close ();
119129 }
@@ -217,10 +227,12 @@ class _ThemePickerButtonState extends material.State<ThemePickerButton> {
217227 final anchor = material.MenuAnchor (
218228 controller: _controller,
219229 onOpen: () {
230+ _exitGeneration++ ;
220231 _closingWithExit = false ;
221232 _menuOpen.value = true ;
222233 },
223234 onClose: () {
235+ _exitGeneration++ ;
224236 _closingWithExit = false ;
225237 _menuOpen.value = false ;
226238 },
@@ -461,7 +473,9 @@ class _ThemePickerButtonState extends material.State<ThemePickerButton> {
461473 child: material.InkWell (
462474 onTap: _enabled
463475 ? () {
464- if (controller.isOpen) {
476+ if (_closingWithExit) {
477+ _cancelExit ();
478+ } else if (controller.isOpen) {
465479 unawaited (_closeWithExit ());
466480 } else {
467481 _clearSearch ();
@@ -498,7 +512,7 @@ class _ThemePickerButtonState extends material.State<ThemePickerButton> {
498512}
499513
500514/// Enter/exit fade-slide for theme menu body while the overlay stays mounted.
501- class _ThemePickerMenuEnter extends material.StatelessWidget {
515+ class _ThemePickerMenuEnter extends material.StatefulWidget {
502516 const _ThemePickerMenuEnter ({
503517 required this .openNotifier,
504518 required this .child,
@@ -507,24 +521,48 @@ class _ThemePickerMenuEnter extends material.StatelessWidget {
507521 final material.ValueNotifier <bool > openNotifier;
508522 final material.Widget child;
509523
524+ @override
525+ material.State <_ThemePickerMenuEnter > createState () =>
526+ _ThemePickerMenuEnterState ();
527+ }
528+
529+ class _ThemePickerMenuEnterState
530+ extends material.State <_ThemePickerMenuEnter > {
531+ bool _entered = false ;
532+
533+ @override
534+ void initState () {
535+ super .initState ();
536+ material.WidgetsBinding .instance.addPostFrameCallback ((_) {
537+ if (mounted) {
538+ setState (() {
539+ _entered = true ;
540+ });
541+ }
542+ });
543+ }
544+
510545 @override
511546 material.Widget build (material.BuildContext context) {
512547 final duration = context.motionDuration (QueryaMotion .standard);
513548 final enter = context.motionCurve (QueryaMotion .enter);
514549 final exit = context.motionCurve (QueryaMotion .exit);
550+ final instant = duration == QueryaMotion .instant;
551+
515552 return material.ValueListenableBuilder <bool >(
516- valueListenable: openNotifier,
553+ valueListenable: widget. openNotifier,
517554 builder: (context, open, _) {
518- final curve = open ? enter : exit;
555+ final isOpen = (open && _entered) || (open && instant);
556+ final curve = isOpen ? enter : exit;
519557 return material.AnimatedSlide (
520- offset: open ? material.Offset .zero : const material.Offset (0 , - 0.04 ),
558+ offset: isOpen ? material.Offset .zero : const material.Offset (0 , - 0.04 ),
521559 duration: duration,
522560 curve: curve,
523561 child: material.AnimatedOpacity (
524- opacity: open ? 1 : 0 ,
562+ opacity: isOpen ? 1 : 0 ,
525563 duration: duration,
526564 curve: curve,
527- child: child,
565+ child: widget. child,
528566 ),
529567 );
530568 },
0 commit comments