Removed almost all hardcoded constants and deleted offline playlist model

This commit is contained in:
antonio 2023-03-10 17:46:03 +01:00
parent e98429503b
commit ff1a1350f9
24 changed files with 64 additions and 380 deletions

View file

@ -10,7 +10,6 @@ import com.cappielloantonio.play.App;
import com.cappielloantonio.play.database.converter.DateConverters;
import com.cappielloantonio.play.database.dao.ChronologyDao;
import com.cappielloantonio.play.database.dao.DownloadDao;
import com.cappielloantonio.play.database.dao.PlaylistDao;
import com.cappielloantonio.play.database.dao.QueueDao;
import com.cappielloantonio.play.database.dao.RecentSearchDao;
import com.cappielloantonio.play.database.dao.ServerDao;
@ -19,12 +18,11 @@ import com.cappielloantonio.play.model.Download;
import com.cappielloantonio.play.model.Queue;
import com.cappielloantonio.play.model.RecentSearch;
import com.cappielloantonio.play.model.Server;
import com.cappielloantonio.play.subsonic.models.Playlist;
@Database(
version = 60,
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Playlist.class, Chronology.class},
autoMigrations = {@AutoMigration(from = 59, to = 60)}
version = 61,
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Chronology.class},
autoMigrations = {@AutoMigration(from = 60, to = 61)}
)
@TypeConverters({DateConverters.class})
public abstract class AppDatabase extends RoomDatabase {
@ -49,7 +47,5 @@ public abstract class AppDatabase extends RoomDatabase {
public abstract DownloadDao downloadDao();
public abstract PlaylistDao playlistDao();
public abstract ChronologyDao chronologyDao();
}

View file

@ -3,12 +3,9 @@ package com.cappielloantonio.play.repository;
import android.util.Log;
import androidx.annotation.NonNull;
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.PlaylistDao;
import com.cappielloantonio.play.subsonic.base.ApiResponse;
import com.cappielloantonio.play.subsonic.models.Child;
import com.cappielloantonio.play.subsonic.models.Playlist;
@ -22,8 +19,6 @@ import retrofit2.Callback;
import retrofit2.Response;
public class PlaylistRepository {
private final PlaylistDao playlistDao = AppDatabase.getInstance().playlistDao();
public MutableLiveData<List<Playlist>> getPlaylists(boolean random, int size) {
MutableLiveData<List<Playlist>> listLivePlaylists = new MutableLiveData<>(new ArrayList<>());
@ -143,51 +138,4 @@ public class PlaylistRepository {
}
});
}
public LiveData<List<Playlist>> getPinnedPlaylists(String serverId) {
// return playlistDao.getAll(serverId);
return playlistDao.getAll();
}
public void insert(Playlist playlist) {
InsertThreadSafe insert = new InsertThreadSafe(playlistDao, playlist);
Thread thread = new Thread(insert);
thread.start();
}
public void delete(Playlist playlist) {
DeleteThreadSafe delete = new DeleteThreadSafe(playlistDao, playlist);
Thread thread = new Thread(delete);
thread.start();
}
private static class InsertThreadSafe implements Runnable {
private final PlaylistDao playlistDao;
private final Playlist playlist;
public InsertThreadSafe(PlaylistDao playlistDao, Playlist playlist) {
this.playlistDao = playlistDao;
this.playlist = playlist;
}
@Override
public void run() {
playlistDao.insert(playlist);
}
}
private static class DeleteThreadSafe implements Runnable {
private final PlaylistDao playlistDao;
private final Playlist playlist;
public DeleteThreadSafe(PlaylistDao playlistDao, Playlist playlist) {
this.playlistDao = playlistDao;
this.playlist = playlist;
}
@Override
public void run() {
playlistDao.delete(playlist);
}
}
}

View file

@ -96,8 +96,8 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
public void onClick() {
Bundle bundle = new Bundle();
bundle.putParcelable(Constants.ARTIST_OBJECT, artists.get(getBindingAdapterPosition()));
bundle.putBoolean("is_mix", mix);
bundle.putBoolean("is_best_of", bestOf);
bundle.putBoolean(Constants.MEDIA_MIX, mix);
bundle.putBoolean(Constants.MEDIA_BEST_OF, bestOf);
click.onArtistClick(bundle);
}

View file

@ -78,7 +78,7 @@ public class DiscoverSongAdapter extends RecyclerView.Adapter<DiscoverSongAdapte
public void onClick() {
Bundle bundle = new Bundle();
bundle.putParcelable(Constants.TRACK_OBJECT, songs.get(getBindingAdapterPosition()));
bundle.putBoolean("is_mix", true);
bundle.putBoolean(Constants.MEDIA_MIX, true);
click.onMediaClick(bundle);
}

View file

