chore: 初始化脚手架 — sunny_mochi 企业级 Flutter 模板

Core 基础设施:Flavor 三包体系、Drift+SQLCipher 加密数据库
7 拦截器 Dio 网络栈、CrashReporter 崩溃日志、Sealed Failure 错误体系
5 色板主题系统、Auth 认证骨架(Clean Architecture)、Dev Panel、Mock Adapter

通过验证:flutter analyze(0 errors)、flutter test(全绿)、staging APK 74.8MB
This commit is contained in:
SkyJourney
2026-05-14 12:51:05 +08:00
commit 61017f1c39
204 changed files with 15386 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
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<void> 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(),
);
}
}