106 lines
3.5 KiB
Dart
106 lines
3.5 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:package_info_plus/package_info_plus.dart';
|
||
import 'package:provider/provider.dart';
|
||
|
||
import 'auth/auth_screen.dart';
|
||
import 'auth/session_store.dart';
|
||
import 'camera/camera_screen.dart';
|
||
import 'container.dart';
|
||
import 'home/home_screen.dart';
|
||
import 'legal/terms_screen.dart';
|
||
import 'models/model_manager.dart';
|
||
import 'payment/paywall_screen.dart';
|
||
import 'update/update_checker.dart';
|
||
import 'update/update_screen.dart';
|
||
|
||
class ObserverApp extends StatelessWidget {
|
||
final AppContainer container;
|
||
|
||
const ObserverApp({super.key, required this.container});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return MultiProvider(
|
||
providers: [
|
||
Provider.value(value: container),
|
||
Provider.value(value: container.sessionStore),
|
||
ChangeNotifierProvider.value(value: container.authViewModel),
|
||
ChangeNotifierProvider.value(value: container.homeViewModel),
|
||
ChangeNotifierProvider.value(value: container.paywallViewModel),
|
||
],
|
||
child: MaterialApp(
|
||
title: '视野',
|
||
theme: ThemeData(
|
||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
|
||
),
|
||
initialRoute: '/gate',
|
||
routes: {
|
||
'/gate': (_) => const StartupGate(),
|
||
'/terms': (_) => const TermsScreen(),
|
||
'/login': (_) => const AuthScreen(),
|
||
'/home': (_) => const HomeScreen(),
|
||
'/paywall': (_) => const PaywallScreen(),
|
||
'/camera': (_) => const CameraScreen(),
|
||
},
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 启动门卫:无登录 token → 登录页;已登录 → 主界面(到期状态由主界面展示)
|
||
class StartupGate extends StatefulWidget {
|
||
const StartupGate({super.key});
|
||
|
||
@override
|
||
State<StartupGate> createState() => _StartupGateState();
|
||
}
|
||
|
||
class _StartupGateState extends State<StartupGate> {
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_check();
|
||
}
|
||
|
||
Future<void> _check() async {
|
||
// 首次启动强制协议;同意后不再展示(拒绝则退出应用)
|
||
final accepted = await TermsScreen.readAccepted();
|
||
if (!mounted) return;
|
||
if (accepted != '1') {
|
||
Navigator.of(context).pushReplacementNamed('/terms');
|
||
return;
|
||
}
|
||
// 版本更新检查(公开接口,无需登录态;仅 Android):服务器版本高于已装
|
||
// 版本即强制更新,弹全屏阻塞页 → 浏览器下载 APK 手动安装
|
||
// (2026-09-03:App 内安装在小米等 ROM 失败,改浏览器下载)
|
||
final info = await UpdateChecker().fetch();
|
||
final current = await PackageInfo.fromPlatform();
|
||
if (!mounted) return;
|
||
final session = context.read<SessionStore>();
|
||
if (UpdateChecker.needsUpdate(info.version, current.version)) {
|
||
Navigator.of(context).pushReplacement(MaterialPageRoute(
|
||
builder: (_) => UpdateScreen(
|
||
version: info.version,
|
||
url: UpdateChecker.downloadUrl(),
|
||
notes: info.notes,
|
||
),
|
||
));
|
||
return;
|
||
}
|
||
final token = await session.readToken();
|
||
if (!mounted) return;
|
||
// 模型热更新:后台拉取模型目录并下载/更新各数据集模型(不阻塞启动,
|
||
// 相机页打开前若未就绪会兜底等待;未下载模型时仅预览)
|
||
ModelManager.instance.refresh();
|
||
Navigator.of(context)
|
||
.pushReplacementNamed(token == null ? '/login' : '/home');
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return const Scaffold(
|
||
body: Center(child: CircularProgressIndicator()),
|
||
);
|
||
}
|
||
}
|