mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
dbus MPRIS implemented, OS media control support added
Hotkey support removed due to too much key_display_binding issue caused by window resize & re-renders
This commit is contained in:
parent
580d7eea60
commit
bea7fd14b7
@ -18,7 +18,6 @@ import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
|||||||
import 'package:spotube/components/Player/Player.dart';
|
import 'package:spotube/components/Player/Player.dart';
|
||||||
import 'package:spotube/components/Library/UserLibrary.dart';
|
import 'package:spotube/components/Library/UserLibrary.dart';
|
||||||
import 'package:spotube/hooks/useBreakpointValue.dart';
|
import 'package:spotube/hooks/useBreakpointValue.dart';
|
||||||
import 'package:spotube/hooks/useHotKeys.dart';
|
|
||||||
import 'package:spotube/hooks/usePaginatedFutureProvider.dart';
|
import 'package:spotube/hooks/usePaginatedFutureProvider.dart';
|
||||||
import 'package:spotube/hooks/useUpdateChecker.dart';
|
import 'package:spotube/hooks/useUpdateChecker.dart';
|
||||||
import 'package:spotube/models/Logger.dart';
|
import 'package:spotube/models/Logger.dart';
|
||||||
@ -54,8 +53,6 @@ class Home extends HookConsumerWidget {
|
|||||||
final _selectedIndex = useState(0);
|
final _selectedIndex = useState(0);
|
||||||
_onSelectedIndexChanged(int index) => _selectedIndex.value = index;
|
_onSelectedIndexChanged(int index) => _selectedIndex.value = index;
|
||||||
|
|
||||||
// initializing global hot keys
|
|
||||||
useHotKeys(ref);
|
|
||||||
// checks for latest version of the application
|
// checks for latest version of the application
|
||||||
useUpdateChecker(ref);
|
useUpdateChecker(ref);
|
||||||
|
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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';
|
||||||
import 'package:spotube/components/Settings/About.dart';
|
import 'package:spotube/components/Settings/About.dart';
|
||||||
import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart';
|
import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart';
|
||||||
import 'package:spotube/components/Settings/SettingsHotkeyTile.dart';
|
|
||||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||||
import 'package:spotube/helpers/search-youtube.dart';
|
import 'package:spotube/helpers/search-youtube.dart';
|
||||||
import 'package:spotube/models/SpotifyMarkets.dart';
|
import 'package:spotube/models/SpotifyMarkets.dart';
|
||||||
import 'package:spotube/models/SpotubeTrack.dart';
|
import 'package:spotube/models/SpotubeTrack.dart';
|
||||||
import 'package:spotube/provider/Auth.dart';
|
import 'package:spotube/provider/Auth.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class Settings extends HookConsumerWidget {
|
class Settings extends HookConsumerWidget {
|
||||||
@ -57,29 +53,6 @@ class Settings extends HookConsumerWidget {
|
|||||||
constraints: const BoxConstraints(maxWidth: 1366),
|
constraints: const BoxConstraints(maxWidth: 1366),
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
if (!kIsMobile) ...[
|
|
||||||
SettingsHotKeyTile(
|
|
||||||
title: "Next track global shortcut",
|
|
||||||
currentHotKey: preferences.nextTrackHotKey,
|
|
||||||
onHotKeyRecorded: (value) {
|
|
||||||
preferences.setNextTrackHotKey(value);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SettingsHotKeyTile(
|
|
||||||
title: "Prev track global shortcut",
|
|
||||||
currentHotKey: preferences.prevTrackHotKey,
|
|
||||||
onHotKeyRecorded: (value) {
|
|
||||||
preferences.setPrevTrackHotKey(value);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SettingsHotKeyTile(
|
|
||||||
title: "Play/Pause global shortcut",
|
|
||||||
currentHotKey: preferences.playPauseHotKey,
|
|
||||||
onHotKeyRecorded: (value) {
|
|
||||||
preferences.setPlayPauseHotKey(value);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text("Theme"),
|
title: const Text("Theme"),
|
||||||
horizontalTitleGap: 10,
|
horizontalTitleGap: 10,
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
|
||||||
import 'package:spotube/components/Shared/RecordHotKeyDialog.dart';
|
|
||||||
|
|
||||||
class SettingsHotKeyTile extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
final HotKey? currentHotKey;
|
|
||||||
final ValueChanged<HotKey> onHotKeyRecorded;
|
|
||||||
const SettingsHotKeyTile({
|
|
||||||
required this.onHotKeyRecorded,
|
|
||||||
required this.title,
|
|
||||||
Key? key,
|
|
||||||
this.currentHotKey,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(title),
|
|
||||||
trailing: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (currentHotKey != null) HotKeyVirtualView(hotKey: currentHotKey!),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
ElevatedButton(
|
|
||||||
child: const Text("Set Shortcut"),
|
|
||||||
onPressed: () {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
return RecordHotKeyDialog(
|
|
||||||
onHotKeyRecorded: onHotKeyRecorded,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -115,6 +115,24 @@ class DownloadTrackButton extends HookConsumerWidget {
|
|||||||
|
|
||||||
if (!await outputFile.exists()) await outputFile.create(recursive: true);
|
if (!await outputFile.exists()) await outputFile.create(recursive: true);
|
||||||
|
|
||||||
|
IOSink outputFileStream = outputFile.openWrite();
|
||||||
|
await audioStream.pipe(outputFileStream);
|
||||||
|
await outputFileStream.flush();
|
||||||
|
await outputFileStream.close().then((value) async {
|
||||||
|
if (status.value == TrackStatus.downloading) {
|
||||||
|
status.value = TrackStatus.done;
|
||||||
|
await Future.delayed(
|
||||||
|
const Duration(seconds: 3),
|
||||||
|
() {
|
||||||
|
if (status.value == TrackStatus.done) {
|
||||||
|
status.value = TrackStatus.idle;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return statusCb.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
if (preferences.saveTrackLyrics && playback.currentTrack != null) {
|
if (preferences.saveTrackLyrics && playback.currentTrack != null) {
|
||||||
if (!await outputLyricsFile.exists()) {
|
if (!await outputLyricsFile.exists()) {
|
||||||
await outputLyricsFile.create(recursive: true);
|
await outputLyricsFile.create(recursive: true);
|
||||||
@ -136,24 +154,6 @@ class DownloadTrackButton extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IOSink outputFileStream = outputFile.openWrite();
|
|
||||||
await audioStream.pipe(outputFileStream);
|
|
||||||
await outputFileStream.flush();
|
|
||||||
await outputFileStream.close().then((value) async {
|
|
||||||
if (status.value == TrackStatus.downloading) {
|
|
||||||
status.value = TrackStatus.done;
|
|
||||||
await Future.delayed(
|
|
||||||
const Duration(seconds: 3),
|
|
||||||
() {
|
|
||||||
if (status.value == TrackStatus.done) {
|
|
||||||
status.value = TrackStatus.idle;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return statusCb.cancel();
|
|
||||||
});
|
|
||||||
}, [
|
}, [
|
||||||
track,
|
track,
|
||||||
status,
|
status,
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
|
||||||
|
|
||||||
class RecordHotKeyDialog extends HookWidget {
|
|
||||||
final ValueChanged<HotKey> onHotKeyRecorded;
|
|
||||||
|
|
||||||
const RecordHotKeyDialog({
|
|
||||||
Key? key,
|
|
||||||
required this.onHotKeyRecorded,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final _hotKey = useState<HotKey?>(null);
|
|
||||||
return AlertDialog(
|
|
||||||
content: SingleChildScrollView(
|
|
||||||
child: ListBody(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
'Press the keys you want to use',
|
|
||||||
style: Theme.of(context).textTheme.headline5,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
const Text(
|
|
||||||
"DO NOT Use only letters (e.g. k, g etc..)\nUse in combination with these"),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
KeyCode.control,
|
|
||||||
KeyCode.shift,
|
|
||||||
KeyCode.alt,
|
|
||||||
KeyCode.superKey,
|
|
||||||
KeyCode.meta,
|
|
||||||
]
|
|
||||||
.map((key) => HotKeyVirtualView(
|
|
||||||
hotKey: HotKey(key),
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
width: 100,
|
|
||||||
height: 60,
|
|
||||||
margin: const EdgeInsets.only(top: 20),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: [
|
|
||||||
HotKeyRecorder(
|
|
||||||
onHotKeyRecorded: (hotKey) {
|
|
||||||
_hotKey.value = hotKey;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
child: const Text('Cancel'),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
child: const Text('OK'),
|
|
||||||
onPressed: _hotKey.value == null
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
onHotKeyRecorded(_hotKey.value!);
|
|
||||||
GoRouter.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
|
||||||
import 'package:spotube/hooks/playback.dart';
|
|
||||||
import 'package:spotube/models/GlobalKeyActions.dart';
|
|
||||||
import 'package:spotube/provider/Playback.dart';
|
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
|
||||||
import 'package:spotube/utils/platform.dart';
|
|
||||||
|
|
||||||
useHotKeys(WidgetRef ref) {
|
|
||||||
final playback = ref.watch(playbackProvider);
|
|
||||||
final preferences = ref.watch(userPreferencesProvider);
|
|
||||||
List<GlobalKeyActions> _hotKeys = [];
|
|
||||||
|
|
||||||
final onNext = useNextTrack(playback);
|
|
||||||
|
|
||||||
final onPrevious = usePreviousTrack(playback);
|
|
||||||
|
|
||||||
final _playOrPause = useTogglePlayPause(playback);
|
|
||||||
|
|
||||||
useEffect(() {
|
|
||||||
if (kIsMobile) return null;
|
|
||||||
_hotKeys = [
|
|
||||||
GlobalKeyActions(
|
|
||||||
HotKey(KeyCode.space, scope: HotKeyScope.inapp),
|
|
||||||
_playOrPause,
|
|
||||||
),
|
|
||||||
if (preferences.nextTrackHotKey != null)
|
|
||||||
GlobalKeyActions(preferences.nextTrackHotKey!, (key) => onNext()),
|
|
||||||
if (preferences.prevTrackHotKey != null)
|
|
||||||
GlobalKeyActions(preferences.prevTrackHotKey!, (key) => onPrevious()),
|
|
||||||
if (preferences.playPauseHotKey != null)
|
|
||||||
GlobalKeyActions(preferences.playPauseHotKey!, _playOrPause)
|
|
||||||
];
|
|
||||||
Future.wait(
|
|
||||||
_hotKeys.map((e) {
|
|
||||||
return hotKeyManager.register(
|
|
||||||
e.hotKey,
|
|
||||||
keyDownHandler: e.onKeyDown,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return () {
|
|
||||||
Future.wait(_hotKeys.map((e) => hotKeyManager.unregister(e.hotKey)));
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
207
lib/interfaces/media_player2.dart
Normal file
207
lib/interfaces/media_player2.dart
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
// This file was generated using the following command and may be overwritten.
|
||||||
|
// dart-dbus generate-object defs/org.mpris.MediaPlayer2.xml
|
||||||
|
|
||||||
|
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||||
|
import 'package:dbus/dbus.dart';
|
||||||
|
|
||||||
|
class Media_Player extends DBusObject {
|
||||||
|
/// Creates a new object to expose on [path].
|
||||||
|
Media_Player() : super(DBusObjectPath('/org/mpris/MediaPlayer2'));
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.CanQuit
|
||||||
|
Future<DBusMethodResponse> getCanQuit() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Fullscreen
|
||||||
|
Future<DBusMethodResponse> getFullscreen() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets property org.mpris.MediaPlayer2.Fullscreen
|
||||||
|
Future<DBusMethodResponse> setFullscreen(bool value) async {
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.CanSetFullscreen
|
||||||
|
Future<DBusMethodResponse> getCanSetFullscreen() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.CanRaise
|
||||||
|
Future<DBusMethodResponse> getCanRaise() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.HasTrackList
|
||||||
|
Future<DBusMethodResponse> getHasTrackList() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Identity
|
||||||
|
Future<DBusMethodResponse> getIdentity() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusString("Spotube")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.DesktopEntry
|
||||||
|
Future<DBusMethodResponse> getDesktopEntry() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusString("spotube")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.SupportedUriSchemes
|
||||||
|
Future<DBusMethodResponse> getSupportedUriSchemes() async {
|
||||||
|
return DBusMethodSuccessResponse([
|
||||||
|
DBusArray.string(["http"])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.SupportedMimeTypes
|
||||||
|
Future<DBusMethodResponse> getSupportedMimeTypes() async {
|
||||||
|
return DBusMethodSuccessResponse([
|
||||||
|
DBusArray.string(["audio/mpeg"])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Raise()
|
||||||
|
Future<DBusMethodResponse> doRaise() async {
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Quit()
|
||||||
|
Future<DBusMethodResponse> doQuit() async {
|
||||||
|
appWindow.close();
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<DBusIntrospectInterface> introspect() {
|
||||||
|
return [
|
||||||
|
DBusIntrospectInterface('org.mpris.MediaPlayer2', methods: [
|
||||||
|
DBusIntrospectMethod('Raise'),
|
||||||
|
DBusIntrospectMethod('Quit')
|
||||||
|
], properties: [
|
||||||
|
DBusIntrospectProperty('CanQuit', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('Fullscreen', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.readwrite),
|
||||||
|
DBusIntrospectProperty('CanSetFullscreen', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('CanRaise', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('HasTrackList', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('Identity', DBusSignature('s'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('DesktopEntry', DBusSignature('s'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('SupportedUriSchemes', DBusSignature('as'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('SupportedMimeTypes', DBusSignature('as'),
|
||||||
|
access: DBusPropertyAccess.read)
|
||||||
|
])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> handleMethodCall(DBusMethodCall methodCall) async {
|
||||||
|
if (methodCall.interface == 'org.mpris.MediaPlayer2') {
|
||||||
|
if (methodCall.name == 'Raise') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doRaise();
|
||||||
|
} else if (methodCall.name == 'Quit') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doQuit();
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownMethod();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownInterface();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> getProperty(String interface, String name) async {
|
||||||
|
if (interface == 'org.mpris.MediaPlayer2') {
|
||||||
|
if (name == 'CanQuit') {
|
||||||
|
return getCanQuit();
|
||||||
|
} else if (name == 'Fullscreen') {
|
||||||
|
return getFullscreen();
|
||||||
|
} else if (name == 'CanSetFullscreen') {
|
||||||
|
return getCanSetFullscreen();
|
||||||
|
} else if (name == 'CanRaise') {
|
||||||
|
return getCanRaise();
|
||||||
|
} else if (name == 'HasTrackList') {
|
||||||
|
return getHasTrackList();
|
||||||
|
} else if (name == 'Identity') {
|
||||||
|
return getIdentity();
|
||||||
|
} else if (name == 'DesktopEntry') {
|
||||||
|
return getDesktopEntry();
|
||||||
|
} else if (name == 'SupportedUriSchemes') {
|
||||||
|
return getSupportedUriSchemes();
|
||||||
|
} else if (name == 'SupportedMimeTypes') {
|
||||||
|
return getSupportedMimeTypes();
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> setProperty(
|
||||||
|
String interface, String name, DBusValue value) async {
|
||||||
|
if (interface == 'org.mpris.MediaPlayer2') {
|
||||||
|
if (name == 'CanQuit') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'Fullscreen') {
|
||||||
|
if (value.signature != DBusSignature('b')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return setFullscreen((value as DBusBoolean).value);
|
||||||
|
} else if (name == 'CanSetFullscreen') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'CanRaise') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'HasTrackList') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'Identity') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'DesktopEntry') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'SupportedUriSchemes') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'SupportedMimeTypes') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> getAllProperties(String interface) async {
|
||||||
|
var properties = <String, DBusValue>{};
|
||||||
|
if (interface == 'org.mpris.MediaPlayer2') {
|
||||||
|
properties['CanQuit'] = (await getCanQuit()).returnValues[0];
|
||||||
|
properties['Fullscreen'] = (await getFullscreen()).returnValues[0];
|
||||||
|
properties['CanSetFullscreen'] =
|
||||||
|
(await getCanSetFullscreen()).returnValues[0];
|
||||||
|
properties['CanRaise'] = (await getCanRaise()).returnValues[0];
|
||||||
|
properties['HasTrackList'] = (await getHasTrackList()).returnValues[0];
|
||||||
|
properties['Identity'] = (await getIdentity()).returnValues[0];
|
||||||
|
properties['DesktopEntry'] = (await getDesktopEntry()).returnValues[0];
|
||||||
|
properties['SupportedUriSchemes'] =
|
||||||
|
(await getSupportedUriSchemes()).returnValues[0];
|
||||||
|
properties['SupportedMimeTypes'] =
|
||||||
|
(await getSupportedMimeTypes()).returnValues[0];
|
||||||
|
}
|
||||||
|
return DBusMethodSuccessResponse([DBusDict.stringVariant(properties)]);
|
||||||
|
}
|
||||||
|
}
|
470
lib/interfaces/media_player2_player.dart
Normal file
470
lib/interfaces/media_player2_player.dart
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
// This file was generated using the following command and may be overwritten.
|
||||||
|
// dart-dbus generate-object defs/org.mpris.MediaPlayer2.Player.xml
|
||||||
|
|
||||||
|
import 'package:dbus/dbus.dart';
|
||||||
|
import 'package:just_audio/just_audio.dart';
|
||||||
|
import 'package:spotube/helpers/image-to-url-string.dart';
|
||||||
|
import 'package:spotube/models/SpotubeTrack.dart';
|
||||||
|
import 'package:spotube/provider/Playback.dart';
|
||||||
|
|
||||||
|
class Player_Interface extends DBusObject {
|
||||||
|
final AudioPlayer player;
|
||||||
|
final Playback playback;
|
||||||
|
|
||||||
|
/// Creates a new object to expose on [path].
|
||||||
|
Player_Interface({
|
||||||
|
required this.player,
|
||||||
|
required this.playback,
|
||||||
|
}) : super(DBusObjectPath("/org/mpris/MediaPlayer2"));
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.PlaybackStatus
|
||||||
|
Future<DBusMethodResponse> getPlaybackStatus() async {
|
||||||
|
final status = player.playing
|
||||||
|
? "Playing"
|
||||||
|
: playback.currentPlaylist == null
|
||||||
|
? "Stopped"
|
||||||
|
: "Paused";
|
||||||
|
return DBusMethodSuccessResponse([DBusString(status)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.LoopStatus
|
||||||
|
Future<DBusMethodResponse> getLoopStatus() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusString("Playlist")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets property org.mpris.MediaPlayer2.Player.LoopStatus
|
||||||
|
Future<DBusMethodResponse> setLoopStatus(String value) async {
|
||||||
|
return DBusMethodErrorResponse.failed(
|
||||||
|
'Set org.mpris.MediaPlayer2.Player.LoopStatus not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.Rate
|
||||||
|
Future<DBusMethodResponse> getRate() async {
|
||||||
|
return DBusMethodSuccessResponse([DBusDouble(player.speed)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets property org.mpris.MediaPlayer2.Player.Rate
|
||||||
|
Future<DBusMethodResponse> setRate(double value) async {
|
||||||
|
player.setSpeed(value);
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.Shuffle
|
||||||
|
Future<DBusMethodResponse> getShuffle() async {
|
||||||
|
return DBusMethodSuccessResponse([DBusBoolean(playback.shuffled)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets property org.mpris.MediaPlayer2.Player.Shuffle
|
||||||
|
Future<DBusMethodResponse> setShuffle(bool value) async {
|
||||||
|
if (value) {
|
||||||
|
playback.shuffle();
|
||||||
|
} else {
|
||||||
|
playback.unshuffle();
|
||||||
|
}
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.Metadata
|
||||||
|
Future<DBusMethodResponse> getMetadata() async {
|
||||||
|
try {
|
||||||
|
if (playback.currentTrack == null) {
|
||||||
|
return DBusMethodSuccessResponse([DBusDict.stringVariant({})]);
|
||||||
|
}
|
||||||
|
final id = (playback.currentPlaylist != null
|
||||||
|
? playback.currentPlaylist!.tracks.indexWhere(
|
||||||
|
(track) => playback.currentTrack!.id == track.id!,
|
||||||
|
)
|
||||||
|
: 0)
|
||||||
|
.abs();
|
||||||
|
|
||||||
|
return DBusMethodSuccessResponse([
|
||||||
|
DBusDict.stringVariant({
|
||||||
|
"mpris:trackid": DBusString("${path.value}/Track/$id"),
|
||||||
|
"mpris:length": DBusInt32(playback.duration?.inMicroseconds ?? 0),
|
||||||
|
"mpris:artUrl": DBusString(
|
||||||
|
imageToUrlString(playback.currentTrack?.album?.images)),
|
||||||
|
"xesam:album": DBusString(playback.currentTrack!.album!.name!),
|
||||||
|
"xesam:artist": DBusArray.string(
|
||||||
|
playback.currentTrack!.artists!.map((artist) => artist.name!),
|
||||||
|
),
|
||||||
|
"xesam:title": DBusString(playback.currentTrack!.name!),
|
||||||
|
"xesam:url": DBusString(
|
||||||
|
playback.currentTrack is SpotubeTrack
|
||||||
|
? (playback.currentTrack as SpotubeTrack).ytUri
|
||||||
|
: playback.currentTrack!.previewUrl!,
|
||||||
|
),
|
||||||
|
"xesam:genre": const DBusString("Unknown"),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
print("[DBUS ERROR] $e");
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.Volume
|
||||||
|
Future<DBusMethodResponse> getVolume() async {
|
||||||
|
return DBusMethodSuccessResponse([DBusDouble(player.volume)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets property org.mpris.MediaPlayer2.Player.Volume
|
||||||
|
Future<DBusMethodResponse> setVolume(double value) async {
|
||||||
|
player.setVolume(value);
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.Position
|
||||||
|
Future<DBusMethodResponse> getPosition() async {
|
||||||
|
return DBusMethodSuccessResponse([
|
||||||
|
DBusInt64(player.position.inMicroseconds),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.MinimumRate
|
||||||
|
Future<DBusMethodResponse> getMinimumRate() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusDouble(1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.MaximumRate
|
||||||
|
Future<DBusMethodResponse> getMaximumRate() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusDouble(1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.CanGoNext
|
||||||
|
Future<DBusMethodResponse> getCanGoNext() async {
|
||||||
|
return DBusMethodSuccessResponse([
|
||||||
|
DBusBoolean(
|
||||||
|
playback.currentPlaylist?.tracks.isNotEmpty == true,
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.CanGoPrevious
|
||||||
|
Future<DBusMethodResponse> getCanGoPrevious() async {
|
||||||
|
return DBusMethodSuccessResponse([
|
||||||
|
DBusBoolean(
|
||||||
|
playback.currentPlaylist?.tracks.isNotEmpty == true,
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.CanPlay
|
||||||
|
Future<DBusMethodResponse> getCanPlay() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.CanPause
|
||||||
|
Future<DBusMethodResponse> getCanPause() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.CanSeek
|
||||||
|
Future<DBusMethodResponse> getCanSeek() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets value of property org.mpris.MediaPlayer2.Player.CanControl
|
||||||
|
Future<DBusMethodResponse> getCanControl() async {
|
||||||
|
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.Next()
|
||||||
|
Future<DBusMethodResponse> doNext() async {
|
||||||
|
playback.movePlaylistPositionBy(1);
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.Previous()
|
||||||
|
Future<DBusMethodResponse> doPrevious() async {
|
||||||
|
playback.movePlaylistPositionBy(-1);
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.Pause()
|
||||||
|
Future<DBusMethodResponse> doPause() async {
|
||||||
|
player.pause();
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.PlayPause()
|
||||||
|
Future<DBusMethodResponse> doPlayPause() async {
|
||||||
|
player.playing ? player.pause() : player.play();
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.Stop()
|
||||||
|
Future<DBusMethodResponse> doStop() async {
|
||||||
|
await player.pause();
|
||||||
|
await player.seek(Duration.zero);
|
||||||
|
playback.reset();
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.Play()
|
||||||
|
Future<DBusMethodResponse> doPlay() async {
|
||||||
|
player.play();
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.Seek()
|
||||||
|
Future<DBusMethodResponse> doSeek(int offset) async {
|
||||||
|
player.seek(Duration(microseconds: offset));
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.SetPosition()
|
||||||
|
Future<DBusMethodResponse> doSetPosition(String TrackId, int Position) async {
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of org.mpris.MediaPlayer2.Player.OpenUri()
|
||||||
|
Future<DBusMethodResponse> doOpenUri(String Uri) async {
|
||||||
|
return DBusMethodSuccessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits signal org.mpris.MediaPlayer2.Player.Seeked
|
||||||
|
Future<void> emitSeeked(int Position) async {
|
||||||
|
await emitSignal(
|
||||||
|
'org.mpris.MediaPlayer2.Player', 'Seeked', [DBusInt64(Position)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<DBusIntrospectInterface> introspect() {
|
||||||
|
return [
|
||||||
|
DBusIntrospectInterface('org.mpris.MediaPlayer2.Player', methods: [
|
||||||
|
DBusIntrospectMethod('Next'),
|
||||||
|
DBusIntrospectMethod('Previous'),
|
||||||
|
DBusIntrospectMethod('Pause'),
|
||||||
|
DBusIntrospectMethod('PlayPause'),
|
||||||
|
DBusIntrospectMethod('Stop'),
|
||||||
|
DBusIntrospectMethod('Play'),
|
||||||
|
DBusIntrospectMethod('Seek', args: [
|
||||||
|
DBusIntrospectArgument(DBusSignature('x'), DBusArgumentDirection.in_,
|
||||||
|
name: 'Offset')
|
||||||
|
]),
|
||||||
|
DBusIntrospectMethod('SetPosition', args: [
|
||||||
|
DBusIntrospectArgument(DBusSignature('o'), DBusArgumentDirection.in_,
|
||||||
|
name: 'TrackId'),
|
||||||
|
DBusIntrospectArgument(DBusSignature('x'), DBusArgumentDirection.in_,
|
||||||
|
name: 'Position')
|
||||||
|
]),
|
||||||
|
DBusIntrospectMethod('OpenUri', args: [
|
||||||
|
DBusIntrospectArgument(DBusSignature('s'), DBusArgumentDirection.in_,
|
||||||
|
name: 'Uri')
|
||||||
|
])
|
||||||
|
], signals: [
|
||||||
|
DBusIntrospectSignal('Seeked', args: [
|
||||||
|
DBusIntrospectArgument(DBusSignature('x'), DBusArgumentDirection.out,
|
||||||
|
name: 'Position')
|
||||||
|
])
|
||||||
|
], properties: [
|
||||||
|
DBusIntrospectProperty('PlaybackStatus', DBusSignature('s'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('LoopStatus', DBusSignature('s'),
|
||||||
|
access: DBusPropertyAccess.readwrite),
|
||||||
|
DBusIntrospectProperty('Rate', DBusSignature('d'),
|
||||||
|
access: DBusPropertyAccess.readwrite),
|
||||||
|
DBusIntrospectProperty('Shuffle', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.readwrite),
|
||||||
|
DBusIntrospectProperty('Metadata', DBusSignature('a{sv}'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('Volume', DBusSignature('d'),
|
||||||
|
access: DBusPropertyAccess.readwrite),
|
||||||
|
DBusIntrospectProperty('Position', DBusSignature('x'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('MinimumRate', DBusSignature('d'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('MaximumRate', DBusSignature('d'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('CanGoNext', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('CanGoPrevious', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('CanPlay', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('CanPause', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('CanSeek', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read),
|
||||||
|
DBusIntrospectProperty('CanControl', DBusSignature('b'),
|
||||||
|
access: DBusPropertyAccess.read)
|
||||||
|
])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> handleMethodCall(DBusMethodCall methodCall) async {
|
||||||
|
if (methodCall.interface == 'org.mpris.MediaPlayer2.Player') {
|
||||||
|
if (methodCall.name == 'Next') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doNext();
|
||||||
|
} else if (methodCall.name == 'Previous') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doPrevious();
|
||||||
|
} else if (methodCall.name == 'Pause') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doPause();
|
||||||
|
} else if (methodCall.name == 'PlayPause') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doPlayPause();
|
||||||
|
} else if (methodCall.name == 'Stop') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doStop();
|
||||||
|
} else if (methodCall.name == 'Play') {
|
||||||
|
if (methodCall.values.isNotEmpty) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doPlay();
|
||||||
|
} else if (methodCall.name == 'Seek') {
|
||||||
|
if (methodCall.signature != DBusSignature('x')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doSeek((methodCall.values[0] as DBusInt64).value);
|
||||||
|
} else if (methodCall.name == 'SetPosition') {
|
||||||
|
if (methodCall.signature != DBusSignature('ox')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doSetPosition((methodCall.values[0] as DBusObjectPath).value,
|
||||||
|
(methodCall.values[1] as DBusInt64).value);
|
||||||
|
} else if (methodCall.name == 'OpenUri') {
|
||||||
|
if (methodCall.signature != DBusSignature('s')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return doOpenUri((methodCall.values[0] as DBusString).value);
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownMethod();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownInterface();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> getProperty(String interface, String name) async {
|
||||||
|
if (interface == 'org.mpris.MediaPlayer2.Player') {
|
||||||
|
if (name == 'PlaybackStatus') {
|
||||||
|
return getPlaybackStatus();
|
||||||
|
} else if (name == 'LoopStatus') {
|
||||||
|
return getLoopStatus();
|
||||||
|
} else if (name == 'Rate') {
|
||||||
|
return getRate();
|
||||||
|
} else if (name == 'Shuffle') {
|
||||||
|
return getShuffle();
|
||||||
|
} else if (name == 'Metadata') {
|
||||||
|
return getMetadata();
|
||||||
|
} else if (name == 'Volume') {
|
||||||
|
return getVolume();
|
||||||
|
} else if (name == 'Position') {
|
||||||
|
return getPosition();
|
||||||
|
} else if (name == 'MinimumRate') {
|
||||||
|
return getMinimumRate();
|
||||||
|
} else if (name == 'MaximumRate') {
|
||||||
|
return getMaximumRate();
|
||||||
|
} else if (name == 'CanGoNext') {
|
||||||
|
return getCanGoNext();
|
||||||
|
} else if (name == 'CanGoPrevious') {
|
||||||
|
return getCanGoPrevious();
|
||||||
|
} else if (name == 'CanPlay') {
|
||||||
|
return getCanPlay();
|
||||||
|
} else if (name == 'CanPause') {
|
||||||
|
return getCanPause();
|
||||||
|
} else if (name == 'CanSeek') {
|
||||||
|
return getCanSeek();
|
||||||
|
} else if (name == 'CanControl') {
|
||||||
|
return getCanControl();
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> setProperty(
|
||||||
|
String interface, String name, DBusValue value) async {
|
||||||
|
if (interface == 'org.mpris.MediaPlayer2.Player') {
|
||||||
|
if (name == 'PlaybackStatus') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'LoopStatus') {
|
||||||
|
if (value.signature != DBusSignature('s')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return setLoopStatus((value as DBusString).value);
|
||||||
|
} else if (name == 'Rate') {
|
||||||
|
if (value.signature != DBusSignature('d')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return setRate((value as DBusDouble).value);
|
||||||
|
} else if (name == 'Shuffle') {
|
||||||
|
if (value.signature != DBusSignature('b')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return setShuffle((value as DBusBoolean).value);
|
||||||
|
} else if (name == 'Metadata') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'Volume') {
|
||||||
|
if (value.signature != DBusSignature('d')) {
|
||||||
|
return DBusMethodErrorResponse.invalidArgs();
|
||||||
|
}
|
||||||
|
return setVolume((value as DBusDouble).value);
|
||||||
|
} else if (name == 'Position') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'MinimumRate') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'MaximumRate') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'CanGoNext') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'CanGoPrevious') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'CanPlay') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'CanPause') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'CanSeek') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else if (name == 'CanControl') {
|
||||||
|
return DBusMethodErrorResponse.propertyReadOnly();
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DBusMethodErrorResponse.unknownProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DBusMethodResponse> getAllProperties(String interface) async {
|
||||||
|
var properties = <String, DBusValue>{};
|
||||||
|
if (interface == 'org.mpris.MediaPlayer2.Player') {
|
||||||
|
properties['PlaybackStatus'] =
|
||||||
|
(await getPlaybackStatus()).returnValues[0];
|
||||||
|
properties['LoopStatus'] = (await getLoopStatus()).returnValues[0];
|
||||||
|
properties['Rate'] = (await getRate()).returnValues[0];
|
||||||
|
properties['Shuffle'] = (await getShuffle()).returnValues[0];
|
||||||
|
properties['Metadata'] = (await getMetadata()).returnValues[0];
|
||||||
|
properties['Volume'] = (await getVolume()).returnValues[0];
|
||||||
|
properties['Position'] = (await getPosition()).returnValues[0];
|
||||||
|
properties['MinimumRate'] = (await getMinimumRate()).returnValues[0];
|
||||||
|
properties['MaximumRate'] = (await getMaximumRate()).returnValues[0];
|
||||||
|
properties['CanGoNext'] = (await getCanGoNext()).returnValues[0];
|
||||||
|
properties['CanGoPrevious'] = (await getCanGoPrevious()).returnValues[0];
|
||||||
|
properties['CanPlay'] = (await getCanPlay()).returnValues[0];
|
||||||
|
properties['CanPause'] = (await getCanPause()).returnValues[0];
|
||||||
|
properties['CanSeek'] = (await getCanSeek()).returnValues[0];
|
||||||
|
properties['CanControl'] = (await getCanControl()).returnValues[0];
|
||||||
|
}
|
||||||
|
return DBusMethodSuccessResponse([DBusDict.stringVariant(properties)]);
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||||
|
import 'package:dbus/dbus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
|
||||||
import 'package:spotube/entities/CacheTrack.dart';
|
import 'package:spotube/entities/CacheTrack.dart';
|
||||||
|
import 'package:spotube/interfaces/media_player2.dart';
|
||||||
import 'package:spotube/models/GoRouteDeclarations.dart';
|
import 'package:spotube/models/GoRouteDeclarations.dart';
|
||||||
import 'package:spotube/models/Logger.dart';
|
import 'package:spotube/models/Logger.dart';
|
||||||
import 'package:spotube/provider/AudioPlayer.dart';
|
import 'package:spotube/provider/AudioPlayer.dart';
|
||||||
|
import 'package:spotube/provider/DBus.dart';
|
||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
import 'package:spotube/provider/YouTube.dart';
|
import 'package:spotube/provider/YouTube.dart';
|
||||||
@ -34,7 +34,8 @@ void main() async {
|
|||||||
);
|
);
|
||||||
if (kIsDesktop) {
|
if (kIsDesktop) {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await hotKeyManager.unregisterAll();
|
// final client = DBusClient.session();
|
||||||
|
// await client.registerObject(Media_Player());
|
||||||
doWhenWindowReady(() {
|
doWhenWindowReady(() {
|
||||||
appWindow.minSize = const Size(359, 700);
|
appWindow.minSize = const Size(359, 700);
|
||||||
appWindow.alignment = Alignment.center;
|
appWindow.alignment = Alignment.center;
|
||||||
@ -49,10 +50,12 @@ void main() async {
|
|||||||
playbackProvider.overrideWithProvider(ChangeNotifierProvider(
|
playbackProvider.overrideWithProvider(ChangeNotifierProvider(
|
||||||
(ref) {
|
(ref) {
|
||||||
final youtube = ref.watch(youtubeProvider);
|
final youtube = ref.watch(youtubeProvider);
|
||||||
|
final dbus = ref.watch(dbusClientProvider);
|
||||||
return Playback(
|
return Playback(
|
||||||
player: audioPlayerHandler,
|
player: audioPlayerHandler,
|
||||||
youtube: youtube,
|
youtube: youtube,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
|
dbus: dbus,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
|
||||||
|
|
||||||
class GlobalKeyActions {
|
|
||||||
late final HotKey hotKey;
|
|
||||||
late final Function(HotKey hotKey) onKeyDown;
|
|
||||||
GlobalKeyActions(this.hotKey, this.onKeyDown);
|
|
||||||
}
|
|
@ -24,8 +24,8 @@ GoRouter createGoRouter() => GoRouter(
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/settings",
|
path: "/settings",
|
||||||
pageBuilder: (context, state) => SpotubePage(
|
pageBuilder: (context, state) => const SpotubePage(
|
||||||
child: const Settings(),
|
child: Settings(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
|
6
lib/provider/DBus.dart
Normal file
6
lib/provider/DBus.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import 'package:dbus/dbus.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
final dbusClientProvider = Provider((ref) {
|
||||||
|
return DBusClient.session();
|
||||||
|
});
|
@ -1,7 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
|
import 'package:dbus/dbus.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:just_audio/just_audio.dart';
|
import 'package:just_audio/just_audio.dart';
|
||||||
@ -10,8 +13,11 @@ import 'package:spotube/entities/CacheTrack.dart';
|
|||||||
import 'package:spotube/helpers/artist-to-string.dart';
|
import 'package:spotube/helpers/artist-to-string.dart';
|
||||||
import 'package:spotube/helpers/image-to-url-string.dart';
|
import 'package:spotube/helpers/image-to-url-string.dart';
|
||||||
import 'package:spotube/helpers/search-youtube.dart';
|
import 'package:spotube/helpers/search-youtube.dart';
|
||||||
|
import 'package:spotube/interfaces/media_player2.dart';
|
||||||
|
import 'package:spotube/interfaces/media_player2_player.dart';
|
||||||
import 'package:spotube/models/CurrentPlaylist.dart';
|
import 'package:spotube/models/CurrentPlaylist.dart';
|
||||||
import 'package:spotube/models/Logger.dart';
|
import 'package:spotube/models/Logger.dart';
|
||||||
|
import 'package:spotube/provider/DBus.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
import 'package:spotube/provider/YouTube.dart';
|
import 'package:spotube/provider/YouTube.dart';
|
||||||
import 'package:spotube/utils/AudioPlayerHandler.dart';
|
import 'package:spotube/utils/AudioPlayerHandler.dart';
|
||||||
@ -37,15 +43,23 @@ class Playback extends PersistedChangeNotifier {
|
|||||||
|
|
||||||
LazyBox<CacheTrack>? cacheTrackBox;
|
LazyBox<CacheTrack>? cacheTrackBox;
|
||||||
|
|
||||||
|
@protected
|
||||||
|
final DBusClient dbus;
|
||||||
|
final Media_Player _media_player;
|
||||||
|
late final Player_Interface _mpris;
|
||||||
|
|
||||||
Playback({
|
Playback({
|
||||||
required this.player,
|
required this.player,
|
||||||
required this.youtube,
|
required this.youtube,
|
||||||
required this.ref,
|
required this.ref,
|
||||||
|
required this.dbus,
|
||||||
CurrentPlaylist? currentPlaylist,
|
CurrentPlaylist? currentPlaylist,
|
||||||
Track? currentTrack,
|
Track? currentTrack,
|
||||||
}) : _currentPlaylist = currentPlaylist,
|
}) : _currentPlaylist = currentPlaylist,
|
||||||
_currentTrack = currentTrack,
|
_currentTrack = currentTrack,
|
||||||
|
_media_player = Media_Player(),
|
||||||
super() {
|
super() {
|
||||||
|
_mpris = Player_Interface(player: player.core, playback: this);
|
||||||
player.onNextRequest = () {
|
player.onNextRequest = () {
|
||||||
movePlaylistPositionBy(1);
|
movePlaylistPositionBy(1);
|
||||||
};
|
};
|
||||||
@ -61,6 +75,19 @@ class Playback extends PersistedChangeNotifier {
|
|||||||
StreamSubscription<bool>? _playingStream;
|
StreamSubscription<bool>? _playingStream;
|
||||||
|
|
||||||
void _init() async {
|
void _init() async {
|
||||||
|
// dbus m.p.r.i.s stuff
|
||||||
|
try {
|
||||||
|
final nameStatus =
|
||||||
|
await dbus.requestName("org.mpris.MediaPlayer2.spotube");
|
||||||
|
if (nameStatus == DBusRequestNameReply.exists) {
|
||||||
|
await dbus.requestName("org.mpris.MediaPlayer2.spotube.instance$pid");
|
||||||
|
}
|
||||||
|
await dbus.registerObject(_media_player);
|
||||||
|
await dbus.registerObject(_mpris);
|
||||||
|
} catch (e) {
|
||||||
|
logger.e("[MPRIS initialization error]", e);
|
||||||
|
}
|
||||||
|
|
||||||
cacheTrackBox = await Hive.openLazyBox<CacheTrack>("track-cache");
|
cacheTrackBox = await Hive.openLazyBox<CacheTrack>("track-cache");
|
||||||
|
|
||||||
_playingStream = player.core.playingStream.listen(
|
_playingStream = player.core.playingStream.listen(
|
||||||
@ -118,6 +145,8 @@ class Playback extends PersistedChangeNotifier {
|
|||||||
_playingStream?.cancel();
|
_playingStream?.cancel();
|
||||||
_durationStream?.cancel();
|
_durationStream?.cancel();
|
||||||
cacheTrackBox?.close();
|
cacheTrackBox?.close();
|
||||||
|
dbus.unregisterObject(_media_player);
|
||||||
|
dbus.unregisterObject(_mpris);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,9 +328,11 @@ class Playback extends PersistedChangeNotifier {
|
|||||||
final playbackProvider = ChangeNotifierProvider<Playback>((ref) {
|
final playbackProvider = ChangeNotifierProvider<Playback>((ref) {
|
||||||
final player = AudioPlayerHandler();
|
final player = AudioPlayerHandler();
|
||||||
final youtube = ref.watch(youtubeProvider);
|
final youtube = ref.watch(youtubeProvider);
|
||||||
|
final dbus = ref.watch(dbusClientProvider);
|
||||||
return Playback(
|
return Playback(
|
||||||
player: player,
|
player: player,
|
||||||
youtube: youtube,
|
youtube: youtube,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
|
dbus: dbus,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
|
||||||
import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart';
|
import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart';
|
||||||
import 'package:spotube/helpers/get-random-element.dart';
|
import 'package:spotube/helpers/get-random-element.dart';
|
||||||
import 'package:spotube/helpers/search-youtube.dart';
|
import 'package:spotube/helpers/search-youtube.dart';
|
||||||
@ -18,9 +16,6 @@ class UserPreferences extends PersistedChangeNotifier {
|
|||||||
String recommendationMarket;
|
String recommendationMarket;
|
||||||
bool saveTrackLyrics;
|
bool saveTrackLyrics;
|
||||||
String geniusAccessToken;
|
String geniusAccessToken;
|
||||||
HotKey? nextTrackHotKey;
|
|
||||||
HotKey? prevTrackHotKey;
|
|
||||||
HotKey? playPauseHotKey;
|
|
||||||
bool checkUpdate;
|
bool checkUpdate;
|
||||||
SpotubeTrackMatchAlgorithm trackMatchAlgorithm;
|
SpotubeTrackMatchAlgorithm trackMatchAlgorithm;
|
||||||
AudioQuality audioQuality;
|
AudioQuality audioQuality;
|
||||||
@ -35,9 +30,6 @@ class UserPreferences extends PersistedChangeNotifier {
|
|||||||
this.saveTrackLyrics = false,
|
this.saveTrackLyrics = false,
|
||||||
this.accentColorScheme = Colors.green,
|
this.accentColorScheme = Colors.green,
|
||||||
this.backgroundColorScheme = Colors.grey,
|
this.backgroundColorScheme = Colors.grey,
|
||||||
this.nextTrackHotKey,
|
|
||||||
this.prevTrackHotKey,
|
|
||||||
this.playPauseHotKey,
|
|
||||||
this.checkUpdate = true,
|
this.checkUpdate = true,
|
||||||
this.trackMatchAlgorithm = SpotubeTrackMatchAlgorithm.authenticPopular,
|
this.trackMatchAlgorithm = SpotubeTrackMatchAlgorithm.authenticPopular,
|
||||||
this.audioQuality = AudioQuality.high,
|
this.audioQuality = AudioQuality.high,
|
||||||
@ -67,24 +59,6 @@ class UserPreferences extends PersistedChangeNotifier {
|
|||||||
updatePersistence();
|
updatePersistence();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNextTrackHotKey(HotKey? value) {
|
|
||||||
nextTrackHotKey = value;
|
|
||||||
notifyListeners();
|
|
||||||
updatePersistence();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPrevTrackHotKey(HotKey? value) {
|
|
||||||
prevTrackHotKey = value;
|
|
||||||
notifyListeners();
|
|
||||||
updatePersistence();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPlayPauseHotKey(HotKey? value) {
|
|
||||||
playPauseHotKey = value;
|
|
||||||
notifyListeners();
|
|
||||||
updatePersistence();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setYtSearchFormat(String format) {
|
void setYtSearchFormat(String format) {
|
||||||
ytSearchFormat = format;
|
ytSearchFormat = format;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -128,15 +102,7 @@ class UserPreferences extends PersistedChangeNotifier {
|
|||||||
checkUpdate = map["checkUpdate"] ?? checkUpdate;
|
checkUpdate = map["checkUpdate"] ?? checkUpdate;
|
||||||
geniusAccessToken =
|
geniusAccessToken =
|
||||||
map["geniusAccessToken"] ?? getRandomElement(lyricsSecrets);
|
map["geniusAccessToken"] ?? getRandomElement(lyricsSecrets);
|
||||||
nextTrackHotKey = map["nextTrackHotKey"] != null
|
|
||||||
? HotKey.fromJson(jsonDecode(map["nextTrackHotKey"]))
|
|
||||||
: null;
|
|
||||||
prevTrackHotKey = map["prevTrackHotKey"] != null
|
|
||||||
? HotKey.fromJson(jsonDecode(map["prevTrackHotKey"]))
|
|
||||||
: null;
|
|
||||||
playPauseHotKey = map["playPauseHotKey"] != null
|
|
||||||
? HotKey.fromJson(jsonDecode(map["playPauseHotKey"]))
|
|
||||||
: null;
|
|
||||||
ytSearchFormat = map["ytSearchFormat"] ?? ytSearchFormat;
|
ytSearchFormat = map["ytSearchFormat"] ?? ytSearchFormat;
|
||||||
themeMode = ThemeMode.values[map["themeMode"] ?? 0];
|
themeMode = ThemeMode.values[map["themeMode"] ?? 0];
|
||||||
backgroundColorScheme = colorsMap.values
|
backgroundColorScheme = colorsMap.values
|
||||||
@ -159,15 +125,6 @@ class UserPreferences extends PersistedChangeNotifier {
|
|||||||
"saveTrackLyrics": saveTrackLyrics,
|
"saveTrackLyrics": saveTrackLyrics,
|
||||||
"recommendationMarket": recommendationMarket,
|
"recommendationMarket": recommendationMarket,
|
||||||
"geniusAccessToken": geniusAccessToken,
|
"geniusAccessToken": geniusAccessToken,
|
||||||
"nextTrackHotKey": nextTrackHotKey != null
|
|
||||||
? jsonEncode(nextTrackHotKey?.toJson())
|
|
||||||
: null,
|
|
||||||
"prevTrackHotKey": prevTrackHotKey != null
|
|
||||||
? jsonEncode(prevTrackHotKey?.toJson())
|
|
||||||
: null,
|
|
||||||
"playPauseHotKey": playPauseHotKey != null
|
|
||||||
? jsonEncode(playPauseHotKey?.toJson())
|
|
||||||
: null,
|
|
||||||
"ytSearchFormat": ytSearchFormat,
|
"ytSearchFormat": ytSearchFormat,
|
||||||
"themeMode": themeMode.index,
|
"themeMode": themeMode.index,
|
||||||
"backgroundColorScheme": backgroundColorScheme.value,
|
"backgroundColorScheme": backgroundColorScheme.value,
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
|
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
|
||||||
#include <hotkey_manager/hotkey_manager_plugin.h>
|
|
||||||
#include <libwinmedia/libwinmedia_plugin.h>
|
#include <libwinmedia/libwinmedia_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
@ -15,9 +14,6 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
|
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
|
||||||
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar);
|
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) hotkey_manager_registrar =
|
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "HotkeyManagerPlugin");
|
|
||||||
hotkey_manager_plugin_register_with_registrar(hotkey_manager_registrar);
|
|
||||||
g_autoptr(FlPluginRegistrar) libwinmedia_registrar =
|
g_autoptr(FlPluginRegistrar) libwinmedia_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "LibwinmediaPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "LibwinmediaPlugin");
|
||||||
libwinmedia_plugin_register_with_registrar(libwinmedia_registrar);
|
libwinmedia_plugin_register_with_registrar(libwinmedia_registrar);
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
bitsdojo_window_linux
|
bitsdojo_window_linux
|
||||||
hotkey_manager
|
|
||||||
libwinmedia
|
libwinmedia
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
@ -8,7 +8,6 @@ import Foundation
|
|||||||
import audio_service
|
import audio_service
|
||||||
import audio_session
|
import audio_session
|
||||||
import bitsdojo_window_macos
|
import bitsdojo_window_macos
|
||||||
import hotkey_manager
|
|
||||||
import just_audio
|
import just_audio
|
||||||
import package_info_plus_macos
|
import package_info_plus_macos
|
||||||
import path_provider_macos
|
import path_provider_macos
|
||||||
@ -20,7 +19,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
||||||
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||||
BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin"))
|
BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin"))
|
||||||
HotkeyManagerPlugin.register(with: registry.registrar(forPlugin: "HotkeyManagerPlugin"))
|
|
||||||
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
|
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
|
||||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
14
pubspec.lock
14
pubspec.lock
@ -267,6 +267,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.3"
|
version: "2.2.3"
|
||||||
|
dbus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.3"
|
||||||
fading_edge_scrollview:
|
fading_edge_scrollview:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -429,13 +436,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
hotkey_manager:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: hotkey_manager
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.7"
|
|
||||||
html:
|
html:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -42,7 +42,6 @@ dependencies:
|
|||||||
url_launcher: ^6.0.17
|
url_launcher: ^6.0.17
|
||||||
youtube_explode_dart: ^1.10.8
|
youtube_explode_dart: ^1.10.8
|
||||||
bitsdojo_window: ^0.1.2
|
bitsdojo_window: ^0.1.2
|
||||||
hotkey_manager: ^0.1.6
|
|
||||||
just_audio: ^0.9.18
|
just_audio: ^0.9.18
|
||||||
just_audio_libwinmedia: ^0.0.4
|
just_audio_libwinmedia: ^0.0.4
|
||||||
path: ^1.8.0
|
path: ^1.8.0
|
||||||
@ -64,6 +63,7 @@ dependencies:
|
|||||||
skeleton_text: ^3.0.0
|
skeleton_text: ^3.0.0
|
||||||
hive: ^2.2.2
|
hive: ^2.2.2
|
||||||
hive_flutter: ^1.1.0
|
hive_flutter: ^1.1.0
|
||||||
|
dbus: ^0.7.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||||
#include <hotkey_manager/hotkey_manager_plugin.h>
|
|
||||||
#include <libwinmedia/libwinmedia_plugin.h>
|
#include <libwinmedia/libwinmedia_plugin.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
@ -15,8 +14,6 @@
|
|||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
BitsdojoWindowPluginRegisterWithRegistrar(
|
BitsdojoWindowPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
|
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
|
||||||
HotkeyManagerPluginRegisterWithRegistrar(
|
|
||||||
registry->GetRegistrarForPlugin("HotkeyManagerPlugin"));
|
|
||||||
LibwinmediaPluginRegisterWithRegistrar(
|
LibwinmediaPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("LibwinmediaPlugin"));
|
registry->GetRegistrarForPlugin("LibwinmediaPlugin"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
bitsdojo_window_windows
|
bitsdojo_window_windows
|
||||||
hotkey_manager
|
|
||||||
libwinmedia
|
libwinmedia
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
Loading…
Reference in New Issue
Block a user