feat: windows OS media control panel support

This commit is contained in:
Kingkor Roy Tirtho 2023-04-14 11:08:12 +06:00
parent 06a043764d
commit f0b426ae89
5 changed files with 121 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/services/audio_player.dart'; import 'package:spotube/services/audio_player.dart';
import 'package:spotube/services/linux_audio_service.dart'; import 'package:spotube/services/linux_audio_service.dart';
import 'package:spotube/services/mobile_audio_service.dart'; import 'package:spotube/services/mobile_audio_service.dart';
import 'package:spotube/services/windows_audio_service.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:spotube/utils/type_conversion_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart';
@ -137,6 +138,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
final Ref ref; final Ref ref;
MobileAudioService? mobileService; MobileAudioService? mobileService;
LinuxAudioService? linuxService; LinuxAudioService? linuxService;
WindowsAudioService? windowsService;
static final provider = static final provider =
StateNotifierProvider<PlaylistQueueNotifier, PlaylistQueue?>( StateNotifierProvider<PlaylistQueueNotifier, PlaylistQueue?>(
@ -166,6 +168,9 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
if (kIsLinux) { if (kIsLinux) {
linuxService = LinuxAudioService(ref, this); linuxService = LinuxAudioService(ref, this);
} }
if (kIsWindows) {
windowsService = WindowsAudioService(ref, this);
}
addListener((state) { addListener((state) {
linuxService?.player.updateProperties(); linuxService?.player.updateProperties();
}); });
@ -363,6 +368,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
duration: state!.activeTrack.duration, duration: state!.activeTrack.duration,
); );
mobileService?.addItem(mediaItem); mobileService?.addItem(mediaItem);
windowsService?.addTrack(state!.activeTrack);
if (state!.activeTrack is LocalTrack) { if (state!.activeTrack is LocalTrack) {
await audioPlayer.play( await audioPlayer.play(
DeviceFileSource((state!.activeTrack as LocalTrack).path), DeviceFileSource((state!.activeTrack as LocalTrack).path),
@ -512,6 +518,12 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return state?.toJson() ?? {}; return state?.toJson() ?? {};
} }
@override
void dispose() {
windowsService?.dispose();
super.dispose();
}
} }
class VolumeProvider extends PersistedStateNotifier<double> { class VolumeProvider extends PersistedStateNotifier<double> {

View File

@ -0,0 +1,99 @@
import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:smtc_windows/smtc_windows.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/services/audio_player.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
class WindowsAudioService {
final SMTCWindows smtc;
final Ref ref;
final PlaylistQueueNotifier playlistNotifier;
final subscriptions = <StreamSubscription>[];
WindowsAudioService(this.ref, this.playlistNotifier) : smtc = SMTCWindows() {
smtc.setPlaybackStatus(PlaybackStatus.Stopped);
final buttonStream = smtc.buttonPressStream.listen((event) {
switch (event) {
case PressedButton.play:
playlistNotifier.resume();
break;
case PressedButton.pause:
playlistNotifier.pause();
break;
case PressedButton.next:
playlistNotifier.next();
break;
case PressedButton.previous:
playlistNotifier.previous();
break;
case PressedButton.stop:
playlistNotifier.stop();
break;
default:
break;
}
});
final playerStateStream =
audioPlayer.onPlayerStateChanged.listen((state) async {
switch (state) {
case PlayerState.playing:
await smtc.setPlaybackStatus(PlaybackStatus.Playing);
break;
case PlayerState.paused:
await smtc.setPlaybackStatus(PlaybackStatus.Paused);
break;
case PlayerState.stopped:
await smtc.setPlaybackStatus(PlaybackStatus.Stopped);
break;
case PlayerState.completed:
await smtc.setPlaybackStatus(PlaybackStatus.Changing);
break;
default:
break;
}
});
final positionStream = audioPlayer.onPositionChanged.listen((pos) async {
await smtc.setPosition(pos);
});
final durationStream =
audioPlayer.onDurationChanged.listen((duration) async {
await smtc.setEndTime(duration);
});
subscriptions.addAll([
buttonStream,
playerStateStream,
positionStream,
durationStream,
]);
}
Future<void> addTrack(Track track) async {
await smtc.updateMetadata(MusicMetadata(
title: track.name!,
albumArtist: track.artists?.first.name ?? "Unknown",
artist: TypeConversionUtils.artists_X_String<Artist>(track.artists ?? []),
album: track.album?.name ?? "Unknown",
trackNumber: track.trackNumber ?? 0,
thumbnail: TypeConversionUtils.image_X_UrlString(
track.album?.images ?? [],
placeholder: ImagePlaceholder.albumArt,
),
));
}
void dispose() {
smtc.dispose();
for (var element in subscriptions) {
element.cancel();
}
}
}

View File

@ -1452,6 +1452,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.99"
smtc_windows:
dependency: "direct main"
description:
path: "../smtc_windows/packages/smtc_windows"
relative: true
source: path
version: "0.0.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:

View File

@ -84,6 +84,8 @@ dependencies:
youtube_explode_dart: ^1.12.1 youtube_explode_dart: ^1.12.1
flutter_desktop_tools: flutter_desktop_tools:
path: ../flutter_desktop_tools path: ../flutter_desktop_tools
smtc_windows:
path: ../smtc_windows/packages/smtc_windows
dev_dependencies: dev_dependencies:
build_runner: ^2.3.2 build_runner: ^2.3.2

View File

@ -18,6 +18,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
metadata_god metadata_god
smtc_windows
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)