118 lines
3.9 KiB
Dart
118 lines
3.9 KiB
Dart
import 'dart:async';
|
||
import 'dart:io';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:maibu_satabot_v2/features/auth/presentation/bloc/app_user_cubit.dart';
|
||
import 'package:maibu_satabot_v2/core/infrastructure/logging/app_bloc_observer.dart';
|
||
import 'package:maibu_satabot_v2/core/logging/i_logger_service.dart';
|
||
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
|
||
import 'package:maibu_satabot_v2/features/auth/presentation/bloc/auth_cubit.dart';
|
||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart';
|
||
|
||
import 'core/di/injection.dart';
|
||
import 'core/network/base/i_connection.dart';
|
||
import 'features/auth/presentation/bloc/login_cubit.dart';
|
||
import 'features/connectivity/presentation/bloc/connectivity_cubit.dart';
|
||
import 'features/connectivity/presentation/bloc/connectivity_state.dart';
|
||
|
||
void main() async {
|
||
// 1. 使用 runZonedGuarded 捕获所有未处理的异步错误
|
||
runZonedGuarded(
|
||
() async {
|
||
WidgetsFlutterBinding.ensureInitialized();
|
||
|
||
// 2. 初始化依赖注入 (这里面应包含 ILoggerService 的注册)
|
||
await init();
|
||
|
||
// 3. 从 sl 中获取 logger 实例并初始化 Sentry
|
||
final logger = sl<ILoggerService>();
|
||
await logger.init();
|
||
|
||
// 4. 设置全局 Bloc 观察者,自动上报 Bloc 错误
|
||
Bloc.observer = AppBlocObserver(logger);
|
||
|
||
runApp(const MyApp());
|
||
},
|
||
(error, stack) {
|
||
// 5. 捕获顶级错误并上报
|
||
sl<ILoggerService>().captureException(error, stackTrace: stack);
|
||
},
|
||
);
|
||
}
|
||
|
||
class MyApp extends StatelessWidget {
|
||
const MyApp({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
sl<AuthCubit>().appStarted();
|
||
return MultiBlocProvider(
|
||
providers: [
|
||
//BlocProvider<LoginBloc>(create: (_) => sl<LoginBloc>()),
|
||
BlocProvider<AppUserCubit>(create: (_) => sl<AppUserCubit>()),
|
||
BlocProvider<LoginCubit>(create: (_) => sl<LoginCubit>()),
|
||
BlocProvider<DevicesCubit>(
|
||
create: (_) =>
|
||
sl<DevicesCubit>()
|
||
..fetchAllDevices(sl<AppUserCubit>().state.user!.username),
|
||
),
|
||
BlocProvider(create: (_) => sl<ConnectivityCubit>()),
|
||
],
|
||
child: MaterialApp.router(
|
||
title: 'Maibu Satabot',
|
||
theme: AppTheme.lightTheme,
|
||
routerConfig: sl<GoRouter>(),
|
||
builder: (context, child) {
|
||
return BlocListener<ConnectivityCubit, ConnectivityState>(
|
||
// 只有当状态真正变为 disconnected 时才弹出
|
||
listenWhen: (prev, curr) => prev.status != curr.status,
|
||
listener: (context, state) {
|
||
if (state.status == ConnectionStatus.disconnected) {
|
||
_showGlobalDisconnectDialog();
|
||
}
|
||
},
|
||
child: child, // child 就是当前路由显示的页面内容
|
||
);
|
||
},
|
||
),
|
||
|
||
);
|
||
}
|
||
|
||
// 全局断连提示弹窗
|
||
void _showGlobalDisconnectDialog() {
|
||
// 直接从全局变量获取真正的 Navigator Context
|
||
final context = rootNavigatorKey.currentContext;
|
||
|
||
if (context != null) {
|
||
showDialog(
|
||
context: context,
|
||
barrierDismissible: false,
|
||
builder: (context) => AlertDialog(
|
||
title: const Row(
|
||
children: [
|
||
Icon(Icons.warning, color: Colors.red),
|
||
SizedBox(width: 8),
|
||
Text("连接已断开"),
|
||
],
|
||
),
|
||
content: const Text("与服务器通信丢失,请检查网络连接。"),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () {
|
||
Navigator.of(context).pop(); // 关闭弹窗
|
||
// 如果需要,这里可以执行 context.go('/login');
|
||
},
|
||
child: const Text("知道了"),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
} else {
|
||
print("DEBUG: 弹窗失败,rootNavigatorKey.currentContext 为空");
|
||
}
|
||
}
|
||
}
|