mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00

Add features to display current playing track information and support media controls on iOS. * **HomePlayerWidget.swift** - Add track title, artist name, and album art display in the HomePlayerWidget. - Update SimpleEntry struct to include trackTitle, artistName, and albumArt properties. - Modify placeholder, getSnapshot, and getTimeline methods to include new properties. - Update HomePlayerWidgetEntryView to display new track information. * **Info.plist** - Add support for media controls on the lock screen and control center. - Add integration with Siri for voice commands to control playback. * **main.dart** - Register the HomePlayerWidget for iOS by adding glanceProvider listener. * **glance.dart** - Add code to update the HomePlayerWidget with the current track information, including track title, artist name, and album art.
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/initializers.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/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_gen/gen_l10n/app_localizations.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(serverProvider, (_, __) {});
|
|
ref.listen(trayManagerProvider, (_, __) {});
|
|
ref.listen(glanceProvider, (_, __) {}); // Register the HomePlayerWidget for iOS
|
|
|
|
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(),
|
|
},
|
|
);
|
|
}
|
|
}
|