refactor: refactored artist page layout for consistent vertical scrolling

This commit is contained in:
CappielloAntonio 2024-03-16 17:44:18 +01:00
parent 2712b73dac
commit b4180afa36
7 changed files with 49 additions and 101 deletions

View file

@ -132,9 +132,10 @@ public class AlbumRepository {
.enqueue(new Callback<ApiResponse>() { .enqueue(new Callback<ApiResponse>() {
@Override @Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) { public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getArtist() != null) { if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getArtist() != null && response.body().getSubsonicResponse().getArtist().getAlbums() != null) {
List<AlbumID3> albums = response.body().getSubsonicResponse().getArtist().getAlbums(); List<AlbumID3> albums = response.body().getSubsonicResponse().getArtist().getAlbums();
albums.sort(Comparator.comparing(AlbumID3::getYear)); albums.sort(Comparator.comparing(AlbumID3::getYear));
Collections.reverse(albums);
artistsAlbum.setValue(albums); artistsAlbum.setValue(albums);
} }
} }

View file

@ -2,6 +2,7 @@ package com.cappielloantonio.tempo.ui.adapter;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Filter; import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
@ -24,6 +25,7 @@ import java.util.List;
public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAdapter.ViewHolder> implements Filterable { public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAdapter.ViewHolder> implements Filterable {
private final ClickCallback click; private final ClickCallback click;
private String currentFilter; private String currentFilter;
private boolean showArtist;
private final Filter filtering = new Filter() { private final Filter filtering = new Filter() {
@Override @Override
@ -59,11 +61,12 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
private List<AlbumID3> albums; private List<AlbumID3> albums;
private List<AlbumID3> albumsFull; private List<AlbumID3> albumsFull;
public AlbumCatalogueAdapter(ClickCallback click) { public AlbumCatalogueAdapter(ClickCallback click, boolean showArtist) {
this.click = click; this.click = click;
this.albums = Collections.emptyList(); this.albums = Collections.emptyList();
this.albumsFull = Collections.emptyList(); this.albumsFull = Collections.emptyList();
this.currentFilter = ""; this.currentFilter = "";
this.showArtist = showArtist;
} }
@NonNull @NonNull
@ -79,6 +82,7 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
holder.item.albumNameLabel.setText(MusicUtil.getReadableString(album.getName())); holder.item.albumNameLabel.setText(MusicUtil.getReadableString(album.getName()));
holder.item.artistNameLabel.setText(MusicUtil.getReadableString(album.getArtist())); holder.item.artistNameLabel.setText(MusicUtil.getReadableString(album.getArtist()));
holder.item.artistNameLabel.setVisibility(showArtist ? View.VISIBLE : View.GONE);
CustomGlideRequest.Builder CustomGlideRequest.Builder
.from(holder.itemView.getContext(), album.getCoverArtId(), CustomGlideRequest.ResourceType.Album) .from(holder.itemView.getContext(), album.getCoverArtId(), CustomGlideRequest.ResourceType.Album)

View file

@ -112,7 +112,7 @@ public class AlbumCatalogueFragment extends Fragment implements ClickCallback {
bind.albumCatalogueRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false)); bind.albumCatalogueRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
bind.albumCatalogueRecyclerView.setHasFixedSize(true); bind.albumCatalogueRecyclerView.setHasFixedSize(true);
albumAdapter = new AlbumCatalogueAdapter(this); albumAdapter = new AlbumCatalogueAdapter(this, true);
albumAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY); albumAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);
bind.albumCatalogueRecyclerView.setAdapter(albumAdapter); bind.albumCatalogueRecyclerView.setAdapter(albumAdapter);
albumCatalogueViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> albumAdapter.setItems(albums)); albumCatalogueViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> albumAdapter.setItems(albums));

View file

