@@ -17,6 +17,7 @@ import 'package:yandex_keyboard_desktop/src/app_ui/app_controls.dart';
1717import 'package:yandex_keyboard_desktop/src/app_ui/app_tokens.dart' ;
1818import 'package:yandex_keyboard_desktop/src/app/desktop_surface.dart' ;
1919import 'package:yandex_keyboard_desktop/src/app/diagnostic_log.dart' ;
20+ import 'package:yandex_keyboard_desktop/src/app/frame_settle.dart' ;
2021import 'package:yandex_keyboard_desktop/src/app/desktop_visual_preferences.dart' ;
2122import 'package:yandex_keyboard_desktop/src/app/ios_bootstrap.dart' ;
2223import 'package:yandex_keyboard_desktop/src/features/settings/presentation/settings_window.dart' ;
@@ -413,14 +414,14 @@ class _AppState extends State<App>
413414 Future <void > _showHotKeyErrorSurfaceNow () async {
414415 if (mounted && _surface != DesktopSurface .overlay) {
415416 setState (() => _surface = DesktopSurface .overlay);
416- await WidgetsBinding .instance.endOfFrame ;
417+ await settleFrame () ;
417418 }
418419 const size = Size (460 , 96 );
419420 await windowManager.setMinimumSize (size);
420421 await windowManager.setSize (size);
421422 await windowManager.setAlwaysOnTop (true );
422423 await windowManager.center ();
423- await WidgetsBinding .instance.endOfFrame ;
424+ await settleFrame () ;
424425 await _showOverlayWindowInactive (widget.overlayGateway);
425426 }
426427
@@ -464,6 +465,11 @@ class _AppState extends State<App>
464465 }
465466
466467 Future <void > _handleWindowHiddenNow () async {
468+ // Only react to the settings window being dismissed natively (its close
469+ // button hides the shared window). Overlay-driven hides are orchestrated
470+ // by the overlay itself; restoring here as well races the overlay's own
471+ // placement queue and clobbers the window bounds mid-presentation.
472+ if (_surface != DesktopSurface .settings) return ;
467473 widget.textOperationGate.reset ();
468474 if (_hotKeyErrorCode == null ) await _restoreOverlayWindowNow ();
469475 }
@@ -486,16 +492,23 @@ class _AppState extends State<App>
486492
487493 Future <bool > _ensureOverlayHostSurface () async {
488494 var ready = false ;
495+ diag ('ensureOverlayHostSurface: requested (surface=$_surface )' );
489496 await _runSurfaceTransition (() async {
497+ diag ('ensureOverlayHostSurface: transition started' );
490498 if (_surface == DesktopSurface .overlay) {
491499 ready = true ;
492500 return ;
493501 }
494- if (! await _confirmSettingsExitIfNeeded ()) return ;
502+ if (! await _confirmSettingsExitIfNeeded ()) {
503+ diag ('ensureOverlayHostSurface: discard declined' );
504+ return ;
505+ }
495506 if (! mounted) return ;
496507 setState (() => _surface = DesktopSurface .overlay);
508+ diag ('ensureOverlayHostSurface: hiding settings window' );
497509 await windowManager.hide ();
498- await WidgetsBinding .instance.endOfFrame;
510+ await settleFrame ();
511+ diag ('ensureOverlayHostSurface: ready' );
499512 ready = true ;
500513 });
501514 return ready;
@@ -549,6 +562,16 @@ class _AppState extends State<App>
549562
550563 Future <bool > _confirmSettingsExitIfNeeded () async {
551564 if (! widget.settingsController.state.isDirty) return true ;
565+ // The discard dialog renders inside the shared window; make sure it is
566+ // visible and focused, otherwise the confirmation silently blocks the
567+ // surface-transition queue while sitting in a background window.
568+ if (_surface == DesktopSurface .settings) {
569+ await _bestEffort (() async {
570+ await _setNativeWindowCanActivate (widget.overlayGateway, true );
571+ await windowManager.show ();
572+ await windowManager.focus ();
573+ });
574+ }
552575 return await _settingsWindowKey.currentState? .confirmDiscardIfNeeded () ??
553576 false ;
554577 }
@@ -643,7 +666,7 @@ class _AppState extends State<App>
643666 await _bestEffort (() => windowManager.setMovable (true ));
644667 try {
645668 await _setNativeWindowCanActivate (widget.overlayGateway, true );
646- await WidgetsBinding .instance.endOfFrame ;
669+ await settleFrame () ;
647670 await windowManager.show ();
648671 await windowManager.focus ();
649672 } catch (_) {
@@ -675,6 +698,9 @@ class _AppState extends State<App>
675698 if (! await _confirmSettingsExitIfNeeded ()) return ;
676699 }
677700 setState (() => _surface = DesktopSurface .overlay);
701+ // Hide the (large, activatable) settings window before morphing it
702+ // into the compact overlay so the resize never plays out on screen.
703+ await _bestEffort (windowManager.hide);
678704 }
679705 var resolvedTarget = targetHandle;
680706 if (resolvedTarget == null &&
@@ -691,7 +717,7 @@ class _AppState extends State<App>
691717 await OverlayWindowController .initialize (
692718 size: overlaySize,
693719 );
694- await WidgetsBinding .instance.endOfFrame ;
720+ await settleFrame () ;
695721 await _showOverlayWindowInactive (widget.overlayGateway);
696722 }
697723
@@ -702,7 +728,7 @@ class _AppState extends State<App>
702728 );
703729 if (mounted && _surface != DesktopSurface .overlay) {
704730 setState (() => _surface = DesktopSurface .overlay);
705- await WidgetsBinding .instance.endOfFrame ;
731+ await settleFrame () ;
706732 }
707733 await OverlayWindowController .initialize (size: overlaySize);
708734 if (show) {
0 commit comments