Added discover/recentryAddedAlbum/recentlyPlayedAlbum/mostPlayedAlbum data retrieval

This commit is contained in:
CappielloAntonio 2021-07-27 12:10:28 +02:00
parent 304a5f078a
commit 532fcd1ee6
45 changed files with 351 additions and 1205 deletions

View file

@ -52,7 +52,7 @@ public class App extends Application {
}
private static ApiClient getApiClient(Context context) {
String server = PreferenceUtil.getInstance(context).getServer();
String server = "http://192.168.1.81:8096";
JellyfinOptions.Builder options = new JellyfinOptions.Builder();
options.setLogger(new NullLogger());

View file

@ -47,7 +47,7 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
holder.textArtistName.setText(album.getArtistName());
CustomGlideRequest.Builder
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.ALBUM_PIC)
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.ALBUM_PIC)
.build()
.into(holder.cover);
}
@ -93,6 +93,8 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
Navigation.findNavController(view).navigate(R.id.action_libraryFragment_to_albumPageFragment, bundle);
} else if (Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.albumCatalogueFragment) {
Navigation.findNavController(view).navigate(R.id.action_albumCatalogueFragment_to_albumPageFragment, bundle);
} else if (Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.homeFragment) {
Navigation.findNavController(view).navigate(R.id.action_homeFragment_to_albumPageFragment, bundle);
}
}

View file

@ -46,7 +46,7 @@ public class AlbumArtistPageOrSimilarAdapter extends RecyclerView.Adapter<AlbumA
holder.textArtistName.setText(album.getArtistName());
CustomGlideRequest.Builder
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.ALBUM_PIC)
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.ALBUM_PIC)
.build()
.into(holder.cover);
}

View file

@ -84,7 +84,7 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
holder.textArtistName.setText(album.getArtistName());
CustomGlideRequest.Builder
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.ALBUM_PIC)
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.ALBUM_PIC)
.build()
.override(300)
.into(holder.cover);

View file

@ -46,7 +46,7 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
holder.textArtistName.setText(artist.getName());
CustomGlideRequest.Builder
.from(context, artist.getPrimary(), artist.getPrimaryBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.ARTIST_PIC)
.from(context, artist.getPrimary(), artist.getPrimaryBlurHash(), CustomGlideRequest.ARTIST_PIC)
.build()
.into(holder.cover);
}

View file

@ -83,7 +83,7 @@ public class ArtistCatalogueAdapter extends RecyclerView.Adapter<ArtistCatalogue
holder.textArtistName.setText(artist.getName());
CustomGlideRequest.Builder
.from(context, artist.getPrimary(), artist.getPrimaryBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.ARTIST_PIC)
.from(context, artist.getPrimary(), artist.getPrimaryBlurHash(), CustomGlideRequest.ARTIST_PIC)
.build()
.into(holder.cover);
}

View file

@ -46,7 +46,7 @@ public class ArtistSimilarAdapter extends RecyclerView.Adapter<ArtistSimilarAdap
holder.textArtistName.setText(artist.getName());
CustomGlideRequest.Builder
.from(context, artist.getPrimary(), artist.getPrimaryBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.ALBUM_PIC)
.from(context, artist.getPrimary(), artist.getPrimaryBlurHash(), CustomGlideRequest.ALBUM_PIC)
.build()
.into(holder.cover);
}

View file

@ -53,7 +53,7 @@ public class DiscoverSongAdapter extends RecyclerView.Adapter<DiscoverSongAdapte
holder.textAlbum.setText(song.getAlbumName());
CustomGlideRequest.Builder
.from(context, song.getPrimary(), song.getPrimary(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(holder.cover);
}

View file

@ -41,7 +41,7 @@ public class PlayerNowPlayingSongAdapter extends RecyclerView.Adapter<PlayerNowP
Song song = songs.get(position);
CustomGlideRequest.Builder
.from(context, song.getPrimary(), song.getPrimary(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.PRIMARY)
.build()
.into(holder.cover);
}

View file

@ -53,7 +53,7 @@ public class PlayerSongQueueAdapter extends RecyclerView.Adapter<PlayerSongQueue
holder.songDuration.setText(MusicUtil.getReadableDurationString(song.getDuration()));
CustomGlideRequest.Builder
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(holder.cover);

View file

@ -47,7 +47,7 @@ public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.ViewHo
holder.textPlaylistName.setText(playlist.getName());
CustomGlideRequest.Builder
.from(context, playlist.getPrimary(), playlist.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.PLAYLIST_PIC)
.from(context, playlist.getPrimary(), playlist.getBlurHash(), CustomGlideRequest.PLAYLIST_PIC)
.build()
.into(holder.cover);
}

View file

@ -81,7 +81,7 @@ public class PlaylistCatalogueAdapter extends RecyclerView.Adapter<PlaylistCatal
holder.textPlaylistName.setText(playlist.getName());
CustomGlideRequest.Builder
.from(context, playlist.getPrimary(), playlist.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.PLAYLIST_PIC)
.from(context, playlist.getPrimary(), playlist.getBlurHash(), CustomGlideRequest.PLAYLIST_PIC)
.build()
.into(holder.cover);
}

View file

@ -58,7 +58,7 @@ public class RecentMusicAdapter extends RecyclerView.Adapter<RecentMusicAdapter.
holder.textAlbum.setText(song.getAlbumName());
CustomGlideRequest.Builder
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(holder.cover);
}

View file

@ -63,7 +63,7 @@ public class SongResultSearchAdapter extends RecyclerView.Adapter<SongResultSear
}
CustomGlideRequest.Builder
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(context).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(context, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(holder.cover);
}

View file

