From 14939d20fdf0e3f08489ac2bbfe44bde6e263c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:06:51 +0200 Subject: [PATCH 1/2] feat: Replace play/pause button with an icon, allow tapping on full item to play/pause song in Queue --- .../ui/adapter/PlayerSongQueueAdapter.java | 24 ++++++++----------- .../res/layout/item_player_queue_song.xml | 14 ++++------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java b/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java index 9a35fd92..1f7f12f6 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java @@ -112,7 +112,7 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter { + holder.itemView.setOnClickListener(v -> { mediaBrowserListenableFuture.addListener(() -> { try { MediaBrowser mediaBrowser = mediaBrowserListenableFuture.get(); @@ -138,23 +138,19 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter - From 969f0b5b21eddebe30ec5ed3615245f9a407caf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:40:48 +0200 Subject: [PATCH 2/2] feat: Replace play/pause button with an icon, allow tapping on full item to play/pause song in song lists --- .../ui/adapter/PlayerSongQueueAdapter.java | 2 +- .../ui/adapter/SongHorizontalAdapter.java | 64 +++++++++++-------- .../tempo/ui/fragment/AlbumPageFragment.java | 10 +++ .../tempo/ui/fragment/ArtistPageFragment.java | 10 +++ .../ui/fragment/HomeTabMusicFragment.java | 12 ++++ .../ui/fragment/PlaylistPageFragment.java | 11 ++++ .../tempo/ui/fragment/SearchFragment.java | 6 ++ .../ui/fragment/SongListPageFragment.java | 11 ++++ .../main/res/layout/item_horizontal_track.xml | 12 +--- 9 files changed, 101 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java b/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java index 1f7f12f6..4db3a572 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/adapter/PlayerSongQueueAdapter.java @@ -149,7 +149,7 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter implements Filterable { @@ -49,6 +50,7 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter currentPlayingPositions = Collections.emptyList(); + private ListenableFuture mediaBrowserListenableFuture; private final Filter filtering = new Filter() { @Override @@ -190,44 +192,30 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter { - Activity a = (Activity) v.getContext(); - View root = a.findViewById(android.R.id.content); - View exoPlayPause = root.findViewById(R.id.exo_play_pause); - if (exoPlayPause != null) exoPlayPause.performClick(); - }); bindPlaybackState(holder, song); } private void bindPlaybackState(@NonNull ViewHolder holder, @NonNull Child song) { - boolean isCurrent = currentPlayingId != null && currentPlayingId.equals(song.getId()) && isPlaying; + boolean isCurrent = currentPlayingId != null && currentPlayingId.equals(song.getId()); if (isCurrent) { - holder.item.playPauseButton.setVisibility(View.VISIBLE); - holder.item.playPauseButton.setChecked(true); + holder.item.playPauseIcon.setVisibility(View.VISIBLE); + if (isPlaying) { + holder.item.playPauseIcon.setImageResource(R.drawable.ic_pause); + } else { + holder.item.playPauseIcon.setImageResource(R.drawable.ic_play); + } if (!showCoverArt) { - holder.item.trackNumberTextView.setVisibility(View.GONE); + holder.item.trackNumberTextView.setVisibility(View.INVISIBLE); } else { holder.item.coverArtOverlay.setVisibility(View.VISIBLE); } } else { - boolean sameIdPaused = currentPlayingId != null && currentPlayingId.equals(song.getId()) && !isPlaying; - if (sameIdPaused) { - holder.item.playPauseButton.setVisibility(View.VISIBLE); - holder.item.playPauseButton.setChecked(false); - if (!showCoverArt) { - holder.item.trackNumberTextView.setVisibility(View.GONE); - } else { - holder.item.coverArtOverlay.setVisibility(View.VISIBLE); - } + holder.item.playPauseIcon.setVisibility(View.INVISIBLE); + if (!showCoverArt) { + holder.item.trackNumberTextView.setVisibility(View.VISIBLE); } else { - holder.item.playPauseButton.setVisibility(View.GONE); - holder.item.playPauseButton.setChecked(false); - if (!showCoverArt) { - holder.item.trackNumberTextView.setVisibility(View.VISIBLE); - } else { - holder.item.coverArtOverlay.setVisibility(View.INVISIBLE); - } + holder.item.coverArtOverlay.setVisibility(View.INVISIBLE); } } } @@ -320,11 +308,29 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter(MusicUtil.limitPlayableMedia(songs, getBindingAdapterPosition()))); bundle.putInt(Constants.ITEM_POSITION, MusicUtil.getPlayableMediaPosition(songs, getBindingAdapterPosition())); - click.onMediaClick(bundle); + if (tappedSong.getId().equals(currentPlayingId)) { + Log.i("SongHorizontalAdapter", "Tapping on currently playing song, toggling playback"); + try{ + MediaBrowser mediaBrowser = mediaBrowserListenableFuture.get(); + Log.i("SongHorizontalAdapter", "MediaBrowser retrieved, isPlaying: " + isPlaying); + if (isPlaying) { + mediaBrowser.pause(); + } else { + mediaBrowser.play(); + } + } catch (ExecutionException | InterruptedException e) { + Log.e("SongHorizontalAdapter", "Error getting MediaBrowser", e); + } + } else { + click.onMediaClick(bundle); + } } private boolean onLongClick() { @@ -352,4 +358,8 @@ 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 50a09fe7..03ea9100 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 @@ -99,6 +99,11 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { observePlayback(); } + public void onResume() { + super.onResume(); + if (songHorizontalAdapter != null) setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -277,6 +282,7 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, false, false, album); bind.songRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); reapplyPlayback(); albumPageViewModel.getAlbumSongLiveList().observe(getViewLifecycleOwner(), songs -> { @@ -328,4 +334,8 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter.setPlaybackState(id, playing != null && playing); } } + + private void setMediaBrowserListenableFuture() { + 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 1d1cb7d1..48453b8c 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 @@ -83,6 +83,11 @@ public class ArtistPageFragment extends Fragment implements ClickCallback { observePlayback(); } + public void onResume() { + super.onResume(); + if (songHorizontalAdapter != null) setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -175,6 +180,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, true, true, null); bind.mostStreamedSongRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); reapplyPlayback(); artistPageViewModel.getArtistTopSongList().observe(getViewLifecycleOwner(), songs -> { if (songs == null) { @@ -299,4 +305,8 @@ public class ArtistPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter.setPlaybackState(id, playing != null && playing); } } + + private void setMediaBrowserListenableFuture() { + 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 ae95f35f..4c47f0c9 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 @@ -151,6 +151,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { public void onResume() { super.onResume(); refreshSharesView(); + if (topSongAdapter != null) setTopSongsMediaBrowserListenableFuture(); + if (starredSongAdapter != null) setStarredSongsMediaBrowserListenableFuture(); } @Override @@ -484,6 +486,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { topSongAdapter = new SongHorizontalAdapter(this, true, false, null); bind.topSongsRecyclerView.setAdapter(topSongAdapter); + setTopSongsMediaBrowserListenableFuture(); reapplyTopSongsPlayback(); homeViewModel.getChronologySample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), chronologies -> { if (chronologies == null || chronologies.isEmpty()) { @@ -524,6 +527,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { starredSongAdapter = new SongHorizontalAdapter(this, true, false, null); bind.starredTracksRecyclerView.setAdapter(starredSongAdapter); + setStarredSongsMediaBrowserListenableFuture(); reapplyStarredSongsPlayback(); homeViewModel.getStarredTracks(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> { if (songs == null) { @@ -1102,4 +1106,12 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback { topSongAdapter.setPlaybackState(id, playing != null && playing); } } + + private void setTopSongsMediaBrowserListenableFuture() { + topSongAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture); + } + + private void setStarredSongsMediaBrowserListenableFuture() { + 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 ef58e96c..7fefe7db 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 @@ -117,6 +117,12 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback { observePlayback(); } + @Override + public void onResume() { + super.onResume(); + if (songHorizontalAdapter != null) setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -254,6 +260,7 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, true, false, null); bind.songRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); reapplyPlayback(); playlistPageViewModel.getPlaylistSongLiveList().observe(getViewLifecycleOwner(), songs -> { @@ -303,4 +310,8 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter.setPlaybackState(id, playing != null && playing); } } + + private void setMediaBrowserListenableFuture() { + 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 b6c3b8d3..c4b5f3b1 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 @@ -81,6 +81,7 @@ public class SearchFragment extends Fragment implements ClickCallback { @Override public void onResume() { super.onResume(); + if (songHorizontalAdapter != null) setMediaBrowserListenableFuture(); } @Override @@ -121,6 +122,7 @@ public class SearchFragment extends Fragment implements ClickCallback { bind.searchResultTracksRecyclerView.setHasFixedSize(true); songHorizontalAdapter = new SongHorizontalAdapter(this, true, false, null); + setMediaBrowserListenableFuture(); reapplyPlayback(); bind.searchResultTracksRecyclerView.setAdapter(songHorizontalAdapter); @@ -321,4 +323,8 @@ public class SearchFragment extends Fragment implements ClickCallback { songHorizontalAdapter.setPlaybackState(id, playing != null && playing); } } + + private void setMediaBrowserListenableFuture() { + 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 4f8bad46..a524e7c7 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 @@ -90,6 +90,12 @@ public class SongListPageFragment extends Fragment implements ClickCallback { observePlayback(); } + @Override + public void onResume() { + super.onResume(); + setMediaBrowserListenableFuture(); + } + @Override public void onStop() { releaseMediaBrowser(); @@ -197,6 +203,7 @@ public class SongListPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter = new SongHorizontalAdapter(this, true, false, null); bind.songListRecyclerView.setAdapter(songHorizontalAdapter); + setMediaBrowserListenableFuture(); reapplyPlayback(); songListPageViewModel.getSongList().observe(getViewLifecycleOwner(), songs -> { isLoading = false; @@ -356,4 +363,8 @@ public class SongListPageFragment extends Fragment implements ClickCallback { songHorizontalAdapter.setPlaybackState(id, playing != null && playing); } } + + private void setMediaBrowserListenableFuture() { + 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 57711a1c..dfead0fd 100644 --- a/app/src/main/res/layout/item_horizontal_track.xml +++ b/app/src/main/res/layout/item_horizontal_track.xml @@ -66,18 +66,12 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/different_disk_divider_sector" /> -