mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-05-07 00:10:47 +00:00
Flutter already knows how to switch the theme automatically. No need to listen to onPlatformBrightnessChanged. This works on cold start. Works when app is running and system theme changes. And works when backup was done on different system theme and restore is being done on different system theme.
199 lines
7.2 KiB
Dart
199 lines
7.2 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'package:app_links/app_links.dart';
|
|
import 'package:bot_toast/bot_toast.dart';
|
|
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:intl/date_symbol_data_local.dart';
|
|
import 'package:isar/isar.dart';
|
|
import 'package:mangayomi/eval/model/m_bridge.dart';
|
|
import 'package:mangayomi/models/manga.dart';
|
|
import 'package:mangayomi/models/settings.dart';
|
|
import 'package:mangayomi/modules/more/data_and_storage/providers/storage_usage.dart';
|
|
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
|
import 'package:mangayomi/providers/l10n_providers.dart';
|
|
import 'package:mangayomi/providers/storage_provider.dart';
|
|
import 'package:mangayomi/router/router.dart';
|
|
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
|
|
import 'package:mangayomi/l10n/generated/app_localizations.dart';
|
|
import 'package:mangayomi/src/rust/frb_generated.dart';
|
|
import 'package:mangayomi/utils/url_protocol/api.dart';
|
|
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_provider.dart';
|
|
import 'package:media_kit/media_kit.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:window_manager/window_manager.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
late Isar isar;
|
|
WebViewEnvironment? webViewEnvironment;
|
|
void main(List<String> args) async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
if (Platform.isLinux && runWebViewTitleBarWidget(args)) return;
|
|
MediaKit.ensureInitialized();
|
|
await RustLib.init();
|
|
if (!(Platform.isAndroid || Platform.isIOS)) {
|
|
await windowManager.ensureInitialized();
|
|
}
|
|
if (Platform.isWindows) {
|
|
registerProtocolHandler("mangayomi");
|
|
}
|
|
if (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows) {
|
|
final availableVersion = await WebViewEnvironment.getAvailableVersion();
|
|
if (availableVersion != null) {
|
|
final document = await getApplicationDocumentsDirectory();
|
|
webViewEnvironment = await WebViewEnvironment.create(
|
|
settings: WebViewEnvironmentSettings(
|
|
userDataFolder: p.join(document.path, 'flutter_inappwebview'),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
isar = await StorageProvider().initDB(null, inspector: kDebugMode);
|
|
|
|
runApp(const ProviderScope(child: MyApp()));
|
|
unawaited(postLaunchInit()); // Defer non-essential async operations
|
|
}
|
|
|
|
Future<void> postLaunchInit() async {
|
|
await StorageProvider().requestPermission();
|
|
await StorageProvider().deleteBtDirectory();
|
|
}
|
|
|
|
class MyApp extends ConsumerStatefulWidget {
|
|
const MyApp({super.key});
|
|
|
|
@override
|
|
ConsumerState<MyApp> createState() => _MyAppState();
|
|
}
|
|
|
|
class _MyAppState extends ConsumerState<MyApp> {
|
|
late AppLinks _appLinks;
|
|
StreamSubscription<Uri>? _linkSubscription;
|
|
Uri? lastUri;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
initializeDateFormatting();
|
|
_initDeepLinks();
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
if (ref.read(clearChapterCacheOnAppLaunchStateProvider)) {
|
|
ref
|
|
.read(totalChapterCacheSizeStateProvider.notifier)
|
|
.clearCache(showToast: false);
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final followSystem = ref.watch(followSystemThemeStateProvider);
|
|
final forcedDark = ref.watch(themeModeStateProvider);
|
|
final themeMode =
|
|
followSystem
|
|
? ThemeMode.system
|
|
: (forcedDark ? ThemeMode.dark : ThemeMode.light);
|
|
final locale = ref.watch(l10nLocaleStateProvider);
|
|
final router = ref.watch(routerProvider);
|
|
|
|
return MaterialApp.router(
|
|
theme: ref.watch(lightThemeProvider),
|
|
darkTheme: ref.watch(darkThemeProvider),
|
|
themeMode: themeMode,
|
|
debugShowCheckedModeBanner: false,
|
|
locale: locale,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
builder: BotToastInit(),
|
|
routeInformationParser: router.routeInformationParser,
|
|
routerDelegate: router.routerDelegate,
|
|
routeInformationProvider: router.routeInformationProvider,
|
|
title: 'MangaYomi',
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_linkSubscription?.cancel();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _initDeepLinks() async {
|
|
_appLinks = AppLinks();
|
|
_linkSubscription = _appLinks.uriLinkStream.listen((uri) {
|
|
if (uri == lastUri) return; // Debouncing Deep Links
|
|
lastUri = uri;
|
|
switch (uri.host) {
|
|
case "add-repo":
|
|
final repoName = uri.queryParameters["repo_name"];
|
|
final repoUrl = uri.queryParameters["repo_url"];
|
|
final mangaRepoUrls = uri.queryParametersAll["manga_url"];
|
|
final animeRepoUrls = uri.queryParametersAll["anime_url"];
|
|
final novelRepoUrls = uri.queryParametersAll["novel_url"];
|
|
final context = navigatorKey.currentContext;
|
|
if (context == null || !context.mounted) return;
|
|
final l10n = context.l10n;
|
|
showDialog(
|
|
context: navigatorKey.currentContext!,
|
|
builder: (BuildContext context) {
|
|
return AlertDialog(
|
|
title: Text(l10n.add_repo),
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text("${l10n.name}: ${repoName ?? 'Unknown'}"),
|
|
const SizedBox(height: 8),
|
|
Text("URL: ${repoUrl ?? 'Unknown'}"),
|
|
],
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
child: Text(l10n.cancel),
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
),
|
|
FilledButton(
|
|
child: Text(l10n.add),
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
|
|
void addRepos(ItemType type, List<String>? urls) {
|
|
if (urls == null) return;
|
|
final current = ref.read(
|
|
extensionsRepoStateProvider(type),
|
|
);
|
|
final updated = [
|
|
...current,
|
|
...urls.map(
|
|
(e) => Repo(
|
|
name: repoName,
|
|
jsonUrl: e,
|
|
website: repoUrl,
|
|
),
|
|
),
|
|
];
|
|
ref
|
|
.read(extensionsRepoStateProvider(type).notifier)
|
|
.set(updated);
|
|
}
|
|
|
|
addRepos(ItemType.manga, mangaRepoUrls);
|
|
addRepos(ItemType.anime, animeRepoUrls);
|
|
addRepos(ItemType.novel, novelRepoUrls);
|
|
botToast(l10n.repo_added);
|
|
},
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
break;
|
|
default:
|
|
}
|
|
});
|
|
}
|
|
}
|