mirror of
https://github.com/antebudimir/tempus.git
synced 2026-01-01 18:03:33 +00:00
Add playlist catalogue page and item
This commit is contained in:
parent
717986ea2c
commit
ee8509032a
15 changed files with 411 additions and 60 deletions
|
|
@ -5,14 +5,17 @@ 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.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -23,11 +26,13 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
|
|||
private List<Playlist> playlists;
|
||||
private LayoutInflater mInflater;
|
||||
private Context context;
|
||||
private MainActivity activity;
|
||||
|
||||
public PlaylistAdapter(Context context) {
|
||||
public PlaylistAdapter(MainActivity activity, Context context, List<Playlist> playlists) {
|
||||
this.activity = activity;
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.playlists = new ArrayList<>();
|
||||
this.playlists = playlists;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -41,6 +46,11 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
|
|||
Playlist playlist = playlists.get(position);
|
||||
|
||||
holder.textPlaylistName.setText(playlist.getName());
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(context, playlist.getPrimary(), playlist.getBlurHash(), CustomGlideRequest.PRIMARY, CustomGlideRequest.TOP_QUALITY, CustomGlideRequest.PLAYLIST_PIC)
|
||||
.build()
|
||||
.into(holder.cover);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -50,11 +60,13 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
|
|||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
TextView textPlaylistName;
|
||||
ImageView cover;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
textPlaylistName = itemView.findViewById(R.id.playlist_name_text);
|
||||
cover = itemView.findViewById(R.id.playlist_cover_image_view);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
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.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlaylistCatalogueAdapter extends RecyclerView.Adapter<PlaylistCatalogueAdapter.ViewHolder> {
|
||||
|
||||
private List<Playlist> playlists;
|
||||
private LayoutInflater mInflater;
|
||||
private Context context;
|
||||
|
||||
public PlaylistCatalogueAdapter(Context context) {
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.playlists = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.item_library_catalogue_playlist, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Playlist playlist = playlists.get(position);
|
||||
|
||||
holder.textPlaylistName.setText(playlist.getName());
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(context, playlist.getPrimary(), playlist.getBlurHash(), CustomGlideRequest.PRIMARY, CustomGlideRequest.TOP_QUALITY, CustomGlideRequest.PLAYLIST_PIC)
|
||||
.build()
|
||||
.into(holder.cover);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return playlists.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
TextView textPlaylistName;
|
||||
ImageView cover;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
textPlaylistName = itemView.findViewById(R.id.playlist_name_text);
|
||||
cover = itemView.findViewById(R.id.playlist_cover_image_view);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("playlist_object", playlists.get(getBindingAdapterPosition()));
|
||||
Navigation.findNavController(view).navigate(R.id.action_playlistCatalogueFragment_to_playlistPageFragment, bundle);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Playlist getItem(int position) {
|
||||
return playlists.get(position);
|
||||
}
|
||||
|
||||
public void setItems(List<Playlist> playlists) {
|
||||
this.playlists = playlists;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import androidx.room.OnConflictStrategy;
|
|||
import androidx.room.Query;
|
||||
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -21,4 +22,7 @@ public interface PlaylistDao {
|
|||
|
||||
@Query("DELETE FROM playlist")
|
||||
void deleteAll();
|
||||
|
||||
@Query("SELECT * FROM playlist ORDER BY RANDOM() LIMIT :number")
|
||||
List<Playlist> random(int number);
|
||||
}
|
||||
|
|
@ -6,7 +6,9 @@ import androidx.lifecycle.LiveData;
|
|||
|
||||
import com.cappielloantonio.play.database.AppDatabase;
|
||||
import com.cappielloantonio.play.database.dao.PlaylistDao;
|
||||
import com.cappielloantonio.play.database.dao.SongDao;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -65,4 +67,41 @@ public class PlaylistRepository {
|
|||
playlistDao.deleteAll();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Playlist> getRandomSample(int number) {
|
||||
List<Playlist> sample = new ArrayList<>();
|
||||
|
||||
PickRandomThreadSafe randomThread = new PickRandomThreadSafe(playlistDao, number);
|
||||
Thread thread = new Thread(randomThread);
|
||||
thread.start();
|
||||
|
||||
try {
|
||||
thread.join();
|
||||
sample = randomThread.getSample();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
private static class PickRandomThreadSafe implements Runnable {
|
||||
private PlaylistDao playlistDao;
|
||||
private int elementNumber;
|
||||
private List<Playlist> sample;
|
||||
|
||||
public PickRandomThreadSafe(PlaylistDao playlistDao, int number) {
|
||||
this.playlistDao = playlistDao;
|
||||
this.elementNumber = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
sample = playlistDao.random(elementNumber);
|
||||
}
|
||||
|
||||
public List<Playlist> getSample() {
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ public class MainActivity extends BaseActivity {
|
|||
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
|
||||
navController.navigate(R.id.action_landingFragment_to_homeFragment);
|
||||
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.syncFragment) {
|
||||
navController.navigate(R.id.action_syncFragment_to_libraryFragment);
|
||||
navController.navigate(R.id.action_syncFragment_to_homeFragment);
|
||||
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
|
||||
navController.navigate(R.id.action_loginFragment_to_homeFragment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
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;
|
||||
|
|
@ -9,19 +10,23 @@ import android.widget.Toast;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.adapter.AlbumAdapter;
|
||||
import com.cappielloantonio.play.adapter.ArtistAdapter;
|
||||
import com.cappielloantonio.play.adapter.DiscoverSongAdapter;
|
||||
import com.cappielloantonio.play.adapter.GenreAdapter;
|
||||
import com.cappielloantonio.play.adapter.PlaylistAdapter;
|
||||
import com.cappielloantonio.play.databinding.FragmentLibraryBinding;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
import com.cappielloantonio.play.util.MusicUtil;
|
||||
import com.cappielloantonio.play.util.PreferenceUtil;
|
||||
import com.cappielloantonio.play.viewmodel.LibraryViewModel;
|
||||
|
||||
|
|
@ -58,7 +63,7 @@ public class LibraryFragment extends Fragment {
|
|||
initAlbumView();
|
||||
initArtistView();
|
||||
initGenreView();
|
||||
initPlaylistView();
|
||||
initPlaylistSlideView();
|
||||
initCatalogueSyncCheck();
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +83,7 @@ public class LibraryFragment extends Fragment {
|
|||
bind.albumCatalogueTextViewClickable.setOnClickListener(v -> activity.navController.navigate(R.id.action_libraryFragment_to_albumCatalogueFragment));
|
||||
bind.artistCatalogueTextViewClickable.setOnClickListener(v -> activity.navController.navigate(R.id.action_libraryFragment_to_artistCatalogueFragment));
|
||||
bind.genreCatalogueTextViewClickable.setOnClickListener(v -> activity.navController.navigate(R.id.action_libraryFragment_to_genreCatalogueFragment));
|
||||
bind.playlistCatalogueTextViewClickable.setOnClickListener(v -> activity.navController.navigate(R.id.action_libraryFragment_to_playlistCatalogueFragment));
|
||||
}
|
||||
|
||||
private void initAlbumView() {
|
||||
|
|
@ -115,16 +121,15 @@ public class LibraryFragment extends Fragment {
|
|||
});
|
||||
}
|
||||
|
||||
private void initPlaylistView() {
|
||||
bind.playlistRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
|
||||
bind.playlistRecyclerView.setHasFixedSize(true);
|
||||
private void initPlaylistSlideView() {
|
||||
bind.playlistViewPager.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
|
||||
|
||||
playlistAdapter = new PlaylistAdapter(requireContext());
|
||||
bind.playlistRecyclerView.setAdapter(playlistAdapter);
|
||||
libraryViewModel.getPlaylistList().observe(requireActivity(), playlists -> {
|
||||
if(bind != null) bind.libraryPlaylistSector.setVisibility(playlists.size() > 0 ? View.VISIBLE : View.GONE);
|
||||
playlistAdapter.setItems(playlists);
|
||||
});
|
||||
playlistAdapter = new PlaylistAdapter(activity, requireContext(), libraryViewModel.getPlaylistSample());
|
||||
bind.playlistViewPager.setAdapter(playlistAdapter);
|
||||
bind.playlistViewPager.setOffscreenPageLimit(3);
|
||||
setDiscoverSongSlideViewOffset(20, 16);
|
||||
|
||||
Log.i(TAG, "initDiscoverSongSlideView: " + MusicUtil.getRandomSongNumber(requireContext(), 10, 3));
|
||||
}
|
||||
|
||||
private void initCatalogueSyncCheck() {
|
||||
|
|
@ -137,4 +142,19 @@ public class LibraryFragment extends Fragment {
|
|||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
private void setDiscoverSongSlideViewOffset(float pageOffset, float pageMargin) {
|
||||
bind.playlistViewPager.setPageTransformer((page, position) -> {
|
||||
float myOffset = position * -(2 * pageOffset + pageMargin);
|
||||
if (bind.playlistViewPager.getOrientation() == ViewPager2.ORIENTATION_HORIZONTAL) {
|
||||
if (ViewCompat.getLayoutDirection(bind.playlistViewPager) == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||
page.setTranslationX(-myOffset);
|
||||
} else {
|
||||
page.setTranslationX(myOffset);
|
||||
}
|
||||
} else {
|
||||
page.setTranslationY(myOffset);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.adapter.GenreCatalogueAdapter;
|
||||
import com.cappielloantonio.play.adapter.PlaylistAdapter;
|
||||
import com.cappielloantonio.play.adapter.PlaylistCatalogueAdapter;
|
||||
import com.cappielloantonio.play.databinding.FragmentGenreCatalogueBinding;
|
||||
import com.cappielloantonio.play.databinding.FragmentPlaylistCatalogueBinding;
|
||||
import com.cappielloantonio.play.helper.recyclerview.GridItemDecoration;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
import com.cappielloantonio.play.ui.activities.MainActivity;
|
||||
import com.cappielloantonio.play.viewmodel.GenreCatalogueViewModel;
|
||||
import com.cappielloantonio.play.viewmodel.PlaylistCatalogueViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PlaylistCatalogueFragment extends Fragment {
|
||||
private static final String TAG = "GenreCatalogueFragment";;
|
||||
|
||||
private FragmentPlaylistCatalogueBinding bind;
|
||||
private MainActivity activity;
|
||||
private PlaylistCatalogueViewModel playlistCatalogueViewModel;
|
||||
|
||||
private PlaylistCatalogueAdapter playlistCatalogueAdapter;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
bind = FragmentPlaylistCatalogueBinding.inflate(inflater, container, false);
|
||||
View view = bind.getRoot();
|
||||
playlistCatalogueViewModel = new ViewModelProvider(requireActivity()).get(PlaylistCatalogueViewModel.class);
|
||||
|
||||
initArtistCatalogueView();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
activity.setBottomNavigationBarVisibility(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
bind = null;
|
||||
}
|
||||
|
||||
private void initArtistCatalogueView() {
|
||||
bind.playlistCatalogueRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||
bind.playlistCatalogueRecyclerView.setHasFixedSize(true);
|
||||
|
||||
playlistCatalogueAdapter = new PlaylistCatalogueAdapter(requireContext());
|
||||
bind.playlistCatalogueRecyclerView.setAdapter(playlistCatalogueAdapter);
|
||||
playlistCatalogueViewModel.getPlaylistList().observe(requireActivity(), playlist -> {
|
||||
playlistCatalogueAdapter.setItems(playlist);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -28,8 +28,4 @@ public class GenreCatalogueViewModel extends AndroidViewModel {
|
|||
genreList = genreRepository.getListLiveGenres();
|
||||
return genreList;
|
||||
}
|
||||
|
||||
public List<Genre> getGenres() {
|
||||
return genreRepository.getListGenre();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.cappielloantonio.play.model.Album;
|
|||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.model.Song;
|
||||
import com.cappielloantonio.play.repository.AlbumRepository;
|
||||
import com.cappielloantonio.play.repository.ArtistRepository;
|
||||
import com.cappielloantonio.play.repository.GenreRepository;
|
||||
|
|
@ -24,10 +25,10 @@ public class LibraryViewModel extends AndroidViewModel {
|
|||
private GenreRepository genreRepository;
|
||||
private PlaylistRepository playlistRepository;
|
||||
|
||||
private List<Playlist> playlistSample;
|
||||
private LiveData<List<Album>> sampleAlbum;
|
||||
private LiveData<List<Artist>> sampleArtist;
|
||||
private LiveData<List<Genre>> sampleGenres;
|
||||
private LiveData<List<Playlist>> allPlaylist;
|
||||
|
||||
public LibraryViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
|
@ -42,11 +43,15 @@ public class LibraryViewModel extends AndroidViewModel {
|
|||
sampleAlbum = albumRepository.getListLiveSampleAlbum();
|
||||
sampleArtist = artistRepository.getListLiveSampleArtist();
|
||||
sampleGenres = genreRepository.getListLiveSampleGenre();
|
||||
allPlaylist = playlistRepository.getListLivePlaylists();
|
||||
playlistSample = playlistRepository.getRandomSample(5);
|
||||
}
|
||||
|
||||
public LiveData<List<Playlist>> getPlaylistList() {
|
||||
return allPlaylist;
|
||||
public List<Playlist> getPlaylistSample() {
|
||||
if(playlistSample.isEmpty()) {
|
||||
playlistSample = playlistRepository.getRandomSample(5);
|
||||
}
|
||||
|
||||
return playlistSample;
|
||||
}
|
||||
|
||||
public LiveData<List<Album>> getAlbumSample() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package com.cappielloantonio.play.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.model.Genre;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.repository.GenreRepository;
|
||||
import com.cappielloantonio.play.repository.PlaylistRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlaylistCatalogueViewModel extends AndroidViewModel {
|
||||
private PlaylistRepository playlistRepository;
|
||||
|
||||
private LiveData<List<Playlist>> playlistList;
|
||||
|
||||
public PlaylistCatalogueViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
playlistRepository = new PlaylistRepository(application);
|
||||
}
|
||||
|
||||
public LiveData<List<Playlist>> getPlaylistList() {
|
||||
playlistList = playlistRepository.getListLivePlaylists();
|
||||
return playlistList;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue