Added starred tracks, starred albums and starred artists view

This commit is contained in:
CappielloAntonio 2021-07-27 16:58:38 +02:00
parent 9495fbd83d
commit 7742cbdd08
23 changed files with 752 additions and 171 deletions

View file

@ -0,0 +1,125 @@
package com.cappielloantonio.play.adapter;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.fragment.app.FragmentManager;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.RecyclerView;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.QueueRepository;
import com.cappielloantonio.play.service.MusicPlayerRemote;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.MusicUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class AlbumHorizontalAdapter extends RecyclerView.Adapter<AlbumHorizontalAdapter.ViewHolder> {
private static final String TAG = "AlbumHorizontalAdapter";
private List<Album> albums;
private LayoutInflater mInflater;
private MainActivity mainActivity;
private Context context;
private FragmentManager fragmentManager;
public AlbumHorizontalAdapter(MainActivity mainActivity, Context context, FragmentManager fragmentManager) {
this.mainActivity = mainActivity;
this.context = context;
this.fragmentManager = fragmentManager;
this.mInflater = LayoutInflater.from(context);
this.albums = new ArrayList<>();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_horizontal_album, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Album album = albums.get(position);
holder.albumTitle.setText(album.getTitle());
holder.albumArtist.setText(album.getArtistName());
CustomGlideRequest.Builder
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(holder.cover);
}
@Override
public int getItemCount() {
return albums.size();
}
public void setItems(List<Album> albums) {
this.albums = albums;
notifyDataSetChanged();
}
public Album getItem(int id) {
return albums.get(id);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView albumTitle;
TextView albumArtist;
ImageView more;
ImageView cover;
ViewHolder(View itemView) {
super(itemView);
albumTitle = itemView.findViewById(R.id.album_title_text_view);
albumArtist = itemView.findViewById(R.id.album_artist_text_view);
more = itemView.findViewById(R.id.album_more_button);
cover = itemView.findViewById(R.id.album_cover_image_view);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
more.setOnClickListener(v -> {
openMore(v);
});
albumTitle.setSelected(true);
}
@Override
public void onClick(View view) {
Bundle bundle = new Bundle();
bundle.putParcelable("album_object", albums.get(getBindingAdapterPosition()));
if (Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.homeFragment) {
Navigation.findNavController(view).navigate(R.id.action_homeFragment_to_albumPageFragment, bundle);
}
}
@Override
public boolean onLongClick(View v) {
openMore(v);
return true;
}
private void openMore(View view) {
Bundle bundle = new Bundle();
bundle.putParcelable("album_object", albums.get(getBindingAdapterPosition()));
Navigation.findNavController(view).navigate(R.id.albumBottomSheetDialog, bundle);
}
}
}

View file

