mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
308 lines
11 KiB
Dart
308 lines
11 KiB
Dart
import 'dart:async';
|
|
import 'dart:ui';
|
|
|
|
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart' as material;
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_discord_rpc/flutter_discord_rpc.dart';
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
|
|
|
import 'package:home_widget/home_widget.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:local_notifier/local_notifier.dart';
|
|
import 'package:media_kit/media_kit.dart';
|
|
import 'package:metadata_god/metadata_god.dart';
|
|
import 'package:smtc_windows/smtc_windows.dart';
|
|
import 'package:spotube/collections/env.dart';
|
|
import 'package:spotube/collections/intents.dart';
|
|
import 'package:spotube/collections/routes.dart';
|
|
import 'package:spotube/hooks/configurators/use_close_behavior.dart';
|
|
import 'package:spotube/hooks/configurators/use_deep_linking.dart';
|
|
import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart';
|
|
import 'package:spotube/hooks/configurators/use_fix_window_stretching.dart';
|
|
import 'package:spotube/hooks/configurators/use_get_storage_perms.dart';
|
|
import 'package:spotube/hooks/configurators/use_has_touch.dart';
|
|
import 'package:spotube/models/database/database.dart';
|
|
import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart';
|
|
import 'package:spotube/provider/audio_player/audio_player_streams.dart';
|
|
import 'package:spotube/provider/database/database.dart';
|
|
import 'package:spotube/provider/glance/glance.dart';
|
|
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
|
|
import 'package:spotube/provider/server/bonsoir.dart';
|
|
import 'package:spotube/provider/server/server.dart';
|
|
import 'package:spotube/provider/tray_manager/tray_manager.dart';
|
|
import 'package:spotube/l10n/l10n.dart';
|
|
import 'package:spotube/provider/connect/clients.dart';
|
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
|
import 'package:spotube/services/cli/cli.dart';
|
|
import 'package:spotube/services/kv_store/encrypted_kv_store.dart';
|
|
import 'package:spotube/services/kv_store/kv_store.dart';
|
|
import 'package:spotube/services/logger/logger.dart';
|
|
import 'package:spotube/services/wm_tools/wm_tools.dart';
|
|
import 'package:spotube/utils/migrations/sandbox.dart';
|
|
import 'package:spotube/utils/platform.dart';
|
|
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
|
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
|
import 'package:timezone/data/latest.dart' as tz;
|
|
import 'package:window_manager/window_manager.dart';
|
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
|
import 'package:yt_dlp_dart/yt_dlp_dart.dart';
|
|
import 'package:flutter_new_pipe_extractor/flutter_new_pipe_extractor.dart';
|
|
|
|
Future<void> main(List<String> rawArgs) async {
|
|
if (rawArgs.contains("web_view_title_bar")) {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
if (runWebViewTitleBarWidget(rawArgs)) {
|
|
return;
|
|
}
|
|
}
|
|
final arguments = await startCLI(rawArgs);
|
|
AppLogger.initialize(arguments["verbose"]);
|
|
|
|
AppLogger.runZoned(() async {
|
|
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
// await registerWindowsScheme("spotify");
|
|
|
|
tz.initializeTimeZones();
|
|
|
|
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
|
|
|
MediaKit.ensureInitialized();
|
|
|
|
await migrateMacOsFromSandboxToNoSandbox();
|
|
|
|
// force High Refresh Rate on some Android devices (like One Plus)
|
|
if (kIsAndroid) {
|
|
await FlutterDisplayMode.setHighRefreshRate();
|
|
await NewPipeExtractor.init();
|
|
}
|
|
|
|
if (!kIsWeb) {
|
|
MetadataGod.initialize();
|
|
}
|
|
|
|
await KVStoreService.initialize();
|
|
|
|
if (kIsDesktop) {
|
|
await windowManager.setPreventClose(true);
|
|
await YtDlp.instance
|
|
.setBinaryLocation(
|
|
KVStoreService.getYoutubeEnginePath(YoutubeClientEngine.ytDlp) ??
|
|
"yt-dlp${kIsWindows ? '.exe' : ''}",
|
|
)
|
|
.catchError((e, stack) => null);
|
|
await FlutterDiscordRPC.initialize(Env.discordAppId);
|
|
}
|
|
|
|
if (kIsWindows) {
|
|
await SMTCWindows.initialize();
|
|
}
|
|
|
|
await EncryptedKvStoreService.initialize();
|
|
|
|
final database = AppDatabase();
|
|
|
|
if (kIsDesktop) {
|
|
await localNotifier.setup(appName: "Spotube");
|
|
await WindowManagerTools.initialize();
|
|
}
|
|
|
|
if (kIsIOS) {
|
|
HomeWidget.setAppGroupId("group.spotube_home_player_widget");
|
|
}
|
|
|
|
runApp(
|
|
ProviderScope(
|
|
overrides: [
|
|
databaseProvider.overrideWith((ref) => database),
|
|
],
|
|
observers: const [
|
|
AppLoggerProviderObserver(),
|
|
],
|
|
child: const Spotube(),
|
|
),
|
|
);
|
|
});
|
|
}
|
|
|
|
class Spotube extends HookConsumerWidget {
|
|
const Spotube({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, ref) {
|
|
final themeMode =
|
|
ref.watch(userPreferencesProvider.select((s) => s.themeMode));
|
|
final locale = ref.watch(userPreferencesProvider.select((s) => s.locale));
|
|
final accentMaterialColor =
|
|
ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme));
|
|
final router = useMemoized(() => AppRouter(ref), []);
|
|
final hasTouchSupport = useHasTouch();
|
|
|
|
ref.listen(audioPlayerStreamListenersProvider, (_, __) {});
|
|
ref.listen(bonsoirProvider, (_, __) {});
|
|
ref.listen(connectClientsProvider, (_, __) {});
|
|
ref.listen(metadataPluginsProvider, (_, __) {});
|
|
ref.listen(metadataPluginProvider, (_, __) {});
|
|
ref.listen(serverProvider, (_, __) {});
|
|
ref.listen(trayManagerProvider, (_, __) {});
|
|
|
|
useFixWindowStretching();
|
|
useDisableBatteryOptimizations();
|
|
useDeepLinking(ref, router);
|
|
useCloseBehavior(ref);
|
|
useGetStoragePermissions(ref);
|
|
|
|
useEffect(() {
|
|
FlutterNativeSplash.remove();
|
|
|
|
if (kIsMobile) {
|
|
HomeWidget.registerInteractivityCallback(glanceBackgroundCallback);
|
|
}
|
|
|
|
return () {
|
|
/// For enabling hot reload for audio player
|
|
if (!kDebugMode) return;
|
|
audioPlayer.dispose();
|
|
};
|
|
}, []);
|
|
|
|
return ShadcnApp.router(
|
|
supportedLocales: L10n.all,
|
|
locale: locale.languageCode == "system" ? null : locale,
|
|
localizationsDelegates: const [
|
|
AppLocalizations.delegate,
|
|
GlobalMaterialLocalizations.delegate,
|
|
GlobalWidgetsLocalizations.delegate,
|
|
GlobalCupertinoLocalizations.delegate,
|
|
],
|
|
routerConfig: router.config(),
|
|
debugShowCheckedModeBanner: false,
|
|
title: 'Spotube',
|
|
builder: (context, child) {
|
|
child = ScrollConfiguration(
|
|
behavior: ScrollConfiguration.of(context).copyWith(
|
|
dragDevices: hasTouchSupport
|
|
? {
|
|
PointerDeviceKind.touch,
|
|
PointerDeviceKind.stylus,
|
|
PointerDeviceKind.invertedStylus,
|
|
}
|
|
: null,
|
|
),
|
|
child: child!,
|
|
);
|
|
|
|
if (kIsLinux) {
|
|
child = DragToResizeArea(
|
|
resizeEdgeSize: 2.5,
|
|
child: child,
|
|
);
|
|
}
|
|
|
|
return child;
|
|
},
|
|
scaling: const AdaptiveScaling(1),
|
|
theme: ThemeData(
|
|
radius: .5,
|
|
iconTheme: const IconThemeProperties(),
|
|
colorScheme:
|
|
colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.light) ??
|
|
ColorSchemes.lightOrange(),
|
|
surfaceOpacity: .8,
|
|
surfaceBlur: 10,
|
|
),
|
|
darkTheme: ThemeData(
|
|
radius: .5,
|
|
iconTheme: const IconThemeProperties(),
|
|
colorScheme:
|
|
colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.dark) ??
|
|
ColorSchemes.darkOrange(),
|
|
surfaceOpacity: .8,
|
|
surfaceBlur: 10,
|
|
),
|
|
materialTheme: material.ThemeData(
|
|
brightness: switch (themeMode) {
|
|
ThemeMode.system => MediaQuery.platformBrightnessOf(context),
|
|
ThemeMode.light => Brightness.light,
|
|
ThemeMode.dark => Brightness.dark,
|
|
},
|
|
splashFactory: material.NoSplash.splashFactory,
|
|
appBarTheme: const material.AppBarTheme(
|
|
surfaceTintColor: Colors.transparent,
|
|
scrolledUnderElevation: 0,
|
|
shadowColor: Colors.transparent,
|
|
elevation: 0,
|
|
),
|
|
),
|
|
themeMode: themeMode,
|
|
shortcuts: {
|
|
...WidgetsApp.defaultShortcuts.map((key, value) {
|
|
return MapEntry(
|
|
LogicalKeySet.fromSet(key.triggers?.toSet() ?? {}),
|
|
value,
|
|
);
|
|
}),
|
|
LogicalKeySet(LogicalKeyboardKey.space): PlayPauseIntent(ref),
|
|
LogicalKeySet(LogicalKeyboardKey.comma, LogicalKeyboardKey.control):
|
|
NavigationIntent(router, "/settings"),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit1,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.browse),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit2,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.search),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit3,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.lyrics),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit4,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.userPlaylists),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit5,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.userArtists),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit6,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.userAlbums),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit7,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.userLocalLibrary),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.digit8,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): HomeTabIntent(router, tab: HomeTabs.userDownloads),
|
|
LogicalKeySet(
|
|
LogicalKeyboardKey.keyW,
|
|
LogicalKeyboardKey.control,
|
|
LogicalKeyboardKey.shift,
|
|
): CloseAppIntent(),
|
|
},
|
|
actions: {
|
|
...WidgetsApp.defaultActions,
|
|
PlayPauseIntent: PlayPauseAction(),
|
|
NavigationIntent: NavigationAction(),
|
|
HomeTabIntent: HomeTabAction(),
|
|
CloseAppIntent: CloseAppAction(),
|
|
},
|
|
);
|
|
}
|
|
}
|