mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 09:33:33 +00:00
Fix bug in image visualization
This commit is contained in:
parent
a0f417fa94
commit
18fae806a6
36 changed files with 431 additions and 150 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue