-
-
Notifications
You must be signed in to change notification settings - Fork 112
[Help Wanted] feat: add cover flow to player #653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Changes from all commits
7380cc2
5311bdd
b2f54ab
decc37a
1d0dfb3
5ff9ff5
30e6ff8
5c9083f
005a09f
4702091
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package com.cappielloantonio.tempo.factory; | ||
|
|
||
| import androidx.annotation.NonNull; | ||
| import androidx.lifecycle.ViewModel; | ||
| import androidx.lifecycle.ViewModelProvider; | ||
|
|
||
| import com.cappielloantonio.tempo.repository.CoverRepository; | ||
| import com.cappielloantonio.tempo.viewmodel.CoverFlowViewModel; | ||
|
|
||
| public class CoverFlowViewModelFactory implements ViewModelProvider.Factory { | ||
|
|
||
| private final CoverRepository repository; | ||
|
|
||
| public CoverFlowViewModelFactory(@NonNull CoverRepository repository) { | ||
| this.repository = repository; | ||
| } | ||
|
|
||
| @NonNull | ||
| @Override | ||
| public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { | ||
| if (modelClass.isAssignableFrom(CoverFlowViewModel.class)) { | ||
| //noinspection unchecked | ||
| return (T) new CoverFlowViewModel(repository); | ||
| } | ||
| throw new IllegalArgumentException("Unknown ViewModel class"); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.cappielloantonio.tempo.model; | ||
|
|
||
| import androidx.annotation.NonNull; | ||
| import androidx.annotation.Nullable; | ||
|
|
||
| public class Cover { | ||
| private final String url; // image to show in the flow | ||
| private final String coverArtId; // id used by the CustomGlideRequest (may be null) | ||
|
|
||
| public Cover(@NonNull String url, @Nullable String coverArtId) { | ||
| this.url = url; | ||
| this.coverArtId = coverArtId; | ||
| } | ||
|
|
||
| @NonNull | ||
| public String getUrl() { | ||
| return url; | ||
| } | ||
|
|
||
| /** Returns the id that the CustomGlideRequest needs – can be null. */ | ||
| @Nullable | ||
| public String getCoverArtId() { | ||
| return coverArtId; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.cappielloantonio.tempo.repository; | ||
|
|
||
| import androidx.annotation.NonNull; | ||
| import androidx.annotation.WorkerThread; | ||
| import androidx.media3.common.MediaMetadata; | ||
| import androidx.media3.session.MediaBrowser; | ||
|
|
||
| import com.cappielloantonio.tempo.model.Cover; | ||
| import com.google.common.util.concurrent.ListenableFuture; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
|
|
||
| public interface CoverRepository { | ||
| /** Returns a list of covers. Call should be made off the UI thread. */ | ||
| @WorkerThread | ||
| List<Cover> getCovers() throws Exception; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package com.cappielloantonio.tempo.repository; | ||
|
|
||
| import androidx.annotation.NonNull; | ||
| import androidx.annotation.WorkerThread; | ||
| import androidx.media3.common.MediaMetadata; | ||
| import androidx.media3.session.MediaBrowser; | ||
|
|
||
| import com.cappielloantonio.tempo.glide.CustomGlideRequest; | ||
| import com.cappielloantonio.tempo.model.Cover; | ||
| import com.google.common.util.concurrent.ListenableFuture; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; /** Example implementation that extracts data from a MediaBrowser */ | ||
| public class MediaBrowserCoverRepository implements CoverRepository { | ||
|
|
||
| private final ListenableFuture<MediaBrowser> mediaBrowserFuture; | ||
|
|
||
| public MediaBrowserCoverRepository(@NonNull ListenableFuture<MediaBrowser> mediaBrowserFuture) { | ||
| this.mediaBrowserFuture = mediaBrowserFuture; | ||
| } | ||
|
|
||
| @Override | ||
| @WorkerThread | ||
| public List<Cover> getCovers() throws Exception { | ||
| MediaBrowser mediaBrowser = mediaBrowserFuture.get(); // blocks only inside a background thread | ||
| MediaMetadata metadata = mediaBrowser.getMediaMetadata(); | ||
|
|
||
| // Inject this here, somehow, since it grabs the covertArtId | ||
| /*` | ||
| CustomGlideRequest.Builder | ||
| .from(requireContext(), metadata.extras.getString("coverArtId"), CustomGlideRequest.ResourceType.Song) | ||
| .build() | ||
| .into(bind.playerHeaderLayout.playerHeaderMediaCoverImage); | ||
|
|
||
| */ | ||
| // ----------------------------------------------------------------- | ||
| // Replace the below with the real extraction logic from metadata. | ||
| // For demonstration we just return the three dog‑image URLs. | ||
| // ----------------------------------------------------------------- | ||
| List<String> urls = Arrays.asList( | ||
| "https://images.dog.ceo/breeds/affenpinscher/n02110627_11858.jpg", | ||
| "https://images.dog.ceo/breeds/hound-english/n02089973_811.jpg", | ||
| "https://images.dog.ceo/breeds/shiba/shiba-14.jpg" | ||
| ); | ||
|
|
||
| List<Cover> covers = new ArrayList<>(); | ||
| for (String url : urls) { | ||
| covers.add(new Cover(url, null)); // coverArtId can be filled later if needed | ||
| } | ||
| return covers; | ||
|
Comment on lines
+27
to
+51
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Repository currently bypasses the playback source, so Cover Flow cannot sync with queue state. At Line 27 metadata is retrieved, but Lines 41-50 return a static dog URL list instead of mapping the actual playback/queue data. This breaks the intended data contract for end-to-end queue synchronization. Direction for fix- MediaMetadata metadata = mediaBrowser.getMediaMetadata();
- ...
- List<String> urls = Arrays.asList(...);
- List<Cover> covers = new ArrayList<>();
- for (String url : urls) {
- covers.add(new Cover(url, null));
- }
- return covers;
+ // Build covers from the active queue/media items so RecyclerView state
+ // and playback queue represent the same ordering/source of truth.
+ // (Use media item art URI and/or coverArtId extracted from metadata extras.)
+ return extractCoversFromQueue(mediaBrowser);🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| package com.cappielloantonio.tempo.ui.adapter; | ||
|
|
||
| import android.content.Context; | ||
| import android.view.LayoutInflater; | ||
| import android.view.View; | ||
| import android.view.ViewGroup; | ||
| import android.widget.ImageView; | ||
|
|
||
| import androidx.recyclerview.widget.RecyclerView; | ||
|
|
||
| import com.bumptech.glide.Glide; | ||
| import com.cappielloantonio.tempo.R; | ||
| import com.cappielloantonio.tempo.model.Cover; | ||
|
|
||
| import org.jspecify.annotations.NonNull; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify whether JSpecify is explicitly declared and how broadly it's used.
set -euo pipefail
echo "== Build files mentioning jspecify =="
rg -n --iglob '*gradle*' 'jspecify|org\.jspecify'
echo
echo "== Java/Kotlin files importing org.jspecify.annotations.NonNull =="
rg -n 'import\s+org\.jspecify\.annotations\.NonNull'
echo
echo "== Java/Kotlin files importing androidx.annotation.NonNull =="
rg -n 'import\s+androidx\.annotation\.NonNull'Repository: eddyizm/tempus Length of output: 96 🏁 Script executed: # Check if the file exists and read its imports
fd -n 'CoverFlowAdapter.java' --exec head -80 {}
echo "=== Checking for build files ==="
fd -t f -e gradle -e xml | grep -E '(build|pom)' | head -20Repository: eddyizm/tempus Length of output: 370 🏁 Script executed: # More comprehensive search for jspecify in the entire codebase
echo "== All files with jspecify anywhere in content =="
rg 'jspecify' -i
echo
echo "== All imports of NonNull annotations =="
rg 'import.*NonNull' -A 1Repository: eddyizm/tempus Length of output: 45111 🏁 Script executed: # Check main build.gradle files for dependencies
echo "=== app/build.gradle ==="
cat app/build.gradle | grep -A 100 "dependencies"
echo
echo "=== Root build.gradle ==="
head -100 build.gradleRepository: eddyizm/tempus Length of output: 3326 🏁 Script executed: # Check if jspecify appears anywhere in gradle files (even if commented)
echo "=== Any mention of jspecify in all gradle files ==="
rg 'jspecify' -i app/build.gradle build.gradle gradle.properties settings.gradle 2>/dev/null || echo "No jspecify found"
# Also check if CoverFlowAdapter.java and UIUtil.java are the ONLY files with jspecify imports
echo
echo "=== All lines mentioning jspecify in source files ==="
rg 'org\.jspecify' --type javaRepository: eddyizm/tempus Length of output: 405 Replace JSpecify is not declared as a dependency in the build configuration. This adapter and UIUtil.java are the only two files in the codebase using JSpecify annotations; all other files use AndroidX annotations. The inconsistency should be resolved by standardizing on 🤖 Prompt for AI Agents |
||
|
|
||
| import java.util.List; | ||
|
|
||
| public class CoverFlowAdapter extends RecyclerView.Adapter<CoverFlowAdapter.CoverViewHolder> { | ||
|
|
||
| /** Callback that is invoked for every bound item – useful for the extra Glide request. */ | ||
| public interface OnCoverBoundListener { | ||
| void onCoverBound(@NonNull Cover cover, @NonNull ImageView coverImage); | ||
| } | ||
|
|
||
| private final Context context; | ||
| private final List<Cover> covers; | ||
| private final OnCoverBoundListener boundListener; | ||
|
|
||
| public CoverFlowAdapter(@NonNull Context context, | ||
| @NonNull List<Cover> covers, | ||
| @NonNull OnCoverBoundListener boundListener) { | ||
| this.context = context; | ||
| this.covers = covers; | ||
| this.boundListener = boundListener; | ||
| } | ||
|
|
||
| @NonNull | ||
| @Override | ||
| public CoverViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||
| // Inflate a simple item layout that contains only an ImageView. | ||
| View view = LayoutInflater.from(context).inflate(R.layout.item_cover_flow, parent, false); | ||
| return new CoverViewHolder(view); | ||
| } | ||
|
|
||
| @Override | ||
| public void onBindViewHolder(@NonNull CoverViewHolder holder, int position) { | ||
| Cover cover = covers.get(position); | ||
| holder.bind(cover); | ||
| // Let the fragment (or caller) run the extra CustomGlideRequest if it needs the id. | ||
| boundListener.onCoverBound(cover, holder.coverImage); | ||
| } | ||
|
Comment on lines
+47
to
+52
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid issuing two image loads for the same bind target.
Suggested fix- Cover cover = covers.get(position);
- holder.bind(cover);
- // Let the fragment (or caller) run the extra CustomGlideRequest if it needs the id.
- boundListener.onCoverBound(cover, holder.coverImage);
+ Cover cover = covers.get(position);
+ // Use one source-of-truth load path per item.
+ if (cover.getCoverArtId() != null) {
+ boundListener.onCoverBound(cover, holder.coverImage);
+ } else {
+ holder.bind(cover);
+ }Also applies to: 70-75 🤖 Prompt for AI Agents |
||
|
|
||
| @Override | ||
| public int getItemCount() { | ||
| return covers.size(); | ||
| } | ||
|
|
||
| /** ----------------------------------------------------------------- | ||
| * ViewHolder – each item holds a single ImageView. | ||
| * ----------------------------------------------------------------- */ | ||
| class CoverViewHolder extends RecyclerView.ViewHolder { | ||
| final ImageView coverImage; | ||
|
|
||
| CoverViewHolder(@NonNull View itemView) { | ||
| super(itemView); | ||
| coverImage = itemView.findViewById(R.id.item_cover_image); | ||
| } | ||
|
|
||
| void bind(@NonNull Cover cover) { | ||
| // Normal image loading (the flow thumbnails) | ||
| Glide.with(context) | ||
| .load(cover.getUrl()) | ||
| .centerCrop() | ||
| .into(coverImage); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import android.widget.Toast; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.annotation.NonNull; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.annotation.Nullable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.appcompat.widget.PopupMenu; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.constraintlayout.widget.ConstraintLayout; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.fragment.app.Fragment; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -36,6 +37,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.navigation.NavController; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.navigation.NavOptions; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.navigation.fragment.NavHostFragment; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.recyclerview.widget.RecyclerView; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.transition.ChangeBounds; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.transition.Slide; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.transition.TransitionManager; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -44,9 +47,15 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.R; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.databinding.InnerFragmentPlayerControllerBinding; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.factory.CoverFlowViewModelFactory; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.glide.CustomGlideRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.model.Cover; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.repository.CoverRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.repository.MediaBrowserCoverRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.equalizer.EqualizerManager; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.service.MediaService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.ui.activity.MainActivity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.ui.adapter.CoverFlowAdapter; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.ui.dialog.PlaybackSpeedDialog; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.ui.dialog.SleepTimerDialog; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.util.SleepTimerManager; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -60,6 +69,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.util.Constants; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.util.MusicUtil; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.util.Preferences; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.util.UIUtil; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.viewmodel.CoverFlowViewModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.viewmodel.PlayerBottomSheetViewModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.cappielloantonio.tempo.viewmodel.RatingViewModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.google.android.material.chip.Chip; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -71,6 +82,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.lang.reflect.Field; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.lang.reflect.Method; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.ArrayList; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Arrays; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Objects; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -99,6 +111,8 @@ public class PlayerControllerFragment extends Fragment { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private LinearLayout sleepTimerContainer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private ImageButton sleepTimerButton; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private android.widget.TextView sleepTimerLabel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private RecyclerView playerCoverFlow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private ChipGroup assetLinkChipGroup; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Chip playerSongLinkChip; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Chip playerAlbumLinkChip; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -136,6 +150,78 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return view; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private CoverFlowViewModel viewModel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // public CoverFlowFragment() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // super(R.layout.inner_fragment_player_controller_layout); // your layout that contains the RecyclerView | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void onViewCreated(@NonNull View root, @Nullable Bundle savedInstanceState) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onViewCreated(root, savedInstanceState); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 1️⃣ Find the RecyclerView (the id changed to player_cover_flow) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow = root.findViewById(R.id.player_cover_flow); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 2️⃣ Set up the ViewModel (repository injection omitted for brevity) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // CoverRepository repository = new MediaBrowserCoverRepository(mediaBrowserListenableFuture); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // viewModel = new ViewModelProvider(this, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // new CoverFlowViewModelFactory(repository)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // .get(CoverFlowViewModel.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CoverRepository repository = new MediaBrowserCoverRepository(mediaBrowserListenableFuture); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CoverFlowViewModelFactory factory = new CoverFlowViewModelFactory(repository); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewModel = new ViewModelProvider(this, factory) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .get(CoverFlowViewModel.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+175
to
+179
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Initialize At Line 175, Also applies to: 319-321 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 3️⃣ Observe the LiveData and build the UI when data arrives | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| viewModel.getCovers().observe(getViewLifecycleOwner(), this::setupCoverFlow); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Called once the list of covers is available */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private void setupCoverFlow(@NonNull List<Cover> covers) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (covers.isEmpty()) return; // optionally show an empty‑state view | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 4️⃣ Create the adapter – the lambda receives the Cover object | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // and the ImageView that just got bound. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CoverFlowAdapter adapter = new CoverFlowAdapter( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| requireContext(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| covers, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (cover, imageView) -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Run the *extra* Glide request only when we have a valid id. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String coverArtId = cover.getCoverArtId(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (coverArtId != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CustomGlideRequest.Builder | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from(requireContext(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| coverArtId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CustomGlideRequest.ResourceType.Song) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .into(imageView); // load into the same thumbnail ImageView | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 5️⃣ RecyclerView basics (same as your original code) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow.setAdapter(adapter); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow.setLayoutManager( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new LinearLayoutManager(requireContext(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LinearLayoutManager.HORIZONTAL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| false)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow.addItemDecoration(UIUtil.horizontalSpacing(32)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow.addOnScrollListener(UIUtil.scaleOnScroll()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UIUtil.centerAndSnapRecyclerView(playerCoverFlow); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+188
to
+223
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "PlayerControllerFragment.java" -type fRepository: eddyizm/tempus Length of output: 147 🏁 Script executed: rg "setupCoverFlow" -B 5 -A 15Repository: eddyizm/tempus Length of output: 3535 🏁 Script executed: rg "playerCoverFlow" --max-count 20 -B 2 -A 2Repository: eddyizm/tempus Length of output: 5242 🏁 Script executed: cat -n app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java | head -250Repository: eddyizm/tempus Length of output: 12624 🏁 Script executed: rg "UIUtil\.(centerAndSnapRecyclerView|horizontalSpacing|scaleOnScroll)" -A 10Repository: eddyizm/tempus Length of output: 1545 🏁 Script executed: find . -name "UIUtil.java" -type fRepository: eddyizm/tempus Length of output: 122 🏁 Script executed: rg "class UIUtil|fun centerAndSnapRecyclerView|fun horizontalSpacing|fun scaleOnScroll" -A 20Repository: eddyizm/tempus Length of output: 2162 🏁 Script executed: rg "centerAndSnapRecyclerView|horizontalSpacing|scaleOnScroll" -B 2 -A 15 app/src/main/java/com/cappielloantonio/tempo/util/UIUtil.javaRepository: eddyizm/tempus Length of output: 1603 🏁 Script executed: rg "centerAndSnapRecyclerView" -A 40 app/src/main/java/com/cappielloantonio/tempo/util/UIUtil.javaRepository: eddyizm/tempus Length of output: 1132 Make Lines 220–222 execute on every LiveData emission, accumulating item decorations, scroll listeners, and reattaching the snap helper. Each call to Guard the decoration, listener, and snap setup with a flag to run only on first initialization, while updating the adapter on each call: + private boolean coverFlowInitialized = false;
private void setupCoverFlow(`@NonNull` List<Cover> covers) {
- if (covers.isEmpty()) return; // optionally show an empty‑state view
+ if (covers.isEmpty()) {
+ playerCoverFlow.setAdapter(null);
+ playerCoverFlow.setVisibility(View.GONE);
+ return;
+ }
+ playerCoverFlow.setVisibility(View.VISIBLE);
CoverFlowAdapter adapter = new CoverFlowAdapter(
requireContext(),
covers,
(cover, imageView) -> {
String coverArtId = cover.getCoverArtId();
if (coverArtId != null) {
CustomGlideRequest.Builder
.from(requireContext(), coverArtId, CustomGlideRequest.ResourceType.Song)
.build()
.into(imageView);
}
});
playerCoverFlow.setAdapter(adapter);
- playerCoverFlow.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
- playerCoverFlow.addItemDecoration(UIUtil.horizontalSpacing(32));
- playerCoverFlow.addOnScrollListener(UIUtil.scaleOnScroll());
- UIUtil.centerAndSnapRecyclerView(playerCoverFlow);
+ if (!coverFlowInitialized) {
+ playerCoverFlow.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
+ playerCoverFlow.addItemDecoration(UIUtil.horizontalSpacing(32));
+ playerCoverFlow.addOnScrollListener(UIUtil.scaleOnScroll());
+ UIUtil.centerAndSnapRecyclerView(playerCoverFlow);
+ coverFlowInitialized = true;
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void onStart() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onStart(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -169,6 +255,7 @@ private void init() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerOpenQueueButton = bind.getRoot().findViewById(R.id.player_open_queue_button); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerOpenLyricsButton = bind.getRoot().findViewById(R.id.player_open_lyrics_button); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerTrackInfo = bind.getRoot().findViewById(R.id.player_info_track); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow = bind.getRoot().findViewById(R.id.player_cover_flow); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| songRatingBar = bind.getRoot().findViewById(R.id.song_rating_bar); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ratingContainer = bind.getRoot().findViewById(R.id.rating_container); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| equalizerButton = bind.getRoot().findViewById(R.id.player_open_equalizer_button); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -215,14 +302,20 @@ private void initQuickActionView() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerOpenLyricsButton.setOnClickListener(view -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int currentItem = playerMediaCoverViewPager.getCurrentItem(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentItem == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerMediaCoverViewPager.setCurrentItem(1, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerMediaCoverViewPager.setCurrentItem(1, false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow.setVisibility(View.GONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerMediaCoverViewPager.setVisibility(View.VISIBLE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (currentItem == 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerMediaCoverViewPager.setCurrentItem(0, true);; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerMediaCoverViewPager.setCurrentItem(0, false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerCoverFlow.setVisibility(View.VISIBLE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| playerMediaCoverViewPager.setVisibility(View.GONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private void initializeBrowser() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a bounded wait when resolving
mediaBrowserFuture.Line 26 uses
mediaBrowserFuture.get()with no timeout; if the future never resolves, cover loading can hang indefinitely and never post data.Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents