diff --git a/frontend/mining-app/lib/presentation/widgets/main_shell.dart b/frontend/mining-app/lib/presentation/widgets/main_shell.dart index 47dac9be..8a6bd8a2 100644 --- a/frontend/mining-app/lib/presentation/widgets/main_shell.dart +++ b/frontend/mining-app/lib/presentation/widgets/main_shell.dart @@ -1,19 +1,82 @@ +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import '../../core/router/routes.dart'; import '../../core/constants/app_colors.dart'; +import '../../core/updater/update_service.dart'; +import '../../core/updater/channels/self_hosted_updater.dart'; -class MainShell extends StatelessWidget { +class MainShell extends StatefulWidget { final Widget child; const MainShell({super.key, required this.child}); + @override + State createState() => _MainShellState(); +} + +class _MainShellState extends State with WidgetsBindingObserver { + /// 下次允许检查更新的时间(static 防止 widget rebuild 重置) + static DateTime? _nextCheckAllowedTime; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance.addPostFrameCallback((_) { + _checkForUpdateIfNeeded(); + }); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (state == AppLifecycleState.resumed) { + _checkForUpdateIfNeeded(); + } + } + + Future _checkForUpdateIfNeeded() async { + final now = DateTime.now(); + + // 如果从未检查过,或者已过冷却时间,则检查 + if (_nextCheckAllowedTime == null || now.isAfter(_nextCheckAllowedTime!)) { + // 设置下次允许检查时间(90-300秒随机间隔) + final randomSeconds = 90 + Random().nextInt(211); + _nextCheckAllowedTime = now.add(Duration(seconds: randomSeconds)); + + // 延迟3秒,避免启动时干扰用户 + await Future.delayed(const Duration(seconds: 3)); + if (!mounted) return; + + try { + final result = await UpdateService.instance.checkForUpdate(); + if (!mounted) return; + + if (result.hasUpdate && result.versionInfo != null) { + await SelfHostedUpdater.show( + context, + versionInfo: result.versionInfo!, + isForceUpdate: result.versionInfo!.isForceUpdate, + ); + } + } catch (e) { + debugPrint('[MainShell] 检查更新失败: $e'); + } + } + } + @override Widget build(BuildContext context) { final isDark = AppColors.isDark(context); return Scaffold( - body: child, + body: widget.child, bottomNavigationBar: Container( decoration: BoxDecoration( color: AppColors.cardOf(context),