From 121c2b33da26e7b120dce03e46fcb6afe8ddf23e Mon Sep 17 00:00:00 2001 From: antonio Date: Wed, 29 Nov 2023 19:21:42 +0100 Subject: [PATCH] feat: added filter for songs that don't meet a user defined rating threshold --- .../tempo/ui/fragment/HomeTabMusicFragment.java | 13 +++++++++++++ .../bottomsheetdialog/AlbumBottomSheetDialog.java | 2 ++ .../ArtistBottomSheetDialog.java | 4 ++++ .../bottomsheetdialog/SongBottomSheetDialog.java | 2 ++ .../cappielloantonio/tempo/util/MusicUtil.java | 13 +++++++++++++ .../cappielloantonio/tempo/util/Preferences.kt | 7 +++++++ app/src/main/res/values/arrays.xml | 15 +++++++++++++++ app/src/main/res/values/strings.xml | 4 ++++ app/src/main/res/xml/global_preferences.xml | 13 +++++++++++++ 9 files changed, 73 insertions(+) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeTabMusicFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeTabMusicFragment.java index 0c2734d8..251699f0 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeTabMusicFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeTabMusicFragment.java @@ -51,6 +51,7 @@ import com.cappielloantonio.tempo.ui.adapter.YearAdapter; import com.cappielloantonio.tempo.util.Constants; import com.cappielloantonio.tempo.util.DownloadUtil; import com.cappielloantonio.tempo.util.MappingUtil; +import com.cappielloantonio.tempo.util.MusicUtil; import com.cappielloantonio.tempo.util.Preferences; import com.cappielloantonio.tempo.util.UIUtil; import com.cappielloantonio.tempo.viewmodel.HomeViewModel; @@ -153,6 +154,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { bind.discoveryTextViewClickable.setOnClickListener(v -> { homeViewModel.getRandomShuffleSample().observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs.size() > 0) { MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0); activity.setBottomSheetInPeek(true); @@ -306,6 +309,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { bind.discoverSongViewPager.setAdapter(discoverSongAdapter); bind.discoverSongViewPager.setOffscreenPageLimit(1); homeViewModel.getDiscoverSongSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs == null) { if (bind != null) bind.homeDiscoveryPlaceholder.placeholder.setVisibility(View.VISIBLE); @@ -330,6 +335,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { similarMusicAdapter = new SimilarTrackAdapter(this); bind.similarTracksRecyclerView.setAdapter(similarMusicAdapter); homeViewModel.getStarredTracksSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs == null) { if (bind != null) bind.homeSimilarTracksPlaceholder.placeholder.setVisibility(View.VISIBLE); @@ -744,6 +751,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { if (mediaBrowserListenableFuture != null) { homeViewModel.getMediaInstantMix(getViewLifecycleOwner(), bundle.getParcelable(Constants.TRACK_OBJECT)).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs != null && songs.size() > 0) { MediaManager.enqueue(mediaBrowserListenableFuture, songs, true); } @@ -783,6 +792,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { if (mediaBrowserListenableFuture != null) { homeViewModel.getArtistInstantMix(getViewLifecycleOwner(), bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs.size() > 0) { MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0); activity.setBottomSheetInPeek(true); @@ -792,6 +803,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { } else if (bundle.containsKey(Constants.MEDIA_BEST_OF) && bundle.getBoolean(Constants.MEDIA_BEST_OF)) { if (mediaBrowserListenableFuture != null) { homeViewModel.getArtistBestOf(getViewLifecycleOwner(), bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs.size() > 0) { MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0); activity.setBottomSheetInPeek(true); diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/AlbumBottomSheetDialog.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/AlbumBottomSheetDialog.java index e60bb375..a8059622 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/AlbumBottomSheetDialog.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/AlbumBottomSheetDialog.java @@ -115,6 +115,8 @@ public class AlbumBottomSheetDialog extends BottomSheetDialogFragment implements @Override public void onLoadMedia(List media) { + MusicUtil.ratingFilter((ArrayList) media); + if (media.size() > 0) { MediaManager.startQueue(mediaBrowserListenableFuture, (ArrayList) media, 0); ((MainActivity) requireActivity()).setBottomSheetInPeek(true); diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/ArtistBottomSheetDialog.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/ArtistBottomSheetDialog.java index e2fdded7..fde89f3b 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/ArtistBottomSheetDialog.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/ArtistBottomSheetDialog.java @@ -89,6 +89,8 @@ public class ArtistBottomSheetDialog extends BottomSheetDialogFragment implement ArtistRepository artistRepository = new ArtistRepository(); artistRepository.getInstantMix(artist, 20).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs.size() > 0) { MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0); ((MainActivity) requireActivity()).setBottomSheetInPeek(true); @@ -102,6 +104,8 @@ public class ArtistBottomSheetDialog extends BottomSheetDialogFragment implement playRandom.setOnClickListener(v -> { ArtistRepository artistRepository = new ArtistRepository(); artistRepository.getRandomSong(artist, 50).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs.size() > 0) { MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0); ((MainActivity) requireActivity()).setBottomSheetInPeek(true); diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java index 9e6c6a4b..d7d444dc 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java @@ -114,6 +114,8 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements ((MainActivity) requireActivity()).setBottomSheetInPeek(true); songBottomSheetViewModel.getInstantMix(getViewLifecycleOwner(), song).observe(getViewLifecycleOwner(), songs -> { + MusicUtil.ratingFilter(songs); + if (songs == null) { dismissBottomSheet(); return; diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java b/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java index 9fdb1250..b0a7931c 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java +++ b/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java @@ -307,4 +307,17 @@ public class MusicUtil { private static ConnectivityManager getConnectivityManager() { return (ConnectivityManager) App.getContext().getSystemService(Context.CONNECTIVITY_SERVICE); } + + public static void ratingFilter(List toFilter) { + if (toFilter == null || toFilter.isEmpty()) return; + + List filtered = toFilter + .stream() + .filter(child -> (child.getUserRating() != null && child.getUserRating() >= Preferences.getMinStarRatingAccepted()) || (child.getUserRating() == null)) + .collect(Collectors.toList()); + + toFilter.clear(); + + toFilter.addAll(filtered); + } } 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 71a8e711..701eda68 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt @@ -43,6 +43,9 @@ object Preferences { private const val SCROBBLING = "scrobbling" private const val ESTIMATE_CONTENT_LENGTH = "estimate_content_length" private const val BUFFERING_STRATEGY = "buffering_strategy" + private const val SKIP_MIN_STAR_RATING = "skip_min_star_rating" + private const val MIN_STAR_RATING = "min_star_rating" + @JvmStatic fun getServer(): String? { @@ -338,4 +341,8 @@ object Preferences { return App.getInstance().preferences.getString(BUFFERING_STRATEGY, "1")!!.toDouble() } + @JvmStatic + fun getMinStarRatingAccepted(): Int { + return App.getInstance().preferences.getInt(MIN_STAR_RATING, 0) + } } \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index f3989e9c..6ef0a129 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -224,4 +224,19 @@ 4 8 + + + 0 star minimum + 1 star minimum + 2 stars minimum + 3 stars minimum + 4 stars minimum + + + 0 + 1 + 2 + 3 + 4 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 99979d04..f1deb6e6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -274,6 +274,7 @@ Enable music scrobbling Enable music sharing It\'s important to note that scrobbling also relies on the server being enabled to receive this data. + When listening to an artist\'s radio, an instant mix or when shuffling all, tracks below a certain user rating will be ignored. Replay gain is a feature that allows you to adjust the volume level of audio tracks for a consistent listening experience. This setting is only effective if the track contains the necessary metadata. Scrobbling is a feature that allows your device to send information about the songs you listen to the music server. This information helps create personalized recommendations based on your music preferences. Allows the user to share music via a link. The functionality must be supported and enabled server-side and is limited to individual tracks, albums and playlists. @@ -286,8 +287,11 @@ Theme Data General + Rating Replay Gain Scrobble + Ignore tracks based on rating + Songs with a rating of: Share Syncing Transcoding diff --git a/app/src/main/res/xml/global_preferences.xml b/app/src/main/res/xml/global_preferences.xml index b2702929..ef6c8f15 100644 --- a/app/src/main/res/xml/global_preferences.xml +++ b/app/src/main/res/xml/global_preferences.xml @@ -232,6 +232,19 @@ + + + + +