From 05166ed5c6658b360f223431d0584a180ebda07f Mon Sep 17 00:00:00 2001 From: XUANJI233 Date: Sun, 10 May 2026 13:46:11 +0800 Subject: [PATCH] fix(windows): refine background animation suspension - ensure topology sync runs on background-state transitions to toggle animationEffect reliably - pause UI tickers while app is backgrounded and resume on foreground events - clean up window controls debug print and minor sync timestamp handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/screens/main_screen.dart | 122 ++++++++++-------- .../widgets/common/network_topology.dart | 26 ++-- .../widgets/common/windows_controls.dart | 3 - 3 files changed, 84 insertions(+), 67 deletions(-) diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index 640166d5..b013c36d 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -28,7 +28,10 @@ class MainScreen extends StatefulWidget { // MainScreen的状态管理类 class _MainScreenState extends State - with SingleTickerProviderStateMixin, WidgetsBindingObserver, WindowListener { + with + SingleTickerProviderStateMixin, + WidgetsBindingObserver, + WindowListener { @override void initState() { super.initState(); @@ -107,13 +110,6 @@ class _MainScreenState extends State // 屏幕尺寸变化时更新 final mediaQuery = MediaQuery.of(context); final screenWidth = mediaQuery.size.width; - final screenHeight = mediaQuery.size.height; - - // 记录小窗口状态变化 - bool isSmallWindow = screenWidth < 300 || screenHeight < 400; - print( - 'Screen size changed: $screenWidth x $screenHeight, isSmallWindow: $isSmallWindow', - ); // 更新分割宽度 ServiceManager().uiState.updateScreenSplitWidth(screenWidth); @@ -144,6 +140,18 @@ class _MainScreenState extends State _setAppBackground(false); } + @override + void onWindowEvent(String eventName) { + if (const {'hide', 'minimize', 'blur'}.contains(eventName)) { + _setAppBackground(true); + return; + } + + if (const {'show', 'restore', 'focus', 'unminimize'}.contains(eventName)) { + _setAppBackground(false); + } + } + // 定义导航项列表 List get navigationItems => [ NavigationItem( @@ -201,59 +209,65 @@ class _MainScreenState extends State // 使用安全的索引值,确保不会越界 final safeIndex = (currentIndex >= 0 && currentIndex < itemCount) ? currentIndex : 0; + final isInBackground = ServiceManager().uiState.isInBackground.value; // 构建Scaffold组件 - return Scaffold( - // 自定义应用栏 - appBar: isSmallWindow ? null : StatusBar(), - // 主体内容:使用Row布局 - body: Row( - children: [ - // 根据是否为桌面端决定是否显示左侧导航 - if (ServiceManager().uiState.isDesktop.value && !isSmallWindow) - LeftNav(items: navigationItems, colorScheme: colorScheme), - // 主要内容区域 - Expanded( - child: Column( - children: [ - // 在小窗口模式下显示简化的状态栏 - if (isSmallWindow) - Container( - height: 36, - color: colorScheme.primaryContainer.withOpacity(0.4), - padding: const EdgeInsets.symmetric(horizontal: 8.0), - alignment: Alignment.centerLeft, - child: Text( - safeIndex < navigationItems.length - ? navigationItems[safeIndex].label - : '', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: colorScheme.onPrimaryContainer, + return TickerMode( + enabled: !isInBackground, + child: Scaffold( + // 自定义应用栏 + appBar: isSmallWindow ? null : StatusBar(), + // 主体内容:使用Row布局 + body: Row( + children: [ + // 根据是否为桌面端决定是否显示左侧导航 + if (ServiceManager().uiState.isDesktop.value && !isSmallWindow) + LeftNav(items: navigationItems, colorScheme: colorScheme), + // 主要内容区域 + Expanded( + child: Column( + children: [ + // 在小窗口模式下显示简化的状态栏 + if (isSmallWindow) + Container( + height: 36, + color: colorScheme.primaryContainer.withValues( + alpha: 0.4, + ), + padding: const EdgeInsets.symmetric(horizontal: 8.0), + alignment: Alignment.centerLeft, + child: Text( + safeIndex < navigationItems.length + ? navigationItems[safeIndex].label + : '', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: colorScheme.onPrimaryContainer, + ), ), ), + // 主内容区域 + Expanded( + child: IndexedStack( + index: safeIndex, // 使用安全的索引 + children: _pages, // 页面列表 + ), ), - // 主内容区域 - Expanded( - child: IndexedStack( - index: safeIndex, // 使用安全的索引 - children: _pages, // 页面列表 - ), - ), - ], + ], + ), ), - ), - ], + ], + ), + // 底部导航栏:在非桌面端或小窗口模式下显示 + bottomNavigationBar: + (ServiceManager().uiState.isDesktop.value && !isSmallWindow) + ? null + : BottomNav( + navigationItems: navigationItems, + colorScheme: colorScheme, + ), ), - // 底部导航栏:在非桌面端或小窗口模式下显示 - bottomNavigationBar: - (ServiceManager().uiState.isDesktop.value && !isSmallWindow) - ? null - : BottomNav( - navigationItems: navigationItems, - colorScheme: colorScheme, - ), ); }); } diff --git a/lib/shared/widgets/common/network_topology.dart b/lib/shared/widgets/common/network_topology.dart index d7fba579..7dc79083 100644 --- a/lib/shared/widgets/common/network_topology.dart +++ b/lib/shared/widgets/common/network_topology.dart @@ -43,8 +43,9 @@ class _NetworkTopologyViewState extends State { @override void didUpdateWidget(NetworkTopologyView oldWidget) { super.didUpdateWidget(oldWidget); - final resumedFromBackground = oldWidget.isInBackground && !widget.isInBackground; - _syncGraph(force: resumedFromBackground); + final backgroundStateChanged = + oldWidget.isInBackground != widget.isInBackground; + _syncGraph(force: backgroundStateChanged); } @override @@ -58,20 +59,23 @@ class _NetworkTopologyViewState extends State { } void _syncGraph({bool force = false}) { - if (!force && widget.isInBackground) { - return; - } + final now = DateTime.now(); + final shouldAnimate = _shouldAnimateConnections; + final animationStateChanged = + _lastShouldAnimateConnections != shouldAnimate; + + if (!force && widget.isInBackground && !animationStateChanged) return; if (!force && widget.reduceUpdates && + !animationStateChanged && _lastGraphSyncAt != null && - DateTime.now().difference(_lastGraphSyncAt!) < _reducedSyncInterval) { + now.difference(_lastGraphSyncAt!) < _reducedSyncInterval) { return; } final localIp = ServiceManager().networkConfigState.ipv4.value; final graphSignature = _calculateGraphSignature(widget.nodes, localIp); - final shouldAnimate = _shouldAnimateConnections; if (_controller != null && _lastGraphSignature == graphSignature && _lastShouldAnimateConnections == shouldAnimate) { @@ -102,14 +106,14 @@ class _NetworkTopologyViewState extends State { ); _lastGraphSignature = graphSignature; _lastShouldAnimateConnections = shouldAnimate; - _lastGraphSyncAt = DateTime.now(); + _lastGraphSyncAt = now; return; } _applyGraphDiff(model); _lastGraphSignature = graphSignature; _lastShouldAnimateConnections = shouldAnimate; - _lastGraphSyncAt = DateTime.now(); + _lastGraphSyncAt = now; } int _calculateGraphSignature(List nodes, String localIp) { @@ -419,7 +423,9 @@ class _NetworkTopologyViewState extends State { targetNodeId: hopId, targetPortId: 'in', animationEffect: - _shouldAnimateConnections ? ConnectionEffects.particles : null, + _shouldAnimateConnections + ? ConnectionEffects.particles + : null, label: ConnectionLabel(text: _formatLatencyLabel(hop.latencyMs)), ); } diff --git a/lib/shared/widgets/common/windows_controls.dart b/lib/shared/widgets/common/windows_controls.dart index f2488146..11d75c20 100644 --- a/lib/shared/widgets/common/windows_controls.dart +++ b/lib/shared/widgets/common/windows_controls.dart @@ -105,11 +105,8 @@ class _WindowControlsState extends State IconButton( icon: const Icon(Icons.remove), onPressed: () async { - - print('Minimize button was pressed!'); ServiceManager().uiState.setBackground(true); await windowManager.minimize(); - }, tooltip: '最小化', iconSize: 20,