From 176db09662bd4499469ffd1680c004adaff9850e Mon Sep 17 00:00:00 2001 From: CappielloAntonio Date: Sun, 2 Jun 2024 19:18:16 +0200 Subject: [PATCH] feat: Implemented continuous playing --- .../tempo/repository/SongRepository.java | 8 +-- .../tempo/service/MediaManager.java | 36 +++++++++- .../tempo/util/Preferences.kt | 19 ++++++ .../tempo/viewmodel/HomeViewModel.java | 2 +- .../viewmodel/PlayerBottomSheetViewModel.java | 2 +- .../viewmodel/SongBottomSheetViewModel.java | 2 +- app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/global_preferences.xml | 6 ++ .../tempo/service/MediaService.kt | 68 ++++++++++--------- 9 files changed, 101 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java b/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java index d8038e26..85ceed53 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java +++ b/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java @@ -1,13 +1,9 @@ package com.cappielloantonio.tempo.repository; -import android.util.Log; - import androidx.annotation.NonNull; import androidx.lifecycle.MutableLiveData; import com.cappielloantonio.tempo.App; -import com.cappielloantonio.tempo.database.AppDatabase; -import com.cappielloantonio.tempo.database.dao.FavoriteDao; import com.cappielloantonio.tempo.subsonic.base.ApiResponse; import com.cappielloantonio.tempo.subsonic.models.Child; @@ -54,12 +50,12 @@ public class SongRepository { return starredSongs; } - public MutableLiveData> getInstantMix(Child song, int count) { + public MutableLiveData> getInstantMix(String id, int count) { MutableLiveData> instantMix = new MutableLiveData<>(); App.getSubsonicClientInstance(false) .getBrowsingClient() - .getSimilarSongs2(song.getId(), count) + .getSimilarSongs2(id, count) .enqueue(new Callback() { @Override public void onResponse(@NonNull Call call, @NonNull Response response) { diff --git a/app/src/main/java/com/cappielloantonio/tempo/service/MediaManager.java b/app/src/main/java/com/cappielloantonio/tempo/service/MediaManager.java index 57962f23..ea1dcaba 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/service/MediaManager.java +++ b/app/src/main/java/com/cappielloantonio/tempo/service/MediaManager.java @@ -1,8 +1,16 @@ package com.cappielloantonio.tempo.service; -import androidx.media3.common.MediaItem; -import androidx.media3.session.MediaBrowser; +import android.content.ComponentName; +import androidx.annotation.OptIn; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; +import androidx.media3.common.MediaItem; +import androidx.media3.common.util.UnstableApi; +import androidx.media3.session.MediaBrowser; +import androidx.media3.session.SessionToken; + +import com.cappielloantonio.tempo.App; import com.cappielloantonio.tempo.interfaces.MediaIndexCallback; import com.cappielloantonio.tempo.model.Chronology; import com.cappielloantonio.tempo.repository.ChronologyRepository; @@ -299,6 +307,30 @@ public class MediaManager { } } + @OptIn(markerClass = UnstableApi.class) + public static void continuousPlay(MediaItem mediaItem) { + if (mediaItem != null && Preferences.isContinuousPlayEnabled() && Preferences.isInstantMixUsable()) { + Preferences.setLastInstantMix(); + + LiveData> instantMix = getSongRepository().getInstantMix(mediaItem.mediaId, 10); + instantMix.observeForever(new Observer>() { + @Override + public void onChanged(List media) { + if (media != null) { + ListenableFuture mediaBrowserListenableFuture = new MediaBrowser.Builder( + App.getContext(), + new SessionToken(App.getContext(), new ComponentName(App.getContext(), MediaService.class)) + ).buildAsync(); + + enqueue(mediaBrowserListenableFuture, media, true); + } + + instantMix.removeObserver(this); + } + }); + } + } + public static void saveChronology(MediaItem mediaItem) { if (mediaItem != null) { getChronologyRepository().insert(new Chronology(mediaItem)); diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt index 93f67145..636a26cd 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt @@ -62,6 +62,8 @@ object Preferences { private const val HOME_SECTOR_LIST = "home_sector_list" private const val RATING_PER_ITEM = "rating_per_item" private const val NEXT_UPDATE_CHECK = "next_update_check" + private const val CONTINUOUS_PLAY = "continuous_play" + private const val LAST_INSTANT_MIX = "last_instant_mix" @JvmStatic @@ -476,4 +478,21 @@ object Preferences { fun setTempoUpdateReminder() { App.getInstance().preferences.edit().putLong(NEXT_UPDATE_CHECK, System.currentTimeMillis()).apply() } + + @JvmStatic + fun isContinuousPlayEnabled(): Boolean { + return App.getInstance().preferences.getBoolean(CONTINUOUS_PLAY, true) + } + + @JvmStatic + fun setLastInstantMix() { + App.getInstance().preferences.edit().putLong(LAST_INSTANT_MIX, System.currentTimeMillis()).apply() + } + + @JvmStatic + fun isInstantMixUsable(): Boolean { + return App.getInstance().preferences.getLong( + LAST_INSTANT_MIX, 0 + ) + 5000 < System.currentTimeMillis() + } } \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/HomeViewModel.java b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/HomeViewModel.java index fb933e9f..a31258c0 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/HomeViewModel.java +++ b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/HomeViewModel.java @@ -203,7 +203,7 @@ public class HomeViewModel extends AndroidViewModel { public LiveData> getMediaInstantMix(LifecycleOwner owner, Child media) { mediaInstantMix.setValue(Collections.emptyList()); - songRepository.getInstantMix(media, 20).observe(owner, mediaInstantMix::postValue); + songRepository.getInstantMix(media.getId(), 20).observe(owner, mediaInstantMix::postValue); return mediaInstantMix; } diff --git a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java index eb7c7f8f..d1efd694 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java +++ b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java @@ -190,7 +190,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel { public LiveData> getMediaInstantMix(LifecycleOwner owner, Child media) { instantMix.setValue(Collections.emptyList()); - songRepository.getInstantMix(media, 20).observe(owner, instantMix::postValue); + songRepository.getInstantMix(media.getId(), 20).observe(owner, instantMix::postValue); return instantMix; } diff --git a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/SongBottomSheetViewModel.java b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/SongBottomSheetViewModel.java index 0919b7ea..79f1655b 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/SongBottomSheetViewModel.java +++ b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/SongBottomSheetViewModel.java @@ -128,7 +128,7 @@ public class SongBottomSheetViewModel extends AndroidViewModel { public LiveData> getInstantMix(LifecycleOwner owner, Child media) { instantMix.setValue(Collections.emptyList()); - songRepository.getInstantMix(media, 20).observe(owner, instantMix::postValue); + songRepository.getInstantMix(media.getId(), 20).observe(owner, instantMix::postValue); return instantMix; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a2ab19e8..83ed71bc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -262,6 +262,8 @@ Priority on transcoding of track given to server Buffering strategy For the change to take effect you must manually restart the app. + Allows music to keep playing after a playlist has ended, playing similar songs + Continuous play Size of artwork cache In order to reduce data consumption, avoid downloading covers. Limit mobile data usage diff --git a/app/src/main/res/xml/global_preferences.xml b/app/src/main/res/xml/global_preferences.xml index 55b4f525..c90779b2 100644 --- a/app/src/main/res/xml/global_preferences.xml +++ b/app/src/main/res/xml/global_preferences.xml @@ -109,6 +109,12 @@ app:title="@string/settings_image_size" app:useSimpleSummaryProvider="true" /> + +