@ -0,0 +1,126 @@
package com.cappielloantonio.play.adapter;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.fragment.app.FragmentManager;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.RecyclerView;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.QueueRepository;
import com.cappielloantonio.play.service.MusicPlayerRemote;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.MusicUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class ArtistHorizontalAdapter extends RecyclerView.Adapter<ArtistHorizontalAdapter.ViewHolder> {
private static final String TAG = "ArtistHorizontalAdapter";
private List<Artist> artists;
private LayoutInflater mInflater;
private MainActivity mainActivity;
private Context context;
private FragmentManager fragmentManager;
public ArtistHorizontalAdapter(MainActivity mainActivity, Context context, FragmentManager fragmentManager) {
this.mainActivity = mainActivity;
this.context = context;
this.fragmentManager = fragmentManager;
this.mInflater = LayoutInflater.from(context);
this.artists = new ArrayList<>();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_horizontal_artist, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Artist artist = artists.get(position);
holder.artistName.setText(artist.getName());
holder.artistInfo.setText("--");
CustomGlideRequest.Builder
.from(context, artist.getPrimary(), artist.getPrimaryBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(holder.cover);
}
@Override
public int getItemCount() {
return artists.size();
}
public void setItems(List<Artist> artists) {
this.artists = artists;
notifyDataSetChanged();
}
public Artist getItem(int id) {
return artists.get(id);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView artistName;
TextView artistInfo;
ImageView more;
ImageView cover;
ViewHolder(View itemView) {
super(itemView);
artistName = itemView.findViewById(R.id.artist_name_text_view);
artistInfo = itemView.findViewById(R.id.artist_info_text_view);
more = itemView.findViewById(R.id.artist_more_button);
cover = itemView.findViewById(R.id.artist_cover_image_view);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
more.setOnClickListener(v -> {
openMore(v);
});
artistName.setSelected(true);
}
@Override
public void onClick(View view) {
Bundle bundle = new Bundle();
bundle.putParcelable("artist_object", artists.get(getBindingAdapterPosition()));
if (Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.homeFragment) {
Navigation.findNavController(view).navigate(R.id.action_homeFragment_to_artistPageFragment, bundle);
}
}
@Override
public boolean onLongClick(View v) {
openMore(v);
return true;
}
private void openMore(View view) {
Bundle bundle = new Bundle();
bundle.putParcelable("song_object", artists.get(getBindingAdapterPosition()));
Navigation.findNavController(view).navigate(R.id.songBottomSheetDialog, bundle);
}
}
}

View file

@ -20,21 +20,19 @@ import com.cappielloantonio.play.repository.QueueRepository;
import com.cappielloantonio.play.service.MusicPlayerRemote;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.MusicUtil;
import com.cappielloantonio.play.util.PreferenceUtil;
import java.util.ArrayList;
import java.util.List;
public class SongResultSearchAdapter extends RecyclerView.Adapter<SongResultSearchAdapter.ViewHolder> {
private static final String TAG = "SongResultSearchAdapter";
public class SongHorizontalAdapter extends RecyclerView.Adapter<SongHorizontalAdapter.ViewHolder> {
private static final String TAG = "SongHorizontalAdapter";
private List<Song> songs;
private LayoutInflater mInflater;
private MainActivity mainActivity;
private Context context;
private FragmentManager fragmentManager;
public SongResultSearchAdapter(MainActivity mainActivity, Context context, FragmentManager fragmentManager) {
public SongHorizontalAdapter(MainActivity mainActivity, Context context, FragmentManager fragmentManager) {
this.mainActivity = mainActivity;
this.context = context;
this.fragmentManager = fragmentManager;
@ -44,7 +42,7 @@ public class SongResultSearchAdapter extends RecyclerView.Adapter<SongResultSear
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_search_result_song, parent, false);
View view = mInflater.inflate(R.layout.item_horizontal_track, parent, false);
return new ViewHolder(view);
}
@ -94,7 +92,7 @@ public class SongResultSearchAdapter extends RecyclerView.Adapter<SongResultSear
super(itemView);
songTitle = itemView.findViewById(R.id.search_result_song_title_text_view);
songArtist = itemView.findViewById(R.id.search_result_song_artist_text_view);
songArtist = itemView.findViewById(R.id.album_artist_text_view);
songDuration = itemView.findViewById(R.id.search_result_song_duration_text_view);
downloadIndicator = itemView.findViewById(R.id.search_result_dowanload_indicator_image_view);
more = itemView.findViewById(R.id.search_result_song_more_button);

View file

@ -56,7 +56,6 @@ public class Album implements Parcelable {
this.artistId = albumID3.getArtistId();
this.artistName = albumID3.getArtist();
this.primary = albumID3.getCoverArtId();
this.blurHash = blurHash;
}
@NonNull

View file

@ -9,6 +9,8 @@ import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import com.cappielloantonio.play.subsonic.models.ArtistID3;
import java.util.ArrayList;
import java.util.List;
@ -51,6 +53,13 @@ public class Artist implements Parcelable {
this.backdropBlurHash = backdropBlurHash;
}
public Artist(ArtistID3 artistID3) {
this.id = artistID3.getId();
this.name = artistID3.getName();
this.primary = artistID3.getCoverArtId();
this.backdrop = artistID3.getCoverArtId();
}
@Ignore
public Artist(String id, String name) {
this.id = id;

View file

@ -8,9 +8,11 @@ import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.AlbumDao;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.subsonic.api.albumsonglist.AlbumSongListClient;
import com.cappielloantonio.play.subsonic.models.ResponseStatus;
import com.cappielloantonio.play.subsonic.models.SubsonicResponse;
import com.cappielloantonio.play.util.MappingUtil;
@ -27,11 +29,13 @@ public class AlbumRepository {
private AlbumSongListClient albumSongListClient;
private AlbumDao albumDao;
private LiveData<List<Album>> listLiveAlbums;
private LiveData<List<Album>> artistListLiveAlbums;
private LiveData<List<Album>> listLiveSampleAlbum;
private LiveData<List<Album>> searchListLiveAlbum;
private MutableLiveData<List<Album>> listLiveRecentlyAddedAlbums = new MutableLiveData<>();
private MutableLiveData<List<Album>> listLiveMostPlayedAlbums = new MutableLiveData<>();
private MutableLiveData<List<Album>> listLiveRecentlyPlayedAlbums = new MutableLiveData<>();
public AlbumRepository(Application application) {
albumSongListClient = App.getSubsonicClientInstance(application, false).getAlbumSongListClient();
@ -41,15 +45,24 @@ public class AlbumRepository {
}
public LiveData<List<Album>> getListLiveAlbums(String type, int size) {
MutableLiveData<List<Album>> listLiveAlbums = new MutableLiveData<>();
albumSongListClient
.getAlbumList2(type, size, 0)
.enqueue(new Callback<SubsonicResponse>() {
@Override
public void onResponse(Call<SubsonicResponse> call, Response<SubsonicResponse> response) {
List<Album> albums = new ArrayList<>(MappingUtil.mapAlbum(response.body().getAlbumList2().getAlbums()));
listLiveAlbums.setValue(albums);
switch (type) {
case "newest":
listLiveRecentlyAddedAlbums.setValue(albums);
break;
case "frequent":
listLiveMostPlayedAlbums.setValue(albums);
break;
case "recent":
listLiveRecentlyPlayedAlbums.setValue(albums);
break;
}
}
@Override
@ -58,7 +71,38 @@ public class AlbumRepository {
}
});
return listLiveAlbums;
switch (type) {
case "newest":
return listLiveRecentlyAddedAlbums;
case "frequent":
return listLiveMostPlayedAlbums;
case "recent":
return listLiveRecentlyPlayedAlbums;
default:
return new MutableLiveData<>();
}
}
public MutableLiveData<List<Album>> getStarredAlbums() {
MutableLiveData<List<Album>> starredAlbums = new MutableLiveData<>();
albumSongListClient
.getStarred2()
.enqueue(new Callback<SubsonicResponse>() {
@Override
public void onResponse(Call<SubsonicResponse> call, Response<SubsonicResponse> response) {
if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) {
List<Album> albums = new ArrayList<>(MappingUtil.mapAlbum(response.body().getStarred2().getAlbums()));
starredAlbums.setValue(albums);
}
}
@Override
public void onFailure(Call<SubsonicResponse> call, Throwable t) {
}
});
return starredAlbums;
}
public LiveData<List<Album>> getArtistListLiveAlbums(String artistId) {

View file

@ -3,26 +3,62 @@ package com.cappielloantonio.play.repository;
import android.app.Application;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.ArtistDao;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.subsonic.api.albumsonglist.AlbumSongListClient;
import com.cappielloantonio.play.subsonic.models.ResponseStatus;
import com.cappielloantonio.play.subsonic.models.SubsonicResponse;
import com.cappielloantonio.play.util.MappingUtil;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ArtistRepository {
private AlbumSongListClient albumSongListClient;
private ArtistDao artistDao;
private LiveData<List<Artist>> listLiveArtists;
private LiveData<List<Artist>> listLiveSampleArtist;
private LiveData<List<Artist>> searchListLiveArtist;
private MutableLiveData<List<Artist>> starredArtists = new MutableLiveData<>();
public ArtistRepository(Application application) {
albumSongListClient = App.getSubsonicClientInstance(application, false).getAlbumSongListClient();
AppDatabase database = AppDatabase.getInstance(application);
artistDao = database.artistDao();
}
public MutableLiveData<List<Artist>> getStarredArtists() {
albumSongListClient
.getStarred2()
.enqueue(new Callback<SubsonicResponse>() {
@Override
public void onResponse(Call<SubsonicResponse> call, Response<SubsonicResponse> response) {
if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) {
List<Artist> artists = new ArrayList<>(MappingUtil.mapArtist(response.body().getStarred2().getArtists()));
starredArtists.setValue(artists);
}
}
@Override
public void onFailure(Call<SubsonicResponse> call, Throwable t) {
}
});
return starredArtists;
}
public LiveData<List<Artist>> getListLiveArtists() {
listLiveArtists = artistDao.getAll();
return listLiveArtists;

View file

@ -50,6 +50,8 @@ public class SongRepository {
private LiveData<List<Song>> listLiveSampleDownloadedSong;
private LiveData<List<Song>> listLiveDownloadedSong;
private MutableLiveData<List<Song>> starredSongs = new MutableLiveData<>();
public SongRepository(Application application) {
albumSongListClient = App.getSubsonicClientInstance(application, false).getAlbumSongListClient();
browsingClient = App.getSubsonicClientInstance(application, false).getBrowsingClient();
@ -59,17 +61,15 @@ public class SongRepository {
songGenreCrossDao = database.songGenreCrossDao();
}
public MutableLiveData<List<Song>> getSongs() {
MutableLiveData<List<Song>> liveSongs = new MutableLiveData<>();
public MutableLiveData<List<Song>> getStarredSongs() {
albumSongListClient
.getRandomSongs(10)
.getStarred2()
.enqueue(new Callback<SubsonicResponse>() {
@Override
public void onResponse(Call<SubsonicResponse> call, Response<SubsonicResponse> response) {
if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) {
List<Song> songs = new ArrayList<>(MappingUtil.mapSong(response.body().getRandomSongs().getSongs()));
liveSongs.setValue(songs);
List<Song> songs = new ArrayList<>(MappingUtil.mapSong(response.body().getStarred2().getSongs()));
starredSongs.setValue(songs);
}
}
@ -79,7 +79,7 @@ public class SongRepository {
}
});
return liveSongs;
return starredSongs;
}
public void getInstantMix(Song song, int count, MediaCallback callback) {
@ -344,23 +344,6 @@ public class SongRepository {
thread.start();
}
/*public List<Song> getRandomSample(int number) {
List<Song> sample = new ArrayList<>();
PickRandomThreadSafe randomThread = new PickRandomThreadSafe(songDao, number);
Thread thread = new Thread(randomThread);
thread.start();
try {
thread.join();
sample = randomThread.getSample();
} catch (InterruptedException e) {
e.printStackTrace();
}
return sample;
}*/
public void getRandomSample(int number, MediaCallback callback) {
albumSongListClient
.getRandomSongs(number)

View file

@ -1,91 +1,50 @@
package com.cappielloantonio.play.subsonic.models;
import com.tickaroo.tikxml.annotation.Element;
import com.tickaroo.tikxml.annotation.Xml;
import java.util.ArrayList;
import java.util.List;
@Xml
public class Starred2 {
@Element(name = "artist")
protected List<ArtistID3> artists;
@Element(name = "album")
protected List<AlbumID3> albums;
@Element(name = "song")
protected List<Child> songs;
/**
* Gets the value of the artists property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the artists property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getArtists().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link ArtistID3 }
*/
public List<ArtistID3> getArtists() {
if (artists == null) {
artists = new ArrayList<ArtistID3>();
artists = new ArrayList<>();
}
return this.artists;
}
/**
* Gets the value of the albums property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the albums property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getAlbums().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link AlbumID3 }
*/
public void setArtists(List<ArtistID3> artists) {
this.artists = artists;
}
public List<AlbumID3> getAlbums() {
if (albums == null) {
albums = new ArrayList<AlbumID3>();
albums = new ArrayList<>();
}
return this.albums;
}
/**
* Gets the value of the songs property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the songs property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getSongs().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Child }
*/
public void setAlbums(List<AlbumID3> albums) {
this.albums = albums;
}
public List<Child> getSongs() {
if (songs == null) {
songs = new ArrayList<Child>();
songs = new ArrayList<>();
}
return this.songs;
}
public void setSongs(List<Child> songs) {
this.songs = songs;
}
}

View file

@ -17,6 +17,7 @@ public class SubsonicResponse {
private ArtistInfo2 artistInfo2;
private ArtistInfo artistInfo;
private AlbumInfo albumInfo;
@Element(name = "starred2")
private Starred2 starred2;
private Starred starred;
private Shares shares;

View file

@ -11,7 +11,6 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -19,7 +18,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.AlbumArtistPageOrSimilarAdapter;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.databinding.FragmentAlbumPageBinding;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.interfaces.MediaCallback;
@ -45,7 +44,7 @@ public class AlbumPageFragment extends Fragment {
private MainActivity activity;
private AlbumPageViewModel albumPageViewModel;
private SongResultSearchAdapter songResultSearchAdapter;
private SongHorizontalAdapter songHorizontalAdapter;
private AlbumArtistPageOrSimilarAdapter albumArtistPageOrSimilarAdapter;
@Override
@ -189,11 +188,11 @@ public class AlbumPageFragment extends Fragment {
bind.songRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
bind.songRecyclerView.setHasFixedSize(true);
songResultSearchAdapter = new SongResultSearchAdapter(activity, requireContext(), getChildFragmentManager());
bind.songRecyclerView.setAdapter(songResultSearchAdapter);
songHorizontalAdapter = new SongHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.songRecyclerView.setAdapter(songHorizontalAdapter);
albumPageViewModel.getAlbumSongLiveList().observe(requireActivity(), songs -> {
songResultSearchAdapter.setItems(songs);
songHorizontalAdapter.setItems(songs);
});
}

View file

@ -18,11 +18,10 @@ import com.cappielloantonio.play.App;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.AlbumArtistPageOrSimilarAdapter;
import com.cappielloantonio.play.adapter.ArtistSimilarAdapter;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.databinding.FragmentArtistPageBinding;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.service.MusicPlayerRemote;
import com.cappielloantonio.play.model.Song;
@ -41,7 +40,7 @@ public class ArtistPageFragment extends Fragment {
private MainActivity activity;
private ArtistPageViewModel artistPageViewModel;
private SongResultSearchAdapter songResultSearchAdapter;
private SongHorizontalAdapter songHorizontalAdapter;
private AlbumArtistPageOrSimilarAdapter albumArtistPageOrSimilarAdapter;
private ArtistSimilarAdapter artistSimilarAdapter;
@ -155,9 +154,9 @@ public class ArtistPageFragment extends Fragment {
private void initTopSongsView() {
bind.mostStreamedSongRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
songResultSearchAdapter = new SongResultSearchAdapter(activity, requireContext(), getChildFragmentManager());
bind.mostStreamedSongRecyclerView.setAdapter(songResultSearchAdapter);
artistPageViewModel.getArtistTopSongList().observe(requireActivity(), songs -> songResultSearchAdapter.setItems(songs));
songHorizontalAdapter = new SongHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.mostStreamedSongRecyclerView.setAdapter(songHorizontalAdapter);
artistPageViewModel.getArtistTopSongList().observe(requireActivity(), songs -> songHorizontalAdapter.setItems(songs));
}
private void initAlbumsView() {

View file

@ -18,9 +18,11 @@ import androidx.viewpager2.widget.ViewPager2;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.AlbumAdapter;
import com.cappielloantonio.play.adapter.AlbumHorizontalAdapter;
import com.cappielloantonio.play.adapter.ArtistHorizontalAdapter;
import com.cappielloantonio.play.adapter.DiscoverSongAdapter;
import com.cappielloantonio.play.adapter.RecentMusicAdapter;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.adapter.YearAdapter;
import com.cappielloantonio.play.databinding.FragmentHomeBinding;
import com.cappielloantonio.play.interfaces.MediaCallback;
@ -37,9 +39,10 @@ public class HomeFragment extends Fragment {
private MainActivity activity;
private HomeViewModel homeViewModel;
private YearAdapter yearAdapter;
private SongResultSearchAdapter favoriteSongAdapter;
private SongHorizontalAdapter starredSongAdapter;
private AlbumHorizontalAdapter starredAlbumAdapter;
private ArtistHorizontalAdapter starredArtistAdapter;
private RecentMusicAdapter dowanloadedMusicAdapter;
// ---------------------------------------------------- SUBSONIC ADAPTER
@ -69,7 +72,9 @@ public class HomeFragment extends Fragment {
initDiscoverSongSlideView();
initMostPlayedAlbumView();
initRecentPlayedAlbumView();
initFavoritesSongView();
initStarredTracksView();
initStarredAlbumsView();
initStarredArtistsView();
initYearSongView();
initRecentAddedAlbumView();
initDownloadedSongView();
@ -107,7 +112,19 @@ public class HomeFragment extends Fragment {
activity.navController.navigate(R.id.action_homeFragment_to_songListPageFragment, bundle);
});
bind.favoritesTracksTextViewClickable.setOnClickListener(v -> {
bind.starredTracksTextViewClickable.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString(Song.IS_FAVORITE, Song.IS_FAVORITE);
activity.navController.navigate(R.id.action_homeFragment_to_songListPageFragment, bundle);
});
bind.starredAlbumsTextViewClickable.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString(Song.IS_FAVORITE, Song.IS_FAVORITE);
activity.navController.navigate(R.id.action_homeFragment_to_songListPageFragment, bundle);
});
bind.starredArtistsTextViewClickable.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString(Song.IS_FAVORITE, Song.IS_FAVORITE);
activity.navController.navigate(R.id.action_homeFragment_to_songListPageFragment, bundle);
@ -180,19 +197,49 @@ public class HomeFragment extends Fragment {
bind.yearsRecyclerView.setAdapter(yearAdapter);
}
private void initFavoritesSongView() {
bind.favoritesTracksRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 5, GridLayoutManager.HORIZONTAL, false));
bind.favoritesTracksRecyclerView.setHasFixedSize(true);
private void initStarredTracksView() {
bind.starredTracksRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 5, GridLayoutManager.HORIZONTAL, false));
bind.starredTracksRecyclerView.setHasFixedSize(true);
favoriteSongAdapter = new SongResultSearchAdapter(activity, requireContext(), getChildFragmentManager());
bind.favoritesTracksRecyclerView.setAdapter(favoriteSongAdapter);
homeViewModel.getFavorites().observe(requireActivity(), songs -> {
if(bind != null) bind.homeFavoriteTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
favoriteSongAdapter.setItems(songs);
starredSongAdapter = new SongHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.starredTracksRecyclerView.setAdapter(starredSongAdapter);
homeViewModel.getStarredTracks().observe(requireActivity(), songs -> {
if(bind != null) bind.homeStarredTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
starredSongAdapter.setItems(songs);
});
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
pagerSnapHelper.attachToRecyclerView(bind.favoritesTracksRecyclerView);
pagerSnapHelper.attachToRecyclerView(bind.starredTracksRecyclerView);
}
private void initStarredAlbumsView() {
bind.starredAlbumsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 5, GridLayoutManager.HORIZONTAL, false));
bind.starredAlbumsRecyclerView.setHasFixedSize(true);
starredAlbumAdapter = new AlbumHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.starredAlbumsRecyclerView.setAdapter(starredAlbumAdapter);
homeViewModel.getStarredAlbums().observe(requireActivity(), albums -> {
if(bind != null) bind.homeStarredAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
starredAlbumAdapter.setItems(albums);
});
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
pagerSnapHelper.attachToRecyclerView(bind.starredAlbumsRecyclerView);
}
private void initStarredArtistsView() {
bind.starredArtistsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 5, GridLayoutManager.HORIZONTAL, false));
bind.starredArtistsRecyclerView.setHasFixedSize(true);
starredArtistAdapter = new ArtistHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.starredArtistsRecyclerView.setAdapter(starredArtistAdapter);
homeViewModel.getStarredArtists().observe(requireActivity(), artists -> {
if(bind != null) bind.homeStarredArtistsSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
starredArtistAdapter.setItems(artists);
});
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
pagerSnapHelper.attachToRecyclerView(bind.starredArtistsRecyclerView);
}
private void initRecentAddedAlbumView() {
@ -246,7 +293,9 @@ public class HomeFragment extends Fragment {
bind.homeLinearLayoutContainer.addView(bind.homeDiscoverSector);
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedAlbumsSector);
bind.homeLinearLayoutContainer.addView(bind.homeFlashbackSector);
bind.homeLinearLayoutContainer.addView(bind.homeFavoriteTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeStarredTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeStarredAlbumsSector);
bind.homeLinearLayoutContainer.addView(bind.homeStarredArtistsSector);
bind.homeLinearLayoutContainer.addView(bind.homeDownloadedTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeMostPlayedAlbumsSector);
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyPlayedAlbumsSector);

View file

@ -18,14 +18,13 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.databinding.FragmentPlaylistPageBinding;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.repository.QueueRepository;
import com.cappielloantonio.play.service.MusicPlayerRemote;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.DownloadUtil;
import com.cappielloantonio.play.util.PreferenceUtil;
import com.cappielloantonio.play.viewmodel.PlaylistPageViewModel;
import java.util.Collections;
@ -36,7 +35,7 @@ public class PlaylistPageFragment extends Fragment {
private MainActivity activity;
private PlaylistPageViewModel playlistPageViewModel;
private SongResultSearchAdapter songResultSearchAdapter;
private SongHorizontalAdapter songHorizontalAdapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@ -159,10 +158,10 @@ public class PlaylistPageFragment extends Fragment {
bind.playlistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
bind.playlistRecyclerView.setHasFixedSize(true);
songResultSearchAdapter = new SongResultSearchAdapter(activity, requireContext(), getChildFragmentManager());
bind.playlistRecyclerView.setAdapter(songResultSearchAdapter);
songHorizontalAdapter = new SongHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.playlistRecyclerView.setAdapter(songHorizontalAdapter);
playlistPageViewModel.getPlaylistSongLiveList().observe(requireActivity(), songs -> {
songResultSearchAdapter.setItems(songs);
songHorizontalAdapter.setItems(songs);
});
}
}

View file

@ -1,7 +1,6 @@
package com.cappielloantonio.play.ui.fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -18,12 +17,11 @@ import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.AlbumAdapter;
import com.cappielloantonio.play.adapter.ArtistAdapter;
import com.cappielloantonio.play.adapter.GenreCatalogueAdapter;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.databinding.FragmentSearchBinding;
import com.cappielloantonio.play.helper.recyclerview.GridItemDecoration;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.PreferenceUtil;
import com.cappielloantonio.play.viewmodel.SearchViewModel;
import com.paulrybitskyi.persistentsearchview.adapters.model.SuggestionItem;
import com.paulrybitskyi.persistentsearchview.listeners.OnSuggestionChangeListener;
@ -36,7 +34,7 @@ public class SearchFragment extends Fragment {
private MainActivity activity;
private SearchViewModel searchViewModel;
private SongResultSearchAdapter songResultSearchAdapter;
private SongHorizontalAdapter songHorizontalAdapter;
private AlbumAdapter albumAdapter;
private ArtistAdapter artistAdapter;
private GenreCatalogueAdapter genreCatalogueAdapter;
@ -79,8 +77,8 @@ public class SearchFragment extends Fragment {
bind.searchResultTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
bind.searchResultTracksRecyclerView.setHasFixedSize(true);
songResultSearchAdapter = new SongResultSearchAdapter(activity, requireContext(), getChildFragmentManager());
bind.searchResultTracksRecyclerView.setAdapter(songResultSearchAdapter);
songHorizontalAdapter = new SongHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.searchResultTracksRecyclerView.setAdapter(songHorizontalAdapter);
// Albums
bind.searchResultAlbumRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
@ -177,7 +175,7 @@ public class SearchFragment extends Fragment {
private void performSearch(String query) {
searchViewModel.searchSong(query, requireContext()).observe(requireActivity(), songs -> {
if(bind != null) bind.searchSongSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
songResultSearchAdapter.setItems(songs);
songHorizontalAdapter.setItems(songs);
});
searchViewModel.searchAlbum(query, requireContext()).observe(requireActivity(), albums -> {
if(bind != null) bind.searchAlbumSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);

View file

@ -4,7 +4,6 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
@ -12,7 +11,7 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.databinding.FragmentSongListPageBinding;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.QueueRepository;
@ -21,7 +20,6 @@ import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.viewmodel.SongListPageViewModel;
import java.util.Collections;
import java.util.List;
public class SongListPageFragment extends Fragment {
@ -29,7 +27,7 @@ public class SongListPageFragment extends Fragment {
private MainActivity activity;
private SongListPageViewModel songListPageViewModel;
private SongResultSearchAdapter songResultSearchAdapter;
private SongHorizontalAdapter songHorizontalAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -161,8 +159,8 @@ public class SongListPageFragment extends Fragment {
bind.songListRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
bind.songListRecyclerView.setHasFixedSize(true);
songResultSearchAdapter = new SongResultSearchAdapter(activity, requireContext(), getChildFragmentManager());
bind.songListRecyclerView.setAdapter(songResultSearchAdapter);
songListPageViewModel.getSongList().observe(requireActivity(), songs -> songResultSearchAdapter.setItems(songs));
songHorizontalAdapter = new SongHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
bind.songListRecyclerView.setAdapter(songHorizontalAdapter);
songListPageViewModel.getSongList().observe(requireActivity(), songs -> songHorizontalAdapter.setItems(songs));
}
}

View file

@ -1,8 +1,10 @@
package com.cappielloantonio.play.util;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.subsonic.models.AlbumID3;
import com.cappielloantonio.play.subsonic.models.ArtistID3;
import com.cappielloantonio.play.subsonic.models.Child;
import java.util.ArrayList;
@ -28,4 +30,14 @@ public class MappingUtil {
return albums;
}
public static ArrayList<Artist> mapArtist(List<ArtistID3> albumID3List) {
ArrayList<Artist> artists = new ArrayList();
for(ArtistID3 artistID3 : albumID3List){
artists.add(new Artist(artistID3));
}
return artists;
}
}

View file

@ -8,8 +8,10 @@ import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.AlbumRepository;
import com.cappielloantonio.play.repository.ArtistRepository;
import com.cappielloantonio.play.repository.SongRepository;
import java.util.ArrayList;
@ -19,28 +21,28 @@ public class HomeViewModel extends AndroidViewModel {
private static final String TAG = "HomeViewModel";
private SongRepository songRepository;
private AlbumRepository albumRepository;
private ArtistRepository artistRepository;
private List<Song> dicoverSongSample = new ArrayList<>();
private LiveData<List<Song>> recentlyPlayedSongSample;
private LiveData<List<Song>> recentlyAddedSongSample;
private LiveData<List<Song>> mostPlayedSongSample;
private LiveData<List<Song>> favoritesSongSample;
private LiveData<List<Song>> downloadedSongSample;
private List<Integer> years;
private List<Song> dicoverSongSample = new ArrayList<>();
private LiveData<List<Album>> mostPlayedAlbumSample;
private LiveData<List<Album>> recentlyAddedAlbumSample;
private LiveData<List<Album>> recentlyPlayedAlbumSample;
private LiveData<List<Song>> starredTracks;
private LiveData<List<Album>> starredAlbums;
private LiveData<List<Artist>> starredArtists;
public HomeViewModel(@NonNull Application application) {
super(application);
songRepository = new SongRepository(application);
albumRepository = new AlbumRepository(application);
artistRepository = new ArtistRepository(application);
recentlyPlayedSongSample = songRepository.getListLiveRecentlyPlayedSampleSong(20);
recentlyAddedSongSample = songRepository.getListLiveRecentlyAddedSampleSong(20);
mostPlayedSongSample = songRepository.getListLiveMostPlayedSampleSong(20);
favoritesSongSample = songRepository.getListLiveFavoritesSampleSong(20);
downloadedSongSample = songRepository.getListLiveDownloadedSampleSong(20);
years = songRepository.getYearList();
@ -48,24 +50,16 @@ public class HomeViewModel extends AndroidViewModel {
mostPlayedAlbumSample = albumRepository.getListLiveAlbums("frequent", 20);
recentlyAddedAlbumSample = albumRepository.getListLiveAlbums("newest", 20);
recentlyPlayedAlbumSample = albumRepository.getListLiveAlbums("recent", 20);
starredTracks = songRepository.getStarredSongs();
starredAlbums = albumRepository.getStarredAlbums();
starredArtists = artistRepository.getStarredArtists();
}
public SongRepository getSongRepository() {
return songRepository;
}
public LiveData<List<Song>> getRecentlyAddedSongList() {
return recentlyAddedSongSample;
}
public LiveData<List<Song>> getRecentlyPlayedSongList() {
return recentlyPlayedSongSample;
}
public LiveData<List<Song>> getMostPlayedSongList() {
return mostPlayedSongSample;
}
public List<Integer> getYearList() {
return years;
}
@ -74,6 +68,18 @@ public class HomeViewModel extends AndroidViewModel {
return favoritesSongSample;
}
public LiveData<List<Song>> getStarredTracks() {
return starredTracks;
}
public LiveData<List<Album>> getStarredAlbums() {
return starredAlbums;
}
public LiveData<List<Artist>> getStarredArtists() {
return starredArtists;
}
public LiveData<List<Song>> getDownloaded() {
return downloadedSongSample;
}

View file

@ -201,7 +201,7 @@
<!-- Favorites -->
<LinearLayout
android:id="@+id/home_favorite_tracks_sector"
android:id="@+id/home_starred_tracks_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@ -223,11 +223,11 @@
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="Favorites" />
android:text="Starred tracks" />
<TextView
android:id="@+id/favorites_tracks_text_view_clickable"
android:id="@+id/starred_tracks_text_view_clickable"
style="@style/SubheadTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -239,7 +239,105 @@
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/favorites_tracks_recycler_view"
android:id="@+id/starred_tracks_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false"
android:paddingTop="8dp"
android:paddingBottom="8dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/home_starred_albums_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Label and button -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:paddingEnd="8dp">
<TextView
style="@style/HeadlineTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="Starred albums" />
<TextView
android:id="@+id/starred_albums_text_view_clickable"
style="@style/SubheadTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="See all" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/starred_albums_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false"
android:paddingTop="8dp"
android:paddingBottom="8dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/home_starred_artists_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Label and button -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:paddingEnd="8dp">
<TextView
style="@style/HeadlineTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="Starred artists" />
<TextView
android:id="@+id/starred_artists_text_view_clickable"
style="@style/SubheadTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="See all" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/starred_artists_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"

View file

@ -0,0 +1,70 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clipChildren="false"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:id="@+id/album_cover_image_view"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_gravity="center"
android:layout_margin="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/album_title_text_view"
style="@style/ItemTitleTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:paddingStart="12dp"
android:paddingTop="10dp"
android:paddingEnd="12dp"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toStartOf="@+id/album_more_button"
app:layout_constraintStart_toEndOf="@+id/album_cover_image_view"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/album_artist_text_view"
style="@style/ItemSubtitleTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:paddingStart="12dp"
android:paddingEnd="16dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toStartOf="@+id/album_more_button"
app:layout_constraintStart_toEndOf="@+id/album_cover_image_view"
app:layout_constraintTop_toBottomOf="@+id/album_title_text_view"/>
<ImageView
android:id="@+id/album_more_button"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:background="@drawable/ic_more_vert"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,70 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clipChildren="false"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<ImageView
android:id="@+id/artist_cover_image_view"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_gravity="center"
android:layout_margin="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/artist_name_text_view"
style="@style/ItemTitleTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:paddingStart="12dp"
android:paddingTop="10dp"
android:paddingEnd="12dp"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toStartOf="@+id/artist_more_button"
app:layout_constraintStart_toEndOf="@+id/artist_cover_image_view"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/artist_info_text_view"
style="@style/ItemSubtitleTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:paddingStart="12dp"
android:paddingEnd="16dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toStartOf="@+id/artist_more_button"
app:layout_constraintStart_toEndOf="@+id/artist_cover_image_view"
app:layout_constraintTop_toBottomOf="@+id/artist_name_text_view"/>
<ImageView
android:id="@+id/artist_more_button"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:background="@drawable/ic_more_vert"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -49,7 +49,7 @@
app:layout_constraintTop_toBottomOf="@+id/search_result_song_title_text_view">
<TextView
android:id="@+id/search_result_song_artist_text_view"
android:id="@+id/album_artist_text_view"
style="@style/ItemSubtitleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View file

@ -48,6 +48,9 @@
<action
android:id="@+id/action_homeFragment_to_albumPageFragment"
app:destination="@id/albumPageFragment" />
<action
android:id="@+id/action_homeFragment_to_artistPageFragment"
app:destination="@id/artistPageFragment" />
</fragment>
<fragment
android:id="@+id/libraryFragment"