@ -27,9 +27,11 @@ import com.cappielloantonio.tempo.helper.recyclerview.GridItemDecoration;
import com.cappielloantonio.tempo.interfaces.ClickCallback; import com.cappielloantonio.tempo.interfaces.ClickCallback;
import com.cappielloantonio.tempo.service.MediaManager; import com.cappielloantonio.tempo.service.MediaManager;
import com.cappielloantonio.tempo.service.MediaService; import com.cappielloantonio.tempo.service.MediaService;
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
import com.cappielloantonio.tempo.ui.activity.MainActivity; import com.cappielloantonio.tempo.ui.activity.MainActivity;
import com.cappielloantonio.tempo.ui.adapter.AlbumArtistPageOrSimilarAdapter; import com.cappielloantonio.tempo.ui.adapter.AlbumArtistPageOrSimilarAdapter;
import com.cappielloantonio.tempo.ui.adapter.AlbumCatalogueAdapter; import com.cappielloantonio.tempo.ui.adapter.AlbumCatalogueAdapter;
import com.cappielloantonio.tempo.ui.adapter.ArtistCatalogueAdapter;
import com.cappielloantonio.tempo.ui.adapter.ArtistSimilarAdapter; import com.cappielloantonio.tempo.ui.adapter.ArtistSimilarAdapter;
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter; import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
import com.cappielloantonio.tempo.util.Constants; import com.cappielloantonio.tempo.util.Constants;
@ -38,6 +40,10 @@ import com.cappielloantonio.tempo.util.Preferences;
import com.cappielloantonio.tempo.viewmodel.ArtistPageViewModel; import com.cappielloantonio.tempo.viewmodel.ArtistPageViewModel;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@UnstableApi @UnstableApi
public class ArtistPageFragment extends Fragment implements ClickCallback { public class ArtistPageFragment extends Fragment implements ClickCallback {
private FragmentArtistPageBinding bind; private FragmentArtistPageBinding bind;
@ -45,9 +51,8 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
private ArtistPageViewModel artistPageViewModel; private ArtistPageViewModel artistPageViewModel;
private SongHorizontalAdapter songHorizontalAdapter; private SongHorizontalAdapter songHorizontalAdapter;
private AlbumArtistPageOrSimilarAdapter albumArtistPageOrSimilarAdapter;
private AlbumCatalogueAdapter albumCatalogueAdapter; private AlbumCatalogueAdapter albumCatalogueAdapter;
private ArtistSimilarAdapter artistSimilarAdapter; private ArtistCatalogueAdapter artistCatalogueAdapter;
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture; private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
@ -64,8 +69,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
initArtistInfo(); initArtistInfo();
initPlayButtons(); initPlayButtons();
initTopSongsView(); initTopSongsView();
initHorizontalAlbumsView(); initAlbumsView();
initVerticalAlbumsView();
initSimilarArtistsView(); initSimilarArtistsView();
return view; return view;
@ -99,18 +103,6 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
bundle.putParcelable(Constants.ARTIST_OBJECT, artistPageViewModel.getArtist()); bundle.putParcelable(Constants.ARTIST_OBJECT, artistPageViewModel.getArtist());
activity.navController.navigate(R.id.action_artistPageFragment_to_songListPageFragment, bundle); activity.navController.navigate(R.id.action_artistPageFragment_to_songListPageFragment, bundle);
}); });
bind.artistPageAlbumsSwitchLayoutTextViewClickable.setOnClickListener(view -> {
boolean isHorizontalRecyclerViewVisible = bind.albumsHorizontalRecyclerView.getVisibility() == View.VISIBLE;
bind.albumsHorizontalRecyclerView.setVisibility(isHorizontalRecyclerViewVisible ? View.GONE : View.VISIBLE);
bind.albumsVerticalRecyclerView.setVisibility(isHorizontalRecyclerViewVisible ? View.VISIBLE : View.GONE);
Preferences.setArtistAlbumLayout(!isHorizontalRecyclerViewVisible);
});
bind.albumsHorizontalRecyclerView.setVisibility(Preferences.isArtistAlbumLayoutHorizontal() ? View.VISIBLE : View.GONE);
bind.albumsVerticalRecyclerView.setVisibility(Preferences.isArtistAlbumLayoutHorizontal() ? View.GONE : View.VISIBLE);
} }
private void initAppBar() { private void initAppBar() {
@ -203,36 +195,13 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
}); });
} }
private void initHorizontalAlbumsView() { private void initAlbumsView() {
bind.albumsHorizontalRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)); bind.albumsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
bind.albumsRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
bind.albumsRecyclerView.setHasFixedSize(true);
albumArtistPageOrSimilarAdapter = new AlbumArtistPageOrSimilarAdapter(this); albumCatalogueAdapter = new AlbumCatalogueAdapter(this, false);
bind.albumsHorizontalRecyclerView.setAdapter(albumArtistPageOrSimilarAdapter); bind.albumsRecyclerView.setAdapter(albumCatalogueAdapter);
artistPageViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> {
if (albums == null) {
if (bind != null)
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null) bind.artistPageAlbumsSector.setVisibility(View.GONE);
} else {
if (bind != null)
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null)
bind.artistPageAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
albumArtistPageOrSimilarAdapter.setItems(albums);
}
});
CustomLinearSnapHelper albumSnapHelper = new CustomLinearSnapHelper();
albumSnapHelper.attachToRecyclerView(bind.albumsHorizontalRecyclerView);
}
private void initVerticalAlbumsView() {
bind.albumsVerticalRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
bind.albumsVerticalRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
bind.albumsVerticalRecyclerView.setHasFixedSize(true);
albumCatalogueAdapter = new AlbumCatalogueAdapter(this);
bind.albumsVerticalRecyclerView.setAdapter(albumCatalogueAdapter);
artistPageViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> { artistPageViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> {
if (albums == null) { if (albums == null) {
@ -250,11 +219,13 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
} }
private void initSimilarArtistsView() { private void initSimilarArtistsView() {
bind.similarArtistsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)); bind.similarArtistsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
bind.similarArtistsRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
bind.similarArtistsRecyclerView.setHasFixedSize(true); bind.similarArtistsRecyclerView.setHasFixedSize(true);
artistSimilarAdapter = new ArtistSimilarAdapter(this); artistCatalogueAdapter = new ArtistCatalogueAdapter(this);
bind.similarArtistsRecyclerView.setAdapter(artistSimilarAdapter); bind.similarArtistsRecyclerView.setAdapter(artistCatalogueAdapter);
artistPageViewModel.getArtistInfo(artistPageViewModel.getArtist().getId()).observe(getViewLifecycleOwner(), artist -> { artistPageViewModel.getArtistInfo(artistPageViewModel.getArtist().getId()).observe(getViewLifecycleOwner(), artist -> {
if (artist == null) { if (artist == null) {
if (bind != null) if (bind != null)
@ -263,9 +234,16 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
} else { } else {
if (bind != null) if (bind != null)
bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.GONE); bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null) if (bind != null && artist.getSimilarArtists() != null)
bind.similarArtistSector.setVisibility(!artist.getSimilarArtists().isEmpty() ? View.VISIBLE : View.GONE); bind.similarArtistSector.setVisibility(!artist.getSimilarArtists().isEmpty() ? View.VISIBLE : View.GONE);
artistSimilarAdapter.setItems(artist.getSimilarArtists());
List<ArtistID3> artists = new ArrayList<>();
if (artist.getSimilarArtists() != null) {
artists.addAll(artist.getSimilarArtists());
}
artistCatalogueAdapter.setItems(artists);
} }
}); });

View file

@ -52,7 +52,6 @@ object Preferences {
private const val BUFFERING_STRATEGY = "buffering_strategy" private const val BUFFERING_STRATEGY = "buffering_strategy"
private const val SKIP_MIN_STAR_RATING = "skip_min_star_rating" private const val SKIP_MIN_STAR_RATING = "skip_min_star_rating"
private const val MIN_STAR_RATING = "min_star_rating" private const val MIN_STAR_RATING = "min_star_rating"
private const val ARTIST_ALBUM_LAYOUT = "artist_album_layout"
private const val ALWAYS_ON_DISPLAY = "always_on_display" private const val ALWAYS_ON_DISPLAY = "always_on_display"
private const val AUDIO_QUALITY_PER_ITEM = "audio_quality_per_item" private const val AUDIO_QUALITY_PER_ITEM = "audio_quality_per_item"
@ -376,17 +375,6 @@ object Preferences {
return App.getInstance().preferences.getInt(MIN_STAR_RATING, 0) return App.getInstance().preferences.getInt(MIN_STAR_RATING, 0)
} }
@JvmStatic
fun isArtistAlbumLayoutHorizontal(): Boolean {
return App.getInstance().preferences.getBoolean(ARTIST_ALBUM_LAYOUT, true)
}
@JvmStatic
fun setArtistAlbumLayout(isArtistAlbumLayoutHorizontal: Boolean) {
App.getInstance().preferences.edit().putBoolean(ARTIST_ALBUM_LAYOUT, isArtistAlbumLayoutHorizontal)
.apply()
}
@JvmStatic @JvmStatic
fun isDisplayAlwaysOn(): Boolean { fun isDisplayAlwaysOn(): Boolean {
return App.getInstance().preferences.getBoolean(ALWAYS_ON_DISPLAY, false) return App.getInstance().preferences.getBoolean(ALWAYS_ON_DISPLAY, false)

View file

@ -204,44 +204,16 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <TextView
style="@style/TitleLarge"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/TitleLarge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingStart="16dp"
android:paddingEnd="8dp"
android:text="@string/artist_page_title_album_section" />
<TextView
android:id="@+id/artist_page_albums_switch_layout_text_view_clickable"
style="@style/TitleMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="16dp"
android:text="@string/artist_page_switch_layout_button" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/albums_horizontal_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:paddingBottom="8dp" android:text="@string/artist_page_title_album_section" />
android:visibility="visible"/>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/albums_vertical_recycler_view" android:id="@+id/albums_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
@ -250,8 +222,7 @@
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:paddingBottom="8dp" android:paddingBottom="8dp"/>
android:visibility="gone"/>
</LinearLayout> </LinearLayout>
<include <include
@ -283,7 +254,7 @@
android:clipToPadding="false" android:clipToPadding="false"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingEnd="8dp" android:paddingEnd="16dp"
android:paddingBottom="8dp" /> android:paddingBottom="8dp" />
</LinearLayout> </LinearLayout>

View file

@ -31,10 +31,16 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="marquee" android:ellipsize="marquee"
android:paddingBottom="16dp"
android:singleLine="true" android:singleLine="true"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/album_name_label" /> app:layout_constraintTop_toBottomOf="@+id/album_name_label" />
<View
android:layout_width="match_parent"
android:layout_height="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/artist_name_label"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>