@ -29,7 +29,7 @@ import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.model.SongArtistCross;
import com.cappielloantonio.play.model.SongGenreCross;
@Database(entities = {Album.class, Artist.class, Genre.class, Playlist.class, Song.class, RecentSearch.class, SongGenreCross.class, Queue.class, AlbumArtistCross.class, SongArtistCross.class, PlaylistSongCross.class}, version = 14, exportSchema = false)
@Database(entities = {Album.class, Artist.class, Genre.class, Playlist.class, Song.class, RecentSearch.class, SongGenreCross.class, Queue.class, AlbumArtistCross.class, SongArtistCross.class, PlaylistSongCross.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
private static final String TAG = "AppDatabase";
private final static String DB_NAME = "play_db";

View file

@ -21,14 +21,12 @@ import com.wolt.blurhashkt.BlurHashDecoder;
import org.jellyfin.apiclient.model.dto.ImageOptions;
import org.jellyfin.apiclient.model.entities.ImageType;
import java.util.Map;
public class CustomGlideRequest {
public static final String PRIMARY = "PRIMARY";
public static final String BACKDROP = "BACKDROP";
public static final String TOP_QUALITY = "TOP";
public static final String MEDIUM_QUALITY = "MEDIUM";
public static final String LOW_QUALITY = "LOW";
public static final String SONG_PIC = "SONG";
public static final String ALBUM_PIC = "ALBUM";
public static final String ARTIST_PIC = "ARTIST";
@ -48,42 +46,19 @@ public class CustomGlideRequest {
return options;
}
public static String createUrl(String item, String itemType, String quality) {
ImageOptions options = new ImageOptions();
public static String createUrl(String item) {
String url = App.getSubsonicClientInstance(App.getInstance(), false).getUrl();
Map<String, String> params = App.getSubsonicClientInstance(App.getInstance(), false).getParams();
switch (itemType) {
case PRIMARY: {
options.setImageType(ImageType.Primary);
break;
}
case BACKDROP: {
options.setImageType(ImageType.Backdrop);
break;
}
}
String sb = url + "/rest/" + "getCoverArt" +
"?u=" + params.get("u") +
"&s=" + params.get("s") +
"&t=" + params.get("t") +
"&v=" + params.get("v") +
"&c=" + params.get("c") +
"&id=" + item;
switch (quality) {
case TOP_QUALITY: {
options.setQuality(100);
options.setMaxHeight(800);
options.setEnableImageEnhancers(true);
break;
}
case MEDIUM_QUALITY: {
options.setQuality(100);
options.setMaxHeight(600);
options.setEnableImageEnhancers(true);
break;
}
case LOW_QUALITY: {
options.setQuality(100);
options.setMaxHeight(400);
options.setEnableImageEnhancers(true);
break;
}
}
return App.getApiClientInstance(App.getInstance()).GetImageUrl(item, options);
return sb;
}
public static class Builder {
@ -91,9 +66,9 @@ public class CustomGlideRequest {
private final Object item;
private final Context context;
private Builder(Context context, String item, String placeholder, String itemType, String quality, String category) {
private Builder(Context context, String item, String placeholder, String category) {
this.requestManager = Glide.with(context);
this.item = item != null ? createUrl(item, itemType, quality) : MusicUtil.getDefaultPicPerCategory(category);
this.item = item != null ? createUrl(item) : MusicUtil.getDefaultPicPerCategory(category);
this.context = context;
if (placeholder != null) {
@ -106,8 +81,8 @@ public class CustomGlideRequest {
}
}
public static Builder from(Context context, String item, String placeholder, String itemType, String quality, String category) {
return new Builder(context, item, placeholder, itemType, quality, category);
public static Builder from(Context context, String item, String placeholder, String category) {
return new Builder(context, item, placeholder, category);
}
public BitmapBuilder bitmap() {

View file

@ -10,6 +10,8 @@ import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import com.cappielloantonio.play.subsonic.models.AlbumID3;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.entities.ImageType;
@ -21,19 +23,6 @@ import java.util.UUID;
public class Album implements Parcelable {
private static final String TAG = "Album";
@Ignore
public List<Song> songs;
/*
* TODO: Da capire chi tra albumArtist e artistItems sono i compositori e suonatori dell'album, oppure le comparse
* In teoria AlbumArtist sono i creatori, mentre ArtistItems le comparse
*/
@Ignore
public List<Artist> albumArtists;
@Ignore
public List<Artist> artistItems;
@NonNull
@PrimaryKey
@ColumnInfo(name = "id")
@ -68,37 +57,14 @@ public class Album implements Parcelable {
}
@Ignore
public Album(BaseItemDto itemDto) {
this.id = itemDto.getId();
this.title = itemDto.getName();
this.year = itemDto.getProductionYear() != null ? itemDto.getProductionYear() : 0;
albumArtists = new ArrayList<>();
artistItems = new ArrayList<>();
if (itemDto.getAlbumArtists().size() != 0) {
this.artistId = itemDto.getAlbumArtists().get(0).getId();
this.artistName = itemDto.getAlbumArtists().get(0).getName();
itemDto.getAlbumArtists().forEach(artist -> {
albumArtists.add(new Artist(artist.getId(), artist.getName()));
});
}
else if (itemDto.getArtistItems().size() != 0) {
this.artistId = itemDto.getArtistItems().get(0).getId();
this.artistName = itemDto.getArtistItems().get(0).getName();
itemDto.getArtistItems().forEach(artist -> {
artistItems.add(new Artist(artist.getId(), artist.getName()));
});
}
this.primary = itemDto.getImageTags().containsKey(ImageType.Primary) ? id : null;
if (itemDto.getImageBlurHashes() != null && itemDto.getImageBlurHashes().get(ImageType.Primary) != null) {
this.blurHash = (String) itemDto.getImageBlurHashes().get(ImageType.Primary).values().toArray()[0];
}
this.songs = new ArrayList<>();
public Album(AlbumID3 albumID3) {
this.id = albumID3.getId();
this.title = albumID3.getName();
this.year = albumID3.getYear();
this.artistId = albumID3.getArtistId();
this.artistName = albumID3.getArtist();
this.primary = albumID3.getCoverArtId();
this.blurHash = blurHash;
}
@NonNull
@ -195,8 +161,6 @@ public class Album implements Parcelable {
}
protected Album(Parcel in) {
this.songs = new ArrayList<>();
this.id = in.readString();
this.title = in.readString();
this.year = in.readInt();

View file

@ -93,6 +93,9 @@ public class Song implements Parcelable {
@ColumnInfo(name = "primary")
private String primary;
@ColumnInfo(name = "blurHash")
private String blurHash;
@ColumnInfo(name = "favorite")
private boolean favorite;
@ -120,7 +123,7 @@ public class Song implements Parcelable {
@ColumnInfo(name = "offline")
private boolean offline;
public Song(@NonNull String id, String title, int trackNumber, int discNumber, int year, long duration, String albumId, String albumName, String artistId, String artistName, String primary, boolean favorite, String path, long size, String container, int bitRate, long added, int playCount, long lastPlay, boolean offline) {
public Song(@NonNull String id, String title, int trackNumber, int discNumber, int year, long duration, String albumId, String albumName, String artistId, String artistName, String primary, String blurHash, boolean favorite, String path, long size, String container, int bitRate, long added, int playCount, long lastPlay, boolean offline) {
this.id = id;
this.title = title;
this.trackNumber = trackNumber;
@ -132,6 +135,7 @@ public class Song implements Parcelable {
this.artistId = artistId;
this.artistName = artistName;
this.primary = primary;
this.blurHash = blurHash;
this.favorite = favorite;
this.path = path;
this.size = size;
@ -154,7 +158,7 @@ public class Song implements Parcelable {
this.title = child.getTitle();
this.trackNumber = child.getTrack();
this.discNumber = child.getDiscNumber();
this.year = child.getYear();
this.year = child.getYear() != null ? child.getYear() : 0;
this.duration = child.getDuration();
this.albumId = child.getAlbumId();
this.albumName = child.getAlbum();
@ -217,6 +221,10 @@ public class Song implements Parcelable {
return primary;
}
public String getBlurHash() {
return blurHash;
}
public boolean isFavorite() {
return favorite;
}
@ -297,6 +305,10 @@ public class Song implements Parcelable {
this.primary = primary;
}
public void setBlurHash(String blurHash) {
this.blurHash = blurHash;
}
public void setFavorite(boolean favorite) {
this.favorite = favorite;
}
@ -390,6 +402,7 @@ public class Song implements Parcelable {
dest.writeString(this.artistName);
dest.writeString(this.primary);
dest.writeString(Boolean.toString(favorite));
dest.writeString(this.blurHash);
dest.writeString(this.path);
dest.writeLong(this.size);
dest.writeString(this.container);
@ -414,6 +427,7 @@ public class Song implements Parcelable {
this.artistName = in.readString();
this.primary = in.readString();
this.favorite = Boolean.parseBoolean(in.readString());
this.blurHash = in.readString();
this.path = in.readString();
this.size = in.readLong();
this.container = in.readString();

View file

@ -3,17 +3,29 @@ 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.AlbumDao;
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.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 AlbumRepository {
private static final String TAG = "AlbumRepository";
private AlbumSongListClient albumSongListClient;
private AlbumDao albumDao;
private LiveData<List<Album>> listLiveAlbums;
private LiveData<List<Album>> artistListLiveAlbums;
@ -22,12 +34,30 @@ public class AlbumRepository {
public AlbumRepository(Application application) {
albumSongListClient = App.getSubsonicClientInstance(application, false).getAlbumSongListClient();
AppDatabase database = AppDatabase.getInstance(application);
albumDao = database.albumDao();
}
public LiveData<List<Album>> getListLiveAlbums() {
listLiveAlbums = albumDao.getAll();
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);
}
@Override
public void onFailure(Call<SubsonicResponse> call, Throwable t) {
}
});
return listLiveAlbums;
}

View file

@ -3,9 +3,7 @@ package com.cappielloantonio.play.repository;
import android.app.Application;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.SongArtistCrossDao;
import com.cappielloantonio.play.database.dao.SongGenreCrossDao;
import com.cappielloantonio.play.model.SongArtistCross;
import com.cappielloantonio.play.model.SongGenreCross;
import java.util.List;

View file

@ -3,20 +3,33 @@ 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.SongDao;
import com.cappielloantonio.play.database.dao.SongGenreCrossDao;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.model.SongGenreCross;
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.Collections;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class SongRepository {
private static final String TAG = "SongRepository";
private AlbumSongListClient albumSongListClient;
private SongDao songDao;
private SongGenreCrossDao songGenreCrossDao;
private LiveData<List<Song>> searchListLiveSongs;
@ -36,11 +49,36 @@ public class SongRepository {
private LiveData<List<Song>> listLiveDownloadedSong;
public SongRepository(Application application) {
albumSongListClient = App.getSubsonicClientInstance(application, false).getAlbumSongListClient();
AppDatabase database = AppDatabase.getInstance(application);
songDao = database.songDao();
songGenreCrossDao = database.songGenreCrossDao();
}
public MutableLiveData<List<Song>> getSongs() {
MutableLiveData<List<Song>> liveSongs = new MutableLiveData<>();
albumSongListClient
.getRandomSongs(10)
.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);
}
}
@Override
public void onFailure(Call<SubsonicResponse> call, Throwable t) {
}
});
return liveSongs;
}
public LiveData<List<Song>> searchListLiveSong(String title, int limit) {
searchListLiveSongs = songDao.searchSong(title, limit);
return searchListLiveSongs;
@ -276,7 +314,7 @@ public class SongRepository {
thread.start();
}
public List<Song> getRandomSample(int number) {
/*public List<Song> getRandomSample(int number) {
List<Song> sample = new ArrayList<>();
PickRandomThreadSafe randomThread = new PickRandomThreadSafe(songDao, number);
@ -291,6 +329,28 @@ public class SongRepository {
}
return sample;
}*/
public void getRandomSample(int number, MediaCallback callback) {
albumSongListClient
.getRandomSongs(number)
.enqueue(new Callback<SubsonicResponse>() {
@Override
public void onResponse(Call<SubsonicResponse> call, Response<SubsonicResponse> response) {
List<Song> songs = new ArrayList<>();
if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) {
songs = new ArrayList<>(MappingUtil.mapSong(response.body().getRandomSongs().getSongs()));
}
callback.onLoadMedia(songs);
}
@Override
public void onFailure(Call<SubsonicResponse> call, Throwable t) {
callback.onError(new Exception(t.getMessage()));
}
});
}
public List<Song> getPlaylistSong(String playlistID) {

View file

@ -1,36 +1,24 @@
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 Songs {
@Element(name = "song")
protected List<Child> songs;
/**
* 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 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

@ -26,6 +26,7 @@ public class SubsonicResponse {
private Podcasts podcasts;
private Lyrics lyrics;
private Songs songsByGenre;
@Element(name = "randomSongs")
private Songs randomSongs;
@Element
private AlbumList2 albumList2;

View file

@ -212,45 +212,19 @@ public class MainActivity extends BaseActivity {
navController.navigate(R.id.action_landingFragment_to_loginFragment);
}
public void goToSync() {
setBottomNavigationBarVisibility(false);
setBottomSheetVisibility(false);
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true);
navController.navigate(R.id.action_loginFragment_to_syncFragment, bundle);
}
else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true);
navController.navigate(R.id.action_landingFragment_to_syncFragment, bundle);
}
}
public void goFromSettingsToSync(Bundle bundle) {
setBottomNavigationBarVisibility(false);
setBottomSheetVisibility(false);
navController.navigate(R.id.action_settingsFragment_to_syncFragment, bundle);
}
public void goToHome() {
bottomNavigationView.setVisibility(View.VISIBLE);
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_homeFragment);
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
}
else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
navController.navigate(R.id.action_loginFragment_to_homeFragment);
}
}
public void goFromLogin() {
if (PreferenceUtil.getInstance(getApplicationContext()).getSync()) {
goToHome();
} else {
goToSync();
}
goToHome();
}
@Override

View file

@ -180,7 +180,7 @@ public class AlbumPageFragment extends Fragment {
private void initBackCover() {
CustomGlideRequest.Builder
.from(requireContext(), albumPageViewModel.getAlbum().getPrimary(), albumPageViewModel.getAlbum().getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(requireContext()).getImageQuality(), CustomGlideRequest.ALBUM_PIC)
.from(requireContext(), albumPageViewModel.getAlbum().getPrimary(), albumPageViewModel.getAlbum().getBlurHash(), CustomGlideRequest.ALBUM_PIC)
.build()
.into(bind.albumCoverImageView);
}

View file

@ -114,7 +114,7 @@ public class ArtistPageFragment extends Fragment {
private void initBackdrop() {
CustomGlideRequest.Builder
.from(requireContext(), artistPageViewModel.getArtist().getBackdrop(), artistPageViewModel.getArtist().getBackdropBlurHash(), CustomGlideRequest.BACKDROP, PreferenceUtil.getInstance(requireContext()).getImageQuality(), CustomGlideRequest.ARTIST_PIC)
.from(requireContext(), artistPageViewModel.getArtist().getPrimary(), artistPageViewModel.getArtist().getPrimary(), CustomGlideRequest.ARTIST_PIC)
.build()
.into(bind.artistBackdropImageView);
}

View file

@ -4,6 +4,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -16,16 +17,19 @@ import androidx.recyclerview.widget.PagerSnapHelper;
import androidx.viewpager2.widget.ViewPager2;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.AlbumAdapter;
import com.cappielloantonio.play.adapter.DiscoverSongAdapter;
import com.cappielloantonio.play.adapter.RecentMusicAdapter;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.adapter.YearAdapter;
import com.cappielloantonio.play.databinding.FragmentHomeBinding;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.Util;
import com.cappielloantonio.play.viewmodel.HomeViewModel;
import java.util.List;
public class HomeFragment extends Fragment {
private static final String TAG = "CategoriesFragment";
@ -33,14 +37,17 @@ public class HomeFragment extends Fragment {
private MainActivity activity;
private HomeViewModel homeViewModel;
private DiscoverSongAdapter discoverSongAdapter;
private RecentMusicAdapter recentlyAddedMusicAdapter;
private YearAdapter yearAdapter;
private SongResultSearchAdapter favoriteSongAdapter;
private RecentMusicAdapter recentlyPlayedMusicAdapter;
private RecentMusicAdapter mostPlayedMusicAdapter;
private RecentMusicAdapter dowanloadedMusicAdapter;
// ---------------------------------------------------- SUBSONIC ADAPTER
private DiscoverSongAdapter discoverSongAdapter;
private AlbumAdapter recentlyAddedAlbumAdapter;
private AlbumAdapter recentlyPlayedAlbumAdapter;
private AlbumAdapter mostPlayedAlbumAdapter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -60,11 +67,11 @@ public class HomeFragment extends Fragment {
super.onViewCreated(view, savedInstanceState);
initDiscoverSongSlideView();
initMostPlayedSongView();
initRecentPlayedSongView();
initMostPlayedAlbumView();
initRecentPlayedAlbumView();
initFavoritesSongView();
initYearSongView();
initRecentAddedSongView();
initRecentAddedAlbumView();
initDownloadedSongView();
}
@ -82,19 +89,19 @@ public class HomeFragment extends Fragment {
}
private void init() {
bind.recentlyAddedTracksTextViewClickable.setOnClickListener(v -> {
bind.recentlyAddedAlbumsTextViewClickable.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString(Song.RECENTLY_ADDED, Song.RECENTLY_ADDED);
activity.navController.navigate(R.id.action_homeFragment_to_songListPageFragment, bundle);
});
bind.recentlyPlayedTracksTextViewClickable.setOnClickListener(v -> {
bind.recentlyPlayedAlbumsTextViewClickable.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString(Song.RECENTLY_PLAYED, Song.RECENTLY_PLAYED);
activity.navController.navigate(R.id.action_homeFragment_to_songListPageFragment, bundle);
});
bind.mostPlayedTracksTextViewClickable.setOnClickListener(v -> {
bind.mostPlayedAlbumsTextViewClickable.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString(Song.MOST_PLAYED, Song.MOST_PLAYED);
activity.navController.navigate(R.id.action_homeFragment_to_songListPageFragment, bundle);
@ -118,34 +125,44 @@ public class HomeFragment extends Fragment {
private void initDiscoverSongSlideView() {
bind.discoverSongViewPager.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
discoverSongAdapter = new DiscoverSongAdapter(activity, requireContext(), homeViewModel.getDiscoverSongList());
bind.discoverSongViewPager.setAdapter(discoverSongAdapter);
bind.discoverSongViewPager.setOffscreenPageLimit(3);
setDiscoverSongSlideViewOffset(20, 16);
}
homeViewModel.getSongRepository().getRandomSample(10, new MediaCallback() {
@Override
public void onError(Exception exception) {
Toast.makeText(requireContext(), exception.getMessage(), Toast.LENGTH_SHORT).show();
}
private void initMostPlayedSongView() {
bind.mostPlayedTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.mostPlayedTracksRecyclerView.setHasFixedSize(true);
mostPlayedMusicAdapter = new RecentMusicAdapter(activity, requireContext(), getChildFragmentManager());
bind.mostPlayedTracksRecyclerView.setAdapter(mostPlayedMusicAdapter);
homeViewModel.getMostPlayedSongList().observe(requireActivity(), songs -> {
if(songs.size() < 10) reorder();
if(bind != null) bind.homeMostPlayedTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
mostPlayedMusicAdapter.setItems(songs);
@Override
public void onLoadMedia(List<?> media) {
discoverSongAdapter = new DiscoverSongAdapter(activity, requireContext(), (List<Song>) media);
bind.discoverSongViewPager.setAdapter(discoverSongAdapter);
bind.discoverSongViewPager.setOffscreenPageLimit(3);
setDiscoverSongSlideViewOffset(20, 16);
}
});
}
private void initRecentPlayedSongView() {
bind.recentlyPlayedTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.recentlyPlayedTracksRecyclerView.setHasFixedSize(true);
private void initMostPlayedAlbumView() {
bind.mostPlayedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.mostPlayedAlbumsRecyclerView.setHasFixedSize(true);
recentlyPlayedMusicAdapter = new RecentMusicAdapter(activity, requireContext(), getChildFragmentManager());
bind.recentlyPlayedTracksRecyclerView.setAdapter(recentlyPlayedMusicAdapter);
homeViewModel.getRecentlyPlayedSongList().observe(requireActivity(), songs -> {
if(bind != null) bind.homeRecentlyPlayedTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
recentlyPlayedMusicAdapter.setItems(songs);
mostPlayedAlbumAdapter = new AlbumAdapter(requireContext());
bind.mostPlayedAlbumsRecyclerView.setAdapter(mostPlayedAlbumAdapter);
homeViewModel.getMostPlayedAlbums().observe(requireActivity(), albums -> {
if(albums.size() < 10) reorder();
if(bind != null) bind.homeMostPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
mostPlayedAlbumAdapter.setItems(albums);
});
}
private void initRecentPlayedAlbumView() {
bind.recentlyPlayedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.recentlyPlayedAlbumsRecyclerView.setHasFixedSize(true);
recentlyPlayedAlbumAdapter = new AlbumAdapter(requireContext());
bind.recentlyPlayedAlbumsRecyclerView.setAdapter(recentlyPlayedAlbumAdapter);
homeViewModel.getRecentlyPlayedAlbumList().observe(requireActivity(), albums -> {
if(bind != null) bind.homeRecentlyPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
recentlyPlayedAlbumAdapter.setItems(albums);
});
}
@ -178,13 +195,15 @@ public class HomeFragment extends Fragment {
pagerSnapHelper.attachToRecyclerView(bind.favoritesTracksRecyclerView);
}
private void initRecentAddedSongView() {
bind.recentlyAddedTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.recentlyAddedTracksRecyclerView.setHasFixedSize(true);
private void initRecentAddedAlbumView() {
bind.recentlyAddedAlbumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.recentlyAddedAlbumsRecyclerView.setHasFixedSize(true);
recentlyAddedMusicAdapter = new RecentMusicAdapter(activity, requireContext(), getChildFragmentManager());
bind.recentlyAddedTracksRecyclerView.setAdapter(recentlyAddedMusicAdapter);
homeViewModel.getRecentlyAddedSongList().observe(requireActivity(), songs -> recentlyAddedMusicAdapter.setItems(songs));
recentlyAddedAlbumAdapter = new AlbumAdapter(requireContext());
bind.recentlyAddedAlbumsRecyclerView.setAdapter(recentlyAddedAlbumAdapter);
homeViewModel.getMostRecentlyAddedAlbums().observe(requireActivity(), albums -> {
recentlyAddedAlbumAdapter.setItems(albums);
});
}
private void initDownloadedSongView() {
@ -225,12 +244,12 @@ public class HomeFragment extends Fragment {
if(bind != null) {
bind.homeLinearLayoutContainer.removeAllViews();
bind.homeLinearLayoutContainer.addView(bind.homeDiscoverSector);
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedAlbumsSector);
bind.homeLinearLayoutContainer.addView(bind.homeFlashbackSector);
bind.homeLinearLayoutContainer.addView(bind.homeFavoriteTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeDownloadedTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeMostPlayedTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyPlayedTracksSector);
bind.homeLinearLayoutContainer.addView(bind.homeMostPlayedAlbumsSector);
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyPlayedAlbumsSector);
}
}
}

View file

@ -60,7 +60,6 @@ public class LibraryFragment extends Fragment {
initArtistView();
initGenreView();
initPlaylistSlideView();
initCatalogueSyncCheck();
}
@Override
@ -126,17 +125,6 @@ public class LibraryFragment extends Fragment {
setDiscoverSongSlideViewOffset(20, 16);
}
private void initCatalogueSyncCheck() {
if (!PreferenceUtil.getInstance(requireContext()).getSongGenreSync()) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setMessage("Sync song's genres otherwise nothing will be shown in each genre category")
.setTitle("Song's genres not synchronized")
.setNegativeButton(R.string.ignore, null)
.setPositiveButton("Sync", (dialog, id) -> activity.goToSync())
.show();
}
}
private void setDiscoverSongSlideViewOffset(float pageOffset, float pageMargin) {
bind.playlistViewPager.setPageTransformer((page, position) -> {
float myOffset = position * -(2 * pageOffset + pageMargin);

View file

@ -263,7 +263,7 @@ public class PlayerBottomSheetFragment extends Fragment implements MusicServiceE
bind.playerHeaderLayout.playerHeaderSongArtistLabel.setText(song.getArtistName());
CustomGlideRequest.Builder
.from(requireContext(), song.getPrimary(), song.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(requireContext()).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(requireContext(), song.getPrimary(), song.getBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(bind.playerHeaderLayout.playerHeaderSongCoverImage);

View file

@ -150,7 +150,7 @@ public class PlaylistPageFragment extends Fragment {
private void initBackCover() {
CustomGlideRequest.Builder
.from(requireContext(), playlistPageViewModel.getPlaylist().getPrimary(), playlistPageViewModel.getPlaylist().getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(requireContext()).getImageQuality(), CustomGlideRequest.ALBUM_PIC)
.from(requireContext(), playlistPageViewModel.getPlaylist().getPrimary(), playlistPageViewModel.getPlaylist().getBlurHash(), CustomGlideRequest.ALBUM_PIC)
.build()
.into(bind.albumBackCoverImageView);
}

View file

@ -53,36 +53,5 @@ public class SettingsFragment extends PreferenceFragmentCompat {
return true;
});
}
Preference music_sync_button = findPreference(getString(R.string.music_sync));
music_sync_button.setOnPreferenceClickListener(preference -> {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setMessage("Force reload your entire music library")
.setTitle("Force sync")
.setNegativeButton(R.string.ignore, null)
.setPositiveButton("Sync", (dialog, id) -> {
PreferenceUtil.getInstance(requireContext()).setSync(false);
PreferenceUtil.getInstance(requireContext()).setSongGenreSync(false);
Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true);
activity.goFromSettingsToSync(bundle);
})
.show();
return true;
});
Preference playlist_sync_button = findPreference(getString(R.string.playlist_song_cross_sync));
playlist_sync_button.setOnPreferenceClickListener(preference -> {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setMessage("Sync playlists' songs")
.setTitle("Force sync playlist")
.setNegativeButton(R.string.ignore, null)
.setPositiveButton("Sync", (dialog, id) -> {
Bundle bundle = SyncUtil.getSyncBundle(false, false, false, true, false);
activity.goFromSettingsToSync(bundle);
})
.show();
return true;
});
}
}

View file

@ -1,239 +1,94 @@
package com.cappielloantonio.play.ui.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.databinding.FragmentSyncBinding;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.AlbumArtistCross;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Playlist;
import com.cappielloantonio.play.model.PlaylistSongCross;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.model.SongArtistCross;
import com.cappielloantonio.play.repository.AlbumArtistRepository;
import com.cappielloantonio.play.repository.AlbumRepository;
import com.cappielloantonio.play.repository.ArtistRepository;
import com.cappielloantonio.play.repository.GenreRepository;
import com.cappielloantonio.play.repository.PlaylistRepository;
import com.cappielloantonio.play.repository.PlaylistSongRepository;
import com.cappielloantonio.play.repository.SongArtistRepository;
import com.cappielloantonio.play.repository.SongGenreRepository;
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.Genre;
import com.cappielloantonio.play.ui.activity.MainActivity;
import com.cappielloantonio.play.util.DownloadUtil;
import com.cappielloantonio.play.util.PreferenceUtil;
import com.cappielloantonio.play.util.SyncUtil;
import com.cappielloantonio.play.util.Util;
import com.cappielloantonio.play.viewmodel.SyncViewModel;
import java.util.ArrayList;
import java.util.List;
public class SyncFragment extends Fragment {
private static final String TAG = "SyncFragment";
private MainActivity activity;
private FragmentSyncBinding bind;
private SyncViewModel syncViewModel;
private SongRepository songRepository;
private AlbumRepository albumRepository;
private ArtistRepository artistRepository;
private PlaylistRepository playlistRepository;
private GenreRepository genreRepository;
private PlaylistSongRepository playlistSongRepository;
private final int LIBRARIES = 0;
private final int ALBUMS = 1;
private final int ARTISTS = 2;
private final int GENRES = 3;
private final int PLAYLISTS = 4;
private final int SONGS = 5;
private final int SONG_X_PLAYLIST = 6;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
activity = (MainActivity) getActivity();
bind = FragmentSyncBinding.inflate(inflater, container, false);
View view = bind.getRoot();
syncViewModel = new ViewModelProvider(requireActivity()).get(SyncViewModel.class);
songRepository = new SongRepository(activity.getApplication());
albumRepository = new AlbumRepository(activity.getApplication());
artistRepository = new ArtistRepository(activity.getApplication());
playlistRepository = new PlaylistRepository(activity.getApplication());
genreRepository = new GenreRepository(activity.getApplication());
playlistSongRepository = new PlaylistSongRepository(activity.getApplication());
init();
initView();
initButtonListeners();
syncLibraries();
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind = null;
}
private void init() {
syncViewModel.setArguemnts(getArguments());
bind.syncingDateLabel.setText(Util.getDate());
}
private void initView() {
if (!syncViewModel.isSyncAlbum()) bind.syncAlbumsSector.setVisibility(View.GONE);
if (!syncViewModel.isSyncArtist()) bind.syncArtistsSector.setVisibility(View.GONE);
if (!syncViewModel.isSyncGenres()) bind.syncGenresSector.setVisibility(View.GONE);
if (!syncViewModel.isSyncPlaylist()) bind.syncPlaylistsSector.setVisibility(View.GONE);
if (!syncViewModel.isSyncPlaylist()) bind.syncSongXPlaylistSector.setVisibility(View.GONE);
if (!syncViewModel.isSyncSong()) bind.syncSongsSector.setVisibility(View.GONE);
}
private void initButtonListeners() {
bind.syncLibrariesRetryImageView.setOnClickListener(v -> {
resetSectorInfo(LIBRARIES);
syncLibraries();
});
bind.syncAlbumsRetryImageView.setOnClickListener(v -> {
resetSectorInfo(ALBUMS);
syncAlbums(500, 0, 0);
});
bind.syncArtistsRetryImageView.setOnClickListener(v -> {
resetSectorInfo(ARTISTS);
syncArtists();
});
bind.syncGenresRetryImageView.setOnClickListener(v -> {
resetSectorInfo(GENRES);
syncGenres();
});
bind.syncPlaylistsRetryImageView.setOnClickListener(v -> {
resetSectorInfo(PLAYLISTS);
syncPlaylist();
});
bind.syncSongXPlaylistRetryImageView.setOnClickListener(v -> {
resetSectorInfo(SONG_X_PLAYLIST);
syncSongsPerPlaylist(syncViewModel.getPlaylistList());
});
bind.syncSongsRetryImageView.setOnClickListener(v -> {
resetSectorInfo(SONGS);
syncSongs();
});
bind.syncingGoHomeImageView.setOnClickListener(v -> {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setMessage("Make sure each category has been properly synchronized")
.setTitle("Go home")
.setNegativeButton(R.string.ignore, null)
.setPositiveButton("Go", (dialog, id) -> {
PreferenceUtil.getInstance(requireContext()).setSync(true);
activity.goToHome();
})
.show();
});
}
public class SyncFragment {
private Context context;
private void syncLibraries() {
SyncUtil.getLibraries(requireContext(), new MediaCallback() {
SyncUtil.getLibraries(context, new MediaCallback() {
@Override
public void onError(Exception exception) {
loadSectorInfo(LIBRARIES, exception.getMessage(), false);
}
@Override
public void onLoadMedia(List<?> media) {
loadSectorInfo(LIBRARIES, "", true);
}
});
}
private void syncAlbums(int size, int offset, int page) {
SyncUtil.getAlbums(requireContext(), new MediaCallback() {
SyncUtil.getAlbums(context, new MediaCallback() {
@Override
public void onError(Exception exception) {
loadSectorInfo(ALBUMS, exception.getMessage(), false);
}
@Override
public void onLoadMedia(List<?> media) {
syncViewModel.addToAlbumList((List<AlbumID3>) media);
// syncViewModel.addToAlbumList((List<AlbumID3>) media);
if (media.size() == size) {
syncAlbums(size, size * (page + 1), page + 1);
} else {
loadSectorInfo(ALBUMS, "Found " + syncViewModel.getAlbumList().size() + " elements", true);
}
}
}, size, offset);
}
private void syncArtists() {
SyncUtil.getArtists(requireContext(), new MediaCallback() {
SyncUtil.getArtists(context, new MediaCallback() {
@Override
public void onError(Exception exception) {
loadSectorInfo(ARTISTS, exception.getMessage(), false);
}
@Override
public void onLoadMedia(List<?> media) {
syncViewModel.setArtistList((ArrayList<ArtistID3>) media);
loadSectorInfo(ARTISTS, "Found " + syncViewModel.getArtistList().size() + " elements", true);
// syncViewModel.setArtistList((ArrayList<ArtistID3>) media);
}
});
}
private void syncGenres() {
SyncUtil.getGenres(requireContext(), new MediaCallback() {
SyncUtil.getGenres(context, new MediaCallback() {
@Override
public void onError(Exception exception) {
loadSectorInfo(GENRES, exception.getMessage(), false);
}
@Override
public void onLoadMedia(List<?> media) {
syncViewModel.setGenreList((ArrayList<Genre>) media);
loadSectorInfo(GENRES, "Found " + syncViewModel.getGenreList().size() + " elements", true);
// syncViewModel.setGenreList((ArrayList<Genre>) media);
}
});
}
private void syncPlaylist() {
SyncUtil.getPlaylists(requireContext(), new MediaCallback() {
SyncUtil.getPlaylists(context, new MediaCallback() {
@Override
public void onError(Exception exception) {
loadSectorInfo(PLAYLISTS, exception.getMessage(), false);
}
@Override
public void onLoadMedia(List<?> media) {
syncViewModel.setPlaylistList((ArrayList<Playlist>) media);
loadSectorInfo(PLAYLISTS, "Found " + syncViewModel.getPlaylistList().size() + " elements", true);
// syncViewModel.setPlaylistList((ArrayList<Playlist>) media);
}
});
}
private void syncSongsPerPlaylist(List<Playlist> playlists) {
/* for (Playlist playlist : playlists) {
SyncUtil.getSongsPerPlaylist(requireContext(), new MediaCallback() {
SyncUtil.getSongsPerPlaylist(context(), new MediaCallback() {
@Override
public void onError(Exception exception) {
loadSectorInfo(SONG_X_PLAYLIST, exception.getMessage(), false);
@ -246,236 +101,31 @@ public class SyncFragment extends Fragment {
}
}, playlist.getId());
} */
loadSectorInfo(SONG_X_PLAYLIST, "Playlist processed: SEI BRAVO", true);
enableHomeButton(SONG_X_PLAYLIST);
}
private void syncSongs() {
enableHomeButton(SONGS);
for (AlbumID3 album : syncViewModel.getAlbumList()) {
SyncUtil.getSongs(requireContext(), new MediaCallback() {
/* for (AlbumID3 album : syncViewModel.getAlbumList()) {
SyncUtil.getSongs(context, syncViewModel.getCatalogue(), new MediaCallback() {
@Override
public void onError(Exception exception) {
loadSectorInfo(SONGS, exception.getMessage(), false);
}
@Override
public void onLoadMedia(List<?> media) {
syncViewModel.addToChildList((ArrayList<Child>) media);
loadSectorInfo(SONGS, "Found " + syncViewModel.getChildList().size() + " elements", true);
syncViewModel.addToSongList((ArrayList<Song>) media);
}
}, album);
}
}*/
}
private void syncDownloadedSong() {
songRepository.getListLiveDownloadedSong().observe(requireActivity(), songs -> {
/*songRepository.getListLiveDownloadedSong().observe(requireActivity(), songs -> {
for (Song song : songs) {
if (!DownloadUtil.getDownloadTracker(requireContext()).isDownloaded(song)) {
if (!DownloadUtil.getDownloadTracker(context()).isDownloaded(song)) {
song.setOffline(false);
songRepository.setOfflineStatus(song);
}
}
});
}
private void loadSectorInfo(int sector, String message, boolean isSuccess) {
switch (sector) {
case LIBRARIES:
if (isSuccess) {
if (bind != null) {
bind.syncLibrariesStatusLabel.setText("Status: SUCCESS");
bind.syncLibrariesDetailLabel.setVisibility(View.GONE);
bind.syncLibrariesRetryImageView.setVisibility(View.GONE);
}
syncNextSector(LIBRARIES);
} else {
if (bind != null) {
bind.syncLibrariesStatusLabel.setText("Status: ERROR");
bind.syncLibrariesDetailLabel.setText(message);
bind.syncLibrariesDetailLabel.setVisibility(View.VISIBLE);
bind.syncLibrariesRetryImageView.setVisibility(View.VISIBLE);
}
}
break;
case ALBUMS:
if (isSuccess) {
if (bind != null) {
bind.syncAlbumsStatusLabel.setText("Status: SUCCESS");
bind.syncAlbumsDetailLabel.setText(message);
bind.syncAlbumsRetryImageView.setVisibility(View.GONE);
}
syncNextSector(ALBUMS);
} else {
if (bind != null) {
bind.syncLibrariesStatusLabel.setText("Status: ERROR");
bind.syncAlbumsDetailLabel.setText(message);
bind.syncAlbumsRetryImageView.setVisibility(View.VISIBLE);
}
}
break;
case ARTISTS:
if (isSuccess) {
if (bind != null) {
bind.syncArtistsStatusLabel.setText("Status: SUCCESS");
bind.syncArtistsDetailLabel.setText(message);
bind.syncArtistsRetryImageView.setVisibility(View.GONE);
}
syncNextSector(ARTISTS);
} else {
if (bind != null) {
bind.syncArtistsStatusLabel.setText("Status: ERROR");
bind.syncArtistsDetailLabel.setText(message);
bind.syncArtistsRetryImageView.setVisibility(View.VISIBLE);
}
}
break;
case GENRES:
if (isSuccess) {
if (bind != null) {
bind.syncGenresStatusLabel.setText("Status: SUCCESS");
bind.syncGenresDetailLabel.setText(message);
bind.syncGenresRetryImageView.setVisibility(View.GONE);
}
syncNextSector(GENRES);
} else {
if (bind != null) {
bind.syncGenresStatusLabel.setText("Status: ERROR");
bind.syncGenresDetailLabel.setText(message);
bind.syncGenresRetryImageView.setVisibility(View.VISIBLE);
}
}
break;
case PLAYLISTS:
if (isSuccess) {
if (bind != null) {
bind.syncPlaylistsStatusLabel.setText("Status: SUCCESS");
bind.syncPlaylistsDetailLabel.setText(message);
bind.syncPlaylistsRetryImageView.setVisibility(View.GONE);
}
syncNextSector(PLAYLISTS);
} else {
if (bind != null) {
bind.syncPlaylistsStatusLabel.setText("Status: ERROR");
bind.syncPlaylistsDetailLabel.setText(message);
bind.syncPlaylistsRetryImageView.setVisibility(View.VISIBLE);
}
}
break;
case SONG_X_PLAYLIST:
if (isSuccess) {
if (bind != null) {
bind.syncSongXPlaylistStatusLabel.setText("Status: SUCCESS");
bind.syncSongXPlaylistDetailLabel.setText(message);
bind.syncSongXPlaylistRetryImageView.setVisibility(View.GONE);
}
syncNextSector(SONG_X_PLAYLIST);
} else {
if (bind != null) {
bind.syncSongXPlaylistStatusLabel.setText("Status: ERROR");
bind.syncSongXPlaylistDetailLabel.setText(message);
bind.syncSongXPlaylistRetryImageView.setVisibility(View.VISIBLE);
}
}
break;
case SONGS:
if (isSuccess) {
if (bind != null) {
bind.syncSongsStatusLabel.setText("Status: SUCCESS");
bind.syncSongsDetailLabel.setText(message);
bind.syncSongsRetryImageView.setVisibility(View.GONE);
}
} else {
if (bind != null) {
bind.syncSongsStatusLabel.setText("Status: ERROR");
bind.syncSongsDetailLabel.setText(message);
bind.syncSongsRetryImageView.setVisibility(View.VISIBLE);
}
}
break;
}
}
private void resetSectorInfo(int sector) {
if (bind != null) {
switch (sector) {
case LIBRARIES:
bind.syncLibrariesStatusLabel.setText("Loading...");
bind.syncLibrariesDetailLabel.setText(R.string.label_placeholder);
bind.syncLibrariesDetailLabel.setVisibility(View.GONE);
bind.syncLibrariesRetryImageView.setVisibility(View.GONE);
break;
case ALBUMS:
bind.syncAlbumsStatusLabel.setText("Loading...");
bind.syncAlbumsDetailLabel.setText(R.string.label_placeholder);
bind.syncAlbumsRetryImageView.setVisibility(View.GONE);
break;
case ARTISTS:
bind.syncArtistsStatusLabel.setText("Loading...");
bind.syncArtistsDetailLabel.setText(R.string.label_placeholder);
bind.syncArtistsRetryImageView.setVisibility(View.GONE);
break;
case GENRES:
bind.syncGenresStatusLabel.setText("Loading...");
bind.syncGenresDetailLabel.setText(R.string.label_placeholder);
bind.syncGenresRetryImageView.setVisibility(View.GONE);
break;
case PLAYLISTS:
bind.syncPlaylistsStatusLabel.setText("Loading...");
bind.syncPlaylistsDetailLabel.setText(R.string.label_placeholder);
bind.syncPlaylistsRetryImageView.setVisibility(View.GONE);
break;
case SONG_X_PLAYLIST:
bind.syncSongXPlaylistStatusLabel.setText("Loading...");
bind.syncSongXPlaylistDetailLabel.setText(R.string.label_placeholder);
bind.syncSongXPlaylistRetryImageView.setVisibility(View.GONE);
break;
case SONGS:
bind.syncSongsStatusLabel.setText("Loading...");
bind.syncSongsDetailLabel.setText(R.string.label_placeholder);
bind.syncSongsRetryImageView.setVisibility(View.GONE);
break;
}
}
}
private void syncNextSector(int sector) {
switch (sector) {
case LIBRARIES:
if (syncViewModel.isSyncAlbum()) syncAlbums(500, 0, 0);
else syncPlaylist();
break;
case ALBUMS:
syncArtists();
break;
case ARTISTS:
syncGenres();
break;
case GENRES:
syncPlaylist();
break;
case PLAYLISTS:
syncSongsPerPlaylist(syncViewModel.getPlaylistList());
break;
case SONG_X_PLAYLIST:
if (syncViewModel.isSyncSong()) syncSongs();
break;
case SONGS:
break;
}
}
private void enableHomeButton(int sector) {
switch (sector) {
case SONG_X_PLAYLIST:
if (!syncViewModel.isSyncSong()) bind.syncingGoHomeImageView.setVisibility(View.VISIBLE);
break;
case SONGS:
bind.syncingGoHomeImageView.setVisibility(View.VISIBLE);
break;
}
});*/
}
}

View file

@ -72,7 +72,7 @@ public class AlbumBottomSheetDialog extends BottomSheetDialogFragment implements
private void init(View view) {
coverAlbum = view.findViewById(R.id.album_cover_image_view);
CustomGlideRequest.Builder
.from(requireContext(), albumBottomSheetViewModel.getAlbum().getPrimary(), albumBottomSheetViewModel.getAlbum().getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(requireContext()).getImageQuality(), CustomGlideRequest.ALBUM_PIC)
.from(requireContext(), albumBottomSheetViewModel.getAlbum().getPrimary(), albumBottomSheetViewModel.getAlbum().getBlurHash(), CustomGlideRequest.ALBUM_PIC)
.build()
.into(coverAlbum);

View file

@ -63,7 +63,7 @@ public class ArtistBottomSheetDialog extends BottomSheetDialogFragment implement
private void init(View view) {
coverArtist = view.findViewById(R.id.artist_cover_image_view);
CustomGlideRequest.Builder
.from(requireContext(), artistBottomSheetViewModel.getArtist().getPrimary(), artistBottomSheetViewModel.getArtist().getPrimaryBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(requireContext()).getImageQuality(), CustomGlideRequest.ARTIST_PIC)
.from(requireContext(), artistBottomSheetViewModel.getArtist().getPrimary(), artistBottomSheetViewModel.getArtist().getPrimaryBlurHash(), CustomGlideRequest.ARTIST_PIC)
.build()
.into(coverArtist);

View file

@ -72,7 +72,7 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements
private void init(View view) {
coverSong = view.findViewById(R.id.song_cover_image_view);
CustomGlideRequest.Builder
.from(requireContext(), songBottomSheetViewModel.getSong().getPrimary(), songBottomSheetViewModel.getSong().getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(requireContext()).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(requireContext(), songBottomSheetViewModel.getSong().getPrimary(), songBottomSheetViewModel.getSong().getBlurHash(), CustomGlideRequest.SONG_PIC)
.build()
.into(coverSong);

View file

@ -67,7 +67,7 @@ public class PlayingNotification {
final int bigNotificationImageSize = service.getResources().getDimensionPixelSize(R.dimen.notification_big_image_size);
service.runOnUiThread(() -> CustomGlideRequest.Builder
.from(service, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.PRIMARY, PreferenceUtil.getInstance(service.getApplicationContext()).getImageQuality(), CustomGlideRequest.SONG_PIC)
.from(service, song.getPrimary(), song.getBlurHash(), CustomGlideRequest.SONG_PIC)
.bitmap()
.build()
.into(new CustomTarget<Bitmap>(bigNotificationImageSize, bigNotificationImageSize) {

View file

@ -0,0 +1,31 @@
package com.cappielloantonio.play.util;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.subsonic.models.AlbumID3;
import com.cappielloantonio.play.subsonic.models.Child;
import java.util.ArrayList;
import java.util.List;
public class MappingUtil {
public static ArrayList<Song> mapSong(List<Child> children) {
ArrayList<Song> songs = new ArrayList();
for(Child child : children){
songs.add(new Song(child));
}
return songs;
}
public static ArrayList<Album> mapAlbum(List<AlbumID3> albumID3List) {
ArrayList<Album> albums = new ArrayList();
for(AlbumID3 albumID3 : albumID3List){
albums.add(new Album(albumID3));
}
return albums;
}
}

View file

@ -68,7 +68,7 @@ public class SyncUtil {
});
}
public static void getSongs(Context context, MediaCallback callback, AlbumID3 album) {
public static void getSongs(Context context, Map<Integer, Song> currentCatalogue, MediaCallback callback, AlbumID3 album) {
App.getSubsonicClientInstance(context, false)
.getBrowsingClient()
.getAlbum(album.getId())
@ -79,9 +79,9 @@ public class SyncUtil {
String errorMessage = response.body().getError().getCode().getValue() + " - " + response.body().getError().getMessage();
callback.onError(new Exception(errorMessage));
} else if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) {
List<Child> childList = new ArrayList<>();
childList.addAll(response.body().getAlbum().getSongs());
callback.onLoadMedia(childList);
List<Song> songList = new ArrayList<>(MappingUtil.mapSong(response.body().getAlbum().getSongs()));
updateSongData(currentCatalogue, songList);
callback.onLoadMedia(songList);
} else {
callback.onError(new Exception("Empty response"));
}
@ -307,16 +307,16 @@ public class SyncUtil {
return bundle;
}
private static Song updateSongData(Map<Integer, Song> library, Song newSong) {
if (library.containsKey(newSong.hashCode())) {
Song oldSong = library.get(newSong.hashCode());
newSong.setFavorite(oldSong.isFavorite());
newSong.setAdded(oldSong.getAdded());
newSong.setLastPlay(oldSong.getLastPlay());
newSong.setPlayCount(oldSong.getPlayCount());
newSong.setOffline(oldSong.isOffline());
private static void updateSongData(Map<Integer, Song> library, List<Song> songs) {
for (Song song: songs) {
if (library.containsKey(song.hashCode())) {
Song oldSong = library.get(song.hashCode());
song.setFavorite(oldSong.isFavorite());
song.setAdded(oldSong.getAdded());
song.setLastPlay(oldSong.getLastPlay());
song.setPlayCount(oldSong.getPlayCount());
song.setOffline(oldSong.isOffline());
}
}
return newSong;
}
}

View file

@ -23,7 +23,7 @@ public class AlbumCatalogueViewModel extends AndroidViewModel {
}
public LiveData<List<Album>> getAlbumList() {
albumList = albumRepository.getListLiveAlbums();
// albumList = albumRepository.getListLiveAlbums();
return albumList;
}

View file

@ -6,16 +6,21 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.AlbumRepository;
import com.cappielloantonio.play.repository.SongRepository;
import java.util.ArrayList;
import java.util.List;
public class HomeViewModel extends AndroidViewModel {
private static final String TAG = "HomeViewModel";
private SongRepository songRepository;
private AlbumRepository albumRepository;
private List<Song> dicoverSongSample;
private List<Song> dicoverSongSample = new ArrayList<>();
private LiveData<List<Song>> recentlyPlayedSongSample;
private LiveData<List<Song>> recentlyAddedSongSample;
private LiveData<List<Song>> mostPlayedSongSample;
@ -23,27 +28,30 @@ public class HomeViewModel extends AndroidViewModel {
private LiveData<List<Song>> downloadedSongSample;
private List<Integer> years;
private LiveData<List<Album>> mostPlayedAlbumSample;
private LiveData<List<Album>> recentlyAddedAlbumSample;
private LiveData<List<Album>> recentlyPlayedAlbumSample;
public HomeViewModel(@NonNull Application application) {
super(application);
songRepository = new SongRepository(application);
albumRepository = new AlbumRepository(application);
dicoverSongSample = songRepository.getRandomSample(10);
recentlyPlayedSongSample = songRepository.getListLiveRecentlyPlayedSampleSong(20);
recentlyAddedSongSample = songRepository.getListLiveRecentlyAddedSampleSong(20);
mostPlayedSongSample = songRepository.getListLiveMostPlayedSampleSong(20);
favoritesSongSample = songRepository.getListLiveFavoritesSampleSong(20);
downloadedSongSample = songRepository.getListLiveDownloadedSampleSong(20);
years = songRepository.getYearList();
mostPlayedAlbumSample = albumRepository.getListLiveAlbums("frequent", 20);
recentlyAddedAlbumSample = albumRepository.getListLiveAlbums("newest", 20);
recentlyPlayedAlbumSample = albumRepository.getListLiveAlbums("recent", 20);
}
public List<Song> getDiscoverSongList() {
if (dicoverSongSample.isEmpty()) {
dicoverSongSample = songRepository.getRandomSample(10);
}
return dicoverSongSample;
public SongRepository getSongRepository() {
return songRepository;
}
public LiveData<List<Song>> getRecentlyAddedSongList() {
@ -69,4 +77,16 @@ public class HomeViewModel extends AndroidViewModel {
public LiveData<List<Song>> getDownloaded() {
return downloadedSongSample;
}
public LiveData<List<Album>> getMostPlayedAlbums() {
return mostPlayedAlbumSample;
}
public LiveData<List<Album>> getMostRecentlyAddedAlbums() {
return recentlyAddedAlbumSample;
}
public LiveData<List<Album>> getRecentlyPlayedAlbumList() {
return recentlyPlayedAlbumSample;
}
}

View file

@ -18,6 +18,7 @@ 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.Genre;
import com.cappielloantonio.play.util.MappingUtil;
import java.util.ArrayList;
import java.util.HashMap;
@ -40,9 +41,8 @@ public class SyncViewModel extends AndroidViewModel {
private ArrayList<Genre> genreList = new ArrayList<>();
private ArrayList<Playlist> playlistList = new ArrayList<>();
private ArrayList<Song> songList = new ArrayList<>();
private ArrayList<Child> childList = new ArrayList<>();
private SongRepository songRepository;
private final SongRepository songRepository;
private AlbumRepository albumRepository;
private ArtistRepository artistRepository;
private PlaylistRepository playlistRepository;
@ -128,12 +128,8 @@ public class SyncViewModel extends AndroidViewModel {
this.songList = songList;
}
public ArrayList<Child> getChildList() {
return childList;
}
public void addToChildList(ArrayList<Child> childList) {
this.childList.addAll(childList);
public void addToSongList(ArrayList<Song> songList) {
this.songList.addAll(songList);
}
public Map<Integer, Song> getCatalogue() {

View file

@ -65,9 +65,9 @@
android:paddingBottom="8dp" />
</LinearLayout>
<!-- Most played tracks -->
<!-- Most played albums -->
<LinearLayout
android:id="@+id/home_most_played_tracks_sector"
android:id="@+id/home_most_played_albums_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@ -93,7 +93,7 @@
<TextView
android:id="@+id/most_played_tracks_text_view_clickable"
android:id="@+id/most_played_albums_text_view_clickable"
style="@style/SubheadTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -105,7 +105,7 @@
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/most_played_tracks_recycler_view"
android:id="@+id/most_played_albums_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
@ -117,9 +117,9 @@
android:paddingBottom="8dp" />
</LinearLayout>
<!-- Recently played tracks -->
<!-- Recently played albums -->
<LinearLayout
android:id="@+id/home_recently_played_tracks_sector"
android:id="@+id/home_recently_played_albums_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@ -145,7 +145,7 @@
<TextView
android:id="@+id/recently_played_tracks_text_view_clickable"
android:id="@+id/recently_played_albums_text_view_clickable"
style="@style/SubheadTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -157,7 +157,7 @@
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recently_played_tracks_recycler_view"
android:id="@+id/recently_played_albums_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
@ -301,9 +301,9 @@
android:paddingBottom="8dp" />
</LinearLayout>
<!-- Recently added tracks -->
<!-- Recently added albums -->
<LinearLayout
android:id="@+id/home_recently_added_tracks_sector"
android:id="@+id/home_recently_added_albums_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@ -329,7 +329,7 @@
<TextView
android:id="@+id/recently_added_tracks_text_view_clickable"
android:id="@+id/recently_added_albums_text_view_clickable"
style="@style/SubheadTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -341,7 +341,7 @@
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recently_added_tracks_recycler_view"
android:id="@+id/recently_added_albums_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"

View file

@ -1,481 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/syncing_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false">
<TextView
android:id="@+id/syncing_date_label"
style="@style/SubheadTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:paddingStart="16dp"
android:paddingTop="20dp"
android:paddingEnd="16dp"
android:text="@string/label_placeholder"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/syncing_syncing_label"
style="@style/TitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:text="Syncing"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/syncing_date_label" />
<ImageView
android:id="@+id/syncing_go_home_image_view"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:visibility="gone"
android:background="@drawable/ic_home_filled"
android:backgroundTint="@color/bottomNavIconColor"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
app:layout_constraintBottom_toBottomOf="@+id/syncing_syncing_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
android:id="@+id/home_top_title_divider"
style="@style/Divider"
android:layout_marginStart="18dp"
android:layout_marginTop="18dp"
android:layout_marginEnd="18dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/syncing_syncing_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Libraries -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sync_libraries_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="18dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/sync_libraries_label"
style="@style/ItemTitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync libraries"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sync_libraries_detail_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_libraries_label" />
<TextView
android:id="@+id/sync_libraries_status_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toStartOf="@+id/sync_libraries_retry_image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_libraries_detail_label" />
<ImageView
android:id="@+id/sync_libraries_retry_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/ic_refresh"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/sync_libraries_status_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
style="@style/Divider"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_libraries_status_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Albums -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sync_albums_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/sync_albums_label"
style="@style/ItemTitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync albums"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sync_albums_detail_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_albums_label" />
<TextView
android:id="@+id/sync_albums_status_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_albums_detail_label" />
<ImageView
android:id="@+id/sync_albums_retry_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/ic_refresh"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/sync_albums_status_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
style="@style/Divider"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_albums_status_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Artists -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sync_artists_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/sync_artists_label"
style="@style/ItemTitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync artists"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sync_artists_detail_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_artists_label" />
<TextView
android:id="@+id/sync_artists_status_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_artists_detail_label" />
<ImageView
android:id="@+id/sync_artists_retry_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/ic_refresh"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/sync_artists_status_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
style="@style/Divider"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_artists_status_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Genres -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sync_genres_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/sync_genres_label"
style="@style/ItemTitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync genres"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sync_genres_detail_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_genres_label" />
<TextView
android:id="@+id/sync_genres_status_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_genres_detail_label" />
<ImageView
android:id="@+id/sync_genres_retry_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/ic_refresh"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/sync_genres_status_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
style="@style/Divider"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_genres_status_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Playlists -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sync_playlists_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/sync_playlists_label"
style="@style/ItemTitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync playlists"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sync_playlists_detail_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_playlists_label" />
<TextView
android:id="@+id/sync_playlists_status_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_playlists_detail_label" />
<ImageView
android:id="@+id/sync_playlists_retry_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/ic_refresh"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/sync_playlists_status_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
style="@style/Divider"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_playlists_status_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Song x Playlist -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sync_song_x_playlist_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/sync_song_x_playlist_label"
style="@style/ItemTitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync song x playlist"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sync_song_x_playlist_detail_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_song_x_playlist_label" />
<TextView
android:id="@+id/sync_song_x_playlist_status_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_song_x_playlist_detail_label" />
<ImageView
android:id="@+id/sync_song_x_playlist_retry_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/ic_refresh"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/sync_song_x_playlist_status_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
style="@style/Divider"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_song_x_playlist_status_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Songs -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sync_songs_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/sync_songs_label"
style="@style/ItemTitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sync songs"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sync_songs_detail_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_songs_label" />
<TextView
android:id="@+id/sync_songs_status_label"
style="@style/ItemSubtitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_songs_detail_label" />
<ImageView
android:id="@+id/sync_songs_retry_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/ic_refresh"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/sync_songs_status_label"
app:layout_constraintEnd_toEndOf="parent" />
<View
style="@style/Divider"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sync_songs_status_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View file

@ -20,11 +20,6 @@
app:destination="@id/homeFragment"
app:popUpTo="@id/landingFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_landingFragment_to_syncFragment"
app:destination="@id/syncFragment"
app:popUpTo="@id/landingFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
@ -32,11 +27,6 @@
android:name="com.cappielloantonio.play.ui.fragment.LoginFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_login">
<action
android:id="@+id/action_loginFragment_to_syncFragment"
app:destination="@id/syncFragment"
app:popUpTo="@id/loginFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_loginFragment_to_homeFragment"
app:destination="@id/homeFragment"
@ -44,39 +34,20 @@
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/syncFragment"
android:name="com.cappielloantonio.play.ui.fragment.SyncFragment"
android:label="SyncFragment"
tools:layout="@layout/fragment_sync">
<action
android:id="@+id/action_syncFragment_to_homeFragment"
app:destination="@id/homeFragment"
app:popUpTo="@id/syncFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_syncFragment_to_libraryFragment"
app:destination="@id/libraryFragment"
app:popUpTo="@id/syncFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/homeFragment"
android:name="com.cappielloantonio.play.ui.fragment.HomeFragment"
android:label="HomeFragment"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_homeFragment_to_syncFragment"
app:destination="@id/syncFragment"
app:popUpTo="@id/homeFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_homeFragment_to_songListPageFragment"
app:destination="@id/songListPageFragment" />
<action
android:id="@+id/action_homeFragment_to_settingsFragment"
app:destination="@id/settingsFragment" />
<action
android:id="@+id/action_homeFragment_to_albumPageFragment"
app:destination="@id/albumPageFragment" />
</fragment>
<fragment
android:id="@+id/libraryFragment"
@ -104,11 +75,6 @@
<action
android:id="@+id/action_libraryFragment_to_songListPageFragment"
app:destination="@id/songListPageFragment" />
<action
android:id="@+id/action_libraryFragment_to_syncFragment"
app:destination="@id/syncFragment"
app:popUpTo="@id/libraryFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_libraryFragment_to_playlistPageFragment"
app:destination="@id/playlistPageFragment" />
@ -118,11 +84,6 @@
android:name="com.cappielloantonio.play.ui.fragment.SettingsFragment"
android:label="SettingsFragment"
tools:layout="@layout/fragment_settings">
<action
android:id="@+id/action_settingsFragment_to_syncFragment"
app:destination="@id/syncFragment"
app:popUpTo="@id/homeFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/searchFragment"

View file

@ -56,19 +56,6 @@
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/sync_header">
<Preference
android:key="@string/music_sync"
android:summary="@string/music_sync_caption"
android:title="@string/music_sync" />
<Preference
android:key="@string/playlist_song_cross_sync"
android:summary="@string/playlist_song_cross_sync_caption"
android:title="@string/playlist_song_cross_sync" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/about_header">
<Preference
app:selectable="false"