diff --git a/lib/components/playlist/playlist_card.dart b/lib/components/playlist/playlist_card.dart index 579fbf93..be7abfb9 100644 --- a/lib/components/playlist/playlist_card.dart +++ b/lib/components/playlist/playlist_card.dart @@ -72,7 +72,9 @@ class PlaylistCard extends HookConsumerWidget { playlistNotifier.addCollection(playlist.id!); tracks.value = fetchedTracks; } finally { - updating.value = false; + if (context.mounted) { + updating.value = false; + } } }, onAddToQueuePressed: () async { diff --git a/lib/main.dart b/lib/main.dart index eae240ad..e90642ec 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -156,7 +156,7 @@ if (DesktopTools.platform.isAndroid) { runApp( DevicePreview( availableLocales: L10n.all, - enabled: !kReleaseMode && DesktopTools.platform.isDesktop, + enabled: false, data: const DevicePreviewData( isEnabled: false, orientation: Orientation.portrait, diff --git a/lib/provider/dbus_provider.dart b/lib/provider/dbus_provider.dart deleted file mode 100644 index 938d3687..00000000 --- a/lib/provider/dbus_provider.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:dbus/dbus.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:spotube/utils/platform.dart'; - -final Provider dbusClientProvider = Provider((ref) { - if (kIsLinux) { - return DBusClient.session(); - } - return null; -}); - -final dbus = DBusClient.session(); diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index 31e8bb1f..c7dcfbc2 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; +import 'package:async/async.dart'; import 'package:catcher/catcher.dart'; import 'package:collection/collection.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -68,7 +69,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier () async { notificationService = await AudioServices.create(ref, this); - (String, List)? currentSegments; + ({String source, List segments})? currentSegments; bool isFetchingSegments = false; audioPlayer.activeSourceChangedStream.listen((newActiveSource) async { final newActiveTrack = @@ -110,14 +111,14 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier bool isPreSearching = false; - listenTo60Percent(percent) async { + listenTo2Percent(int percent) async { if (isPreSearching || audioPlayer.currentSource == null || audioPlayer.nextSource == null) return; + try { isPreSearching = true; - // TODO: Make repeat mode sensitive changes later final oldTrack = mapSourcesToTracks([audioPlayer.nextSource!]).firstOrNull; final track = await ensureSourcePlayable(audioPlayer.nextSource!); @@ -126,12 +127,12 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier state = state.copyWith(tracks: mergeTracks([track], state.tracks)); if (currentSegments == null || (oldTrack?.id != null && - currentSegments!.$1 != oldTrack!.id!) && + currentSegments!.source != oldTrack!.id!) && !isFetchingSegments) { isFetchingSegments = true; currentSegments = ( - audioPlayer.currentSource!, - await getAndCacheSkipSegments( + source: audioPlayer.currentSource!, + segments: await getAndCacheSkipSegments( track.ytTrack.id, ), ); @@ -147,47 +148,32 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } } finally { isPreSearching = false; - - /// Sometimes fetching can take a lot of time, so we need to check - /// if next source is playable or not at 99% progress. If not, then - /// it'll be paused automatically - /// - /// After fetching the nextSource and replacing it, we need to check - /// if the player is paused or not. If it is paused, then we need to - /// resume it to skip to next track - if (audioPlayer.isPaused) { + if (percent > 98 && !audioPlayer.isPlaying) { await audioPlayer.resume(); } } } - audioPlayer.percentCompletedStream(60).listen(listenTo60Percent); - - // player stops at 99% if nextSource is still not playable - audioPlayer.percentCompletedStream(99).listen((_) async { - if (audioPlayer.nextSource == null || - isPlayable(audioPlayer.nextSource!)) return; - await audioPlayer.pause(); - }); + audioPlayer.percentCompletedStream(2).listen(listenTo2Percent); audioPlayer.positionStream.listen((position) async { if (preferences.searchMode == SearchMode.youtubeMusic || !preferences.skipNonMusic) return; if (currentSegments == null || - currentSegments!.$1 != state.activeTrack!.id! && + currentSegments!.source != state.activeTrack!.id! && !isFetchingSegments) { isFetchingSegments = true; currentSegments = ( - audioPlayer.currentSource!, - await getAndCacheSkipSegments( + source: audioPlayer.currentSource!, + segments: await getAndCacheSkipSegments( (state.activeTrack as SpotubeTrack).ytTrack.id, ), ); isFetchingSegments = false; } - final (_, segments) = currentSegments!; + final (source: _, :segments) = currentSegments!; if (segments.isEmpty) return; for (final segment in segments) { diff --git a/lib/services/audio_services/linux_audio_service.dart b/lib/services/audio_services/linux_audio_service.dart index 99d840a4..28370c86 100644 --- a/lib/services/audio_services/linux_audio_service.dart +++ b/lib/services/audio_services/linux_audio_service.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:dbus/dbus.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:spotube/provider/dbus_provider.dart'; import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; @@ -12,6 +11,8 @@ import 'package:spotube/services/audio_player/loop_mode.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; import 'package:window_manager/window_manager.dart'; +final dbus = DBusClient.session(); + class _MprisMediaPlayer2 extends DBusObject { /// Creates a new object to expose on [path]. _MprisMediaPlayer2() : super(DBusObjectPath('/org/mpris/MediaPlayer2')) {