diff --git a/app/src/main/java/com/cappielloantonio/play/database/dao/SongDao.java b/app/src/main/java/com/cappielloantonio/play/database/dao/SongDao.java index 231c7279..75b81199 100644 --- a/app/src/main/java/com/cappielloantonio/play/database/dao/SongDao.java +++ b/app/src/main/java/com/cappielloantonio/play/database/dao/SongDao.java @@ -66,7 +66,7 @@ public interface SongDao { @Query("SELECT * FROM song WHERE favorite = 1") LiveData> getFavoriteSong(); - @Query("SELECT * FROM song WHERE offline = 1 ORDER BY RANDOM() LIMIT :number") + @Query("SELECT * FROM song WHERE offline = 1 LIMIT :number") LiveData> getDownloadedSongSample(int number); @Query("SELECT * FROM song WHERE offline = 1 ORDER BY path, albumName, trackNumber") diff --git a/app/src/main/java/com/cappielloantonio/play/service/DownloadTracker.java b/app/src/main/java/com/cappielloantonio/play/service/DownloadTracker.java index d04deee7..44b0f423 100644 --- a/app/src/main/java/com/cappielloantonio/play/service/DownloadTracker.java +++ b/app/src/main/java/com/cappielloantonio/play/service/DownloadTracker.java @@ -66,8 +66,8 @@ public class DownloadTracker { } @Nullable - public DownloadRequest getDownloadRequest(Uri uri) { - return new DownloadRequest.Builder(uri.toString(), uri).build(); + public DownloadRequest getDownloadRequest(String id, Uri uri) { + return new DownloadRequest.Builder(id, uri).build(); } public void toggleDownload(List songs) { @@ -83,7 +83,7 @@ public class DownloadTracker { DownloadService.sendRemoveDownload(context, DownloaderService.class, download.request.id, false); } else { song.setOffline(true); - DownloadService.sendAddDownload(context, DownloaderService.class, getDownloadRequest(mediaItem.playbackProperties.uri), false); + DownloadService.sendAddDownload(context, DownloaderService.class, getDownloadRequest(song.getId(), mediaItem.playbackProperties.uri), false); } songRepository.setOfflineStatus(song); @@ -113,22 +113,19 @@ public class DownloadTracker { } private class DownloadManagerListener implements DownloadManager.Listener { - @Override - public void onDownloadChanged( - @NonNull DownloadManager downloadManager, - @NonNull Download download, - @Nullable Exception finalException) { + public void onDownloadChanged(@NonNull DownloadManager downloadManager, @NonNull Download download, @Nullable Exception finalException) { downloads.put(download.request.uri, download); + for (Listener listener : listeners) { listener.onDownloadsChanged(); } } @Override - public void onDownloadRemoved( - @NonNull DownloadManager downloadManager, @NonNull Download download) { + public void onDownloadRemoved(@NonNull DownloadManager downloadManager, @NonNull Download download) { downloads.remove(download.request.uri); + for (Listener listener : listeners) { listener.onDownloadsChanged(); } diff --git a/app/src/main/java/com/cappielloantonio/play/service/DownloaderService.java b/app/src/main/java/com/cappielloantonio/play/service/DownloaderService.java index 4cc02676..32ca53dd 100644 --- a/app/src/main/java/com/cappielloantonio/play/service/DownloaderService.java +++ b/app/src/main/java/com/cappielloantonio/play/service/DownloaderService.java @@ -48,7 +48,6 @@ public class DownloaderService extends DownloadService { } private static final class TerminalStateNotificationHelper implements DownloadManager.Listener { - private final Context context; private final DownloadNotificationHelper notificationHelper; @@ -65,7 +64,7 @@ public class DownloaderService extends DownloadService { Notification notification; if (download.state == Download.STATE_COMPLETED) { - notification = notificationHelper.buildDownloadCompletedNotification(context, R.drawable.ic_done, null, Util.fromUtf8Bytes(download.request.data)); + notification = notificationHelper.buildDownloadCompletedNotification(context, R.drawable.ic_check_circle, null, Util.fromUtf8Bytes(download.request.data)); } else if (download.state == Download.STATE_FAILED) { notification = notificationHelper.buildDownloadFailedNotification(context, R.drawable.ic_error, null, Util.fromUtf8Bytes(download.request.data)); } else { diff --git a/app/src/main/java/com/cappielloantonio/play/ui/activity/MainActivity.java b/app/src/main/java/com/cappielloantonio/play/ui/activity/MainActivity.java index 04b2e28b..fdf4f262 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/activity/MainActivity.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/activity/MainActivity.java @@ -218,14 +218,8 @@ public class MainActivity extends BaseActivity { setBottomSheetVisibility(false); if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.loginFragment) { - Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true, false); + Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true, true); navController.navigate(R.id.action_loginFragment_to_syncFragment, bundle); - } else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.homeFragment) { - Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true, false); - navController.navigate(R.id.action_homeFragment_to_syncFragment, bundle); - } else if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.libraryFragment) { - Bundle bundle = SyncUtil.getSyncBundle(false, false, true, false, false, true); - navController.navigate(R.id.action_libraryFragment_to_syncFragment, bundle); } } diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java index 17e08d72..98297afd 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java @@ -51,7 +51,7 @@ public class HomeFragment extends Fragment { homeViewModel = new ViewModelProvider(requireActivity()).get(HomeViewModel.class); init(); - initForYouBar(); + initListenNowBar(); return view; } @@ -114,7 +114,7 @@ public class HomeFragment extends Fragment { }); } - private void initForYouBar() { + private void initListenNowBar() { bind.homeDateLabel.setText(Util.getDate()); bind.homeSettingsImageView.setOnClickListener(v -> activity.navController.navigate(R.id.action_homeFragment_to_settingsFragment)); @@ -229,7 +229,7 @@ public class HomeFragment extends Fragment { public void reorder() { if(bind != null) { bind.homeLinearLayoutContainer.removeAllViews(); - bind.homeLinearLayoutContainer.addView(bind.forYouSector); + bind.homeLinearLayoutContainer.addView(bind.listenNowSector); bind.homeLinearLayoutContainer.addView(bind.homeDiscoverSector); bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedTracksSector); bind.homeLinearLayoutContainer.addView(bind.homeFlashbackSector); diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/SettingsFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/SettingsFragment.java index 1af90957..63a1cfb3 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/SettingsFragment.java @@ -34,6 +34,12 @@ public class SettingsFragment extends PreferenceFragmentCompat { return view; } + @Override + public void onStart() { + super.onStart(); + activity.setBottomNavigationBarVisibility(false); + } + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.global_preferences, rootKey); @@ -58,21 +64,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { PreferenceUtil.getInstance(requireContext()).setSync(false); PreferenceUtil.getInstance(requireContext()).setSongGenreSync(false); - Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true, false); - activity.goFromSettingsToSync(bundle); - }) - .show(); - return true; - }); - - Preference cross_sync_button = findPreference(getString(R.string.genres_music_cross_sync)); - cross_sync_button.setOnPreferenceClickListener(preference -> { - AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); - builder.setMessage("Force sync song's genres to display updated and correct songs in each genre category") - .setTitle("Force sync song's genres") - .setNegativeButton(R.string.ignore, null) - .setPositiveButton("Sync", (dialog, id) -> { - Bundle bundle = SyncUtil.getSyncBundle(false, false, true, false, false, true); + Bundle bundle = SyncUtil.getSyncBundle(true, true, true, true, true, true); activity.goFromSettingsToSync(bundle); }) .show(); @@ -93,5 +85,4 @@ public class SettingsFragment extends PreferenceFragmentCompat { return true; }); } - } diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/SyncFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/SyncFragment.java index e5e7ee26..c9729f4b 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/SyncFragment.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/SyncFragment.java @@ -1,17 +1,17 @@ package com.cappielloantonio.play.ui.fragment; import android.os.Bundle; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; 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; @@ -32,8 +32,10 @@ import com.cappielloantonio.play.repository.PlaylistSongRepository; import com.cappielloantonio.play.repository.SongArtistRepository; import com.cappielloantonio.play.repository.SongRepository; 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 org.jellyfin.apiclient.model.dto.BaseItemDto; @@ -57,6 +59,15 @@ public class SyncFragment extends Fragment { private AlbumArtistRepository albumArtistRepository; 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_GENRE = 6; + private final int SONG_X_PLAYLIST = 7; + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -76,6 +87,8 @@ public class SyncFragment extends Fragment { playlistSongRepository = new PlaylistSongRepository(activity.getApplication()); init(); + initView(); + initButtonListeners(); syncLibraries(); return view; @@ -89,14 +102,72 @@ public class SyncFragment extends Fragment { private void init() { syncViewModel.setArguemnts(getArguments()); - bind.loadingProgressBar.setVisibility(View.VISIBLE); + + 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); + if (!syncViewModel.isCrossSyncSongGenre()) + bind.syncSongXGenreSector.setVisibility(View.GONE); + } + + private void initButtonListeners() { + bind.syncLibrariesRetryImageView.setOnClickListener(v -> { + resetSectorInfo(LIBRARIES); + syncLibraries(); + }); + bind.syncAlbumsRetryImageView.setOnClickListener(v -> { + resetSectorInfo(ALBUMS); + syncAlbums(); + }); + bind.syncArtistsRetryImageView.setOnClickListener(v -> { + resetSectorInfo(ARTISTS); + syncArtists(); + }); + bind.syncGenresRetryImageView.setOnClickListener(v -> { + resetSectorInfo(GENRES); + syncGenres(); + }); + bind.syncPlaylistsRetryImageView.setOnClickListener(v -> { + resetSectorInfo(PLAYLISTS); + syncPlaylist(); + }); + bind.syncSongsRetryImageView.setOnClickListener(v -> { + resetSectorInfo(SONGS); + syncSongs(); + }); + bind.syncSongXGenreRetryImageView.setOnClickListener(v -> { + resetSectorInfo(SONG_X_GENRE); + syncSongsPerGenre(syncViewModel.getGenreList()); + }); + bind.syncSongXPlaylistRetryImageView.setOnClickListener(v -> { + resetSectorInfo(SONG_X_PLAYLIST); + syncSongsPerPlaylist(syncViewModel.getPlaylistList()); + }); + 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(); + }); } private void syncLibraries() { SyncUtil.getLibraries(requireContext(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); + loadSectorInfo(LIBRARIES, exception.getMessage(), false); } @Override @@ -104,36 +175,29 @@ public class SyncFragment extends Fragment { List libraries = (List) media; for (BaseItemDto itemDto : libraries) { - if (itemDto.getCollectionType().equals("music")) + if (itemDto.getCollectionType().equals("music")) { PreferenceUtil.getInstance(requireContext()).setMusicLibraryID(itemDto.getId()); + } } - startSyncing(); + loadSectorInfo(LIBRARIES, "", true); } }); } - private void startSyncing() { - if(syncViewModel.isSyncAlbum()) syncAlbums(); - if(syncViewModel.isSyncArtist()) syncArtists(); - if(syncViewModel.isSyncGenres()) syncGenres(); - if(syncViewModel.isSyncPlaylist()) syncPlaylist(); - if(syncViewModel.isSyncSong()) syncSongs(); - } - private void syncAlbums() { SyncUtil.getAlbums(requireContext(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); - animateProgressBar(false); + loadSectorInfo(ALBUMS, exception.getMessage(), false); } @Override public void onLoadMedia(List media) { - albumRepository.insertAll((ArrayList) media); - syncAlbumArtistCross((ArrayList) media); - animateProgressBar(true); + syncViewModel.setAlbumList((ArrayList) media); + albumRepository.insertAll(syncViewModel.getAlbumList()); + syncAlbumArtistCross(syncViewModel.getAlbumList()); + loadSectorInfo(ALBUMS, "Found " + syncViewModel.getAlbumList().size() + " elements", true); } }); } @@ -142,14 +206,14 @@ public class SyncFragment extends Fragment { SyncUtil.getArtists(requireContext(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); - animateProgressBar(false); + loadSectorInfo(ARTISTS, exception.getMessage(), false); } @Override public void onLoadMedia(List media) { - artistRepository.insertAll((ArrayList) media); - animateProgressBar(true); + syncViewModel.setArtistList((ArrayList) media); + artistRepository.insertAll(syncViewModel.getArtistList()); + loadSectorInfo(ARTISTS, "Found " + syncViewModel.getArtistList().size() + " elements", true); } }); } @@ -158,17 +222,14 @@ public class SyncFragment extends Fragment { SyncUtil.getGenres(requireContext(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); - animateProgressBar(false); + loadSectorInfo(GENRES, exception.getMessage(), false); } @Override public void onLoadMedia(List media) { - genreRepository.insertAll((ArrayList) media); - animateProgressBar(true); - - if(syncViewModel.isCrossSyncSongGenre()) syncSongsPerGenre((ArrayList) media); - + syncViewModel.setGenreList((ArrayList) media); + genreRepository.insertAll(syncViewModel.getGenreList()); + loadSectorInfo(GENRES, "Found " + syncViewModel.getGenreList().size() + " elements", true); } }); } @@ -177,15 +238,14 @@ public class SyncFragment extends Fragment { SyncUtil.getPlaylists(requireContext(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); - animateProgressBar(false); + loadSectorInfo(PLAYLISTS, exception.getMessage(), false); } @Override public void onLoadMedia(List media) { - playlistRepository.insertAll((ArrayList) media); - syncSongsPerPlaylist((ArrayList) media); - animateProgressBar(true); + syncViewModel.setPlaylistList((ArrayList) media); + playlistRepository.insertAll(syncViewModel.getPlaylistList()); + loadSectorInfo(PLAYLISTS, "Found " + syncViewModel.getPlaylistList().size() + " elements", true); } }); } @@ -194,17 +254,22 @@ public class SyncFragment extends Fragment { SyncUtil.getSongs(requireContext(), syncViewModel.getCatalogue(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); - animateProgressBar(false); + loadSectorInfo(SONGS, exception.getMessage(), false); } @Override public void onLoadMedia(List media) { + syncViewModel.setSongList((ArrayList) media); + songRepository.deleteAllSongGenreCross(); - songRepository.insertAll((ArrayList) media); - syncSongArtistCross((ArrayList) media); - PreferenceUtil.getInstance(requireContext()).setSongNumber(media.size()); - animateProgressBar(true); + songRepository.insertAll(syncViewModel.getSongList()); + + syncSongArtistCross(syncViewModel.getSongList()); + syncDownloadedSong(); + + loadSectorInfo(SONGS, "Found " + syncViewModel.getSongList().size() + " elements", true); + + PreferenceUtil.getInstance(requireContext()).setSongNumber(syncViewModel.getSongList().size()); } }); } @@ -214,17 +279,17 @@ public class SyncFragment extends Fragment { SyncUtil.getSongsPerGenre(requireContext(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); + loadSectorInfo(SONG_X_GENRE, exception.getMessage(), false); } @Override public void onLoadMedia(List media) { songRepository.insertSongPerGenre((ArrayList) media); + loadSectorInfo(SONG_X_GENRE, "Genre processed: " + genre.getName(), true); } }, genre.id); } - animateProgressBar(true); PreferenceUtil.getInstance(requireContext()).setSongGenreSync(true); } @@ -233,38 +298,18 @@ public class SyncFragment extends Fragment { SyncUtil.getSongsPerPlaylist(requireContext(), new MediaCallback() { @Override public void onError(Exception exception) { - Log.e(TAG, "onError: " + exception.getMessage()); + loadSectorInfo(SONG_X_PLAYLIST, exception.getMessage(), false); } @Override public void onLoadMedia(List media) { playlistSongRepository.insertAll((ArrayList) media); + loadSectorInfo(SONG_X_PLAYLIST, "Playlist processed: " + playlist.getName(), true); } }, playlist.getId()); } } - - private void animateProgressBar(boolean step) { - syncViewModel.setProgress(step); - bind.loadingProgressBar.setProgress(syncViewModel.getProgressBarInfo(), true); - countProgress(); - } - - private void countProgress() { - if (syncViewModel.getProgress() == syncViewModel.getStep()) { - if (syncViewModel.getProgressBarInfo() < 100) - Toast.makeText(requireContext(), "Sync error", Toast.LENGTH_SHORT).show(); - - terminate(); - } - } - - private void terminate() { - PreferenceUtil.getInstance(requireContext()).setSync(true); - activity.goToHome(); - } - // --------------------------------------------------------------------------------------------- /* * Sincronizzazzione dell'album con gli artisti che lo hanno prodotto | isProduced = true @@ -273,19 +318,19 @@ public class SyncFragment extends Fragment { private void syncAlbumArtistCross(ArrayList albums) { List crosses = new ArrayList<>(); - for(Album album: albums) { + for (Album album : albums) { List artists = new ArrayList<>(); - if(album.albumArtists.size() > 0) { - for (Artist artist: album.albumArtists) { + if (album.albumArtists.size() > 0) { + for (Artist artist : album.albumArtists) { artists.add(artist); crosses.add(new AlbumArtistCross(album.getId(), artist.getId(), true)); } } - if(album.artistItems.size() > 0) { - for (Artist artist: album.artistItems) { - if(!artists.contains(artist)) { + if (album.artistItems.size() > 0) { + for (Artist artist : album.artistItems) { + if (!artists.contains(artist)) { crosses.add(new AlbumArtistCross(album.getId(), artist.getId(), false)); } } @@ -298,19 +343,19 @@ public class SyncFragment extends Fragment { private void syncSongArtistCross(ArrayList songs) { List crosses = new ArrayList<>(); - for(Song song: songs) { + for (Song song : songs) { List artists = new ArrayList<>(); - if(song.albumArtists.size() > 0) { - for (Artist artist: song.albumArtists) { + if (song.albumArtists.size() > 0) { + for (Artist artist : song.albumArtists) { artists.add(artist); crosses.add(new SongArtistCross(song.getId(), artist.getId())); } } - if(song.artistItems.size() > 0) { - for (Artist artist: song.artistItems) { - if(!artists.contains(artist)) { + if (song.artistItems.size() > 0) { + for (Artist artist : song.artistItems) { + if (!artists.contains(artist)) { crosses.add(new SongArtistCross(song.getId(), artist.getId())); } } @@ -319,4 +364,207 @@ public class SyncFragment extends Fragment { songArtistRepository.insertAll(crosses); } + + private void syncDownloadedSong() { + songRepository.getListLiveDownloadedSong().observe(requireActivity(), songs -> { + for (Song song : songs) { + if (!DownloadUtil.getDownloadTracker(requireContext()).isDownloaded(song)) { + song.setOffline(false); + songRepository.setOfflineStatus(song); + } + } + }); + } + + private void loadSectorInfo(int sector, String message, boolean isSuccess) { + switch (sector) { + case LIBRARIES: + if (isSuccess) { + bind.syncLibrariesStatusLabel.setText("Status: SUCCESS"); + bind.syncLibrariesDetailLabel.setVisibility(View.GONE); + bind.syncLibrariesRetryImageView.setVisibility(View.GONE); + syncNextSector(LIBRARIES); + } else { + bind.syncLibrariesStatusLabel.setText("Status: ERROR"); + bind.syncLibrariesDetailLabel.setText(message); + bind.syncLibrariesDetailLabel.setVisibility(View.VISIBLE); + bind.syncLibrariesRetryImageView.setVisibility(View.VISIBLE); + } + break; + case ALBUMS: + if (isSuccess) { + bind.syncAlbumsStatusLabel.setText("Status: SUCCESS"); + bind.syncAlbumsDetailLabel.setText(message); + bind.syncAlbumsRetryImageView.setVisibility(View.GONE); + syncViewModel.increaseProggress(); + checkStep(); + syncNextSector(ALBUMS); + } else { + bind.syncLibrariesStatusLabel.setText("Status: ERROR"); + bind.syncAlbumsDetailLabel.setText(message); + bind.syncAlbumsRetryImageView.setVisibility(View.VISIBLE); + } + break; + case ARTISTS: + if (isSuccess) { + bind.syncArtistsStatusLabel.setText("Status: SUCCESS"); + bind.syncArtistsDetailLabel.setText(message); + bind.syncArtistsRetryImageView.setVisibility(View.GONE); + syncViewModel.increaseProggress(); + checkStep(); + syncNextSector(ARTISTS); + } else { + bind.syncArtistsStatusLabel.setText("Status: ERROR"); + bind.syncArtistsDetailLabel.setText(message); + bind.syncArtistsRetryImageView.setVisibility(View.VISIBLE); + } + break; + case GENRES: + if (isSuccess) { + bind.syncGenresStatusLabel.setText("Status: SUCCESS"); + bind.syncGenresDetailLabel.setText(message); + bind.syncGenresRetryImageView.setVisibility(View.GONE); + syncViewModel.increaseProggress(); + checkStep(); + syncNextSector(GENRES); + } else { + bind.syncGenresStatusLabel.setText("Status: ERROR"); + bind.syncGenresDetailLabel.setText(message); + bind.syncGenresRetryImageView.setVisibility(View.VISIBLE); + } + break; + case PLAYLISTS: + if (isSuccess) { + bind.syncPlaylistsStatusLabel.setText("Status: SUCCESS"); + bind.syncPlaylistsDetailLabel.setText(message); + bind.syncPlaylistsRetryImageView.setVisibility(View.GONE); + syncViewModel.increaseProggress(); + checkStep(); + syncNextSector(PLAYLISTS); + } else { + bind.syncPlaylistsStatusLabel.setText("Status: ERROR"); + bind.syncPlaylistsDetailLabel.setText(message); + bind.syncPlaylistsRetryImageView.setVisibility(View.VISIBLE); + } + break; + case SONGS: + if (isSuccess) { + bind.syncSongsStatusLabel.setText("Status: SUCCESS"); + bind.syncSongsDetailLabel.setText(message); + bind.syncSongsRetryImageView.setVisibility(View.GONE); + syncViewModel.increaseProggress(); + checkStep(); + syncNextSector(SONGS); + } else { + bind.syncSongsStatusLabel.setText("Status: ERROR"); + bind.syncSongsDetailLabel.setText(message); + bind.syncSongsRetryImageView.setVisibility(View.VISIBLE); + } + break; + case SONG_X_GENRE: + if (isSuccess) { + bind.syncSongXGenreStatusLabel.setText("Status: SUCCESS"); + bind.syncSongXGenreDetailLabel.setText(message); + bind.syncSongXGenreRetryImageView.setVisibility(View.GONE); + checkStep(); + } else { + bind.syncSongXGenreStatusLabel.setText("Status: ERROR"); + bind.syncSongXGenreDetailLabel.setText(message); + bind.syncSongXGenreRetryImageView.setVisibility(View.VISIBLE); + } + break; + case SONG_X_PLAYLIST: + if (isSuccess) { + bind.syncSongXPlaylistStatusLabel.setText("Status: SUCCESS"); + bind.syncSongXPlaylistDetailLabel.setText(message); + bind.syncSongXPlaylistRetryImageView.setVisibility(View.GONE); + checkStep(); + } else { + bind.syncSongXPlaylistStatusLabel.setText("Status: ERROR"); + bind.syncSongXPlaylistDetailLabel.setText(message); + bind.syncSongXPlaylistRetryImageView.setVisibility(View.VISIBLE); + } + break; + } + } + + private void resetSectorInfo(int sector) { + 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 SONGS: + bind.syncSongsStatusLabel.setText("Loading..."); + bind.syncSongsDetailLabel.setText(R.string.label_placeholder); + bind.syncSongsRetryImageView.setVisibility(View.GONE); + break; + case SONG_X_GENRE: + bind.syncSongXGenreStatusLabel.setText("Loading..."); + bind.syncSongXGenreDetailLabel.setText(R.string.label_placeholder); + bind.syncSongXGenreRetryImageView.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; + } + } + + private void syncNextSector(int sector) { + switch (sector) { + case LIBRARIES: + if (syncViewModel.isSyncAlbum()) syncAlbums(); + else syncPlaylist(); + break; + case ALBUMS: + syncArtists(); + break; + case ARTISTS: + syncGenres(); + break; + case GENRES: + syncPlaylist(); + break; + case PLAYLISTS: + if (syncViewModel.isSyncSong()) syncSongs(); + else syncSongsPerPlaylist(syncViewModel.getPlaylistList()); + break; + case SONGS: + syncSongsPerGenre(syncViewModel.getGenreList()); + syncSongsPerPlaylist(syncViewModel.getPlaylistList()); + break; + case SONG_X_GENRE | SONG_X_PLAYLIST: + break; + } + } + + private void checkStep() { + if (syncViewModel.getStep() == syncViewModel.getProgress()) { + bind.syncingGoHomeImageView.setVisibility(View.VISIBLE); + } + } } diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java index 8fadd33f..9f956170 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/bottomsheetdialog/SongBottomSheetDialog.java @@ -44,7 +44,6 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements private TextView titleSong; private TextView artistSong; private ToggleButton favoriteToggle; - private ImageView downloadIndicator; private TextView playRadio; private TextView playNext; @@ -91,8 +90,6 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements dismissBottomSheet(); }); - downloadIndicator = view.findViewById(R.id.bottom_sheet_song_dowanload_indicator_image_view); - playRadio = view.findViewById(R.id.play_radio_text_view); playRadio.setOnClickListener(v -> { SyncUtil.getInstantMix(requireContext(), new MediaCallback() { @@ -183,10 +180,8 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements private void initDownloadedUI() { if (song.isOffline()) { - downloadIndicator.setVisibility(View.VISIBLE); download.setText("Remove"); } else { - downloadIndicator.setVisibility(View.GONE); download.setText("Download"); } } diff --git a/app/src/main/java/com/cappielloantonio/play/util/DownloadUtil.java b/app/src/main/java/com/cappielloantonio/play/util/DownloadUtil.java index 2260b000..0177bf6e 100644 --- a/app/src/main/java/com/cappielloantonio/play/util/DownloadUtil.java +++ b/app/src/main/java/com/cappielloantonio/play/util/DownloadUtil.java @@ -49,11 +49,9 @@ public final class DownloadUtil { return httpDataSourceFactory; } - public static synchronized DownloadNotificationHelper getDownloadNotificationHelper( - Context context) { + public static synchronized DownloadNotificationHelper getDownloadNotificationHelper(Context context) { if (downloadNotificationHelper == null) { - downloadNotificationHelper = - new DownloadNotificationHelper(context, DOWNLOAD_NOTIFICATION_CHANNEL_ID); + downloadNotificationHelper = new DownloadNotificationHelper(context, DOWNLOAD_NOTIFICATION_CHANNEL_ID); } return downloadNotificationHelper; } @@ -70,11 +68,8 @@ public final class DownloadUtil { public static synchronized Cache getDownloadCache(Context context) { if (downloadCache == null) { - File downloadContentDirectory = - new File(getDownloadDirectory(context), DOWNLOAD_CONTENT_DIRECTORY); - downloadCache = - new SimpleCache( - downloadContentDirectory, new NoOpCacheEvictor(), getDatabaseProvider(context)); + File downloadContentDirectory = new File(getDownloadDirectory(context), DOWNLOAD_CONTENT_DIRECTORY); + downloadCache = new SimpleCache(downloadContentDirectory, new NoOpCacheEvictor(), getDatabaseProvider(context)); } return downloadCache; } @@ -82,37 +77,16 @@ public final class DownloadUtil { private static synchronized void ensureDownloadManagerInitialized(Context context) { if (downloadManager == null) { DefaultDownloadIndex downloadIndex = new DefaultDownloadIndex(getDatabaseProvider(context)); - upgradeActionFile( - context, DOWNLOAD_ACTION_FILE, downloadIndex, false); - upgradeActionFile( - context, - DOWNLOAD_TRACKER_ACTION_FILE, - downloadIndex, - true); - downloadManager = - new DownloadManager( - context, - getDatabaseProvider(context), - getDownloadCache(context), - getHttpDataSourceFactory(context), - Executors.newFixedThreadPool(6)); - downloadTracker = - new DownloadTracker(context, getHttpDataSourceFactory(context), downloadManager); + upgradeActionFile(context, DOWNLOAD_ACTION_FILE, downloadIndex, false); + upgradeActionFile(context, DOWNLOAD_TRACKER_ACTION_FILE, downloadIndex, true); + downloadManager = new DownloadManager(context, getDatabaseProvider(context), getDownloadCache(context), getHttpDataSourceFactory(context), Executors.newFixedThreadPool(6)); + downloadTracker = new DownloadTracker(context, getHttpDataSourceFactory(context), downloadManager); } } - private static synchronized void upgradeActionFile( - Context context, - String fileName, - DefaultDownloadIndex downloadIndex, - boolean addNewDownloadsAsCompleted) { + private static synchronized void upgradeActionFile(Context context, String fileName, DefaultDownloadIndex downloadIndex, boolean addNewDownloadsAsCompleted) { try { - ActionFileUpgradeUtil.upgradeAndDelete( - new File(getDownloadDirectory(context), fileName), - null, - downloadIndex, - true, - addNewDownloadsAsCompleted); + ActionFileUpgradeUtil.upgradeAndDelete(new File(getDownloadDirectory(context), fileName), null, downloadIndex, true, addNewDownloadsAsCompleted); } catch (IOException e) { Log.e(TAG, "Failed to upgrade action file: " + fileName, e); } diff --git a/app/src/main/java/com/cappielloantonio/play/viewmodel/SyncViewModel.java b/app/src/main/java/com/cappielloantonio/play/viewmodel/SyncViewModel.java index 1cfb20b3..adeae45a 100644 --- a/app/src/main/java/com/cappielloantonio/play/viewmodel/SyncViewModel.java +++ b/app/src/main/java/com/cappielloantonio/play/viewmodel/SyncViewModel.java @@ -6,9 +6,14 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; +import com.cappielloantonio.play.model.Album; +import com.cappielloantonio.play.model.Artist; +import com.cappielloantonio.play.model.Genre; +import com.cappielloantonio.play.model.Playlist; import com.cappielloantonio.play.model.Song; import com.cappielloantonio.play.repository.SongRepository; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -24,10 +29,15 @@ public class SyncViewModel extends AndroidViewModel { private boolean syncSong = false; private boolean crossSyncSongGenre = false; + private ArrayList albumList = new ArrayList<>(); + private ArrayList artistList = new ArrayList<>(); + private ArrayList genreList = new ArrayList<>(); + private ArrayList playlistList = new ArrayList<>(); + private ArrayList songList = new ArrayList<>(); + private int step = 0; private int progress = 0; - public SyncViewModel(@NonNull Application application) { super(application); @@ -54,7 +64,6 @@ public class SyncViewModel extends AndroidViewModel { if (syncGenres) step++; if (syncPlaylist) step++; if (syncSong) step++; - if (crossSyncSongGenre) step++; } public boolean isSyncAlbum() { @@ -81,6 +90,50 @@ public class SyncViewModel extends AndroidViewModel { return crossSyncSongGenre; } + public ArrayList getAlbumList() { + return albumList; + } + + public void setAlbumList(ArrayList albumList) { + this.albumList = albumList; + } + + public ArrayList getArtistList() { + return artistList; + } + + public void setArtistList(ArrayList artistList) { + this.artistList = artistList; + } + + public ArrayList getGenreList() { + return genreList; + } + + public void setGenreList(ArrayList genreList) { + this.genreList = genreList; + } + + public ArrayList getPlaylistList() { + return playlistList; + } + + public void setPlaylistList(ArrayList playlistList) { + this.playlistList = playlistList; + } + + public ArrayList getSongList() { + return songList; + } + + public void setSongList(ArrayList songList) { + this.songList = songList; + } + + public void increaseProggress() { + progress++; + } + public int getStep() { return step; } @@ -89,13 +142,6 @@ public class SyncViewModel extends AndroidViewModel { return progress; } - public void setProgress(Boolean step) { - if (step) progress++; - } - - public int getProgressBarInfo() { - return progress * (100 / step); - } public Map getCatalogue() { Map map = new HashMap<>(); diff --git a/app/src/main/res/drawable/ic_download_for_offline.xml b/app/src/main/res/drawable/ic_download_for_offline.xml new file mode 100644 index 00000000..87e6cd5b --- /dev/null +++ b/app/src/main/res/drawable/ic_download_for_offline.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_filled.xml b/app/src/main/res/drawable/ic_home_filled.xml new file mode 100644 index 00000000..189578d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_filled.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_refresh.xml b/app/src/main/res/drawable/ic_refresh.xml new file mode 100644 index 00000000..c5119142 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 19a469c1..ed92275b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -34,6 +34,8 @@ android:id="@+id/bottom_navigation" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingStart="32dp" + android:paddingEnd="32dp" android:background="@drawable/bottom_nav_shape" android:visibility="gone" app:itemIconTint="@drawable/bottom_nav_selector" diff --git a/app/src/main/res/layout/bottom_sheet_song_dialog.xml b/app/src/main/res/layout/bottom_sheet_song_dialog.xml index 5b5522ba..a2e2ba2e 100644 --- a/app/src/main/res/layout/bottom_sheet_song_dialog.xml +++ b/app/src/main/res/layout/bottom_sheet_song_dialog.xml @@ -58,7 +58,7 @@ android:textColor="@color/titleTextColor" android:textSize="14sp" android:textStyle="bold" - app:layout_constraintEnd_toStartOf="@id/bottom_sheet_song_dowanload_indicator_image_view" + app:layout_constraintEnd_toStartOf="@id/button_favorite" app:layout_constraintStart_toEndOf="@+id/song_cover_image_view" app:layout_constraintTop_toTopOf="parent" /> @@ -72,22 +72,10 @@ android:text="@string/label_placeholder" android:textColor="@color/subtitleTextColor" android:textSize="12sp" - app:layout_constraintEnd_toStartOf="@id/bottom_sheet_song_dowanload_indicator_image_view" + app:layout_constraintEnd_toStartOf="@id/button_favorite" app:layout_constraintStart_toEndOf="@+id/song_cover_image_view" app:layout_constraintTop_toBottomOf="@+id/song_title_text_view" /> - - @@ -24,48 +24,48 @@ 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" - android:includeFontPadding="false" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent"/> + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/home_date_label" /> + android:foreground="?android:attr/selectableItemBackgroundBorderless" + app:layout_constraintBottom_toBottomOf="@+id/home_listen_now_label" + app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/home_listen_now_label" /> @@ -80,7 +80,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingStart="16dp" - android:paddingTop="24dp" + android:paddingTop="16dp" android:paddingEnd="16dp" android:text="Music discovery" /> diff --git a/app/src/main/res/layout/fragment_sync.xml b/app/src/main/res/layout/fragment_sync.xml index 062b9315..ecfa306d 100644 --- a/app/src/main/res/layout/fragment_sync.xml +++ b/app/src/main/res/layout/fragment_sync.xml @@ -1,20 +1,540 @@ - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_search_result_song.xml b/app/src/main/res/layout/item_search_result_song.xml index da493a6d..247cd824 100644 --- a/app/src/main/res/layout/item_search_result_song.xml +++ b/app/src/main/res/layout/item_search_result_song.xml @@ -80,7 +80,7 @@ android:layout_height="18dp" android:layout_gravity="center" android:layout_margin="8dp" - android:background="@drawable/ic_check_circle" + android:background="@drawable/ic_download_for_offline" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/search_result_song_more_button" diff --git a/app/src/main/res/xml/global_preferences.xml b/app/src/main/res/xml/global_preferences.xml index fea1b86a..4cb0237b 100644 --- a/app/src/main/res/xml/global_preferences.xml +++ b/app/src/main/res/xml/global_preferences.xml @@ -53,11 +53,6 @@ android:summary="@string/music_sync_caption" android:title="@string/music_sync" /> - -