2025-11-19 17:43:04 +08:00
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
2024-05-08 05:03:49 -04:00
|
|
|
import 'package:flutter/material.dart';
|
2025-10-22 17:58:29 +08:00
|
|
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
2024-05-08 05:03:49 -04:00
|
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
2024-08-23 04:21:46 -04:00
|
|
|
import 'package:vaani/api/server_provider.dart';
|
|
|
|
|
import 'package:vaani/db/storage.dart';
|
2024-10-03 05:54:29 -04:00
|
|
|
import 'package:vaani/features/logging/core/logger.dart';
|
2026-01-05 17:29:24 +08:00
|
|
|
import 'package:vaani/features/player/core/init.dart';
|
2025-12-06 17:50:37 +08:00
|
|
|
import 'package:vaani/features/player/providers/abs_provider.dart';
|
2025-11-28 17:25:33 +08:00
|
|
|
import 'package:vaani/features/settings/api_settings_provider.dart';
|
|
|
|
|
import 'package:vaani/features/settings/app_settings_provider.dart';
|
2025-11-19 17:43:04 +08:00
|
|
|
import 'package:vaani/framework.dart';
|
2025-10-22 17:58:29 +08:00
|
|
|
import 'package:vaani/generated/l10n.dart';
|
2025-11-14 16:34:42 +08:00
|
|
|
import 'package:vaani/globals.dart';
|
2024-08-23 04:21:46 -04:00
|
|
|
import 'package:vaani/router/router.dart';
|
2024-10-05 10:01:08 -04:00
|
|
|
import 'package:vaani/theme/providers/system_theme_provider.dart';
|
2025-11-06 17:09:09 +08:00
|
|
|
import 'package:window_manager/window_manager.dart';
|
2024-05-08 05:03:49 -04:00
|
|
|
|
|
|
|
|
void main() async {
|
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
2025-10-20 17:20:08 +08:00
|
|
|
|
2025-11-23 01:25:57 +08:00
|
|
|
final container = ProviderContainer();
|
2025-11-19 17:43:04 +08:00
|
|
|
_runPlatformSpecificCode();
|
|
|
|
|
|
2025-11-14 16:34:42 +08:00
|
|
|
// Configure the App Metadata
|
|
|
|
|
await initialize();
|
|
|
|
|
|
2024-06-28 06:01:56 -04:00
|
|
|
// Configure the root Logger
|
2024-10-03 05:54:29 -04:00
|
|
|
await initLogging();
|
2024-05-08 05:03:49 -04:00
|
|
|
|
|
|
|
|
// initialize the storage
|
|
|
|
|
await initStorage();
|
2024-05-09 23:23:50 -04:00
|
|
|
|
2024-09-25 03:13:42 -04:00
|
|
|
// initialize audio player
|
2026-01-05 17:29:24 +08:00
|
|
|
await configurePlayer();
|
|
|
|
|
// await container.read(configurePlayerProvider.future);
|
2024-05-17 11:04:20 -04:00
|
|
|
// run the app
|
2024-05-09 23:23:50 -04:00
|
|
|
runApp(
|
2025-11-23 01:25:57 +08:00
|
|
|
UncontrolledProviderScope(
|
|
|
|
|
container: container,
|
2025-12-04 16:55:25 +08:00
|
|
|
child: Framework(AbsApp()),
|
2024-05-08 05:03:49 -04:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-19 17:43:04 +08:00
|
|
|
Future<void> _runPlatformSpecificCode() async {
|
|
|
|
|
if (kIsWeb) return;
|
|
|
|
|
switch (Platform.operatingSystem) {
|
|
|
|
|
case 'android':
|
|
|
|
|
break;
|
|
|
|
|
case 'ios':
|
|
|
|
|
break;
|
|
|
|
|
case 'linux':
|
|
|
|
|
break;
|
|
|
|
|
case 'macos':
|
|
|
|
|
break;
|
|
|
|
|
case 'windows':
|
|
|
|
|
// 初始化窗口管理器
|
|
|
|
|
await windowManager.ensureInitialized();
|
|
|
|
|
final windowOptions = WindowOptions(
|
|
|
|
|
minimumSize: Size(1050, 700),
|
|
|
|
|
center: true,
|
|
|
|
|
skipTaskbar: false,
|
|
|
|
|
);
|
|
|
|
|
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
|
|
|
|
await windowManager.setPreventClose(true);
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-14 16:34:42 +08:00
|
|
|
class AbsApp extends ConsumerWidget {
|
|
|
|
|
const AbsApp({super.key});
|
2024-05-08 05:03:49 -04:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
|
|
|
final servers = ref.watch(audiobookShelfServerProvider);
|
2025-12-24 18:02:24 +08:00
|
|
|
final activeUser =
|
|
|
|
|
ref.watch(apiSettingsProvider.select((v) => v.activeUser));
|
2024-05-08 05:03:49 -04:00
|
|
|
|
2025-12-24 18:02:24 +08:00
|
|
|
final needOnboarding = activeUser == null || servers.isEmpty;
|
2024-05-10 04:11:39 -04:00
|
|
|
|
2024-05-10 17:49:47 -04:00
|
|
|
if (needOnboarding) {
|
|
|
|
|
routerConfig.goNamed(Routes.onboarding.name);
|
|
|
|
|
}
|
2026-01-08 17:49:30 +08:00
|
|
|
final language = ref.watch(appSettingsProvider.select((v) => v.language));
|
|
|
|
|
final themeSettings =
|
|
|
|
|
ref.watch(appSettingsProvider.select((v) => v.themeSettings));
|
|
|
|
|
final currentBook = ref.watch(currentBookProvider);
|
|
|
|
|
final currentTheme = ref.watch(
|
|
|
|
|
CurrentThemeProvider(
|
|
|
|
|
highContrast: MediaQuery.of(context).highContrast,
|
|
|
|
|
id: currentBook?.libraryItemId,
|
2024-10-05 10:01:08 -04:00
|
|
|
),
|
|
|
|
|
);
|
2024-09-16 23:51:50 -04:00
|
|
|
try {
|
|
|
|
|
return MaterialApp.router(
|
2026-01-08 17:49:30 +08:00
|
|
|
locale: Locale(language),
|
2025-10-22 17:58:29 +08:00
|
|
|
localizationsDelegates: [
|
|
|
|
|
// 以下是其他代理
|
|
|
|
|
S.delegate, //String 资源的 本地化
|
|
|
|
|
GlobalMaterialLocalizations.delegate, //Material Widgets 的本地化
|
|
|
|
|
GlobalWidgetsLocalizations.delegate, //基础 Widgets 的本地化
|
|
|
|
|
GlobalCupertinoLocalizations.delegate,
|
|
|
|
|
],
|
|
|
|
|
supportedLocales: S.delegate.supportedLocales,
|
2026-01-08 17:49:30 +08:00
|
|
|
theme: currentTheme.$1,
|
|
|
|
|
darkTheme: currentTheme.$2,
|
2024-10-05 10:01:08 -04:00
|
|
|
themeMode: themeSettings.themeMode,
|
2024-09-16 23:51:50 -04:00
|
|
|
routerConfig: routerConfig,
|
2024-10-05 10:01:08 -04:00
|
|
|
themeAnimationCurve: Curves.easeInOut,
|
2025-12-05 17:59:13 +08:00
|
|
|
debugShowCheckedModeBanner: false,
|
2024-09-16 23:51:50 -04:00
|
|
|
);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
debugPrintStack(stackTrace: StackTrace.current, label: e.toString());
|
2024-10-05 21:02:14 -04:00
|
|
|
appLogger.severe(e.toString());
|
|
|
|
|
|
2024-09-16 23:51:50 -04:00
|
|
|
if (needOnboarding) {
|
|
|
|
|
routerConfig.goNamed(Routes.onboarding.name);
|
|
|
|
|
}
|
|
|
|
|
return const SizedBox.shrink();
|
|
|
|
|
}
|
2024-05-08 05:03:49 -04:00
|
|
|
}
|
|
|
|
|
}
|