From 52ba783a90b08f7c7f3c42e8efb85d13210aad78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Mon, 22 Sep 2025 00:15:52 +0200 Subject: [PATCH] feat: Mark currently playing song in SongHorizontalAdapter --- .../tempo/interfaces/MediaSongIdCallback.java | 8 +++++++ .../tempo/service/MediaManager.java | 20 ++++++++++++++++ .../ui/adapter/SongHorizontalAdapter.java | 24 +++++++++++++++++++ .../tempo/ui/fragment/AlbumPageFragment.java | 14 +++++++++++ .../tempo/ui/fragment/ArtistPageFragment.java | 14 +++++++++++ .../ui/fragment/HomeTabMusicFragment.java | 18 ++++++++++++++ .../ui/fragment/PlaylistPageFragment.java | 14 +++++++++++ .../tempo/ui/fragment/SearchFragment.java | 14 +++++++++++ .../ui/fragment/SongListPageFragment.java | 14 +++++++++++ .../main/res/layout/item_horizontal_track.xml | 22 +++++++++++++++++ 10 files changed, 162 insertions(+) create mode 100644 app/src/main/java/com/cappielloantonio/tempo/interfaces/MediaSongIdCallback.java diff --git a/app/src/main/java/com/cappielloantonio/tempo/interfaces/MediaSongIdCallback.java b/app/src/main/java/com/cappielloantonio/tempo/interfaces/MediaSongIdCallback.java new file mode 100644 index 00000000..de147c58 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/interfaces/MediaSongIdCallback.java @@ -0,0 +1,8 @@ +package com.cappielloantonio.tempo.interfaces; + +import androidx.annotation.Keep; + +@Keep +public interface MediaSongIdCallback { + default void onRecovery(String id) {} +} 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 ea1dcaba..9c9947ba 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/service/MediaManager.java +++ b/app/src/main/java/com/cappielloantonio/tempo/service/MediaManager.java @@ -12,6 +12,7 @@ import androidx.media3.session.SessionToken; import com.cappielloantonio.tempo.App; import com.cappielloantonio.tempo.interfaces.MediaIndexCallback; +import com.cappielloantonio.tempo.interfaces.MediaSongIdCallback; import com.cappielloantonio.tempo.model.Chronology; import com.cappielloantonio.tempo.repository.ChronologyRepository; import com.cappielloantonio.tempo.repository.QueueRepository; @@ -292,6 +293,25 @@ public class MediaManager { } } + public static void getCurrentSongId(ListenableFuture mediaBrowserListenableFuture, MediaSongIdCallback callback) { + if (mediaBrowserListenableFuture != null) { + mediaBrowserListenableFuture.addListener(() -> { + try { + if (mediaBrowserListenableFuture.isDone()) { + MediaItem currentItem = mediaBrowserListenableFuture.get().getCurrentMediaItem(); + if (currentItem != null) { + callback.onRecovery(currentItem.mediaMetadata.extras.getString("id")); + } else { + callback.onRecovery(null); + } + } + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + } + }, MoreExecutors.directExecutor()); + } + } + public static void setLastPlayedTimestamp(MediaItem mediaItem) { if (mediaItem != null) getQueueRepository().setLastPlayedTimestamp(mediaItem.mediaId); } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/SongHorizontalAdapter.java b/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/SongHorizontalAdapter.java index a1630bca..c770b607 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/SongHorizontalAdapter.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/SongHorizontalAdapter.java @@ -10,12 +10,15 @@ import android.widget.Filterable; import androidx.annotation.NonNull; import androidx.appcompat.content.res.AppCompatResources; import androidx.media3.common.util.UnstableApi; +import androidx.media3.session.MediaBrowser; import androidx.recyclerview.widget.RecyclerView; import com.cappielloantonio.tempo.R; import com.cappielloantonio.tempo.databinding.ItemHorizontalTrackBinding; import com.cappielloantonio.tempo.glide.CustomGlideRequest; import com.cappielloantonio.tempo.interfaces.ClickCallback; +import com.cappielloantonio.tempo.interfaces.MediaSongIdCallback; +import com.cappielloantonio.tempo.service.MediaManager; import com.cappielloantonio.tempo.subsonic.models.AlbumID3; import com.cappielloantonio.tempo.subsonic.models.Child; import com.cappielloantonio.tempo.subsonic.models.DiscTitle; @@ -23,6 +26,7 @@ import com.cappielloantonio.tempo.util.Constants; import com.cappielloantonio.tempo.util.DownloadUtil; import com.cappielloantonio.tempo.util.MusicUtil; import com.cappielloantonio.tempo.util.Preferences; +import com.google.common.util.concurrent.ListenableFuture; import java.util.ArrayList; import java.util.Collections; @@ -41,6 +45,7 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter songsFull; private List songs; private String currentFilter; + private ListenableFuture mediaBrowserListenableFuture; private final Filter filtering = new Filter() { @Override @@ -165,6 +170,21 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter mediaBrowserListenableFuture) { + this.mediaBrowserListenableFuture = mediaBrowserListenableFuture; + } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java index 03e71e10..a7326b09 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java @@ -93,6 +93,12 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { initializeMediaBrowser(); } + @Override + public void onResume() { + super.onResume(); + setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -271,6 +277,7 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, false, false, album); bind.songRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); albumPageViewModel.getAlbumSongLiveList().observe(getViewLifecycleOwner(), songs -> songHorizontalAdapter.setItems(songs)); } @@ -288,6 +295,7 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { @Override public void onMediaClick(Bundle bundle) { MediaManager.startQueue(mediaBrowserListenableFuture, bundle.getParcelableArrayList(Constants.TRACKS_OBJECT), bundle.getInt(Constants.ITEM_POSITION)); + songHorizontalAdapter.notifyDataSetChanged(); activity.setBottomSheetInPeek(true); } @@ -295,4 +303,10 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { public void onMediaLongClick(Bundle bundle) { Navigation.findNavController(requireView()).navigate(R.id.songBottomSheetDialog, bundle); } + + private void setMediaBrowserListenableFuture() { + if (songHorizontalAdapter != null) { + songHorizontalAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/ArtistPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/ArtistPageFragment.java index 9dccc83e..65473ec4 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/ArtistPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/ArtistPageFragment.java @@ -82,6 +82,12 @@ public class ArtistPageFragment extends Fragment implements ClickCallback { initializeMediaBrowser(); } + @Override + public void onResume() { + super.onResume(); + setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -174,6 +180,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, true, true, null); bind.mostStreamedSongRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); artistPageViewModel.getArtistTopSongList().observe(getViewLifecycleOwner(), songs -> { if (songs == null) { if (bind != null) bind.artistPageTopSongsSector.setVisibility(View.GONE); @@ -246,6 +253,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback { @Override public void onMediaClick(Bundle bundle) { MediaManager.startQueue(mediaBrowserListenableFuture, bundle.getParcelableArrayList(Constants.TRACKS_OBJECT), bundle.getInt(Constants.ITEM_POSITION)); + songHorizontalAdapter.notifyDataSetChanged(); activity.setBottomSheetInPeek(true); } @@ -273,4 +281,10 @@ public class ArtistPageFragment extends Fragment implements ClickCallback { public void onArtistLongClick(Bundle bundle) { Navigation.findNavController(requireView()).navigate(R.id.artistBottomSheetDialog, bundle); } + + private void setMediaBrowserListenableFuture() { + if (songHorizontalAdapter != null) { + songHorizontalAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + } } \ No newline at end of file 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 4d30ce30..c7ba117d 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 @@ -144,6 +144,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { public void onResume() { super.onResume(); refreshSharesView(); + setTopSongMediaBrowserListenableFuture(); + setStarredSongMediaBrowserListenableFuture(); } @Override @@ -477,6 +479,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { topSongAdapter = new SongHorizontalAdapter(this, true, false, null); bind.topSongsRecyclerView.setAdapter(topSongAdapter); + setTopSongMediaBrowserListenableFuture(); homeViewModel.getChronologySample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), chronologies -> { if (chronologies == null || chronologies.isEmpty()) { if (bind != null) bind.homeGridTracksSector.setVisibility(View.GONE); @@ -515,6 +518,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { starredSongAdapter = new SongHorizontalAdapter(this, true, false, null); bind.starredTracksRecyclerView.setAdapter(starredSongAdapter); + setStarredSongMediaBrowserListenableFuture(); homeViewModel.getStarredTracks(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> { if (songs == null) { if (bind != null) bind.starredTracksSector.setVisibility(View.GONE); @@ -954,6 +958,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { MediaManager.startQueue(mediaBrowserListenableFuture, bundle.getParcelableArrayList(Constants.TRACKS_OBJECT), bundle.getInt(Constants.ITEM_POSITION)); activity.setBottomSheetInPeek(true); } + topSongAdapter.notifyDataSetChanged(); + starredSongAdapter.notifyDataSetChanged(); } @Override @@ -1043,4 +1049,16 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { public void onShareLongClick(Bundle bundle) { Navigation.findNavController(requireView()).navigate(R.id.shareBottomSheetDialog, bundle); } + + private void setTopSongMediaBrowserListenableFuture() { + if (topSongAdapter != null) { + topSongAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + } + + private void setStarredSongMediaBrowserListenableFuture() { + if (starredSongAdapter != null) { + starredSongAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlaylistPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlaylistPageFragment.java index 55b46ff2..9da26370 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlaylistPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlaylistPageFragment.java @@ -111,6 +111,12 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback { initializeMediaBrowser(); } + @Override + public void onResume() { + super.onResume(); + setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -248,6 +254,7 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, true, false, null); bind.songRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); playlistPageViewModel.getPlaylistSongLiveList().observe(getViewLifecycleOwner(), songs -> songHorizontalAdapter.setItems(songs)); } @@ -263,6 +270,7 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback { @Override public void onMediaClick(Bundle bundle) { MediaManager.startQueue(mediaBrowserListenableFuture, bundle.getParcelableArrayList(Constants.TRACKS_OBJECT), bundle.getInt(Constants.ITEM_POSITION)); + songHorizontalAdapter.notifyDataSetChanged(); activity.setBottomSheetInPeek(true); } @@ -270,4 +278,10 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback { public void onMediaLongClick(Bundle bundle) { Navigation.findNavController(requireView()).navigate(R.id.songBottomSheetDialog, bundle); } + + private void setMediaBrowserListenableFuture() { + if (songHorizontalAdapter != null) { + songHorizontalAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SearchFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SearchFragment.java index 8792a98a..a67c6c02 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SearchFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SearchFragment.java @@ -75,6 +75,12 @@ public class SearchFragment extends Fragment implements ClickCallback { initializeMediaBrowser(); } + @Override + public void onResume() { + super.onResume(); + setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -113,6 +119,7 @@ public class SearchFragment extends Fragment implements ClickCallback { bind.searchResultTracksRecyclerView.setHasFixedSize(true); songHorizontalAdapter = new SongHorizontalAdapter(this, true, false, null); + setMediaBrowserListenableFuture(); bind.searchResultTracksRecyclerView.setAdapter(songHorizontalAdapter); } @@ -260,6 +267,7 @@ public class SearchFragment extends Fragment implements ClickCallback { @Override public void onMediaClick(Bundle bundle) { MediaManager.startQueue(mediaBrowserListenableFuture, bundle.getParcelableArrayList(Constants.TRACKS_OBJECT), bundle.getInt(Constants.ITEM_POSITION)); + songHorizontalAdapter.notifyDataSetChanged(); activity.setBottomSheetInPeek(true); } @@ -287,4 +295,10 @@ public class SearchFragment extends Fragment implements ClickCallback { public void onArtistLongClick(Bundle bundle) { Navigation.findNavController(requireView()).navigate(R.id.artistBottomSheetDialog, bundle); } + + private void setMediaBrowserListenableFuture() { + if (songHorizontalAdapter != null) { + songHorizontalAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SongListPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SongListPageFragment.java index fcaeec84..3c75f1da 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SongListPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SongListPageFragment.java @@ -84,6 +84,12 @@ public class SongListPageFragment extends Fragment implements ClickCallback { initializeMediaBrowser(); } + @Override + public void onResume() { + super.onResume(); + setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -191,6 +197,7 @@ public class SongListPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, true, false, null); bind.songListRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); songListPageViewModel.getSongList().observe(getViewLifecycleOwner(), songs -> { isLoading = false; songHorizontalAdapter.setItems(songs); @@ -318,6 +325,7 @@ public class SongListPageFragment extends Fragment implements ClickCallback { public void onMediaClick(Bundle bundle) { hideKeyboard(requireView()); MediaManager.startQueue(mediaBrowserListenableFuture, bundle.getParcelableArrayList(Constants.TRACKS_OBJECT), bundle.getInt(Constants.ITEM_POSITION)); + songHorizontalAdapter.notifyDataSetChanged(); activity.setBottomSheetInPeek(true); } @@ -325,4 +333,10 @@ public class SongListPageFragment extends Fragment implements ClickCallback { public void onMediaLongClick(Bundle bundle) { Navigation.findNavController(requireView()).navigate(R.id.songBottomSheetDialog, bundle); } + + private void setMediaBrowserListenableFuture() { + if (songHorizontalAdapter != null) { + songHorizontalAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/item_horizontal_track.xml b/app/src/main/res/layout/item_horizontal_track.xml index dfea07a9..cc0bd8b6 100644 --- a/app/src/main/res/layout/item_horizontal_track.xml +++ b/app/src/main/res/layout/item_horizontal_track.xml @@ -55,6 +55,28 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/different_disk_divider_sector" /> + + + +