Skip to content

Commit

Permalink
feat: show loading when track metadata is being fetched, android, ios…
Browse files Browse the repository at this point in the history
…, macos enable shuffling
  • Loading branch information
KRTirtho committed May 27, 2023
1 parent a074463 commit bf59570
Show file tree
Hide file tree
Showing 11 changed files with 454 additions and 439 deletions.
4 changes: 1 addition & 3 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ Future<void> main(List<String> rawArgs) async {

FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);

if (DesktopTools.platform.isWindows || DesktopTools.platform.isLinux) {
MediaKit.ensureInitialized();
}
MediaKit.ensureInitialized();

await DesktopTools.ensureInitialized(
DesktopWindowOptions(
Expand Down
4 changes: 2 additions & 2 deletions lib/pages/player/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ class PlayerView extends HookConsumerWidget {
final theme = Theme.of(context);
final auth = ref.watch(AuthenticationNotifier.provider);
final currentTrack = ref.watch(ProxyPlaylistNotifier.provider.select(
(value) => value?.activeTrack,
(value) => value.activeTrack,
));
final isLocalTrack = ref.watch(ProxyPlaylistNotifier.provider.select(
(value) => value?.activeTrack is LocalTrack,
(value) => value.activeTrack is LocalTrack,
));
final breakpoint = useBreakpoints();

Expand Down
60 changes: 33 additions & 27 deletions lib/provider/proxy_playlist/proxy_playlist_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import 'package:spotube/utils/type_conversion_utils.dart';
/// * [x] Prefetch next track as [SpotubeTrack] on 80% of current track
/// * [ ] Mixed Queue containing both [SpotubeTrack] and [LocalTrack]
/// * [ ] Modification of the Queue
/// * [ ] Add track at the end
/// * [x] Add track at the end
/// * [ ] Add track at the beginning
/// * [ ] Remove track
/// * [x] Remove track
/// * [ ] Reorder track
/// * [ ] Caching and loading of cache of tracks
/// * [ ] Shuffling
/// * [x] Shuffling
/// * [x] loop => playlist, track, none
/// * [ ] Alternative Track Source
/// * [x] Blacklisting of tracks and artist
Expand Down Expand Up @@ -65,30 +65,19 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
return;
}

print('=============== Active Track Changed ===============');

print('Current tracks: ${state.tracks.map((e) => e.name).toList()}');
print('newIndexedTrack: ${newActiveTrack.name}');

notificationService.addTrack(newActiveTrack);
state = state.copyWith(
active: state.tracks
.toList()
.indexWhere((element) => element.id == newActiveTrack.id),
);
print('New active: ${state.active}');

print('=============== ----- ===============');
if (preferences.albumColorSync) {
updatePalette();
}
});