@ -67,7 +67,7 @@ public class GenreAdapter extends RecyclerView.Adapter<GenreAdapter.ViewHolder>
private void onClick() {
Bundle bundle = new Bundle();
bundle.putString(Constants.MEDIA_BY_GENRES, Constants.MEDIA_BY_GENRE);
bundle.putString(Constants.MEDIA_BY_GENRE, Constants.MEDIA_BY_GENRE);
bundle.putParcelable(Constants.GENRE_OBJECT, genres.get(getBindingAdapterPosition()));
click.onGenreClick(bundle);

View file

@ -75,7 +75,7 @@ public class GridTrackAdapter extends RecyclerView.Adapter<GridTrackAdapter.View
public void onClick() {
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(Constants.TRACKS_OBJECT, new ArrayList<>(items));
bundle.putBoolean("is_chronology", true);
bundle.putBoolean(Constants.MEDIA_CHRONOLOGY, true);
bundle.putInt(Constants.ITEM_POSITION, getBindingAdapterPosition());
click.onMediaClick(bundle);

View file

@ -14,6 +14,7 @@ import com.cappielloantonio.play.databinding.ItemHomePodcastEpisodeBinding;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.interfaces.ClickCallback;
import com.cappielloantonio.play.subsonic.models.PodcastEpisode;
import com.cappielloantonio.play.util.Constants;
import com.cappielloantonio.play.util.MusicUtil;
import java.text.SimpleDateFormat;
@ -79,14 +80,14 @@ public class PodcastEpisodeAdapter extends RecyclerView.Adapter<PodcastEpisodeAd
public void onClick() {
Bundle bundle = new Bundle();
bundle.putParcelable("podcast_object", podcastEpisodes.get(getBindingAdapterPosition()));
bundle.putParcelable(Constants.PODCAST_OBJECT, podcastEpisodes.get(getBindingAdapterPosition()));
click.onPodcastClick(bundle);
}
private boolean openMore() {
Bundle bundle = new Bundle();
bundle.putParcelable("podcast_object", podcastEpisodes.get(getBindingAdapterPosition()));
bundle.putParcelable(Constants.PODCAST_OBJECT, podcastEpisodes.get(getBindingAdapterPosition()));
click.onPodcastLongClick(bundle);

View file

@ -78,7 +78,7 @@ public class SimilarTrackAdapter extends RecyclerView.Adapter<SimilarTrackAdapte
public void onClick() {
Bundle bundle = new Bundle();
bundle.putParcelable(Constants.TRACK_OBJECT, songs.get(getBindingAdapterPosition()));
bundle.putBoolean("is_mix", true);
bundle.putBoolean(Constants.MEDIA_MIX, true);
click.onMediaClick(bundle);
}

View file

@ -8,7 +8,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -22,7 +21,6 @@ import androidx.navigation.Navigation;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.PagerSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SnapHelper;
import androidx.viewpager2.widget.ViewPager2;
@ -35,7 +33,6 @@ import com.cappielloantonio.play.interfaces.ClickCallback;
import com.cappielloantonio.play.service.MediaManager;
import com.cappielloantonio.play.service.MediaService;
import com.cappielloantonio.play.subsonic.models.Child;
import com.cappielloantonio.play.subsonic.models.Playlist;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.ui.adapter.AlbumAdapter;
import com.cappielloantonio.play.ui.adapter.AlbumHorizontalAdapter;
@ -48,7 +45,6 @@ import com.cappielloantonio.play.ui.adapter.SimilarTrackAdapter;
import com.cappielloantonio.play.ui.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.ui.adapter.YearAdapter;
import com.cappielloantonio.play.util.Constants;
import com.cappielloantonio.play.util.MusicUtil;
import com.cappielloantonio.play.util.UIUtil;
import com.cappielloantonio.play.viewmodel.HomeViewModel;
import com.google.android.gms.cast.framework.CastButtonFactory;
@ -127,7 +123,6 @@ public class HomeFragment extends Fragment implements ClickCallback {
initNewReleasesView();
initYearSongView();
initRecentAddedAlbumView();
initPinnedPlaylistsView();
initNewestPodcastsView();
initGridView();
}
@ -599,62 +594,6 @@ public class HomeFragment extends Fragment implements ClickCallback {
recentAddedAlbumSnapHelper.attachToRecyclerView(bind.recentlyAddedAlbumsRecyclerView);
}
public void initPinnedPlaylistsView() {
homeViewModel.getPinnedPlaylistList(getViewLifecycleOwner(), 5, true).observe(getViewLifecycleOwner(), playlists -> {
if (bind != null && playlists != null) {
for (Playlist playlist : playlists) {
int playlistViewHashCode = playlist.getId().hashCode();
if (requireView().findViewById(playlistViewHashCode) == null) {
View genericPlaylistView = activity.getLayoutInflater().inflate(R.layout.generic_playlist_sector, null);
genericPlaylistView.setId(playlistViewHashCode);
genericPlaylistView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
TextView genericPlaylistTitleTextView = genericPlaylistView.findViewById(R.id.generic_playlist_title_text_view);
TextView genericPlaylistCickableTextView = genericPlaylistView.findViewById(R.id.generic_playlist_text_view_clickable);
RecyclerView genericPlaylistRecyclerView = genericPlaylistView.findViewById(R.id.generic_playlist_recycler_view);
genericPlaylistTitleTextView.setText(MusicUtil.getReadableString(playlist.getName()));
genericPlaylistRecyclerView.setHasFixedSize(true);
SongHorizontalAdapter trackAdapter = new SongHorizontalAdapter(this, true);
genericPlaylistRecyclerView.setAdapter(trackAdapter);
homeViewModel.getPlaylistSongLiveList(playlist.getId()).observe(getViewLifecycleOwner(), songs -> {
if (songs.size() > 0) {
int songsNumber = Math.min(20, songs.size());
genericPlaylistRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), UIUtil.getSpanCount(songsNumber, 5), GridLayoutManager.HORIZONTAL, false));
trackAdapter.setItems(songs.subList(0, songsNumber));
}
});
genericPlaylistCickableTextView.setOnClickListener(view -> {
Bundle bundle = new Bundle();
bundle.putParcelable(Constants.PLAYLIST_OBJECT, playlist);
bundle.putBoolean("is_offline", false);
activity.navController.navigate(R.id.action_homeFragment_to_playlistPageFragment, bundle);
});
SnapHelper genericPlaylistSnapHelper = new PagerSnapHelper();
genericPlaylistSnapHelper.attachToRecyclerView(genericPlaylistRecyclerView);
genericPlaylistRecyclerView.addItemDecoration(
new DotsIndicatorDecoration(
getResources().getDimensionPixelSize(R.dimen.radius),
getResources().getDimensionPixelSize(R.dimen.radius) * 4,
getResources().getDimensionPixelSize(R.dimen.dots_height),
requireContext().getResources().getColor(R.color.titleTextColor, null),
requireContext().getResources().getColor(R.color.titleTextColor, null))
);
bind.homeLinearLayoutContainer.addView(genericPlaylistView);
}
}
}
});
}
private void initNewestPodcastsView() {
bind.newestPodcastsViewPager.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
@ -740,7 +679,7 @@ public class HomeFragment extends Fragment implements ClickCallback {
@Override
public void onMediaClick(Bundle bundle) {
if (bundle.containsKey("is_mix")) {
if (bundle.containsKey(Constants.MEDIA_MIX)) {
MediaManager.startQueue(mediaBrowserListenableFuture, requireContext(), bundle.getParcelable(Constants.TRACK_OBJECT));
activity.setBottomSheetInPeek(true);
@ -751,7 +690,7 @@ public class HomeFragment extends Fragment implements ClickCallback {
}
});
}
} else if (bundle.containsKey("is_chronology")) {
} else if (bundle.containsKey(Constants.MEDIA_CHRONOLOGY)) {
List<Child> media = bundle.getParcelableArrayList(Constants.TRACKS_OBJECT);
MediaManager.startQueue(mediaBrowserListenableFuture, requireContext(), media, bundle.getInt(Constants.ITEM_POSITION));
activity.setBottomSheetInPeek(true);
@ -778,22 +717,22 @@ public class HomeFragment extends Fragment implements ClickCallback {
@Override
public void onArtistClick(Bundle bundle) {
if (bundle.containsKey("is_mix") && bundle.getBoolean("is_mix")) {
if (bundle.containsKey(Constants.MEDIA_MIX) && bundle.getBoolean(Constants.MEDIA_MIX)) {
Snackbar.make(requireView(), R.string.artist_adapter_radio_station_starting, Snackbar.LENGTH_LONG)
.setAnchorView(activity.bind.playerBottomSheet)
.show();
if (mediaBrowserListenableFuture != null) {
homeViewModel.getArtistInstantMix(bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> {
homeViewModel.getArtistInstantMix(getViewLifecycleOwner(), bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> {
if (songs.size() > 0) {
MediaManager.startQueue(mediaBrowserListenableFuture, requireContext(), songs, 0);
activity.setBottomSheetInPeek(true);
}
});
}
} else if (bundle.containsKey("is_best_of") && bundle.getBoolean("is_best_of")) {
} else if (bundle.containsKey(Constants.MEDIA_BEST_OF) && bundle.getBoolean(Constants.MEDIA_BEST_OF)) {
if (mediaBrowserListenableFuture != null) {
homeViewModel.getArtistBestOf(bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> {
homeViewModel.getArtistBestOf(getViewLifecycleOwner(), bundle.getParcelable(Constants.ARTIST_OBJECT)).observe(getViewLifecycleOwner(), songs -> {
if (songs.size() > 0) {
MediaManager.startQueue(mediaBrowserListenableFuture, requireContext(), songs, 0);
activity.setBottomSheetInPeek(true);
@ -817,7 +756,7 @@ public class HomeFragment extends Fragment implements ClickCallback {
@Override
public void onPodcastClick(Bundle bundle) {
MediaManager.startQueue(mediaBrowserListenableFuture, requireContext(), bundle.getParcelable("podcast_object"));
MediaManager.startQueue(mediaBrowserListenableFuture, requireContext(), bundle.getParcelable(Constants.PODCAST_OBJECT));
activity.setBottomSheetInPeek(true);
}

View file

@ -264,7 +264,6 @@ public class LibraryFragment extends Fragment implements ClickCallback {
@Override
public void onPlaylistClick(Bundle bundle) {
bundle.putBoolean("is_offline", false);
Navigation.findNavController(requireView()).navigate(R.id.playlistPageFragment, bundle);
}

View file

@ -26,16 +26,12 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.databinding.FragmentPlaylistCatalogueBinding;
import com.cappielloantonio.play.interfaces.ClickCallback;
import com.cappielloantonio.play.subsonic.models.Playlist;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.ui.adapter.PlaylistHorizontalAdapter;
import com.cappielloantonio.play.ui.dialog.PlaylistEditorDialog;
import com.cappielloantonio.play.util.Constants;
import com.cappielloantonio.play.viewmodel.PlaylistCatalogueViewModel;
import java.util.ArrayList;
import java.util.List;
@UnstableApi
public class PlaylistCatalogueFragment extends Fragment implements ClickCallback {
private FragmentPlaylistCatalogueBinding bind;
@ -111,32 +107,7 @@ public class PlaylistCatalogueFragment extends Fragment implements ClickCallback
bind.playlistCatalogueRecyclerView.setAdapter(playlistHorizontalAdapter);
if (getActivity() != null) {
playlistCatalogueViewModel.getPlaylistList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), playlists ->
playlistCatalogueViewModel.getPinnedPlaylistList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(),
pinnedPlaylists -> {
List<Playlist> sortedList = new ArrayList<>();
List<Playlist> unsortedList = new ArrayList<>(playlists);
List<Playlist> pinnedPlaylistsVerified = new ArrayList<>();
List<Playlist> pinnedPlaylistsNotFound = new ArrayList<>();
if (unsortedList.size() > 0) {
for (Playlist pinnedPlaylist : pinnedPlaylists) {
if (playlists.contains(pinnedPlaylist)) {
pinnedPlaylistsVerified.add(pinnedPlaylist);
} else {
pinnedPlaylistsNotFound.add(pinnedPlaylist);
}
}
unsortedList.removeAll(pinnedPlaylistsVerified);
sortedList.addAll(pinnedPlaylistsVerified);
sortedList.addAll(unsortedList);
}
playlistHorizontalAdapter.setItems(sortedList);
playlistCatalogueViewModel.unpinPlaylist(pinnedPlaylistsNotFound);
}));
playlistCatalogueViewModel.getPlaylistList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), playlists -> playlistHorizontalAdapter.setItems(playlists));
}
bind.playlistCatalogueRecyclerView.setOnTouchListener((v, event) -> {

View file

@ -61,7 +61,6 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.playlist_page_menu, menu);
initMenuOption(menu);
}
@Override
@ -103,7 +102,7 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == R.id.action_download_playlist) {
playlistPageViewModel.getPlaylistSongLiveList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
playlistPageViewModel.getPlaylistSongLiveList().observe(getViewLifecycleOwner(), songs -> {
if (isVisible() && getActivity() != null) {
DownloadUtil.getDownloadTracker(requireContext()).download(
MappingUtil.mapMediaItems(songs, false),
@ -117,12 +116,6 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
}
});
return true;
} else if (item.getItemId() == R.id.action_pin_playlist) {
playlistPageViewModel.setPinned(true);
return true;
} else if (item.getItemId() == R.id.action_unpin_playlist) {
playlistPageViewModel.setPinned(false);
return true;
}
return false;
@ -130,14 +123,6 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
private void init() {
playlistPageViewModel.setPlaylist(requireArguments().getParcelable(Constants.PLAYLIST_OBJECT));
playlistPageViewModel.setOffline(requireArguments().getBoolean("is_offline"));
}
private void initMenuOption(Menu menu) {
playlistPageViewModel.isPinned(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), isPinned -> {
menu.findItem(R.id.action_unpin_playlist).setVisible(isPinned);
menu.findItem(R.id.action_pin_playlist).setVisible(!isPinned);
});
}
private void initAppBar() {
@ -154,18 +139,13 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
bind.playlistSongCountLabel.setText(getString(R.string.playlist_song_count, playlistPageViewModel.getPlaylist().getSongCount()));
bind.playlistDurationLabel.setText(getString(R.string.playlist_duration, MusicUtil.getReadableDurationString(playlistPageViewModel.getPlaylist().getDuration(), false)));
if (playlistPageViewModel.isOffline()) {
bind.playlistSongCountLabel.setVisibility(View.GONE);
bind.playlistDurationLabel.setVisibility(View.GONE);
}
bind.animToolbar.setNavigationOnClickListener(v -> activity.navController.navigateUp());
Objects.requireNonNull(bind.animToolbar.getOverflowIcon()).setTint(requireContext().getResources().getColor(R.color.titleTextColor, null));
}
private void initMusicButton() {
playlistPageViewModel.getPlaylistSongLiveList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
playlistPageViewModel.getPlaylistSongLiveList().observe(getViewLifecycleOwner(), songs -> {
if (bind != null) {
bind.playlistPagePlayButton.setOnClickListener(v -> {
MediaManager.startQueue(mediaBrowserListenableFuture, requireContext(), songs, 0);
@ -182,39 +162,11 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
}
private void initBackCover() {
playlistPageViewModel.getPlaylistSongLiveList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
if (bind != null) {
Collections.shuffle(songs);
// Pic top-left
CustomGlideRequest.Builder
.from(requireContext(), songs.size() > 0 ? songs.get(0).getCoverArtId() : playlistPageViewModel.getPlaylist().getCoverArtId(), CustomGlideRequest.PLAYLIST_PIC, null)
.build()
.transform(new CenterCrop(), new GranularRoundedCorners(CustomGlideRequest.CORNER_RADIUS, 0, 0, 0))
.into(bind.playlistCoverImageViewTopLeft);
// Pic top-right
CustomGlideRequest.Builder
.from(requireContext(), songs.size() > 1 ? songs.get(1).getCoverArtId() : playlistPageViewModel.getPlaylist().getCoverArtId(), CustomGlideRequest.PLAYLIST_PIC, null)
.build()
.transform(new CenterCrop(), new GranularRoundedCorners(0, CustomGlideRequest.CORNER_RADIUS, 0, 0))
.into(bind.playlistCoverImageViewTopRight);
// Pic bottom-left
CustomGlideRequest.Builder
.from(requireContext(), songs.size() > 2 ? songs.get(2).getCoverArtId() : playlistPageViewModel.getPlaylist().getCoverArtId(), CustomGlideRequest.PLAYLIST_PIC, null)
.build()
.transform(new CenterCrop(), new GranularRoundedCorners(0, 0, 0, CustomGlideRequest.CORNER_RADIUS))
.into(bind.playlistCoverImageViewBottomLeft);
// Pic bottom-right
CustomGlideRequest.Builder
.from(requireContext(), songs.size() > 3 ? songs.get(3).getCoverArtId() : playlistPageViewModel.getPlaylist().getCoverArtId(), CustomGlideRequest.PLAYLIST_PIC, null)
.build()
.transform(new CenterCrop(), new GranularRoundedCorners(0, 0, CustomGlideRequest.CORNER_RADIUS, 0))
.into(bind.playlistCoverImageViewBottomRight);
}
});
CustomGlideRequest.Builder
.from(requireContext(), playlistPageViewModel.getPlaylist().getCoverArtId(), CustomGlideRequest.PLAYLIST_PIC, null)
.build()
.transform(new CenterCrop(), new GranularRoundedCorners(CustomGlideRequest.CORNER_RADIUS, 0, 0, 0))
.into(bind.playlistCoverImageView);
}
private void initSongsView() {
@ -224,7 +176,7 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
songHorizontalAdapter = new SongHorizontalAdapter(this, true);
bind.songRecyclerView.setAdapter(songHorizontalAdapter);
playlistPageViewModel.getPlaylistSongLiveList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> songHorizontalAdapter.setItems(songs));
playlistPageViewModel.getPlaylistSongLiveList().observe(getViewLifecycleOwner(), songs -> songHorizontalAdapter.setItems(songs));
}
private void initializeMediaBrowser() {

View file

@ -146,7 +146,7 @@ public class SongListPageFragment extends Fragment implements ClickCallback {
}
private void initButtons() {
songListPageViewModel.getSongList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
songListPageViewModel.getSongList().observe(getViewLifecycleOwner(), songs -> {
if (bind != null) {
bind.songListShuffleImageView.setOnClickListener(v -> {
Collections.shuffle(songs);
@ -163,7 +163,7 @@ public class SongListPageFragment extends Fragment implements ClickCallback {
songHorizontalAdapter = new SongHorizontalAdapter(this, true);
bind.songListRecyclerView.setAdapter(songHorizontalAdapter);
songListPageViewModel.getSongList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> songHorizontalAdapter.setItems(songs));
songListPageViewModel.getSongList().observe(getViewLifecycleOwner(), songs -> songHorizontalAdapter.setItems(songs));
}
private void initializeMediaBrowser() {

View file

@ -22,6 +22,7 @@ import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.service.MediaService;
import com.cappielloantonio.play.subsonic.models.PodcastEpisode;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.Constants;
import com.cappielloantonio.play.util.MusicUtil;
import com.cappielloantonio.play.viewmodel.PodcastBottomSheetViewModel;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
@ -39,7 +40,7 @@ public class PodcastBottomSheetDialog extends BottomSheetDialogFragment implemen
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_sheet_podcast_dialog, container, false);
podcast = requireArguments().getParcelable("podcast_object");
podcast = requireArguments().getParcelable(Constants.PODCAST_OBJECT);
podcastBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PodcastBottomSheetViewModel.class);
podcastBottomSheetViewModel.setPodcast(podcast);

View file

@ -7,8 +7,12 @@ object Constants {
const val TRACK_OBJECT = "TRACK_OBJECT"
const val TRACKS_OBJECT = "TRACKS_OBJECT"
const val ALBUM_OBJECT = "ALBUM_OBJECT"
const val ARTIST_OBJECT = "ARTIST_OBJECT"
const val GENRE_OBJECT = "GENRE_OBJECT"
const val PLAYLIST_OBJECT = "PLAYLIST_OBJECT"
const val PODCAST_OBJECT = "PODCAST_OBJECT"
const val ALBUM_RECENTLY_PLAYED = "ALBUM_RECENTLY_PLAYED"
const val ALBUM_MOST_PLAYED = "ALBUM_MOST_PLAYED"
const val ALBUM_RECENTLY_ADDED = "ALBUM_RECENTLY_ADDED"
@ -21,17 +25,14 @@ object Constants {
const val ALBUM_ORDER_BY_YEAR = "ALBUM_ORDER_BY_YEAR"
const val ALBUM_ORDER_BY_RANDOM = "ALBUM_ORDER_BY_RANDOM"
const val ARTIST_OBJECT = "ARTIST_OBJECT"
const val ARTIST_DOWNLOADED = "ARTIST_DOWNLOADED"
const val ARTIST_STARRED = "ARTIST_STARRED"
const val ARTIST_ORDER_BY_NAME = "ARTIST_ORDER_BY_NAME"
const val ARTIST_ORDER_BY_RANDOM = "ARTIST_ORDER_BY_RANDOM"
const val GENRE_OBJECT = "GENRE_OBJECT"
const val GENRE_ORDER_BY_NAME = "GENRE_ORDER_BY_NAME"
const val GENRE_ORDER_BY_RANDOM = "GENRE_ORDER_BY_RANDOM"
const val PLAYLIST_OBJECT = "PLAYLIST_OBJECT"
const val PLAYLIST_ALL = "ALL"
const val PLAYLIST_DOWNLOADED = "DOWNLOADED"
const val PLAYLIST_ORDER_BY_NAME = "ORDER_BY_NAME"
@ -59,4 +60,7 @@ object Constants {
const val MEDIA_STARRED = "MEDIA_STARRED"
const val MEDIA_DOWNLOADED = "MEDIA_DOWNLOADED"
const val MEDIA_FROM_ALBUM = "MEDIA_FROM_ALBUM"
const val MEDIA_MIX = "MEDIA_MIX"
const val MEDIA_CHRONOLOGY = "MEDIA_CHRONOLOGY"
const val MEDIA_BEST_OF = "MEDIA_BEST_OF"
}

View file

@ -12,13 +12,11 @@ import com.cappielloantonio.play.model.Chronology;
import com.cappielloantonio.play.repository.AlbumRepository;
import com.cappielloantonio.play.repository.ArtistRepository;
import com.cappielloantonio.play.repository.ChronologyRepository;
import com.cappielloantonio.play.repository.PlaylistRepository;
import com.cappielloantonio.play.repository.PodcastRepository;
import com.cappielloantonio.play.repository.SongRepository;
import com.cappielloantonio.play.subsonic.models.AlbumID3;
import com.cappielloantonio.play.subsonic.models.ArtistID3;
import com.cappielloantonio.play.subsonic.models.Child;
import com.cappielloantonio.play.subsonic.models.Playlist;
import com.cappielloantonio.play.subsonic.models.PodcastEpisode;
import com.cappielloantonio.play.util.Preferences;
@ -33,7 +31,6 @@ public class HomeViewModel extends AndroidViewModel {
private final SongRepository songRepository;
private final AlbumRepository albumRepository;
private final ArtistRepository artistRepository;
private final PlaylistRepository playlistRepository;
private final PodcastRepository podcastRepository;
private final ChronologyRepository chronologyRepository;
@ -49,7 +46,6 @@ public class HomeViewModel extends AndroidViewModel {
private final MutableLiveData<List<AlbumID3>> recentlyPlayedAlbumSample = new MutableLiveData<>(null);
private final MutableLiveData<List<Integer>> years = new MutableLiveData<>(null);
private final MutableLiveData<List<AlbumID3>> recentlyAddedAlbumSample = new MutableLiveData<>(null);
private final MutableLiveData<List<Playlist>> pinnedPlaylists = new MutableLiveData<>(null);
private final MutableLiveData<List<PodcastEpisode>> newestPodcastEpisodes = new MutableLiveData<>(null);
private final MutableLiveData<List<Chronology>> thisGridTopSong = new MutableLiveData<>(null);
@ -63,7 +59,6 @@ public class HomeViewModel extends AndroidViewModel {
songRepository = new SongRepository();
albumRepository = new AlbumRepository();
artistRepository = new ArtistRepository();
playlistRepository = new PlaylistRepository();
podcastRepository = new PodcastRepository();
chronologyRepository = new ChronologyRepository();
}
@ -185,20 +180,6 @@ public class HomeViewModel extends AndroidViewModel {
return recentlyPlayedAlbumSample;
}
public LiveData<List<Playlist>> getPinnedPlaylistList(LifecycleOwner owner, int maxNumber, boolean random) {
playlistRepository.getPinnedPlaylists(Preferences.getServerId()).observe(owner, playlists -> {
if (random) Collections.shuffle(playlists);
List<Playlist> subPlaylist = playlists.subList(0, Math.min(maxNumber, playlists.size()));
pinnedPlaylists.postValue(subPlaylist);
});
return pinnedPlaylists;
}
public LiveData<List<Child>> getPlaylistSongLiveList(String playlistId) {
return playlistRepository.getPlaylistSongs(playlistId);
}
public LiveData<List<PodcastEpisode>> getNewestPodcastEpisodes(LifecycleOwner owner) {
if (newestPodcastEpisodes.getValue() == null) {
podcastRepository.getNewestPodcastEpisodes(20).observe(owner, newestPodcastEpisodes::postValue);
@ -215,12 +196,20 @@ public class HomeViewModel extends AndroidViewModel {
return mediaInstantMix;
}
public LiveData<List<Child>> getArtistInstantMix(ArtistID3 artist) {
return artistRepository.getInstantMix(artist, 20);
public LiveData<List<Child>> getArtistInstantMix(LifecycleOwner owner, ArtistID3 artist) {
if (artistInstantMix.getValue() == null) {
artistRepository.getTopSongs(artist.getName(), 10).observe(owner, artistInstantMix::postValue);
}
return artistInstantMix;
}
public LiveData<List<Child>> getArtistBestOf(ArtistID3 artist) {
return artistRepository.getTopSongs(artist.getName(), 10);
public LiveData<List<Child>> getArtistBestOf(LifecycleOwner owner, ArtistID3 artist) {
if (bestOfArtists.getValue() == null) {
artistRepository.getTopSongs(artist.getName(), 10).observe(owner, artistBestOf::postValue);
}
return artistBestOf;
}
public void refreshDiscoverySongSample(LifecycleOwner owner) {

View file

@ -8,63 +8,32 @@ import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.play.repository.DownloadRepository;
import com.cappielloantonio.play.repository.PlaylistRepository;
import com.cappielloantonio.play.subsonic.models.Playlist;
import com.cappielloantonio.play.util.Constants;
import com.cappielloantonio.play.util.Preferences;
import java.util.ArrayList;
import java.util.List;
public class PlaylistCatalogueViewModel extends AndroidViewModel {
private final PlaylistRepository playlistRepository;
private final DownloadRepository downloadRepository;
private String type;
private MutableLiveData<List<Playlist>> playlistList;
private MutableLiveData<List<Playlist>> pinnedPlaylistList;
private final MutableLiveData<List<Playlist>> playlistList = new MutableLiveData<>(null);
public PlaylistCatalogueViewModel(@NonNull Application application) {
super(application);
playlistRepository = new PlaylistRepository();
downloadRepository = new DownloadRepository();
}
public LiveData<List<Playlist>> getPlaylistList(LifecycleOwner owner) {
playlistList = new MutableLiveData<>(new ArrayList<>());
switch (type) {
case Constants.PLAYLIST_ALL:
playlistRepository.getPlaylists(false, -1).observe(owner, playlists -> playlistList.postValue(playlists));
break;
case Constants.PLAYLIST_DOWNLOADED:
// TODO
//downloadRepository.getLivePlaylist().observe(owner, downloads -> playlistList.setValue(MappingUtil.mapDownloadToPlaylist(downloads)));
break;
if (playlistList.getValue() == null) {
playlistRepository.getPlaylists(false, -1).observe(owner, playlistList::postValue);
}
playlistRepository.getPlaylists(false, -1);
return playlistList;
}
public LiveData<List<Playlist>> getPinnedPlaylistList(LifecycleOwner owner) {
pinnedPlaylistList = new MutableLiveData<>(new ArrayList<>());
playlistRepository.getPinnedPlaylists(Preferences.getServerId()).observe(owner, playlists -> pinnedPlaylistList.postValue(playlists));
return pinnedPlaylistList;
}
public void unpinPlaylist(List<Playlist> playlists) {
if (type.equals(Constants.PLAYLIST_ALL)) {
for (Playlist playlist : playlists) {
playlistRepository.delete(playlist);
}
}
}
public void setType(String type) {
this.type = type;
}

View file

@ -4,23 +4,16 @@ import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.play.repository.DownloadRepository;
import com.cappielloantonio.play.repository.PlaylistRepository;
import com.cappielloantonio.play.subsonic.models.Child;
import com.cappielloantonio.play.subsonic.models.Playlist;
import com.cappielloantonio.play.util.Preferences;
import java.util.List;
public class PlaylistPageViewModel extends AndroidViewModel {
private final PlaylistRepository playlistRepository;
private final DownloadRepository downloadRepository;
private MutableLiveData<List<Child>> playlistSongLiveList = new MutableLiveData<>();
private Playlist playlist;
private boolean isOffline;
@ -29,18 +22,10 @@ public class PlaylistPageViewModel extends AndroidViewModel {
super(application);
playlistRepository = new PlaylistRepository();
downloadRepository = new DownloadRepository();
}
public LiveData<List<Child>> getPlaylistSongLiveList(LifecycleOwner owner) {
if (isOffline) {
// TODO
// downloadRepository.getLiveDownloadFromPlaylist(playlist.getId()).observe(owner, downloads -> playlistSongLiveList.postValue(MappingUtil.mapDownloadToMedia(downloads)));
} else {
playlistSongLiveList = playlistRepository.getPlaylistSongs(playlist.getId());
}
return playlistSongLiveList;
public LiveData<List<Child>> getPlaylistSongLiveList() {
return playlistRepository.getPlaylistSongs(playlist.getId());
}
public Playlist getPlaylist() {
@ -49,29 +34,5 @@ public class PlaylistPageViewModel extends AndroidViewModel {
public void setPlaylist(Playlist playlist) {
this.playlist = playlist;
// TODO
// this.playlist.setServer(Preferences.getServerId());
}
public void setOffline(boolean offline) {
isOffline = offline;
}
public boolean isOffline() {
return isOffline;
}
public LiveData<Boolean> isPinned(LifecycleOwner owner) {
MutableLiveData<Boolean> isPinnedLive = new MutableLiveData<>();
playlistRepository.getPinnedPlaylists(Preferences.getServerId()).observe(owner, playlists -> isPinnedLive.postValue(playlists.contains(playlist)));
return isPinnedLive;
}
public void setPinned(boolean isNowPinned) {
if (isNowPinned) {
playlistRepository.insert(playlist);
} else {
playlistRepository.delete(playlist);
}
}
}

View file

@ -5,12 +5,10 @@ import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.play.repository.ArtistRepository;
import com.cappielloantonio.play.repository.DownloadRepository;
import com.cappielloantonio.play.repository.SongRepository;
import com.cappielloantonio.play.subsonic.models.AlbumID3;
import com.cappielloantonio.play.subsonic.models.ArtistID3;
@ -24,7 +22,6 @@ import java.util.List;
public class SongListPageViewModel extends AndroidViewModel {
private final SongRepository songRepository;
private final ArtistRepository artistRepository;
private final DownloadRepository downloadRepository;
public String title;
public String toolbarTitle;
@ -44,10 +41,9 @@ public class SongListPageViewModel extends AndroidViewModel {
songRepository = new SongRepository();
artistRepository = new ArtistRepository();
downloadRepository = new DownloadRepository();
}
public LiveData<List<Child>> getSongList(LifecycleOwner owner) {
public LiveData<List<Child>> getSongList() {
songList = new MutableLiveData<>(new ArrayList<>());
switch (title) {

View file

@ -104,7 +104,7 @@
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:text="@string/download_title_tracks_section" />
android:text="@string/download_title_section" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/downloaded_tracks_recycler_view"

View file

@ -30,48 +30,16 @@
android:paddingTop="8dp">
<ImageView
android:id="@+id/playlist_cover_image_view_top_left"
android:id="@+id/playlist_cover_image_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="64dp"
android:layout_marginTop="8dp"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toStartOf="@id/playlist_cover_image_view_top_right"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/playlist_cover_image_view_top_right"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="64dp"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/playlist_cover_image_view_top_left"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/playlist_cover_image_view_bottom_left"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="64dp"
android:layout_marginBottom="8dp"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toStartOf="@id/playlist_cover_image_view_bottom_right"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/playlist_cover_image_view_top_left" />
<ImageView
android:id="@+id/playlist_cover_image_view_bottom_right"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="64dp"
android:layout_marginBottom="8dp"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/playlist_cover_image_view_bottom_left"
app:layout_constraintTop_toTopOf="@id/playlist_cover_image_view_bottom_left" />
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/playlist_name_label"
@ -87,7 +55,7 @@
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/playlist_cover_image_view_bottom_left" />
app:layout_constraintTop_toBottomOf="@+id/playlist_cover_image_view" />
<TextView
android:id="@+id/playlist_song_count_label"

View file

@ -6,14 +6,4 @@
android:icon="@drawable/ic_file_download"
android:title="@string/menu_download_all_button"
app:showAsAction="never" />
<item
android:id="@+id/action_pin_playlist"
android:icon="@drawable/ic_pin_in"
android:title="@string/menu_pin_button"
app:showAsAction="never" />
<item
android:id="@+id/action_unpin_playlist"
android:icon="@drawable/ic_pin_out"
android:title="@string/menu_unpin_button"
app:showAsAction="never" />
</menu>

View file

@ -2,7 +2,7 @@
<dimen name="appbar_header_height">296dp</dimen>
<dimen name="activity_margin_content">24dp</dimen>
<dimen name="bottom_sheet_peek_height">56dp</dimen>
<dimen name="global_padding_bottom">64dp</dimen>
<dimen name="global_padding_bottom">128dp</dimen>
<dimen name="radius">2dp</dimen>
<dimen name="dots_height">2dp</dimen>
</resources>

View file

@ -56,7 +56,7 @@
<string name="download_title_artist_see_all_button">See all</string>
<string name="download_title_playlist_section">Playlists</string>
<string name="download_title_playlist_see_all_button">See all</string>
<string name="download_title_tracks_section">Tracks</string>
<string name="download_title_section">Downloads</string>
<string name="download_title_tracks_see_all_button">See all</string>
<string name="empty_string" />
<string name="error_required">Required</string>