import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:sunny_mochi/app.dart'; import 'package:sunny_mochi/core/config/env.dart'; import 'package:sunny_mochi/core/crash/crash_reporter.dart'; import 'package:sunny_mochi/core/observability/sentry_setup.dart'; import 'package:sunny_mochi/core/observability/talker_setup.dart'; import 'package:sunny_mochi/core/storage/app_database.dart'; import 'package:sunny_mochi/core/sync/sync_service.dart'; import 'package:sunny_mochi/features/error_report/data/error_logger.dart'; import 'package:sunny_mochi/i18n/strings.g.dart'; import 'package:talker_riverpod_logger/talker_riverpod_logger.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); unawaited(LocaleSettings.useDeviceLocale()); // 1. 崩溃日志预初始化(必须在 Sentry 之前) await CrashReporter.preInit(); final pendingCrash = CrashReporter.consumePending(); // 2. Sentry 初始化(空 DSN 时直接 runApp) await SentrySetup.init( appRunner: () async { // 3. 挂载崩溃钩子 CrashReporter.installHooks(); appTalker.info('App boot · env=${Env.name} · mock=${Env.useMock}'); // 4. 打开加密 SQLite 数据库 final database = await AppDatabase.open(); runApp( TranslationProvider( child: ProviderScope( retry: (_, _) => null, overrides: [ appDatabaseProvider.overrideWithValue(database), pendingCrashProvider.overrideWithValue(pendingCrash), ], observers: [ if (Env.enableDevPanel) TalkerRiverpodObserver(talker: appTalker), ], child: const _SyncBootstrap(child: AppRoot()), ), ), ); }, ); } /// 在 ProviderScope 内启动 SyncService 和 ErrorLogger 清理。 class _SyncBootstrap extends ConsumerStatefulWidget { const _SyncBootstrap({required this.child}); final Widget child; @override ConsumerState<_SyncBootstrap> createState() => _SyncBootstrapState(); } class _SyncBootstrapState extends ConsumerState<_SyncBootstrap> { @override void initState() { super.initState(); unawaited(ref.read(syncServiceProvider).start()); unawaited(ref.read(errorLoggerProvider).pruneOld()); } @override void dispose() { unawaited(ref.read(syncServiceProvider).dispose()); super.dispose(); } @override Widget build(BuildContext context) => widget.child; } class AppRoot extends StatelessWidget { const AppRoot({super.key}); @override Widget build(BuildContext context) { // 设计基准 375pt(与 iOS JPScaleValue 一致;如设计方调整需同步) return const ScreenUtilInit( designSize: Size(375, 812), minTextAdapt: true, child: App(), ); } }