Fix bug in image visualization

This commit is contained in:
Antonio Cappiello 2020-11-27 09:06:50 +01:00
parent a0f417fa94
commit 18fae806a6
36 changed files with 431 additions and 150 deletions

View file

@ -42,7 +42,7 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
holder.textArtistName.setText(album.getArtistName());
CustomGlideRequest.Builder
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY)
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY, CustomGlideRequest.TOP_QUALITY)
.build()
.into(holder.cover);
}

View file

@ -41,7 +41,7 @@ public class AlbumArtistPageAdapter extends RecyclerView.Adapter<AlbumArtistPage
holder.textAlbumName.setText(album.getTitle());
CustomGlideRequest.Builder
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY)
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY, CustomGlideRequest.LOW_QUALITY)
.build()
.into(holder.cover);
}

View file

@ -42,9 +42,9 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
holder.textArtistName.setText(album.getArtistName());
CustomGlideRequest.Builder
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY)
.from(context, album.getPrimary(), album.getBlurHash(), CustomGlideRequest.PRIMARY, CustomGlideRequest.LOW_QUALITY)
.build()
// .override(300)
.override(300)
.into(holder.cover);
}

View file

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

View file

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

View file

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

View file

@ -46,7 +46,7 @@ public class RecentMusicAdapter extends RecyclerView.Adapter<RecentMusicAdapter.
holder.textAlbum.setText(song.getAlbumName());
CustomGlideRequest.Builder
.from(context, song.getPrimary(), song.getPrimary(), CustomGlideRequest.PRIMARY)
.from(context, song.getPrimary(), song.getPrimary(), CustomGlideRequest.PRIMARY, CustomGlideRequest.TOP_QUALITY)
.build()
.into(holder.cover);
}

View file

@ -48,7 +48,7 @@ public class SongResultSearchAdapter extends RecyclerView.Adapter<SongResultSear
holder.songDuration.setText(Util.getReadableDurationString(song.getDuration()));
CustomGlideRequest.Builder
.from(context, song.getPrimary(), song.getPrimary(), CustomGlideRequest.PRIMARY)
.from(context, song.getPrimary(), song.getPrimary(), CustomGlideRequest.PRIMARY, CustomGlideRequest.TOP_QUALITY)
.build()
.into(holder.cover);
}

View file

@ -37,6 +37,9 @@ public interface AlbumDao {
@Delete
void delete(Album album);
@Query("SELECT title FROM album WHERE title LIKE :query || '%' GROUP BY title LIMIT :number")
@Query("SELECT title FROM album WHERE title LIKE :query || '%' OR title like '% ' || :query || '%' GROUP BY title LIMIT :number")
List<String> searchSuggestions(String query, int number);
@Query("DELETE FROM album")
void deleteAll();
}

View file

@ -34,6 +34,9 @@ public interface ArtistDao {
@Delete
void delete(Artist artist);
@Query("SELECT name FROM artist WHERE name LIKE :query || '%' GROUP BY name LIMIT :number")
@Query("SELECT name FROM artist WHERE name LIKE :query || '%' OR name like '% ' || :query || '%' GROUP BY name LIMIT :number")
List<String> searchSuggestions(String query, int number);
@Query("DELETE FROM artist")
void deleteAll();
}

View file

@ -7,8 +7,6 @@ import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Genre;
import java.util.List;
@ -35,4 +33,7 @@ public interface GenreDao {
@Delete
void delete(Genre genre);
@Query("DELETE FROM genre")
void deleteAll();
}

View file

@ -7,7 +7,6 @@ import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Playlist;
import java.util.List;
@ -28,4 +27,7 @@ public interface PlaylistDao {
@Delete
void delete(Playlist playlist);
@Query("DELETE FROM playlist")
void deleteAll();
}

View file