audioPlayer.shuffledStream.listen((event) {
print('=============== Shuffled ===============');

print('oldTracks: ${state.tracks.map((e) => e.name).toList()}');

final newlyOrderedTracks = mapSourcesToTracks(audioPlayer.sources);

print(
Expand All @@ -98,10 +87,6 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
(element) => element.id == state.activeTrack?.id,
);

print('newActiveIndex $newActiveIndex');

print('=============== ----- ===============');

if (newActiveIndex == -1) return;

state = state.copyWith(
Expand Down Expand Up @@ -157,14 +142,10 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
}

Future<SpotubeTrack?> ensureSourcePlayable(String source) async {
print("======== Ensure Source Playable =========");
print("source: $source");

if (isPlayable(source)) return null;

final track = mapSourcesToTracks([source]).firstOrNull;

print("nthTrack: ${track?.name}");
if (track == null || track is LocalTrack) {
return null;
}
Expand All @@ -174,8 +155,6 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
_ => await SpotubeTrack.fetchFromTrack(track, preferences),
};

print("======== ----- =========");

await audioPlayer.replaceSource(
source,
nthFetchedTrack.ytUri,
Expand Down Expand Up @@ -256,9 +235,14 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
Future<void> jumpTo(int index) async {
final oldTrack =
mapSourcesToTracks([audioPlayer.currentSource!]).firstOrNull;
state = state.copyWith(active: index);
await audioPlayer.pause();
final track = await ensureSourcePlayable(audioPlayer.sources[index]);
if (track != null) {
state = state.copyWith(tracks: mergeTracks([track], state.tracks));
state = state.copyWith(
tracks: mergeTracks([track], state.tracks),
active: index,
);
}
await audioPlayer.jumpTo(index);

Expand Down Expand Up @@ -300,9 +284,20 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
Future<void> next() async {
if (audioPlayer.nextSource == null) return;
final oldTrack = mapSourcesToTracks([audioPlayer.nextSource!]).firstOrNull;
state = state.copyWith(
active: state.tracks
.toList()
.indexWhere((element) => element.id == oldTrack?.id),
);
await audioPlayer.pause();
final track = await ensureSourcePlayable(audioPlayer.nextSource!);
if (track != null) {
state = state.copyWith(tracks: mergeTracks([track], state.tracks));
state = state.copyWith(
tracks: mergeTracks([track], state.tracks),
active: state.tracks
.toList()
.indexWhere((element) => element.id == track.id),
);
}
await audioPlayer.skipToNext();

Expand All @@ -318,9 +313,20 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
if (audioPlayer.previousSource == null) return;
final oldTrack =
mapSourcesToTracks([audioPlayer.previousSource!]).firstOrNull;
state = state.copyWith(
active: state.tracks
.toList()
.indexWhere((element) => element.id == oldTrack?.id),
);
await audioPlayer.pause();
final track = await ensureSourcePlayable(audioPlayer.previousSource!);
if (track != null) {
state = state.copyWith(tracks: mergeTracks([track], state.tracks));
state = state.copyWith(
tracks: mergeTracks([track], state.tracks),
active: state.tracks
.toList()
.indexWhere((element) => element.id == track.id),
);
}
await audioPlayer.skipToPrevious();
if (oldTrack != null && track != null) {
Expand Down
145 changes: 77 additions & 68 deletions lib/services/audio_player/audio_player.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:catcher/catcher.dart';
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
import 'package:spotube/services/audio_player/mk_state_player.dart';
import 'package:just_audio/just_audio.dart' as ja;
// import 'package:just_audio/just_audio.dart' as ja;
import 'dart:async';

import 'package:media_kit/media_kit.dart' as mk;
Expand All @@ -14,37 +13,38 @@ part 'audio_players_streams_mixin.dart';
part 'audio_player_impl.dart';

abstract class AudioPlayerInterface {
final MkPlayerWithState? _mkPlayer;
final ja.AudioPlayer? _justAudio;

AudioPlayerInterface()
: _mkPlayer = _mkSupportedPlatform ? MkPlayerWithState() : null,
_justAudio = !_mkSupportedPlatform ? ja.AudioPlayer() : null {
_mkPlayer?.streams.error.listen((event) {
final MkPlayerWithState _mkPlayer;
// final ja.AudioPlayer? _justAudio;

AudioPlayerInterface() : _mkPlayer = MkPlayerWithState()
// _mkPlayer = _mkSupportedPlatform ? MkPlayerWithState() : null,
// _justAudio = !_mkSupportedPlatform ? ja.AudioPlayer() : null
{
_mkPlayer.streams.error.listen((event) {
Catcher.reportCheckedError(event, StackTrace.current);
});
}

/// Whether the current platform supports the audioplayers plugin
static final bool _mkSupportedPlatform =
DesktopTools.platform.isWindows || DesktopTools.platform.isLinux;
static const bool _mkSupportedPlatform = true;
// DesktopTools.platform.isWindows || DesktopTools.platform.isLinux;

bool get mkSupportedPlatform => _mkSupportedPlatform;

Future<Duration?> get duration async {
if (mkSupportedPlatform) {
return _mkPlayer!.state.duration;
} else {
return _justAudio!.duration;
}
return _mkPlayer.state.duration;
// if (mkSupportedPlatform) {
// } else {
// return _justAudio!.duration;
// }
}

Future<Duration?> get position async {
if (mkSupportedPlatform) {
return _mkPlayer!.state.position;
} else {
return _justAudio!.position;
}
return _mkPlayer.state.position;
// if (mkSupportedPlatform) {
// } else {
// return _justAudio!.position;
// }
}

Future<Duration?> get bufferedPosition async {
Expand All @@ -57,78 +57,87 @@ abstract class AudioPlayerInterface {
}

bool get hasSource {
if (mkSupportedPlatform) {
return _mkPlayer!.playlist.medias.isNotEmpty;
} else {
return _justAudio!.audioSource != null;
}
return _mkPlayer.playlist.medias.isNotEmpty;
// if (mkSupportedPlatform) {
// return _mkPlayer.playlist.medias.isNotEmpty;
// } else {
// return _justAudio!.audioSource != null;
// }
}

// states
bool get isPlaying {
if (mkSupportedPlatform) {
return _mkPlayer!.state.playing;
} else {
return _justAudio!.playing;
}
return _mkPlayer.state.playing;
// if (mkSupportedPlatform) {
// return _mkPlayer.state.playing;
// } else {
// return _justAudio!.playing;
// }
}

bool get isPaused {
if (mkSupportedPlatform) {
return !_mkPlayer!.state.playing;
} else {
return !isPlaying;
}
return !_mkPlayer.state.playing;
// if (mkSupportedPlatform) {
// return !_mkPlayer.state.playing;
// } else {
// return !isPlaying;
// }
}

bool get isStopped {
if (mkSupportedPlatform) {
return !hasSource;
} else {
return _justAudio!.processingState == ja.ProcessingState.idle;
}
return !hasSource;
// if (mkSupportedPlatform) {
// return !hasSource;
// } else {
// return _justAudio!.processingState == ja.ProcessingState.idle;
// }
}

Future<bool> get isCompleted async {
if (mkSupportedPlatform) {
return _mkPlayer!.state.completed;
} else {
return _justAudio!.processingState == ja.ProcessingState.completed;
}
return _mkPlayer.state.completed;
// if (mkSupportedPlatform) {
// return _mkPlayer.state.completed;
// } else {
// return _justAudio!.processingState == ja.ProcessingState.completed;
// }
}

Future<bool> get isShuffled async {
if (mkSupportedPlatform) {
return _mkPlayer!.shuffled;
} else {
return _justAudio!.shuffleModeEnabled;
}
return _mkPlayer.shuffled;
// if (mkSupportedPlatform) {
// return _mkPlayer.shuffled;
// } else {
// return _justAudio!.shuffleModeEnabled;
// }
}

Future<PlaybackLoopMode> get loopMode async {
if (mkSupportedPlatform) {
return PlaybackLoopMode.fromPlaylistMode(_mkPlayer!.loopMode);
} else {
return PlaybackLoopMode.fromLoopMode(_justAudio!.loopMode);
}
return PlaybackLoopMode.fromPlaylistMode(_mkPlayer.loopMode);
// if (mkSupportedPlatform) {
// return PlaybackLoopMode.fromPlaylistMode(_mkPlayer.loopMode);
// } else {
// return PlaybackLoopMode.fromLoopMode(_justAudio!.loopMode);
// }
}

/// Returns the current volume of the player, between 0 and 1
double get volume {
if (mkSupportedPlatform) {
return _mkPlayer!.state.volume / 100;
} else {
return _justAudio!.volume;
}
return _mkPlayer.state.volume / 100;
// if (mkSupportedPlatform) {
// return _mkPlayer.state.volume / 100;
// } else {
// return _justAudio!.volume;
// }
}

bool get isBuffering {
if (mkSupportedPlatform) {
// audioplayers doesn't have the capability to get buffering state
return false;
} else {
return _justAudio!.processingState == ja.ProcessingState.buffering ||
_justAudio!.processingState == ja.ProcessingState.loading;
}
return false;
// if (mkSupportedPlatform) {
// // audioplayers doesn't have the capability to get buffering state
// return false;
// } else {
// return _justAudio!.processingState == ja.ProcessingState.buffering ||
// _justAudio!.processingState == ja.ProcessingState.loading;
// }
}
}
Loading

0 comments on commit bf59570

Please sign in to comment.