fix(linux): tray icon not showing #541

upgrade old packages
This commit is contained in:
Kingkor Roy Tirtho 2024-04-17 22:20:13 +06:00
parent 6907f9c756
commit 7ac791757a
48 changed files with 840 additions and 722 deletions

View File

@ -1,4 +1,4 @@
{ {
"flutterSdkVersion": "3.19.1", "flutterSdkVersion": "3.19.5",
"flavors": {} "flavors": {}
} }

View File

@ -4,7 +4,7 @@ on:
inputs: inputs:
version: version:
description: Version to publish (x.x.x) description: Version to publish (x.x.x)
default: 3.1.0 default: 3.6.0
required: true required: true
dry_run: dry_run:
description: Dry run description: Dry run

View File

@ -26,7 +26,7 @@ on:
default: true default: true
env: env:
FLUTTER_VERSION: '3.19.1' FLUTTER_VERSION: '3.19.5'
jobs: jobs:
windows: windows:

View File

@ -1,5 +1,5 @@
import 'package:envied/envied.dart'; import 'package:envied/envied.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:spotube/utils/platform.dart';
part 'env.g.dart'; part 'env.g.dart';
@ -26,7 +26,7 @@ abstract class Env {
static final String _enableUpdateChecker = _Env._enableUpdateChecker; static final String _enableUpdateChecker = _Env._enableUpdateChecker;
static bool get enableUpdateChecker => static bool get enableUpdateChecker =>
DesktopTools.platform.isFlatpak || _enableUpdateChecker == "1"; kIsFlatpak || _enableUpdateChecker == "1";
static String discordAppId = "1176718791388975124"; static String discordAppId = "1176718791388975124";
} }

View File

