Skip to content

Commit

Permalink
feat: windows OS media control panel support
Browse files Browse the repository at this point in the history
  • Loading branch information
KRTirtho committed Apr 14, 2023
1 parent 06a0437 commit f0b426a
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 0 deletions.
12 changes: 12 additions & 0 deletions lib/provider/playlist_queue_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/services/audio_player.dart';
import 'package:spotube/services/linux_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/platform.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
Expand Down Expand Up @@ -137,6 +138,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
final Ref ref;
MobileAudioService? mobileService;
LinuxAudioService? linuxService;
WindowsAudioService? windowsService;

static final provider =
StateNotifierProvider<PlaylistQueueNotifier, PlaylistQueue?>(
Expand Down Expand Up @@ -166,6 +168,9 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
if (kIsLinux) {
linuxService = LinuxAudioService(ref, this);
}
if (kIsWindows) {
windowsService = WindowsAudioService(ref, this);
}
addListener((state) {
linuxService?.player.updateProperties();
});
Expand Down Expand Up @@ -363,6 +368,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
duration: state!.activeTrack.duration,
);
mobileService?.addItem(mediaItem);
windowsService?.addTrack(state!.activeTrack);
if (state!.activeTrack is LocalTrack) {
await audioPlayer.play(
DeviceFileSource((state!.activeTrack as LocalTrack).path),
Expand Down Expand Up @@ -512,6 +518,12 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
Map<String, dynamic> toJson() {
return state?.toJson() ?? {};
}

@override
void dispose() {
windowsService?.dispose();
super.dispose();
}
}

class VolumeProvider extends PersistedStateNotifier<double> {
Expand Down
99 changes: 99 additions & 0 deletions lib/services/windows_audio_service.dart
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
7 changes: 7 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,13 @@ packages:
description: flutter
source: sdk
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:
dependency: transitive
description:
Expand Down
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ dependencies:
youtube_explode_dart: ^1.12.1
flutter_desktop_tools:
path: ../flutter_desktop_tools
smtc_windows:
path: ../smtc_windows/packages/smtc_windows

dev_dependencies:
build_runner: ^2.3.2
Expand Down
1 change: 1 addition & 0 deletions windows/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ list(APPEND FLUTTER_PLUGIN_LIST

list(APPEND FLUTTER_FFI_PLUGIN_LIST
metadata_god
smtc_windows
)

set(PLUGIN_BUNDLED_LIBRARIES)
Expand Down

0 comments on commit f0b426a

Please sign in to comment.