@ -18,6 +18,9 @@ public interface SongDao {
@Query("SELECT * FROM song")
LiveData<List<Song>> getAll();
@Query("SELECT * FROM song")
List<Song> getAllList();
@Query("SELECT * FROM song WHERE title LIKE '%' || :title || '%'")
LiveData<List<Song>> searchSong(String title);
@ -60,12 +63,15 @@ public interface SongDao {
@Delete
void delete(Song song);
@Query("DELETE FROM song")
void deleteAll();
@Update
public void update(Song song);
@Query("SELECT * FROM song ORDER BY RANDOM() LIMIT :number")
List<Song> random(int number);
@Query("SELECT title FROM song WHERE title LIKE :query || '%' GROUP BY title LIMIT :number")
@Query("SELECT title FROM song WHERE title LIKE :query || '%' OR title like '% ' || :query || '%' GROUP BY title LIMIT :number")
List<String> searchSuggestions(String query, int number);
}

View file

@ -8,7 +8,6 @@ import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Update;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.model.SongGenreCross;
import java.util.List;
@ -32,4 +31,7 @@ public interface SongGenreCrossDao {
@Update
void update(SongGenreCross songGenreCross);
@Query("DELETE FROM song_genre_cross")
void deleteAll();
}

View file

@ -24,6 +24,10 @@ 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 DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.ALL;
public static final int DEFAULT_IMAGE = R.drawable.ic_launcher_background;
@ -32,9 +36,9 @@ public class CustomGlideRequest {
private final Object item;
private final Context context;
private Builder(Context context, String item, String placeholder, String itemType) {
private Builder(Context context, String item, String placeholder, String itemType, String quality) {
this.requestManager = Glide.with(context);
this.item = item != null ? createUrl(item, itemType) : DEFAULT_IMAGE;
this.item = item != null ? createUrl(item, itemType, quality) : DEFAULT_IMAGE;
this.context = context;
if (placeholder != null) {
@ -47,8 +51,8 @@ public class CustomGlideRequest {
}
}
public static Builder from(Context context, String item, String placeholder, String itemType) {
return new Builder(context, item, placeholder, itemType);
public static Builder from(Context context, String item, String placeholder, String itemType, String quality) {
return new Builder(context, item, placeholder, itemType, quality);
}
public RequestBuilder<Drawable> build() {
@ -67,8 +71,9 @@ public class CustomGlideRequest {
return options;
}
public static String createUrl(String item, String itemType) {
public static String createUrl(String item, String itemType, String quality) {
ImageOptions options = new ImageOptions();
switch(itemType) {
case PRIMARY: {
options.setImageType(ImageType.Primary);
@ -79,9 +84,27 @@ public class CustomGlideRequest {
break;
}
}
options.setQuality(100);
options.setMaxHeight(500);
options.setEnableImageEnhancers(true);
switch(quality) {
case TOP_QUALITY: {
options.setQuality(100);
options.setMaxHeight(800);
options.setEnableImageEnhancers(true);
break;
}
case MEDIUM_QUALITY: {
options.setQuality(80);
options.setMaxHeight(500);
options.setEnableImageEnhancers(true);
break;
}
case LOW_QUALITY: {
options.setQuality(60);
options.setMaxHeight(300);
options.setEnableImageEnhancers(true);
break;
}
}
return App.getApiClientInstance(App.getInstance()).GetImageUrl(item, options);
}

View file

@ -381,14 +381,14 @@ public class Song implements Parcelable {
this.added = added;
}
public void setAdded(int playCount) {
this.playCount = playCount;
}
public void setLastPlay(long lastPlay) {
this.lastPlay = lastPlay;
}
public void setPlayCount(int playCount) {
this.playCount = playCount;
}
public void nowPlaying() {
this.playCount++;
this.lastPlay = Instant.now().toEpochMilli();

View file

@ -1,17 +1,12 @@
package com.cappielloantonio.play.repository;
import android.app.Application;
import android.util.Log;
import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.AlbumDao;
import com.cappielloantonio.play.database.dao.SongDao;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Song;
import com.paulrybitskyi.persistentsearchview.adapters.model.SuggestionItem;
import java.util.ArrayList;
import java.util.List;
@ -103,6 +98,12 @@ public class AlbumRepository {
thread.start();
}
public void deleteAll() {
DeleteAllThreadSafe delete = new DeleteAllThreadSafe(albumDao);
Thread thread = new Thread(delete);
thread.start();
}
private static class ExistThreadSafe implements Runnable {
private AlbumDao albumDao;
private Album album;
@ -149,6 +150,7 @@ public class AlbumRepository {
@Override
public void run() {
albumDao.deleteAll();
albumDao.insertAll(albums);
}
}
@ -189,4 +191,17 @@ public class AlbumRepository {
return suggestions;
}
}
private static class DeleteAllThreadSafe implements Runnable {
private AlbumDao albumDao;
public DeleteAllThreadSafe(AlbumDao albumDao) {
this.albumDao = albumDao;
}
@Override
public void run() {
albumDao.deleteAll();
}
}
}

View file

@ -5,14 +5,10 @@ import android.app.Application;
import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.AlbumDao;
import com.cappielloantonio.play.database.dao.ArtistDao;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Song;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ArtistRepository {
@ -95,6 +91,12 @@ public class ArtistRepository {
thread.start();
}
public void deleteAll() {
DeleteAllThreadSafe delete = new DeleteAllThreadSafe(artistDao);
Thread thread = new Thread(delete);
thread.start();
}
private static class ExistThreadSafe implements Runnable {
private ArtistDao artistDao;
private Artist artist;
@ -141,6 +143,7 @@ public class ArtistRepository {
@Override
public void run() {
artistDao.deleteAll();
artistDao.insertAll(artists);
}
}
@ -181,4 +184,17 @@ public class ArtistRepository {
return suggestions;
}
}
private static class DeleteAllThreadSafe implements Runnable {
private ArtistDao artistDao;
public DeleteAllThreadSafe(ArtistDao artistDao) {
this.artistDao = artistDao;
}
@Override
public void run() {
artistDao.deleteAll();
}
}
}

View file

@ -7,9 +7,7 @@ import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.GenreDao;
import com.cappielloantonio.play.database.dao.SongGenreCrossDao;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Genre;
import com.cappielloantonio.play.model.SongGenreCross;
import java.util.ArrayList;
import java.util.List;
@ -84,14 +82,20 @@ public class GenreRepository {
thread.start();
}
public void insertPerGenre(ArrayList<SongGenreCross> songGenreCrosses) {
InsertPerGenreThreadSafe insertPerGenre = new InsertPerGenreThreadSafe(songGenreCrossDao, songGenreCrosses);
Thread thread = new Thread(insertPerGenre);
public void delete(Genre genre) {
DeleteThreadSafe delete = new DeleteThreadSafe(genreDao, genre);
Thread thread = new Thread(delete);
thread.start();
}
public void delete(Genre genre) {
DeleteThreadSafe delete = new DeleteThreadSafe(genreDao, genre);
public void deleteAll() {
DeleteAllGenreThreadSafe delete = new DeleteAllGenreThreadSafe(genreDao);
Thread thread = new Thread(delete);
thread.start();
}
public void deleteAllSongGenreCross() {
DeleteAllSongGenreCrossThreadSafe delete = new DeleteAllSongGenreCrossThreadSafe(songGenreCrossDao);
Thread thread = new Thread(delete);
thread.start();
}
@ -160,25 +164,11 @@ public class GenreRepository {
@Override
public void run() {
genreDao.deleteAll();
genreDao.insertAll(genres);
}
}
private static class InsertPerGenreThreadSafe implements Runnable {
private SongGenreCrossDao songGenreCrossDao;
private ArrayList<SongGenreCross> cross;
public InsertPerGenreThreadSafe(SongGenreCrossDao songGenreCrossDao, ArrayList<SongGenreCross> cross) {
this.songGenreCrossDao = songGenreCrossDao;
this.cross = cross;
}
@Override
public void run() {
songGenreCrossDao.insertAll(cross);
}
}
private static class DeleteThreadSafe implements Runnable {
private GenreDao genreDao;
private Genre genre;
@ -193,4 +183,30 @@ public class GenreRepository {
genreDao.delete(genre);
}
}
private static class DeleteAllGenreThreadSafe implements Runnable {
private GenreDao genreDao;
public DeleteAllGenreThreadSafe(GenreDao genreDao) {
this.genreDao = genreDao;
}
@Override
public void run() {
genreDao.deleteAll();
}
}
private static class DeleteAllSongGenreCrossThreadSafe implements Runnable {
private SongGenreCrossDao songGenreCrossDao;
public DeleteAllSongGenreCrossThreadSafe(SongGenreCrossDao songGenreCrossDao) {
this.songGenreCrossDao = songGenreCrossDao;
}
@Override
public void run() {
songGenreCrossDao.deleteAll();
}
}
}

View file

@ -61,6 +61,12 @@ public class PlaylistRepository {
thread.start();
}
public void deleteAll() {
DeleteAllThreadSafe delete = new DeleteAllThreadSafe(playlistDao);
Thread thread = new Thread(delete);
thread.start();
}
private static class ExistThreadSafe implements Runnable {
private PlaylistDao playlistDao;
private Playlist playlist;
@ -107,6 +113,7 @@ public class PlaylistRepository {
@Override
public void run() {
playlistDao.deleteAll();
playlistDao.insertAll(playlists);
}
}
@ -125,4 +132,17 @@ public class PlaylistRepository {
playlistDao.delete(playlist);
}
}
private static class DeleteAllThreadSafe implements Runnable {
private PlaylistDao playlistDao;
public DeleteAllThreadSafe(PlaylistDao playlistDao) {
this.playlistDao = playlistDao;
}
@Override
public void run() {
playlistDao.deleteAll();
}
}
}

View file

@ -5,17 +5,17 @@ import android.app.Application;
import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.AlbumDao;
import com.cappielloantonio.play.database.dao.SongDao;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.database.dao.SongGenreCrossDao;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.model.SongGenreCross;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class SongRepository {
private SongDao songDao;
private SongGenreCrossDao songGenreCrossDao;
private LiveData<List<Song>> searchListLiveSongs;
private LiveData<List<Song>> listLiveSampleRecentlyAddedSongs;
private LiveData<List<Song>> listLiveSampleRecentlyPlayedSongs;
@ -29,6 +29,7 @@ public class SongRepository {
public SongRepository(Application application) {
AppDatabase database = AppDatabase.getInstance(application);
songDao = database.songDao();
songGenreCrossDao = database.songGenreCrossDao();
}
public LiveData<List<Song>> searchListLiveSong(String title) {
@ -93,6 +94,27 @@ public class SongRepository {
return suggestions;
}
/*
* Funzione che ritorna l'intero set di canzoni.
* Utilizzato per l'aggiornamento del catalogo.
*/
public List<Song> getCatalogue() {
List<Song> catalogue = new ArrayList<>();
GetCatalogueThreadSafe getCatalogueThread = new GetCatalogueThreadSafe(songDao);
Thread thread = new Thread(getCatalogueThread);
thread.start();
try {
thread.join();
catalogue = getCatalogueThread.getCatalogue();
} catch (InterruptedException e) {
e.printStackTrace();
}
return catalogue;
}
public boolean exist(Song song) {
boolean exist = false;
@ -117,7 +139,7 @@ public class SongRepository {
}
public void insertAll(ArrayList<Song> songs) {
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(songDao, songs);
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(songDao, songGenreCrossDao, songs);
Thread thread = new Thread(insertAll);
thread.start();
}
@ -136,6 +158,30 @@ public class SongRepository {
thread.start();
}
public void getAll() {
GetCatalogueThreadSafe catalogue = new GetCatalogueThreadSafe(songDao);
Thread thread = new Thread(catalogue);
thread.start();
}
public void insertSongPerGenre(ArrayList<SongGenreCross> songGenreCrosses) {
InsertPerGenreThreadSafe insertPerGenre = new InsertPerGenreThreadSafe(songGenreCrossDao, songGenreCrosses);
Thread thread = new Thread(insertPerGenre);
thread.start();
}
public void deleteAllSong() {
DeleteAllSongThreadSafe delete = new DeleteAllSongThreadSafe(songDao);
Thread thread = new Thread(delete);
thread.start();
}
public void deleteAllSongGenreCross() {
DeleteAllSongGenreCrossThreadSafe delete = new DeleteAllSongGenreCrossThreadSafe(songGenreCrossDao);
Thread thread = new Thread(delete);
thread.start();
}
public List<Song> getRandomSample(int number) {
List<Song> sample = new ArrayList<>();
@ -190,15 +236,19 @@ public class SongRepository {
private static class InsertAllThreadSafe implements Runnable {
private SongDao songDao;
private SongGenreCrossDao songGenreCrossDao;
private ArrayList<Song> songs;
public InsertAllThreadSafe(SongDao songDao, ArrayList<Song> songs) {
public InsertAllThreadSafe(SongDao songDao, SongGenreCrossDao songGenreCrossDao, ArrayList<Song> songs) {
this.songDao = songDao;
this.songGenreCrossDao = songGenreCrossDao;
this.songs = songs;
}
@Override
public void run() {
songDao.deleteAll();
songGenreCrossDao.deleteAll();
songDao.insertAll(songs);
}
}
@ -274,4 +324,63 @@ public class SongRepository {
return suggestions;
}
}
private static class GetCatalogueThreadSafe implements Runnable {
private SongDao songDao;
private List<Song> catalogue = new ArrayList<>();
public GetCatalogueThreadSafe(SongDao songDao) {
this.songDao = songDao;
}
@Override
public void run() {
catalogue = songDao.getAllList();
}
public List<Song> getCatalogue() {
return catalogue;
}
}
private static class InsertPerGenreThreadSafe implements Runnable {
private SongGenreCrossDao songGenreCrossDao;
private ArrayList<SongGenreCross> cross;
public InsertPerGenreThreadSafe(SongGenreCrossDao songGenreCrossDao, ArrayList<SongGenreCross> cross) {
this.songGenreCrossDao = songGenreCrossDao;
this.cross = cross;
}
@Override
public void run() {
songGenreCrossDao.insertAll(cross);
}
}
private static class DeleteAllSongThreadSafe implements Runnable {
private SongDao songDao;
public DeleteAllSongThreadSafe(SongDao songDao) {
this.songDao = songDao;
}
@Override
public void run() {
songDao.deleteAll();
}
}
private static class DeleteAllSongGenreCrossThreadSafe implements Runnable {
private SongGenreCrossDao songGenreCrossDao;
public DeleteAllSongGenreCrossThreadSafe(SongGenreCrossDao songGenreCrossDao) {
this.songGenreCrossDao = songGenreCrossDao;
}
@Override
public void run() {
songGenreCrossDao.deleteAll();
}
}
}

View file

@ -81,6 +81,16 @@ public class MainActivity extends BaseActivity {
});
}
// True: VISIBLE
// False: GONE
public void setBottomNavigationBarVisibility(boolean visibility) {
if (visibility) {
bottomNavigationView.setVisibility(View.VISIBLE);
} else {
bottomNavigationView.setVisibility(View.GONE);
}
}
public void goToLogin() {
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment)
navController.navigate(R.id.action_landingFragment_to_loginFragment);
@ -89,10 +99,7 @@ public class MainActivity extends BaseActivity {
public void goToSync() {
bottomNavigationView.setVisibility(View.GONE);
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true, false);
navController.navigate(R.id.action_landingFragment_to_syncFragment, bundle);
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) {
Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true, false);
navController.navigate(R.id.action_loginFragment_to_syncFragment, bundle);
} else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.homeFragment) {

View file

@ -48,7 +48,7 @@ public class AlbumPageFragment extends Fragment {
private void initBackCover() {
CustomGlideRequest.Builder
.from(requireContext(), albumPageViewModel.getAlbum().getPrimary(), albumPageViewModel.getAlbum().getBlurHash(), CustomGlideRequest.PRIMARY)
.from(requireContext(), albumPageViewModel.getAlbum().getPrimary(), albumPageViewModel.getAlbum().getBlurHash(), CustomGlideRequest.PRIMARY, CustomGlideRequest.TOP_QUALITY)
.build()
.into(bind.albumBackCoverImageView);
}

View file

@ -55,20 +55,17 @@ public class ArtistPageFragment extends Fragment {
artistPageViewModel.setArtist(getArguments().getParcelable("artist_object"));
bind.artistNameLabel.setText(artistPageViewModel.getArtist().getName());
bind.mostStreamedSongTextViewClickable.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString(Song.BY_ARTIST, Song.BY_ARTIST);
bundle.putParcelable("artist_object", artistPageViewModel.getArtist());
activity.navController.navigate(R.id.action_artistPageFragment_to_songListPageFragment, bundle);
}
bind.mostStreamedSongTextViewClickable.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString(Song.BY_ARTIST, Song.BY_ARTIST);
bundle.putParcelable("artist_object", artistPageViewModel.getArtist());
activity.navController.navigate(R.id.action_artistPageFragment_to_songListPageFragment, bundle);
});
}
private void initBackdrop() {
CustomGlideRequest.Builder
.from(requireContext(), artistPageViewModel.getArtist().getBackdrop(), artistPageViewModel.getArtist().getBackdropBlurHash(), CustomGlideRequest.BACKDROP)
.from(requireContext(), artistPageViewModel.getArtist().getBackdrop(), artistPageViewModel.getArtist().getBackdropBlurHash(), CustomGlideRequest.BACKDROP, CustomGlideRequest.TOP_QUALITY)
.build()
.into(bind.artistBackdropImageView);
}

View file

@ -58,14 +58,11 @@ public class GenreCatalogueFragment extends Fragment {
bind.genreCatalogueRecyclerView.setHasFixedSize(true);
genreCatalogueAdapter = new GenreCatalogueAdapter(requireContext(), new ArrayList<>());
genreCatalogueAdapter.setClickListener(new GenreCatalogueAdapter.ItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Bundle bundle = new Bundle();
bundle.putString(Song.BY_GENRE, Song.BY_GENRE);
bundle.putParcelable("genre_object", genreCatalogueAdapter.getItem(position));
activity.navController.navigate(R.id.action_genreCatalogueFragment_to_songListPageFragment, bundle);
}
genreCatalogueAdapter.setClickListener((view, position) -> {
Bundle bundle = new Bundle();
bundle.putString(Song.BY_GENRE, Song.BY_GENRE);
bundle.putParcelable("genre_object", genreCatalogueAdapter.getItem(position));
activity.navController.navigate(R.id.action_genreCatalogueFragment_to_songListPageFragment, bundle);
});
bind.genreCatalogueRecyclerView.setAdapter(genreCatalogueAdapter);

View file

@ -1,8 +1,6 @@
package com.cappielloantonio.play.ui.fragment;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -11,12 +9,10 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.databinding.FragmentSyncBinding;
import com.cappielloantonio.play.interfaces.MediaCallback;
import com.cappielloantonio.play.model.Album;
@ -34,8 +30,6 @@ import com.cappielloantonio.play.ui.activities.MainActivity;
import com.cappielloantonio.play.util.PreferenceUtil;
import com.cappielloantonio.play.util.SyncUtil;
import com.cappielloantonio.play.viewmodel.SyncViewModel;
import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.snackbar.Snackbar;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
@ -181,7 +175,7 @@ public class SyncFragment extends Fragment {
private void syncSongs() {
Log.d(TAG, "syncSongs");
SyncUtil.getSongs(requireContext(), new MediaCallback() {
SyncUtil.getSongs(requireContext(), syncViewModel.getCatalogue(), new MediaCallback() {
@Override
public void onError(Exception exception) {
Log.e(TAG, "onError: " + exception.getMessage());
@ -191,6 +185,7 @@ public class SyncFragment extends Fragment {
@Override
public void onLoadMedia(List<?> media) {
SongRepository repository = new SongRepository(activity.getApplication());
repository.deleteAllSongGenreCross();
repository.insertAll((ArrayList<Song>) media);
animateProgressBar(true);
}
@ -198,6 +193,8 @@ public class SyncFragment extends Fragment {
}
private void syncSongsPerGenre(List<Genre> genres) {
Log.d(TAG, "syncSongsPerGenre");
for (Genre genre : genres) {
SyncUtil.getSongsPerGenre(requireContext(), new MediaCallback() {
@Override
@ -207,24 +204,30 @@ public class SyncFragment extends Fragment {
@Override
public void onLoadMedia(List<?> media) {
GenreRepository repository = new GenreRepository(App.getInstance());
repository.insertPerGenre((ArrayList<SongGenreCross>) media);
SongRepository repository = new SongRepository(App.getInstance());
repository.insertSongPerGenre((ArrayList<SongGenreCross>) media);
}
}, genre.id);
}
Log.d(TAG, "syncSongsPerGenre: set progress");
animateProgressBar(true);
PreferenceUtil.getInstance(requireContext()).setSongGenreSync(true);
}
private void animateProgressBar(boolean step) {
Log.d(TAG, "animateProgressBar: PROGRESS " + step);
syncViewModel.setProgress(step);
bind.loadingProgressBar.setProgress(syncViewModel.getProgressBarInfo(), true);
countProgress();
}
private void countProgress() {
Log.d(TAG, "countProgress = " + syncViewModel.getProgress());
Log.d(TAG, "progressbar = " + syncViewModel.getProgressBarInfo());
if (syncViewModel.getProgress() == syncViewModel.getStep()) {
if (syncViewModel.getProgressBarInfo() >= 100)
terminate();

View file

@ -2,6 +2,7 @@ package com.cappielloantonio.play.util;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.interfaces.MediaCallback;
@ -23,8 +24,11 @@ import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class SyncUtil {
private static final String TAG = "SyncUtil";
public static void getLibraries(Context context, MediaCallback callback) {
String id = App.getApiClientInstance(context).getCurrentUserId();
@ -44,7 +48,7 @@ public class SyncUtil {
});
}
public static void getSongs(Context context, MediaCallback callback) {
public static void getSongs(Context context, Map<Integer, Song> currentCatalogue, MediaCallback callback) {
ItemQuery query = new ItemQuery();
query.setIncludeItemTypes(new String[]{"Audio"});
@ -59,7 +63,7 @@ public class SyncUtil {
ArrayList<Song> songs = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
songs.add(new Song(itemDto));
songs.add(updateSongData(currentCatalogue, new Song(itemDto)));
}
callback.onLoadMedia(songs);
@ -215,4 +219,18 @@ public class SyncUtil {
return bundle;
}
private static Song updateSongData(Map<Integer, Song> library, Song newSong) {
if(library.containsKey(newSong.hashCode())) {
Log.d(TAG, "updateSongData: " + newSong.getTitle());
Song oldSong = library.get(newSong.hashCode());
newSong.setFavorite(oldSong.isFavorite());
newSong.setAdded(oldSong.getAdded());
newSong.setLastPlay(oldSong.getLastPlay());
newSong.setPlayCount(oldSong.getPlayCount());
}
return newSong;
}
}

View file

@ -2,20 +2,21 @@ package com.cappielloantonio.play.viewmodel;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.SongRepository;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
public class SyncViewModel extends AndroidViewModel {
private static final String TAG = "SyncViewModel";
private SongRepository songRepository;
private boolean syncAlbum = false;
private boolean syncArtist = false;
private boolean syncGenres = false;
@ -29,9 +30,14 @@ public class SyncViewModel extends AndroidViewModel {
public SyncViewModel(@NonNull Application application) {
super(application);
songRepository = new SongRepository(application);
}
public void setArguemnts(Bundle bundle) {
step = 0;
progress = 0;
syncAlbum = bundle.getBoolean("sync_album", false);
syncArtist = bundle.getBoolean("sync_artist", false);
syncGenres = bundle.getBoolean("sync_genres", false);
@ -90,4 +96,14 @@ public class SyncViewModel extends AndroidViewModel {
public int getProgressBarInfo() {
return progress * (100 / step);
}
public Map<Integer, Song> getCatalogue() {
Map<Integer, Song> map = new HashMap<>();
for(Song song: songRepository.getCatalogue()){
map.put(song.hashCode(), song);
}
return map;
}
}

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#00000000"
android:endColor="#FF000000"
android:angle="90"
android:dither="true" />
</shape>

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
<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="wrap_content">
@ -32,43 +31,53 @@
android:id="@+id/album_back_cover_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_background_image" />
<TextView
android:id="@+id/album_title_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family"
android:textColor="@android:color/white"
android:textSize="40sp"
android:textStyle="bold"
android:textAlignment="center"
android:textFontWeight="900"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingBottom="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
android:background="@drawable/gradient_backdrop_background_image" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/album_title_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp"
android:elevation="4dp"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingBottom="32dp"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textFontWeight="900"
android:textSize="40sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="86dp"
android:background="@drawable/gradient_backdrop_fading_down_background_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/card_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Label and button -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-54dp"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="16dp"
android:paddingTop="20dp"
android:paddingEnd="16dp"
android:text="Song"
android:textColor="@color/titleTextColor"

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
<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="wrap_content">
@ -32,43 +31,53 @@
android:id="@+id/artist_backdrop_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_background_image" />
<TextView
android:id="@+id/artist_name_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family"
android:textColor="@android:color/white"
android:textSize="40sp"
android:textStyle="bold"
android:textAlignment="center"
android:textFontWeight="900"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingBottom="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
android:background="@drawable/gradient_backdrop_background_image" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/artist_name_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp"
android:elevation="4dp"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingBottom="32dp"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textFontWeight="900"
android:textSize="40sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="86dp"
android:background="@drawable/gradient_backdrop_fading_down_background_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/card_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Label and button -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-58dp"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:paddingEnd="8dp">
<TextView
@ -77,7 +86,6 @@
android:layout_weight="1"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="Most Streamed Songs"
android:textColor="@color/titleTextColor"

View file

@ -167,7 +167,7 @@
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="Music By Genre"
android:text="Music by genre"
android:textColor="@color/titleTextColor"
android:textSize="22sp"
android:textStyle="bold" />

View file

@ -18,7 +18,7 @@
<View
android:layout_width="match_parent"
android:layout_height="172dp"
android:background="@drawable/discover_background_image" />
android:background="@drawable/gradient_discover_background_image" />
<RelativeLayout
android:layout_width="match_parent"

View file

@ -63,7 +63,9 @@
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_homeFragment_to_syncFragment"
app:destination="@id/syncFragment" />
app:destination="@id/syncFragment"
app:popUpTo="@id/homeFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_homeFragment_to_songListPageFragment"
app:destination="@id/songListPageFragment" />