Files
system-design/software-copyright/06-writech-app-mobile/main.dart
T
2026-03-22 15:24:40 +08:00

341 lines
9.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 自然写互动课堂手机端应用软件 V1.0
/// APP入口 - Flutter应用主入口与全局初始化
///
/// 功能说明:
/// 1. Flutter应用初始化(引擎绑定、错误处理)
/// 2. 全局依赖注入(GetIt服务定位器)
/// 3. 推送通知初始化(APNs / FCM
/// 4. 用户认证状态恢复
/// 5. 多主题支持(浅色/深色/护眼模式)
/// 6. 国际化配置(中文/English
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// 全局服务定位器实例
final GetIt getIt = GetIt.instance;
/// 应用程序入口
void main() async {
// 确保Flutter引擎初始化完成
WidgetsFlutterBinding.ensureInitialized();
// 设置全局错误处理(捕获未处理的Flutter框架错误)
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details);
_reportError(details.exception, details.stack);
};
// 初始化全局依赖
await _initDependencies();
// 设置系统UI样式(状态栏透明)
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
));
// 设置屏幕方向(手机端仅支持竖屏)
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
// 运行应用(包裹Zone错误处理)
runZonedGuarded(() {
runApp(const WritechMobileApp());
}, (error, stackTrace) {
_reportError(error, stackTrace);
});
}
/// 初始化全局依赖注入
/// 注册所有服务层单例(API、WebSocket、BLE、本地存储)
Future<void> _initDependencies() async {
// 共享偏好设置(用户配置持久化)
final prefs = await SharedPreferences.getInstance();
getIt.registerSingleton<SharedPreferences>(prefs);
// 注册API服务(云平台REST API通信)
getIt.registerLazySingleton<ApiService>(() => ApiService());
// 注册WebSocket服务(实时通知推送)
getIt.registerLazySingleton<WebSocketService>(() => WebSocketService());
// 注册BLE蓝牙服务(教师端连接点阵笔)
getIt.registerLazySingleton<BleService>(() => BleService());
// 注册本地数据仓库(SQLite缓存)
getIt.registerLazySingleton<LocalRepository>(() => LocalRepository());
// 初始化推送通知
await _initPushNotification();
}
/// 初始化推送通知服务
/// iOS使用APNsAndroid使用FCM
Future<void> _initPushNotification() async {
// 请求通知权限(iOS需要显式请求)
if (Platform.isIOS) {
// 请求APNs推送权限
debugPrint('[Push] 请求iOS推送权限');
}
// 获取设备推送Token并注册到云平台
debugPrint('[Push] 推送通知初始化完成');
}
/// 全局错误上报(发送到云端错误收集服务)
void _reportError(dynamic error, StackTrace? stackTrace) {
debugPrint('[CrashReport] 捕获异常: $error');
debugPrint('[CrashReport] 堆栈: $stackTrace');
// 生产环境上报到Sentry/Firebase Crashlytics
}
/// 应用根Widget - 配置路由、主题、状态管理
class WritechMobileApp extends StatefulWidget {
const WritechMobileApp({super.key});
@override
State<WritechMobileApp> createState() => _WritechMobileAppState();
}
class _WritechMobileAppState extends State<WritechMobileApp>
with WidgetsBindingObserver {
/// 当前主题模式
ThemeMode _themeMode = ThemeMode.light;
/// 用户角色(教师/家长)决定显示的功能入口
String _userRole = 'teacher';
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_loadUserPreferences();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
/// 监听应用生命周期变化
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
// 前台恢复:重建WebSocket连接、刷新Token
debugPrint('[App] 应用回到前台');
getIt<WebSocketService>().reconnect();
break;
case AppLifecycleState.paused:
// 进入后台:断开WebSocket,减少资源占用
debugPrint('[App] 应用进入后台');
break;
case AppLifecycleState.detached:
// 应用销毁:清理所有资源
_cleanup();
break;
default:
break;
}
}
/// 加载用户偏好设置(主题、角色、语言等)
void _loadUserPreferences() {
final prefs = getIt<SharedPreferences>();
final themeName = prefs.getString('theme_mode') ?? 'light';
setState(() {
_themeMode = themeName == 'dark' ? ThemeMode.dark : ThemeMode.light;
_userRole = prefs.getString('user_role') ?? 'teacher';
});
}
/// 清理全局资源
void _cleanup() {
getIt<WebSocketService>().disconnect();
getIt<BleService>().disconnectAll();
debugPrint('[App] 全局资源清理完成');
}
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
// 认证状态管理(登录/登出/Token刷新)
BlocProvider<AuthBloc>(create: (_) => AuthBloc()),
// 作业状态管理(列表/详情/提交)
BlocProvider<AssignmentBloc>(create: (_) => AssignmentBloc()),
// 消息状态管理(通知/家校沟通)
BlocProvider<MessageBloc>(create: (_) => MessageBloc()),
],
child: MaterialApp(
title: '自然写互动课堂',
debugShowCheckedModeBanner: false,
themeMode: _themeMode,
// 浅色主题
theme: _buildLightTheme(),
// 深色主题
darkTheme: _buildDarkTheme(),
// 路由配置
initialRoute: '/splash',
routes: _buildRoutes(),
),
);
}
/// 构建浅色主题
ThemeData _buildLightTheme() {
return ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF2196F3), // 品牌蓝色
brightness: Brightness.light,
),
fontFamily: 'NotoSansSC',
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
);
}
/// 构建深色主题
ThemeData _buildDarkTheme() {
return ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF2196F3),
brightness: Brightness.dark,
),
fontFamily: 'NotoSansSC',
);
}
/// 构建应用路由表
Map<String, WidgetBuilder> _buildRoutes() {
return {
'/splash': (_) => const SplashScreen(),
'/login': (_) => const LoginPage(),
'/teacher_home': (_) => const TeacherHomePage(),
'/parent_home': (_) => const ParentHomePage(),
'/assignment_detail': (_) => const AssignmentDetailPage(),
'/stroke_replay': (_) => const StrokeReplayPage(),
'/report_detail': (_) => const ReportDetailPage(),
'/ble_connect': (_) => const BleConnectPage(),
'/settings': (_) => const SettingsPage(),
};
}
}
/* ========== 占位Widget声明(各页面在独立文件中实现) ========== */
/// 启动页 - 展示Logo + 自动登录检查
class SplashScreen extends StatelessWidget {
const SplashScreen({super.key});
@override
Widget build(BuildContext context) => const Scaffold(body: Center(child: Text('自然写')));
}
/// 登录页占位
class LoginPage extends StatelessWidget {
const LoginPage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/// 教师首页占位
class TeacherHomePage extends StatelessWidget {
const TeacherHomePage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/// 家长首页占位
class ParentHomePage extends StatelessWidget {
const ParentHomePage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/// 作业详情占位
class AssignmentDetailPage extends StatelessWidget {
const AssignmentDetailPage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/// 笔迹回放占位
class StrokeReplayPage extends StatelessWidget {
const StrokeReplayPage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/// 学情报告详情占位
class ReportDetailPage extends StatelessWidget {
const ReportDetailPage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/// BLE蓝牙连接占位
class BleConnectPage extends StatelessWidget {
const BleConnectPage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/// 设置页占位
class SettingsPage extends StatelessWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
/* ========== Bloc占位声明 ========== */
/// 认证Bloc - 管理登录/登出/Token刷新状态
class AuthBloc extends Cubit<int> {
AuthBloc() : super(0);
}
/// 作业Bloc - 管理作业列表/详情/提交状态
class AssignmentBloc extends Cubit<int> {
AssignmentBloc() : super(0);
}
/// 消息Bloc - 管理通知和家校沟通消息
class MessageBloc extends Cubit<int> {
MessageBloc() : super(0);
}
/* ========== 服务占位声明 ========== */
/// API服务占位
class ApiService {}
/// WebSocket服务占位
class WebSocketService {
void reconnect() {}
void disconnect() {}
}
/// BLE服务占位
class BleService {
void disconnectAll() {}
}
/// 本地仓库占位
class LocalRepository {}