@ -1,9 +1,10 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:spotube/utils/platform.dart';
import 'package:win32_registry/win32_registry.dart'; import 'package:win32_registry/win32_registry.dart';
Future<void> registerWindowsScheme(String scheme) async { Future<void> registerWindowsScheme(String scheme) async {
if (!DesktopTools.platform.isWindows) return; if (!kIsWindows) return;
String appPath = Platform.resolvedExecutable; String appPath = Platform.resolvedExecutable;
String protocolRegKey = 'Software\\Classes\\$scheme'; String protocolRegKey = 'Software\\Classes\\$scheme';

View File

@ -1,6 +1,5 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@ -24,6 +23,7 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart
import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/provider/volume_provider.dart'; import 'package:spotube/provider/volume_provider.dart';
import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/platform.dart';
import 'package:window_manager/window_manager.dart';
class BottomPlayer extends HookConsumerWidget { class BottomPlayer extends HookConsumerWidget {
BottomPlayer({super.key}); BottomPlayer({super.key});
@ -95,19 +95,19 @@ class BottomPlayer extends HookConsumerWidget {
tooltip: context.l10n.mini_player, tooltip: context.l10n.mini_player,
icon: const Icon(SpotubeIcons.miniPlayer), icon: const Icon(SpotubeIcons.miniPlayer),
onPressed: () async { onPressed: () async {
final prevSize = if (!kIsDesktop) return;
await DesktopTools.window.getSize();
await DesktopTools.window.setMinimumSize( final prevSize = await windowManager.getSize();
await windowManager.setMinimumSize(
const Size(300, 300), const Size(300, 300),
); );
await DesktopTools.window.setAlwaysOnTop(true); await windowManager.setAlwaysOnTop(true);
if (!kIsLinux) { if (!kIsLinux) {
await DesktopTools.window.setHasShadow(false); await windowManager.setHasShadow(false);
} }
await DesktopTools.window await windowManager
.setAlignment(Alignment.topRight); .setAlignment(Alignment.topRight);
await DesktopTools.window await windowManager.setSize(const Size(400, 500));
.setSize(const Size(400, 500));
await Future.delayed( await Future.delayed(
const Duration(milliseconds: 100), const Duration(milliseconds: 100),
() async { () async {

View File

@ -1,7 +1,7 @@
import 'package:draggable_scrollbar/draggable_scrollbar.dart'; import 'package:draggable_scrollbar/draggable_scrollbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:spotube/utils/platform.dart';
class InterScrollbar extends HookWidget { class InterScrollbar extends HookWidget {
final Widget child; final Widget child;
@ -15,7 +15,7 @@ class InterScrollbar extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (DesktopTools.platform.isDesktop) return child; if (kIsDesktop) return child;
return DraggableScrollbar.semicircle( return DraggableScrollbar.semicircle(
controller: controller, controller: controller,

View File

@ -7,7 +7,8 @@ import 'package:titlebar_buttons/titlebar_buttons.dart';
import 'dart:math'; import 'dart:math';
import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:window_manager/window_manager.dart';
class PageWindowTitleBar extends StatefulHookConsumerWidget class PageWindowTitleBar extends StatefulHookConsumerWidget
implements PreferredSizeWidget { implements PreferredSizeWidget {
@ -89,7 +90,7 @@ class _PageWindowTitleBarState extends ConsumerState<PageWindowTitleBar> {
final systemTitleBar = final systemTitleBar =
ref.read(userPreferencesProvider.select((s) => s.systemTitleBar)); ref.read(userPreferencesProvider.select((s) => s.systemTitleBar));
if (kIsDesktop && !systemTitleBar) { if (kIsDesktop && !systemTitleBar) {
DesktopTools.window.startDragging(); windowManager.startDragging();
} }
} }
@ -107,11 +108,7 @@ class _PageWindowTitleBarState extends ConsumerState<PageWindowTitleBar> {
return SliverPadding( return SliverPadding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: DesktopTools.platform.isMacOS && left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0,
hasFullscreen &&
hasLeadingOrCanPop
? 65
: 0,
), ),
sliver: SliverAppBar( sliver: SliverAppBar(
leading: widget.leading, leading: widget.leading,
@ -149,11 +146,7 @@ class _PageWindowTitleBarState extends ConsumerState<PageWindowTitleBar> {
onVerticalDragStart: onDrag, onVerticalDragStart: onDrag,
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: DesktopTools.platform.isMacOS && left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0,
hasFullscreen &&
hasLeadingOrCanPop
? 65
: 0,
), ),
child: AppBar( child: AppBar(
leading: widget.leading, leading: widget.leading,
@ -193,12 +186,12 @@ class WindowTitleBarButtons extends HookConsumerWidget {
const type = ThemeType.auto; const type = ThemeType.auto;
Future<void> onClose() async { Future<void> onClose() async {
await DesktopTools.window.close(); await windowManager.close();
} }
useEffect(() { useEffect(() {
if (kIsDesktop) { if (kIsDesktop) {
DesktopTools.window.isMaximized().then((value) { windowManager.isMaximized().then((value) {
isMaximized.value = value; isMaximized.value = value;
}); });
} }
@ -235,14 +228,14 @@ class WindowTitleBarButtons extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
MinimizeWindowButton( MinimizeWindowButton(
onPressed: DesktopTools.window.minimize, onPressed: windowManager.minimize,
colors: colors, colors: colors,
), ),
if (isMaximized.value != true) if (isMaximized.value != true)
MaximizeWindowButton( MaximizeWindowButton(
colors: colors, colors: colors,
onPressed: () { onPressed: () {
DesktopTools.window.maximize(); windowManager.maximize();
isMaximized.value = true; isMaximized.value = true;
}, },
) )
@ -250,7 +243,7 @@ class WindowTitleBarButtons extends HookConsumerWidget {
RestoreWindowButton( RestoreWindowButton(
colors: colors, colors: colors,
onPressed: () { onPressed: () {
DesktopTools.window.unmaximize(); windowManager.unmaximize();
isMaximized.value = false; isMaximized.value = false;
}, },
), ),
@ -270,16 +263,16 @@ class WindowTitleBarButtons extends HookConsumerWidget {
children: [ children: [
DecoratedMinimizeButton( DecoratedMinimizeButton(
type: type, type: type,
onPressed: DesktopTools.window.minimize, onPressed: windowManager.minimize,
), ),
DecoratedMaximizeButton( DecoratedMaximizeButton(
type: type, type: type,
onPressed: () async { onPressed: () async {
if (await DesktopTools.window.isMaximized()) { if (await windowManager.isMaximized()) {
await DesktopTools.window.unmaximize(); await windowManager.unmaximize();
isMaximized.value = false; isMaximized.value = false;
} else { } else {
await DesktopTools.window.maximize(); await windowManager.maximize();
isMaximized.value = true; isMaximized.value = true;
} }
}, },

View File

@ -1,7 +1,7 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/assets.gen.dart';
import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/image/universal_image.dart';
@ -12,6 +12,7 @@ import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/hooks/utils/use_palette_color.dart'; import 'package:spotube/hooks/utils/use_palette_color.dart';
import 'package:spotube/utils/platform.dart';
class TrackViewFlexHeader extends HookConsumerWidget { class TrackViewFlexHeader extends HookConsumerWidget {
const TrackViewFlexHeader({super.key}); const TrackViewFlexHeader({super.key});
@ -53,7 +54,7 @@ class TrackViewFlexHeader extends HookConsumerWidget {
floating: false, floating: false,
pinned: true, pinned: true,
expandedHeight: 450, expandedHeight: 450,
automaticallyImplyLeading: DesktopTools.platform.isMobile, automaticallyImplyLeading: kIsMobile,
backgroundColor: palette.color, backgroundColor: palette.color,
title: isExpanded ? null : Text(props.title, style: headingStyle), title: isExpanded ? null : Text(props.title, style: headingStyle),
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sliver_tools/sliver_tools.dart'; import 'package:sliver_tools/sliver_tools.dart';
@ -8,6 +8,7 @@ import 'package:spotube/components/shared/page_window_title_bar.dart';
import 'package:spotube/components/shared/tracks_view/sections/header/flexible_header.dart'; import 'package:spotube/components/shared/tracks_view/sections/header/flexible_header.dart';
import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body.dart';
import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
import 'package:spotube/utils/platform.dart';
class TrackView extends HookConsumerWidget { class TrackView extends HookConsumerWidget {
const TrackView({super.key}); const TrackView({super.key});
@ -18,7 +19,7 @@ class TrackView extends HookConsumerWidget {
final controller = useScrollController(); final controller = useScrollController();
return Scaffold( return Scaffold(
appBar: DesktopTools.platform.isDesktop appBar: kIsDesktop
? const PageWindowTitleBar( ? const PageWindowTitleBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
foregroundColor: Colors.white, foregroundColor: Colors.white,

View File

@ -1,29 +1,31 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/hooks/configurators/use_window_listener.dart'; import 'package:spotube/hooks/configurators/use_window_listener.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
// ignore: depend_on_referenced_packages
import 'package:local_notifier/local_notifier.dart'; import 'package:local_notifier/local_notifier.dart';
import 'package:spotube/utils/platform.dart';
import 'package:window_manager/window_manager.dart';
final closeNotification = DesktopTools.createNotification( final closeNotification = !kIsDesktop
title: 'Spotube', ? null
message: 'Running in background. Minimized to System Tray', : (LocalNotification(
actions: [ title: 'Spotube',
LocalNotificationAction(text: 'Close The App'), body: 'Running in background. Minimized to System Tray',
], actions: [
)?..onClickAction = (value) { LocalNotificationAction(text: 'Close The App'),
exit(0); ],
}; )..onClickAction = (value) {
exit(0);
});
void useCloseBehavior(WidgetRef ref) { void useCloseBehavior(WidgetRef ref) {
useWindowListener( useWindowListener(
onWindowClose: () async { onWindowClose: () async {
final preferences = ref.read(userPreferencesProvider); final preferences = ref.read(userPreferencesProvider);
if (preferences.closeBehavior == CloseBehavior.minimizeToTray) { if (preferences.closeBehavior == CloseBehavior.minimizeToTray) {
await DesktopTools.window.hide(); await windowManager.hide();
closeNotification?.show(); closeNotification?.show();
} else { } else {
exit(0); exit(0);

View File

@ -7,7 +7,7 @@ import 'package:spotube/collections/routes.dart';
import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/provider/spotify_provider.dart';
import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
import 'package:flutter_sharing_intent/model/sharing_file.dart'; import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:spotube/utils/platform.dart';
final appLinks = AppLinks(); final appLinks = AppLinks();
final linkStream = appLinks.allStringLinkStream.asBroadcastStream(); final linkStream = appLinks.allStringLinkStream.asBroadcastStream();
@ -53,7 +53,7 @@ void useDeepLinking(WidgetRef ref) {
StreamSubscription? mediaStream; StreamSubscription? mediaStream;
if (DesktopTools.platform.isMobile) { if (kIsMobile) {
FlutterSharingIntent.instance.getInitialSharing().then(uriListener); FlutterSharingIntent.instance.getInitialSharing().then(uriListener);
mediaStream = mediaStream =

View File

@ -1,12 +1,12 @@
import 'package:disable_battery_optimization/disable_battery_optimization.dart'; import 'package:disable_battery_optimization/disable_battery_optimization.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:spotube/hooks/utils/use_async_effect.dart'; import 'package:spotube/hooks/utils/use_async_effect.dart';
import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/services/kv_store/kv_store.dart';
import 'package:spotube/utils/platform.dart';
void useDisableBatteryOptimizations() { void useDisableBatteryOptimizations() {
useAsyncEffect(() async { useAsyncEffect(() async {
if (!DesktopTools.platform.isAndroid || if (!kIsAndroid || KVStoreService.askedForBatteryOptimization) return;
KVStoreService.askedForBatteryOptimization) return;
await DisableBatteryOptimization.showDisableBatteryOptimizationSettings(); await DisableBatteryOptimization.showDisableBatteryOptimizationSettings();

View File

@ -1,17 +1,18 @@
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:spotube/components/library/user_local_tracks.dart'; import 'package:spotube/components/library/user_local_tracks.dart';
import 'package:spotube/hooks/utils/use_async_effect.dart'; import 'package:spotube/hooks/utils/use_async_effect.dart';
import 'package:spotube/utils/platform.dart';
void useGetStoragePermissions(WidgetRef ref) { void useGetStoragePermissions(WidgetRef ref) {
final context = useContext(); final context = useContext();
useAsyncEffect( useAsyncEffect(
() async { () async {
if (!DesktopTools.platform.isMobile) return; if (!kIsMobile) return;
final androidInfo = await DeviceInfoPlugin().androidInfo; final androidInfo = await DeviceInfoPlugin().androidInfo;

View File

@ -1,128 +0,0 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/intents.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
void useInitSysTray(WidgetRef ref) {
final context = useContext();
final systemTray = useRef<SystemTray?>(null);
final initializeMenu = useCallback(() async {
systemTray.value?.destroy();
final playlist = ref.read(proxyPlaylistProvider);
final playlistQueue = ref.read(proxyPlaylistProvider.notifier);
final preferences = ref.read(userPreferencesProvider);
if (!preferences.showSystemTrayIcon) {
await systemTray.value?.destroy();
systemTray.value = null;
return;
}
final enabled = !playlist.isFetching;
systemTray.value = await DesktopTools.createSystemTrayMenu(
title: DesktopTools.platform.isWindows ? "Spotube" : "",
iconPath: "assets/spotube-logo.png",
windowsIconPath: "assets/spotube-logo.ico",
items: [
MenuItemLabel(
label: "Show/Hide",
name: "show-hide",
onClicked: (item) async {
if (await DesktopTools.window.isVisible()) {
await DesktopTools.window.hide();
} else {
await DesktopTools.window.show();
}
},
),
MenuSeparator(),
MenuItemLabel(
label: "Play/Pause",
name: "play-pause",
enabled: enabled,
onClicked: (_) async {
Actions.maybeInvoke<PlayPauseIntent>(
context, PlayPauseIntent(ref)) ??
PlayPauseAction().invoke(PlayPauseIntent(ref));
},
),
MenuItemLabel(
label: "Next",
name: "next",
enabled: enabled && (playlist.tracks.length) > 1,
onClicked: (p0) async {
await playlistQueue.next();
},
),
MenuItemLabel(
label: "Previous",
name: "previous",
enabled: enabled && (playlist.tracks.length) > 1,
onClicked: (p0) async {
await playlistQueue.previous();
},
),
MenuSeparator(),
MenuItemLabel(
label: "Quit",
name: "quit",
onClicked: (item) async {
exit(0);
},
),
],
onEvent: (event, tray) async {
if (DesktopTools.platform.isWindows) {
switch (event) {
case SystemTrayEvent.click:
await DesktopTools.window.show();
break;
case SystemTrayEvent.rightClick:
await tray.popUpContextMenu();
break;
default:
}
} else {
switch (event) {
case SystemTrayEvent.rightClick:
await DesktopTools.window.show();
break;
case SystemTrayEvent.click:
await tray.popUpContextMenu();
break;
default:
}
}
},
);
}, [ref]);
useReassemble(initializeMenu);
ref.listen<ProxyPlaylist?>(
proxyPlaylistProvider,
(previous, next) {
initializeMenu();
},
);
ref.listen(
userPreferencesProvider.select((s) => s.showSystemTrayIcon),
(previous, next) {
initializeMenu();
},
);
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((_) {
initializeMenu();
});
return () async {
await systemTray.value?.destroy();
};
}, [initializeMenu]);
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:spotube/utils/platform.dart';
import 'package:window_manager/window_manager.dart';
class CallbackWindowListener implements WindowListener { class CallbackWindowListener implements WindowListener {
final VoidCallback? _onWindowClose; final VoidCallback? _onWindowClose;
@ -154,6 +156,8 @@ void useWindowListener({
VoidCallback? onWindowEvent, VoidCallback? onWindowEvent,
}) { }) {
useEffect(() { useEffect(() {
if (!kIsDesktop) return null;
final listener = CallbackWindowListener( final listener = CallbackWindowListener(
onWindowClose: onWindowClose, onWindowClose: onWindowClose,
onWindowFocus: onWindowFocus, onWindowFocus: onWindowFocus,
@ -172,9 +176,9 @@ void useWindowListener({
onWindowUndocked: onWindowUndocked, onWindowUndocked: onWindowUndocked,
onWindowEvent: onWindowEvent, onWindowEvent: onWindowEvent,
); );
DesktopTools.window.addListener(listener); windowManager.addListener(listener);
return () { return () {
DesktopTools.window.removeListener(listener); windowManager.removeListener(listener);
}; };
}, [ }, [
onWindowClose, onWindowClose,

View File

@ -4,11 +4,11 @@ import 'package:device_preview/device_preview.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:local_notifier/local_notifier.dart';
import 'package:media_kit/media_kit.dart'; import 'package:media_kit/media_kit.dart';
import 'package:metadata_god/metadata_god.dart'; import 'package:metadata_god/metadata_god.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -19,6 +19,7 @@ import 'package:spotube/hooks/configurators/use_close_behavior.dart';
import 'package:spotube/hooks/configurators/use_deep_linking.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_disable_battery_optimizations.dart';
import 'package:spotube/hooks/configurators/use_get_storage_perms.dart'; import 'package:spotube/hooks/configurators/use_get_storage_perms.dart';
import 'package:spotube/provider/tray_manager/tray_manager.dart';
import 'package:spotube/l10n/l10n.dart'; import 'package:spotube/l10n/l10n.dart';
import 'package:spotube/models/logger.dart'; import 'package:spotube/models/logger.dart';
import 'package:spotube/models/skip_segment.dart'; import 'package:spotube/models/skip_segment.dart';
@ -31,15 +32,17 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart
import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/cli/cli.dart'; import 'package:spotube/services/cli/cli.dart';
import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/services/kv_store/kv_store.dart';
import 'package:spotube/services/wm_tools/wm_tools.dart';
import 'package:spotube/themes/theme.dart'; import 'package:spotube/themes/theme.dart';
import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/persisted_state_notifier.dart';
import 'package:spotube/utils/platform.dart';
import 'package:system_theme/system_theme.dart'; import 'package:system_theme/system_theme.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:spotube/hooks/configurators/use_init_sys_tray.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/data/latest.dart' as tz;
import 'package:window_manager/window_manager.dart';
Future<void> main(List<String> rawArgs) async { Future<void> main(List<String> rawArgs) async {
final arguments = await startCLI(rawArgs); final arguments = await startCLI(rawArgs);
@ -55,12 +58,12 @@ Future<void> main(List<String> rawArgs) async {
MediaKit.ensureInitialized(); MediaKit.ensureInitialized();
// force High Refresh Rate on some Android devices (like One Plus) // force High Refresh Rate on some Android devices (like One Plus)
if (DesktopTools.platform.isAndroid) { if (kIsAndroid) {
await FlutterDisplayMode.setHighRefreshRate(); await FlutterDisplayMode.setHighRefreshRate();
} }
if (DesktopTools.platform.isDesktop) { if (kIsDesktop) {
await DesktopTools.window.setPreventClose(true); await windowManager.setPreventClose(true);
} }
await SystemTheme.accentColor.load(); await SystemTheme.accentColor.load();
@ -69,7 +72,7 @@ Future<void> main(List<String> rawArgs) async {
MetadataGod.initialize(); MetadataGod.initialize();
} }
if (DesktopTools.platform.isWindows || DesktopTools.platform.isLinux) { if (kIsWindows || kIsLinux) {
DiscordRPC.initialize(); DiscordRPC.initialize();
} }
@ -101,14 +104,10 @@ Future<void> main(List<String> rawArgs) async {
path: hiveCacheDir, path: hiveCacheDir,
); );
await DesktopTools.ensureInitialized( if (kIsDesktop) {
DesktopWindowOptions( await localNotifier.setup(appName: "Spotube");
hideTitleBar: true, await WindowManagerTools.initialize();
title: "Spotube", }
backgroundColor: Colors.transparent,
minimumSize: const Size(300, 700),
),
);
Catcher2( Catcher2(
enableLogger: arguments["verbose"], enableLogger: arguments["verbose"],
@ -189,9 +188,9 @@ class SpotubeState extends ConsumerState<Spotube> {
ref.listen(playbackServerProvider, (_, __) {}); ref.listen(playbackServerProvider, (_, __) {});
ref.listen(connectServerProvider, (_, __) {}); ref.listen(connectServerProvider, (_, __) {});
ref.listen(connectClientsProvider, (_, __) {}); ref.listen(connectClientsProvider, (_, __) {});
ref.listen(trayManagerProvider, (_, __) {});
useDisableBatteryOptimizations(); useDisableBatteryOptimizations();
useInitSysTray(ref);
useDeepLinking(ref); useDeepLinking(ref);
useCloseBehavior(ref); useCloseBehavior(ref);
useGetStoragePermissions(ref); useGetStoragePermissions(ref);
@ -233,9 +232,7 @@ class SpotubeState extends ConsumerState<Spotube> {
builder: (context, child) { builder: (context, child) {
return DevicePreview.appBuilder( return DevicePreview.appBuilder(
context, context,
DesktopTools.platform.isDesktop && !DesktopTools.platform.isMacOS kIsDesktop && !kIsMacOS ? DragToResizeArea(child: child!) : child,
? DragToResizeArea(child: child!)
: child,
); );
}, },
themeMode: themeMode, themeMode: themeMode,

View File

@ -12,7 +12,7 @@ part of 'connect.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
WebSocketLoadEventData _$WebSocketLoadEventDataFromJson( WebSocketLoadEventData _$WebSocketLoadEventDataFromJson(
Map<String, dynamic> json) { Map<String, dynamic> json) {

View File

@ -12,7 +12,7 @@ part of 'home_feed.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
SpotifySectionPlaylist _$SpotifySectionPlaylistFromJson( SpotifySectionPlaylist _$SpotifySectionPlaylistFromJson(
Map<String, dynamic> json) { Map<String, dynamic> json) {

View File

@ -12,7 +12,7 @@ part of 'recommendation_seeds.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc /// @nodoc
mixin _$GeneratePlaylistProviderInput { mixin _$GeneratePlaylistProviderInput {

View File

@ -12,7 +12,7 @@ import 'package:spotube/components/shared/waypoint.dart';
import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/provider/spotify/spotify.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:spotube/utils/platform.dart';
class GenrePlaylistsPage extends HookConsumerWidget { class GenrePlaylistsPage extends HookConsumerWidget {
final Category category; final Category category;
@ -27,7 +27,7 @@ class GenrePlaylistsPage extends HookConsumerWidget {
final scrollController = useScrollController(); final scrollController = useScrollController();
return Scaffold( return Scaffold(
appBar: DesktopTools.platform.isDesktop appBar: kIsDesktop
? const PageWindowTitleBar( ? const PageWindowTitleBar(
leading: BackButton(color: Colors.white), leading: BackButton(color: Colors.white),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@ -53,12 +53,12 @@ class GenrePlaylistsPage extends HookConsumerWidget {
controller: scrollController, controller: scrollController,
slivers: [ slivers: [
SliverAppBar( SliverAppBar(
automaticallyImplyLeading: DesktopTools.platform.isMobile, automaticallyImplyLeading: kIsMobile,
expandedHeight: mediaQuery.mdAndDown ? 200 : 150, expandedHeight: mediaQuery.mdAndDown ? 200 : 150,
title: const Text(""), title: const Text(""),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
centerTitle: DesktopTools.platform.isDesktop, centerTitle: kIsDesktop,
title: Text( title: Text(
category.name!, category.name!,
style: Theme.of(context).textTheme.headlineMedium?.copyWith( style: Theme.of(context).textTheme.headlineMedium?.copyWith(

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -18,6 +17,7 @@ import 'package:spotube/pages/lyrics/synced_lyrics.dart';
import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/authentication_provider.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/platform.dart';
import 'package:window_manager/window_manager.dart';
class MiniLyricsPage extends HookConsumerWidget { class MiniLyricsPage extends HookConsumerWidget {
final Size prevSize; final Size prevSize;
@ -36,9 +36,11 @@ class MiniLyricsPage extends HookConsumerWidget {
final showLyrics = useState(true); final showLyrics = useState(true);
useEffect(() { useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((_) async { if (kIsDesktop) {
wasMaximized.value = await DesktopTools.window.isMaximized(); WidgetsBinding.instance.addPostFrameCallback((_) async {
}); wasMaximized.value = await windowManager.isMaximized();
});
}
return null; return null;
}, []); }, []);
@ -112,11 +114,13 @@ class MiniLyricsPage extends HookConsumerWidget {
areaActive.value = true; areaActive.value = true;
hoverMode.value = false; hoverMode.value = false;
await DesktopTools.window.setSize( if (kIsDesktop) {
showLyrics.value await windowManager.setSize(
? const Size(400, 500) showLyrics.value
: const Size(400, 150), ? const Size(400, 500)
); : const Size(400, 150),
);
}
}, },
), ),
IconButton( IconButton(
@ -135,33 +139,34 @@ class MiniLyricsPage extends HookConsumerWidget {
hoverMode.value = !hoverMode.value; hoverMode.value = !hoverMode.value;
}, },
), ),
FutureBuilder( if (kIsDesktop)
future: DesktopTools.window.isAlwaysOnTop(), FutureBuilder(
builder: (context, snapshot) { future: windowManager.isAlwaysOnTop(),
return IconButton( builder: (context, snapshot) {
tooltip: context.l10n.always_on_top, return IconButton(
icon: Icon( tooltip: context.l10n.always_on_top,
snapshot.data == true icon: Icon(
? SpotubeIcons.pinOn snapshot.data == true
: SpotubeIcons.pinOff, ? SpotubeIcons.pinOn
), : SpotubeIcons.pinOff,
style: ButtonStyle( ),
foregroundColor: snapshot.data == true style: ButtonStyle(
? MaterialStateProperty.all( foregroundColor: snapshot.data == true
theme.colorScheme.primary) ? MaterialStateProperty.all(
: null, theme.colorScheme.primary)
), : null,
onPressed: snapshot.data == null ),
? null onPressed: snapshot.data == null
: () async { ? null
await DesktopTools.window.setAlwaysOnTop( : () async {
snapshot.data == true ? false : true, await windowManager.setAlwaysOnTop(
); snapshot.data == true ? false : true,
update(); );
}, update();
); },
}, );
), },
),
], ],
), ),
), ),
@ -243,19 +248,20 @@ class MiniLyricsPage extends HookConsumerWidget {
tooltip: context.l10n.exit_mini_player, tooltip: context.l10n.exit_mini_player,
icon: const Icon(SpotubeIcons.maximize), icon: const Icon(SpotubeIcons.maximize),
onPressed: () async { onPressed: () async {
if (!kIsDesktop) return;
try { try {
await DesktopTools.window await windowManager
.setMinimumSize(const Size(300, 700)); .setMinimumSize(const Size(300, 700));
await DesktopTools.window.setAlwaysOnTop(false); await windowManager.setAlwaysOnTop(false);
if (wasMaximized.value) { if (wasMaximized.value) {
await DesktopTools.window.maximize(); await windowManager.maximize();
} else { } else {
await DesktopTools.window.setSize(prevSize); await windowManager.setSize(prevSize);
} }
await DesktopTools.window await windowManager.setAlignment(Alignment.center);
.setAlignment(Alignment.center);
if (!kIsLinux) { if (!kIsLinux) {
await DesktopTools.window.setHasShadow(true); await windowManager.setHasShadow(true);
} }
await Future.delayed( await Future.delayed(
const Duration(milliseconds: 200)); const Duration(milliseconds: 200));

View File

@ -2,7 +2,6 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@ -21,6 +20,7 @@ import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/connectivity_adapter.dart'; import 'package:spotube/services/connectivity_adapter.dart';
import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/persisted_state_notifier.dart';
import 'package:spotube/utils/platform.dart';
const rootPaths = { const rootPaths = {
"/": 0, "/": 0,
@ -206,7 +206,7 @@ class RootApp extends HookConsumerWidget {
), ),
extendBody: true, extendBody: true,
drawerScrimColor: Colors.transparent, drawerScrimColor: Colors.transparent,
endDrawer: DesktopTools.platform.isDesktop endDrawer: kIsDesktop
? Container( ? Container(
constraints: const BoxConstraints(maxWidth: 800), constraints: const BoxConstraints(maxWidth: 800),
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
@ -8,6 +7,7 @@ import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart';
import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/utils/platform.dart';
class SettingsDesktopSection extends HookConsumerWidget { class SettingsDesktopSection extends HookConsumerWidget {
const SettingsDesktopSection({super.key}); const SettingsDesktopSection({super.key});
@ -53,7 +53,7 @@ class SettingsDesktopSection extends HookConsumerWidget {
value: preferences.systemTitleBar, value: preferences.systemTitleBar,
onChanged: preferencesNotifier.setSystemTitleBar, onChanged: preferencesNotifier.setSystemTitleBar,
), ),
if (!DesktopTools.platform.isMacOS) if (!kIsMacOS)
SwitchListTile( SwitchListTile(
secondary: const Icon(SpotubeIcons.discord), secondary: const Icon(SpotubeIcons.discord),
title: Text(context.l10n.discord_rich_presence), title: Text(context.l10n.discord_rich_presence),

View File

@ -1,13 +1,13 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:file_selector/file_selector.dart'; import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/settings/section_card_with_heading.dart'; import 'package:spotube/components/settings/section_card_with_heading.dart';
import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/context.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/utils/platform.dart';
class SettingsDownloadsSection extends HookConsumerWidget { class SettingsDownloadsSection extends HookConsumerWidget {
const SettingsDownloadsSection({super.key}); const SettingsDownloadsSection({super.key});
@ -18,7 +18,7 @@ class SettingsDownloadsSection extends HookConsumerWidget {
final preferences = ref.watch(userPreferencesProvider); final preferences = ref.watch(userPreferencesProvider);
final pickDownloadLocation = useCallback(() async { final pickDownloadLocation = useCallback(() async {
if (DesktopTools.platform.isMobile || DesktopTools.platform.isMacOS) { if (kIsMobile || kIsMacOS) {
final dirStr = await FilePicker.platform.getDirectoryPath( final dirStr = await FilePicker.platform.getDirectoryPath(
initialDirectory: preferences.downloadLocation, initialDirectory: preferences.downloadLocation,
); );

View File

@ -1,6 +1,5 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart';
@ -14,6 +13,7 @@ import 'package:spotube/pages/settings/sections/downloads.dart';
import 'package:spotube/pages/settings/sections/language_region.dart'; import 'package:spotube/pages/settings/sections/language_region.dart';
import 'package:spotube/pages/settings/sections/playback.dart'; import 'package:spotube/pages/settings/sections/playback.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/utils/platform.dart';
class SettingsPage extends HookConsumerWidget { class SettingsPage extends HookConsumerWidget {
const SettingsPage({super.key}); const SettingsPage({super.key});
@ -45,8 +45,7 @@ class SettingsPage extends HookConsumerWidget {
const SettingsAppearanceSection(), const SettingsAppearanceSection(),
const SettingsPlaybackSection(), const SettingsPlaybackSection(),
const SettingsDownloadsSection(), const SettingsDownloadsSection(),
if (DesktopTools.platform.isDesktop) if (kIsDesktop) const SettingsDesktopSection(),
const SettingsDesktopSection(),
if (!kIsWeb) const SettingsDevelopersSection(), if (!kIsWeb) const SettingsDevelopersSection(),
const SettingsAboutSection(), const SettingsAboutSection(),
Center( Center(

View File

@ -1,21 +1,19 @@
import 'package:dart_discord_rpc/dart_discord_rpc.dart'; import 'package:dart_discord_rpc/dart_discord_rpc.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/collections/env.dart'; import 'package:spotube/collections/env.dart';
import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/artist_simple.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/utils/platform.dart';
class Discord extends ChangeNotifier { class Discord extends ChangeNotifier {
final DiscordRPC? discordRPC; final DiscordRPC? discordRPC;
final bool isEnabled; final bool isEnabled;
Discord(this.isEnabled) Discord(this.isEnabled)
: discordRPC = (DesktopTools.platform.isWindows || : discordRPC = (kIsWindows || kIsLinux) && isEnabled
DesktopTools.platform.isLinux) &&
isEnabled
? DiscordRPC(applicationId: Env.discordAppId) ? DiscordRPC(applicationId: Env.discordAppId)
: null { : null {
discordRPC?.start(autoRegister: true); discordRPC?.start(autoRegister: true);

View File

@ -0,0 +1,79 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/tray_manager/tray_menu.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/utils/platform.dart';
import 'package:tray_manager/tray_manager.dart';
import 'package:window_manager/window_manager.dart';
class SystemTrayManager with TrayListener {
final Ref ref;
final bool enabled;
SystemTrayManager(
this.ref, {
required this.enabled,
}) {
initialize();
}
Future<void> initialize() async {
if (!kIsDesktop) return;
if (enabled) {
await trayManager.setIcon(
kIsWindows
? 'assets/spotube-logo.ico'
: kIsFlatpak
? 'com.github.KRTirtho.Spotube.png'
: 'assets/spotube-logo.png',
);
trayManager.addListener(this);
} else {
await trayManager.destroy();
}
}
void dispose() {
trayManager.removeListener(this);
}
@override
onTrayIconMouseDown() {
if (kIsWindows) {
windowManager.show();
} else {
trayManager.popUpContextMenu();
}
}
@override
onTrayIconRightMouseDown() {
if (!kIsWindows) {
windowManager.show();
} else {
trayManager.popUpContextMenu();
}
}
}
final trayManagerProvider = Provider(
(ref) {
final enabled = ref.watch(
userPreferencesProvider.select((s) => s.showSystemTrayIcon),
);
ref.listen(trayMenuProvider, (_, menu) {
if (!enabled || !kIsDesktop) return;
trayManager.setContextMenu(menu);
});
final manager = SystemTrayManager(
ref,
enabled: enabled,
);
ref.onDispose(manager.dispose);
return manager;
},
);

View File

@ -0,0 +1,108 @@
import 'dart:io';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
import 'package:spotube/services/audio_player/loop_mode.dart';
import 'package:tray_manager/tray_manager.dart';
import 'package:window_manager/window_manager.dart';
final audioPlayerLoopMode = StreamProvider<PlaybackLoopMode>((ref) {
return audioPlayer.loopModeStream;
});
final audioPlayerShuffleMode = StreamProvider<bool>((ref) {
return audioPlayer.shuffledStream;
});
final audioPlayerPlaying = StreamProvider<bool>((ref) {
return audioPlayer.playingStream;
});
final trayMenuProvider = Provider((ref) {
final playlistNotifier = ref.watch(proxyPlaylistProvider.notifier);
final isPlaybackPlaying =
ref.watch(proxyPlaylistProvider.select((s) => s.activeTrack != null));
final isLoopOne =
ref.watch(audioPlayerLoopMode).asData?.value == PlaybackLoopMode.one;
final isShuffled = ref.watch(audioPlayerShuffleMode).asData?.value ?? false;
final isPlaying = ref.watch(audioPlayerPlaying).asData?.value ?? false;
return Menu(
items: [
MenuItem(
label: "Show/Hide Window",
onClick: (menuItem) async {
if (await windowManager.isVisible()) {
await windowManager.hide();
} else {
await windowManager.focus();
await windowManager.show();
}
},
),
MenuItem.separator(),
MenuItem(
label: isPlaying ? "Pause" : "Play",
disabled: !isPlaybackPlaying,
onClick: (menuItem) async {
if (audioPlayer.isPlaying) {
await audioPlayer.pause();
} else {
await audioPlayer.resume();
}
},
),
MenuItem(
label: "Next",
disabled: !isPlaybackPlaying,
onClick: (menuItem) {
playlistNotifier.next();
},
),
MenuItem(
label: "Previous",
disabled: !isPlaybackPlaying,
onClick: (menuItem) {
playlistNotifier.previous();
},
),
MenuItem.submenu(
label: "Playback",
submenu: Menu(
items: [
MenuItem(
label: "Repeat",
checked: isLoopOne,
onClick: (menuItem) {
audioPlayer.setLoopMode(
isLoopOne ? PlaybackLoopMode.none : PlaybackLoopMode.one,
);
},
),
MenuItem(
label: "Shuffle",
checked: isShuffled,
onClick: (menuItem) {
audioPlayer.setShuffle(!isShuffled);
},
),
MenuItem.separator(),
MenuItem(
label: "Stop",
onClick: (menuItem) {
playlistNotifier.stop();
},
),
],
),
),
MenuItem.separator(),
MenuItem(
label: "Quit",
onClick: (menuItem) {
exit(0);
},
),
],
);
});

View File

@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
@ -15,6 +14,7 @@ import 'package:spotube/services/sourced_track/enums.dart';
import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/persisted_state_notifier.dart';
import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/platform.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:window_manager/window_manager.dart';
class UserPreferencesNotifier extends PersistedStateNotifier<UserPreferences> { class UserPreferencesNotifier extends PersistedStateNotifier<UserPreferences> {
final Ref ref; final Ref ref;
@ -103,8 +103,8 @@ class UserPreferencesNotifier extends PersistedStateNotifier<UserPreferences> {
void setSystemTitleBar(bool isSystemTitleBar) { void setSystemTitleBar(bool isSystemTitleBar) {
state = state.copyWith(systemTitleBar: isSystemTitleBar); state = state.copyWith(systemTitleBar: isSystemTitleBar);
if (DesktopTools.platform.isDesktop) { if (kIsDesktop) {
DesktopTools.window.setTitleBarStyle( windowManager.setTitleBarStyle(
isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden,
); );
} }
@ -151,8 +151,8 @@ class UserPreferencesNotifier extends PersistedStateNotifier<UserPreferences> {
); );
} }
if (DesktopTools.platform.isDesktop) { if (kIsDesktop) {
await DesktopTools.window.setTitleBarStyle( await windowManager.setTitleBarStyle(
state.systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, state.systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden,
); );
} }

View File

@ -62,10 +62,10 @@ class UserPreferences with _$UserPreferences {
@Default(false) bool amoledDarkTheme, @Default(false) bool amoledDarkTheme,
@Default(true) bool checkUpdate, @Default(true) bool checkUpdate,
@Default(false) bool normalizeAudio, @Default(false) bool normalizeAudio,
@Default(true) bool showSystemTrayIcon, @Default(false) bool showSystemTrayIcon,
@Default(false) bool skipNonMusic, @Default(false) bool skipNonMusic,
@Default(false) bool systemTitleBar, @Default(false) bool systemTitleBar,
@Default(CloseBehavior.minimizeToTray) CloseBehavior closeBehavior, @Default(CloseBehavior.close) CloseBehavior closeBehavior,
@Default(SpotubeColor(0xFF2196F3, name: "Blue")) @Default(SpotubeColor(0xFF2196F3, name: "Blue"))
@JsonKey( @JsonKey(
fromJson: UserPreferences._accentColorSchemeFromJson, fromJson: UserPreferences._accentColorSchemeFromJson,

View File

@ -12,7 +12,7 @@ part of 'user_preferences_state.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
UserPreferences _$UserPreferencesFromJson(Map<String, dynamic> json) { UserPreferences _$UserPreferencesFromJson(Map<String, dynamic> json) {
return _UserPreferences.fromJson(json); return _UserPreferences.fromJson(json);
@ -415,10 +415,10 @@ class _$UserPreferencesImpl implements _UserPreferences {
this.amoledDarkTheme = false, this.amoledDarkTheme = false,
this.checkUpdate = true, this.checkUpdate = true,
this.normalizeAudio = false, this.normalizeAudio = false,
this.showSystemTrayIcon = true, this.showSystemTrayIcon = false,
this.skipNonMusic = false, this.skipNonMusic = false,
this.systemTitleBar = false, this.systemTitleBar = false,
this.closeBehavior = CloseBehavior.minimizeToTray, this.closeBehavior = CloseBehavior.close,
@JsonKey( @JsonKey(
fromJson: UserPreferences._accentColorSchemeFromJson, fromJson: UserPreferences._accentColorSchemeFromJson,
toJson: UserPreferences._accentColorSchemeToJson, toJson: UserPreferences._accentColorSchemeToJson,

View File

@ -16,12 +16,12 @@ _$UserPreferencesImpl _$$UserPreferencesImplFromJson(
amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false, amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false,
checkUpdate: json['checkUpdate'] as bool? ?? true, checkUpdate: json['checkUpdate'] as bool? ?? true,
normalizeAudio: json['normalizeAudio'] as bool? ?? false, normalizeAudio: json['normalizeAudio'] as bool? ?? false,
showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? true, showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? false,
skipNonMusic: json['skipNonMusic'] as bool? ?? false, skipNonMusic: json['skipNonMusic'] as bool? ?? false,
systemTitleBar: json['systemTitleBar'] as bool? ?? false, systemTitleBar: json['systemTitleBar'] as bool? ?? false,
closeBehavior: closeBehavior:
$enumDecodeNullable(_$CloseBehaviorEnumMap, json['closeBehavior']) ?? $enumDecodeNullable(_$CloseBehaviorEnumMap, json['closeBehavior']) ??
CloseBehavior.minimizeToTray, CloseBehavior.close,
accentColorScheme: UserPreferences._accentColorSchemeReadValue( accentColorScheme: UserPreferences._accentColorSchemeReadValue(
json, 'accentColorScheme') == json, 'accentColorScheme') ==
null null

View File

@ -101,7 +101,7 @@ abstract class AudioPlayerInterface {
return _mkPlayer.state.completed; return _mkPlayer.state.completed;
} }
Future<bool> get isShuffled async { bool get isShuffled {
return _mkPlayer.shuffled; return _mkPlayer.shuffled;
} }

View File

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:catcher_2/catcher_2.dart'; import 'package:catcher_2/catcher_2.dart';
import 'package:media_kit/media_kit.dart'; import 'package:media_kit/media_kit.dart';
import 'package:flutter_broadcasts/flutter_broadcasts.dart'; import 'package:flutter_broadcasts/flutter_broadcasts.dart';
@ -7,6 +6,7 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:audio_session/audio_session.dart'; import 'package:audio_session/audio_session.dart';
// ignore: implementation_imports // ignore: implementation_imports
import 'package:spotube/services/audio_player/playback_state.dart'; import 'package:spotube/services/audio_player/playback_state.dart';
import 'package:spotube/utils/platform.dart';
/// MediaKit [Player] by default doesn't have a state stream. /// MediaKit [Player] by default doesn't have a state stream.
/// This class adds a state stream to the [Player] class. /// This class adds a state stream to the [Player] class.
@ -54,7 +54,7 @@ class CustomPlayer extends Player {
PackageInfo.fromPlatform().then((packageInfo) { PackageInfo.fromPlatform().then((packageInfo) {
_packageName = packageInfo.packageName; _packageName = packageInfo.packageName;
}); });
if (DesktopTools.platform.isAndroid) { if (kIsAndroid) {
_androidAudioManager = AndroidAudioManager(); _androidAudioManager = AndroidAudioManager();
AudioSession.instance.then((s) async { AudioSession.instance.then((s) async {
_androidAudioSessionId = _androidAudioSessionId =
@ -71,7 +71,7 @@ class CustomPlayer extends Player {
} }
Future<void> notifyAudioSessionUpdate(bool active) async { Future<void> notifyAudioSessionUpdate(bool active) async {
if (DesktopTools.platform.isAndroid) { if (kIsAndroid) {
sendBroadcast( sendBroadcast(
BroadcastMessage( BroadcastMessage(
name: active name: active

View File

@ -1,5 +1,4 @@
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/artist_simple.dart';
@ -8,6 +7,7 @@ import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/audio_services/mobile_audio_service.dart'; import 'package:spotube/services/audio_services/mobile_audio_service.dart';
import 'package:spotube/services/audio_services/windows_audio_service.dart'; import 'package:spotube/services/audio_services/windows_audio_service.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart';
import 'package:spotube/utils/platform.dart';
class AudioServices { class AudioServices {
final MobileAudioService? mobile; final MobileAudioService? mobile;
@ -19,9 +19,7 @@ class AudioServices {
Ref ref, Ref ref,
ProxyPlaylistNotifier playback, ProxyPlaylistNotifier playback,
) async { ) async {
final mobile = DesktopTools.platform.isMobile || final mobile = kIsMobile || kIsMacOS || kIsLinux
DesktopTools.platform.isMacOS ||
DesktopTools.platform.isLinux
? await AudioService.init( ? await AudioService.init(
builder: () => MobileAudioService(playback), builder: () => MobileAudioService(playback),
config: const AudioServiceConfig( config: const AudioServiceConfig(
@ -31,9 +29,7 @@ class AudioServices {
), ),
) )
: null; : null;
final smtc = DesktopTools.platform.isWindows final smtc = kIsWindows ? WindowsAudioService(ref, playback) : null;
? WindowsAudioService(ref, playback)
: null;
return AudioServices( return AudioServices(
mobile, mobile,

View File

@ -1,4 +1,7 @@
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/services/wm_tools/wm_tools.dart';
abstract class KVStoreService { abstract class KVStoreService {
static SharedPreferences? _sharedPreferences; static SharedPreferences? _sharedPreferences;
@ -23,4 +26,21 @@ abstract class KVStoreService {
static Future<void> setRecentSearches(List<String> value) async => static Future<void> setRecentSearches(List<String> value) async =>
await sharedPreferences.setStringList('recentSearches', value); await sharedPreferences.setStringList('recentSearches', value);
static WindowSize? get windowSize {
final raw = sharedPreferences.getString('windowSize');
if (raw == null) {
return null;
}
return WindowSize.fromJson(jsonDecode(raw));
}
static Future<void> setWindowSize(WindowSize value) async =>
await sharedPreferences.setString(
'windowSize',
jsonEncode(
value.toJson(),
),
);
} }

View File

@ -12,7 +12,7 @@ part of 'song_link.dart';
T _$identity<T>(T value) => value; T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
SongLink _$SongLinkFromJson(Map<String, dynamic> json) { SongLink _$SongLinkFromJson(Map<String, dynamic> json) {
return _SongLink.fromJson(json); return _SongLink.fromJson(json);

View File

@ -163,7 +163,7 @@ class PipedSourcedTrack extends SourcedTrack {
final PipedSearchResult(items: searchResults) = await pipedClient.search( final PipedSearchResult(items: searchResults) = await pipedClient.search(
query, query,
preference.searchMode == SearchMode.youtube preference.searchMode == SearchMode.youtube
? PipedFilter.videos ? PipedFilter.video
: PipedFilter.musicSongs, : PipedFilter.musicSongs,
); );

View File

@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
import 'package:spotube/services/kv_store/kv_store.dart';
import 'package:spotube/utils/platform.dart';
import 'package:window_manager/window_manager.dart';
class WindowSize {
final double height;
final double width;
final bool maximized;
WindowSize({
required this.height,
required this.width,
required this.maximized,
});
factory WindowSize.fromJson(Map<String, dynamic> json) => WindowSize(
height: json["height"],
width: json["width"],
maximized: json["maximized"],
);
Map<String, dynamic> toJson() => {
"height": height,
"width": width,
"maximized": maximized,
};
}
class WindowManagerTools with WidgetsBindingObserver {
static WindowManagerTools? _instance;
static WindowManagerTools get instance => _instance!;
WindowManagerTools._();
static Future<void> initialize() async {
await windowManager.ensureInitialized();
_instance = WindowManagerTools._();
WidgetsBinding.instance.addObserver(instance);
await windowManager.waitUntilReadyToShow(
const WindowOptions(
title: "Spotube",
backgroundColor: Colors.transparent,
minimumSize: Size(300, 700),
titleBarStyle: TitleBarStyle.hidden,
),
() async {
final savedSize = KVStoreService.windowSize;
await windowManager.setResizable(true);
if (savedSize?.maximized == true &&
!(await windowManager.isMaximized())) {
await windowManager.maximize();
} else if (savedSize != null) {
await windowManager.setSize(Size(savedSize.width, savedSize.height));
}
await windowManager.focus();
await windowManager.show();
},
);
}
Size? _prevSize;
@override
void didChangeMetrics() async {
super.didChangeMetrics();
if (kIsMobile) return;
final size = await windowManager.getSize();
final windowSameDimension =
_prevSize?.width == size.width && _prevSize?.height == size.height;
if (windowSameDimension || _prevSize == null) {
_prevSize = size;
return;
}
final isMaximized = await windowManager.isMaximized();
await KVStoreService.setWindowSize(
WindowSize(
height: size.height,
width: size.width,
maximized: isMaximized,
),
);
_prevSize = size;
}
}

View File

@ -14,7 +14,7 @@
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h> #include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h> #include <screen_retriever/screen_retriever_plugin.h>
#include <system_theme/system_theme_plugin.h> #include <system_theme/system_theme_plugin.h>
#include <system_tray/system_tray_plugin.h> #include <tray_manager/tray_manager_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
#include <window_manager/window_manager_plugin.h> #include <window_manager/window_manager_plugin.h>
#include <window_size/window_size_plugin.h> #include <window_size/window_size_plugin.h>
@ -44,9 +44,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) system_theme_registrar = g_autoptr(FlPluginRegistrar) system_theme_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SystemThemePlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "SystemThemePlugin");
system_theme_plugin_register_with_registrar(system_theme_registrar); system_theme_plugin_register_with_registrar(system_theme_registrar);
g_autoptr(FlPluginRegistrar) system_tray_registrar = g_autoptr(FlPluginRegistrar) tray_manager_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SystemTrayPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin");
system_tray_plugin_register_with_registrar(system_tray_registrar); tray_manager_plugin_register_with_registrar(tray_manager_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -11,7 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
media_kit_libs_linux media_kit_libs_linux
screen_retriever screen_retriever
system_theme system_theme
system_tray tray_manager
url_launcher_linux url_launcher_linux
window_manager window_manager
window_size window_size

View File

@ -21,7 +21,7 @@ import screen_retriever
import shared_preferences_foundation import shared_preferences_foundation
import sqflite import sqflite
import system_theme import system_theme
import system_tray import tray_manager
import url_launcher_macos import url_launcher_macos
import window_manager import window_manager
import window_size import window_size
@ -37,13 +37,13 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin")) LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin"))
MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin")) MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
SystemThemePlugin.register(with: registry.registrar(forPlugin: "SystemThemePlugin")) SystemThemePlugin.register(with: registry.registrar(forPlugin: "SystemThemePlugin"))
SystemTrayPlugin.register(with: registry.registrar(forPlugin: "SystemTrayPlugin")) TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin"))

View File

@ -44,7 +44,7 @@ PODS:
- FMDB (>= 2.7.5) - FMDB (>= 2.7.5)
- system_theme (0.0.1): - system_theme (0.0.1):
- FlutterMacOS - FlutterMacOS
- system_tray (0.0.1): - tray_manager (0.0.1):
- FlutterMacOS - FlutterMacOS
- url_launcher_macos (0.0.1): - url_launcher_macos (0.0.1):
- FlutterMacOS - FlutterMacOS
@ -73,7 +73,7 @@ DEPENDENCIES:
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
- system_theme (from `Flutter/ephemeral/.symlinks/plugins/system_theme/macos`) - system_theme (from `Flutter/ephemeral/.symlinks/plugins/system_theme/macos`)
- system_tray (from `Flutter/ephemeral/.symlinks/plugins/system_tray/macos`) - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
- window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`)
@ -122,8 +122,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
system_theme: system_theme:
:path: Flutter/ephemeral/.symlinks/plugins/system_theme/macos :path: Flutter/ephemeral/.symlinks/plugins/system_theme/macos
system_tray: tray_manager:
:path: Flutter/ephemeral/.symlinks/plugins/system_tray/macos :path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos
url_launcher_macos: url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
window_manager: window_manager:
@ -132,11 +132,11 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_size/macos :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos
SPEC CHECKSUMS: SPEC CHECKSUMS:
app_links: 4481ed4d71f384b0c3ae5016f4633aa73d32ff67 app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9
audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842 bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9
flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d
flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea
@ -147,13 +147,13 @@ SPEC CHECKSUMS:
media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5 media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5
metadata_god: eceae399d0020475069a5cebc35943ce8562b5d7 metadata_god: eceae399d0020475069a5cebc35943ce8562b5d7
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc
system_tray: e53c972838c69589ff2e77d6d3abfd71332f9e5d tray_manager: 9064e219c56d75c476e46b9a21182087930baf90
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 window_size: 339dafa0b27a95a62a843042038fa6c3c48de195

File diff suppressed because it is too large Load Diff

View File

@ -13,96 +13,89 @@ environment:
flutter: ">=3.10.0" flutter: ">=3.10.0"
dependencies: dependencies:
args: ^2.3.2 args: ^2.5.0
async: ^2.9.0 async: ^2.9.0
audio_service: ^0.18.9 audio_service: ^0.18.13
audio_session: ^0.1.18 audio_service_mpris: ^0.1.3
audio_session: ^0.1.19
auto_size_text: ^3.0.0 auto_size_text: ^3.0.0
buttons_tabbar: ^1.3.6 buttons_tabbar: ^1.3.8
cached_network_image: ^3.3.1 cached_network_image: ^3.3.1
catcher_2: 1.0.0 catcher_2: ^1.2.4
collection: ^1.15.0 collection: ^1.15.0
cupertino_icons: ^1.0.5
curved_navigation_bar: ^1.0.3 curved_navigation_bar: ^1.0.3
dbus: ^0.7.8 dbus: ^0.7.8
device_info_plus: ^9.1.2 device_info_plus: ^10.1.0
device_preview: ^1.1.0 device_preview: ^1.1.0
dio: ^5.4.1 dio: ^5.4.3+1
disable_battery_optimization: ^1.1.0+1 disable_battery_optimization: ^1.1.1
duration: ^3.0.12 duration: ^3.0.12
envied: ^0.3.0 envied: ^0.5.4+1
file_selector: ^1.0.1 file_picker: ^8.0.0+1
fluentui_system_icons: ^1.1.189 file_selector: ^1.0.3
fluentui_system_icons: ^1.1.234
flutter: flutter:
sdk: flutter sdk: flutter
flutter_cache_manager: ^3.3.0 flutter_cache_manager: ^3.3.0
flutter_desktop_tools:
git:
url: https://github.com/KRTirtho/flutter_desktop_tools.git
ref: 1f0bec3283626dcbd8ee2f54e238d096d8dea50e
flutter_displaymode: ^0.6.0 flutter_displaymode: ^0.6.0
flutter_feather_icons: ^2.0.0+1 flutter_feather_icons: ^2.0.0+1
flutter_hooks: ^0.20.5 flutter_hooks: ^0.20.5
flutter_inappwebview: ^6.0.0 flutter_inappwebview: ^6.0.0
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
flutter_native_splash: ^2.3.10 flutter_native_splash: ^2.4.0
flutter_riverpod: ^2.4.10 flutter_riverpod: ^2.5.1
flutter_secure_storage: ^9.0.0 flutter_secure_storage: ^9.0.0
flutter_svg: ^1.1.6 flutter_svg: ^1.1.6
form_validator: ^2.1.1 form_validator: ^2.1.1
fuzzywuzzy: ^1.1.6 fuzzywuzzy: ^1.1.6
go_router: 12.1.3 # Stuck on this https://github.com/flutter/flutter/issues/140869 go_router: 12.1.3 # Stuck on this https://github.com/flutter/flutter/issues/140869
google_fonts: ^6.1.0 google_fonts: ^6.2.1
hive: ^2.2.3 hive: ^2.2.3
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
hooks_riverpod: ^2.4.3 hooks_riverpod: ^2.5.1
html: ^0.15.1 html: ^0.15.1
http: ^1.2.0 http: ^1.2.0
image_picker: ^1.0.4 image_picker: ^1.1.0
intl: ^0.18.0 intl: ^0.18.0
introduction_screen: ^3.0.2 introduction_screen: ^3.1.14
json_annotation: ^4.8.1 json_annotation: ^4.8.1
logger: ^2.0.2 logger: ^2.0.2
media_kit: ^1.1.3 media_kit: ^1.1.10+1
media_kit_libs_audio: ^1.0.3 media_kit_libs_audio: ^1.0.4
metadata_god: ^0.5.2+1 metadata_god: ^0.5.2+1
mime: ^1.0.2 mime: ^1.0.2
package_info_plus: ^4.1.0 package_info_plus: ^6.0.0
palette_generator: ^0.3.3 palette_generator: ^0.3.3
path: ^1.8.0 path: ^1.8.0
path_provider: ^2.0.8 path_provider: ^2.1.3
permission_handler: ^11.0.1 permission_handler: ^11.3.1
piped_client: piped_client: ^0.1.1
git:
url: https://github.com/KRTirtho/piped_client.git
popover: ^0.3.0 popover: ^0.3.0
scrobblenaut: scrobblenaut:
git: git:
url: https://github.com/KRTirtho/scrobblenaut.git url: https://github.com/KRTirtho/scrobblenaut.git
ref: dart-3-support ref: dart-3-support
scroll_to_index: ^3.0.1 scroll_to_index: ^3.0.1
sidebarx: ^0.16.3 sidebarx: ^0.17.1
shared_preferences: ^2.2.2 shared_preferences: ^2.2.3
skeleton_text: ^3.0.1 skeleton_text: ^3.0.1
smtc_windows: ^0.1.1 smtc_windows: ^0.1.2
stroke_text: ^0.0.2 stroke_text: ^0.0.2
system_theme: ^2.1.0 system_theme: ^2.1.0
titlebar_buttons: ^1.0.0 titlebar_buttons: ^1.0.0
url_launcher: ^6.1.7 url_launcher: ^6.2.6
uuid: ^3.0.7 uuid: ^4.4.0
version: ^3.0.2 version: ^3.0.2
visibility_detector: ^0.4.0+2 visibility_detector: ^0.4.0+2
window_manager: ^0.3.1 window_manager: ^0.3.8
window_size: window_size:
git: git:
url: https://github.com/google/flutter-desktop-embedding.git url: https://github.com/google/flutter-desktop-embedding.git
ref: a738913c8ce2c9f47515382d40827e794a334274 ref: a738913c8ce2c9f47515382d40827e794a334274
path: plugins/window_size path: plugins/window_size
youtube_explode_dart: ^2.0.1 youtube_explode_dart: ^2.2.0
simple_icons: ^7.10.0 simple_icons: ^10.1.3
audio_service_mpris: ^0.1.0
file_picker: ^6.0.0
jiosaavn: ^0.1.0 jiosaavn: ^0.1.0
draggable_scrollbar: draggable_scrollbar:
git: git:
@ -116,28 +109,29 @@ dependencies:
url: https://github.com/Tommypop2/dart_discord_rpc.git url: https://github.com/Tommypop2/dart_discord_rpc.git
html_unescape: ^2.0.0 html_unescape: ^2.0.0
wikipedia_api: ^0.1.0 wikipedia_api: ^0.1.0
skeletonizer: ^0.8.0 skeletonizer: ^1.1.1
app_links: ^3.5.0 app_links: ^4.0.1
win32_registry: ^1.1.2 win32_registry: ^1.1.3
flutter_sharing_intent: ^1.1.0 flutter_sharing_intent: ^1.1.0
flutter_broadcasts: ^0.4.0 flutter_broadcasts: ^0.4.0
freezed_annotation: ^2.4.1 freezed_annotation: ^2.4.1
spotify: ^0.13.3 spotify: ^0.13.5
bonsoir: ^5.1.9 bonsoir: ^5.1.9
shelf: ^1.4.1 shelf: ^1.4.1
shelf_router: ^1.1.4 shelf_router: ^1.1.4
shelf_web_socket: ^1.0.4 shelf_web_socket: ^1.0.4
web_socket_channel: ^2.4.4 web_socket_channel: ^2.4.5
lrc: ^1.0.2 lrc: ^1.0.2
pub_api_client: ^2.4.0 pub_api_client: ^2.4.0
pubspec_parse: ^1.2.2 pubspec_parse: ^1.2.2
timezone: ^0.9.2 timezone: ^0.9.2
crypto: ^3.0.3 crypto: ^3.0.3
local_notifier: ^0.1.6
tray_manager: ^0.2.2
dev_dependencies: dev_dependencies:
build_runner: ^2.4.9 build_runner: ^2.4.9
envied_generator: ^0.3.0+3 envied_generator: ^0.5.4+1
flutter_distributor: ^0.0.2
flutter_gen_runner: ^5.4.0 flutter_gen_runner: ^5.4.0
flutter_launcher_icons: ^0.13.1 flutter_launcher_icons: ^0.13.1
flutter_lints: ^3.0.1 flutter_lints: ^3.0.1
@ -147,12 +141,12 @@ dev_dependencies:
sdk: flutter sdk: flutter
hive_generator: ^2.0.0 hive_generator: ^2.0.0
json_serializable: ^6.6.2 json_serializable: ^6.6.2
freezed: ^2.4.6 freezed: ^2.5.2
custom_lint: ^0.5.11 custom_lint: ^0.6.4
riverpod_lint: ^2.1.1 riverpod_lint: ^2.3.10
dependency_overrides: dependency_overrides:
system_tray: 2.0.2 uuid: ^4.4.0
flutter: flutter:
generate: true generate: true

View File

@ -16,7 +16,7 @@
#include <permission_handler_windows/permission_handler_windows_plugin.h> #include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h> #include <screen_retriever/screen_retriever_plugin.h>
#include <system_theme/system_theme_plugin.h> #include <system_theme/system_theme_plugin.h>
#include <system_tray/system_tray_plugin.h> #include <tray_manager/tray_manager_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
#include <window_manager/window_manager_plugin.h> #include <window_manager/window_manager_plugin.h>
#include <window_size/window_size_plugin.h> #include <window_size/window_size_plugin.h>
@ -42,8 +42,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
SystemThemePluginRegisterWithRegistrar( SystemThemePluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SystemThemePlugin")); registry->GetRegistrarForPlugin("SystemThemePlugin"));
SystemTrayPluginRegisterWithRegistrar( TrayManagerPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SystemTrayPlugin")); registry->GetRegistrarForPlugin("TrayManagerPlugin"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows")); registry->GetRegistrarForPlugin("UrlLauncherWindows"));
WindowManagerPluginRegisterWithRegistrar( WindowManagerPluginRegisterWithRegistrar(

View File

@ -13,7 +13,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
permission_handler_windows permission_handler_windows
screen_retriever screen_retriever
system_theme system_theme
system_tray tray_manager
url_launcher_windows url_launcher_windows
window_manager window_manager
window_size window_size