mirror of
https://github.com/antebudimir/tempus.git
synced 2026-01-01 18:03:33 +00:00
feat: adds sync starred albums functionality #66
This commit is contained in:
parent
cc5abd150a
commit
f854f49686
9 changed files with 231 additions and 7 deletions
|
|
@ -0,0 +1,81 @@
|
|||
package com.cappielloantonio.tempo.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.databinding.DialogStarredSyncBinding;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.viewmodel.StarredAlbumsSyncViewModel;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class StarredAlbumSyncDialog extends DialogFragment {
|
||||
private StarredAlbumsSyncViewModel starredAlbumsSyncViewModel;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
DialogStarredSyncBinding bind = DialogStarredSyncBinding.inflate(getLayoutInflater());
|
||||
|
||||
starredAlbumsSyncViewModel = new ViewModelProvider(requireActivity()).get(StarredAlbumsSyncViewModel.class);
|
||||
|
||||
return new MaterialAlertDialogBuilder(getActivity())
|
||||
.setView(bind.getRoot())
|
||||
.setTitle(R.string.starred_album_sync_dialog_title)
|
||||
.setPositiveButton(R.string.starred_sync_dialog_positive_button, null)
|
||||
.setNeutralButton(R.string.starred_sync_dialog_neutral_button, null)
|
||||
.setNegativeButton(R.string.starred_sync_dialog_negative_button, null)
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setButtonAction(requireContext());
|
||||
}
|
||||
|
||||
private void setButtonAction(Context context) {
|
||||
androidx.appcompat.app.AlertDialog dialog = (androidx.appcompat.app.AlertDialog) getDialog();
|
||||
|
||||
if (dialog != null) {
|
||||
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);
|
||||
positiveButton.setOnClickListener(v -> {
|
||||
starredAlbumsSyncViewModel.getStarredAlbumSongs(requireActivity()).observe(this, allSongs -> {
|
||||
if (allSongs != null && !allSongs.isEmpty()) {
|
||||
DownloadUtil.getDownloadTracker(context).download(
|
||||
MappingUtil.mapDownloads(allSongs),
|
||||
allSongs.stream().map(Download::new).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
});
|
||||
|
||||
Button neutralButton = dialog.getButton(Dialog.BUTTON_NEUTRAL);
|
||||
neutralButton.setOnClickListener(v -> {
|
||||
Preferences.setStarredAlbumsSyncEnabled(true);
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
Button negativeButton = dialog.getButton(Dialog.BUTTON_NEGATIVE);
|
||||
negativeButton.setOnClickListener(v -> {
|
||||
Preferences.setStarredAlbumsSyncEnabled(false);
|
||||
dialog.dismiss();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
|||
import com.cappielloantonio.tempo.ui.dialog.DeleteDownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.DownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredAlbumSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StreamingCacheStorageDialog;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
|
@ -94,6 +95,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
|
||||
actionLogout();
|
||||
actionScan();
|
||||
actionSyncStarredAlbums();
|
||||
actionSyncStarredTracks();
|
||||
actionChangeStreamingCacheStorage();
|
||||
actionChangeDownloadStorage();
|
||||
|
|
@ -263,6 +265,18 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
});
|
||||
}
|
||||
|
||||
private void actionSyncStarredAlbums() {
|
||||
findPreference("sync_starred_albums_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
StarredAlbumSyncDialog dialog = new StarredAlbumSyncDialog();
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionChangeStreamingCacheStorage() {
|
||||
findPreference("streaming_cache_storage").setOnPreferenceClickListener(preference -> {
|
||||
StreamingCacheStorageDialog dialog = new StreamingCacheStorageDialog(new DialogClickCallback() {
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public class AlbumBottomSheetDialog extends BottomSheetDialogFragment implements
|
|||
ToggleButton favoriteToggle = view.findViewById(R.id.button_favorite);
|
||||
favoriteToggle.setChecked(albumBottomSheetViewModel.getAlbum().getStarred() != null);
|
||||
favoriteToggle.setOnClickListener(v -> {
|
||||
albumBottomSheetViewModel.setFavorite();
|
||||
albumBottomSheetViewModel.setFavorite(requireContext());
|
||||
});
|
||||
|
||||
TextView playRadio = view.findViewById(R.id.play_radio_text_view);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ object Preferences {
|
|||
private const val WIFI_ONLY = "wifi_only"
|
||||
private const val DATA_SAVING_MODE = "data_saving_mode"
|
||||
private const val SERVER_UNREACHABLE = "server_unreachable"
|
||||
private const val SYNC_STARRED_ALBUMS_FOR_OFFLINE_USE = "sync_starred_albums_for_offline_use"
|
||||
private const val SYNC_STARRED_TRACKS_FOR_OFFLINE_USE = "sync_starred_tracks_for_offline_use"
|
||||
private const val QUEUE_SYNCING = "queue_syncing"
|
||||
private const val QUEUE_SYNCING_COUNTDOWN = "queue_syncing_countdown"
|
||||
|
|
@ -301,6 +302,18 @@ object Preferences {
|
|||
.apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isStarredAlbumsSyncEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(SYNC_STARRED_ALBUMS_FOR_OFFLINE_USE, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setStarredAlbumsSyncEnabled(isStarredSyncEnabled: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(
|
||||
SYNC_STARRED_ALBUMS_FOR_OFFLINE_USE, isStarredSyncEnabled
|
||||
).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isStarredSyncEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(SYNC_STARRED_TRACKS_FOR_OFFLINE_USE, false)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
|
|
@ -16,10 +19,14 @@ import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
|||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Share;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.NetworkUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
||||
private final AlbumRepository albumRepository;
|
||||
|
|
@ -54,7 +61,7 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
return albumRepository.getAlbumTracks(album.getId());
|
||||
}
|
||||
|
||||
public void setFavorite() {
|
||||
public void setFavorite(Context context) {
|
||||
if (album.getStarred() != null) {
|
||||
if (NetworkUtil.isOffline()) {
|
||||
removeFavoriteOffline();
|
||||
|
|
@ -65,7 +72,7 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
if (NetworkUtil.isOffline()) {
|
||||
setFavoriteOffline();
|
||||
} else {
|
||||
setFavoriteOnline();
|
||||
setFavoriteOnline(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +90,6 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
favoriteRepository.unstar(null, album.getId(), null, new StarCallback() {
|
||||
@Override
|
||||
public void onError() {
|
||||
// album.setStarred(new Date());
|
||||
favoriteRepository.starLater(null, album.getId(), null, false);
|
||||
}
|
||||
});
|
||||
|
|
@ -96,15 +102,31 @@ public class AlbumBottomSheetViewModel extends AndroidViewModel {
|
|||
album.setStarred(new Date());
|
||||
}
|
||||
|
||||
private void setFavoriteOnline() {
|
||||
private void setFavoriteOnline(Context context) {
|
||||
favoriteRepository.star(null, album.getId(), null, new StarCallback() {
|
||||
@Override
|
||||
public void onError() {
|
||||
// album.setStarred(null);
|
||||
favoriteRepository.starLater(null, album.getId(), null, true);
|
||||
}
|
||||
});
|
||||
|
||||
album.setStarred(new Date());
|
||||
if (Preferences.isStarredAlbumsSyncEnabled()) {
|
||||
AlbumRepository albumRepository = new AlbumRepository();
|
||||
MutableLiveData<List<Child>> tracksLiveData = albumRepository.getAlbumTracks(album.getId());
|
||||
|
||||
tracksLiveData.observeForever(new Observer<List<Child>>() {
|
||||
@Override
|
||||
public void onChanged(List<Child> songs) {
|
||||
if (songs != null && !songs.isEmpty()) {
|
||||
DownloadUtil.getDownloadTracker(context).download(
|
||||
MappingUtil.mapDownloads(songs),
|
||||
songs.stream().map(Download::new).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
tracksLiveData.removeObserver(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class StarredAlbumsSyncViewModel extends AndroidViewModel {
|
||||
private final AlbumRepository albumRepository;
|
||||
|
||||
private final MutableLiveData<List<AlbumID3>> starredAlbums = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> starredAlbumSongs = new MutableLiveData<>(null);
|
||||
|
||||
public StarredAlbumsSyncViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
albumRepository = new AlbumRepository();
|
||||
}
|
||||
|
||||
public LiveData<List<AlbumID3>> getStarredAlbums(LifecycleOwner owner) {
|
||||
albumRepository.getStarredAlbums(false, -1).observe(owner, starredAlbums::postValue);
|
||||
return starredAlbums;
|
||||
}
|
||||
|
||||
public LiveData<List<Child>> getStarredAlbumSongs(Activity activity) {
|
||||
albumRepository.getStarredAlbums(false, -1).observe((LifecycleOwner) activity, albums -> {
|
||||
if (albums != null && !albums.isEmpty()) {
|
||||
collectAllAlbumSongs(albums, starredAlbumSongs::postValue);
|
||||
} else {
|
||||
starredAlbumSongs.postValue(new ArrayList<>());
|
||||
}
|
||||
});
|
||||
return starredAlbumSongs;
|
||||
}
|
||||
|
||||
private void collectAllAlbumSongs(List<AlbumID3> albums, AlbumSongsCallback callback) {
|
||||
List<Child> allSongs = new ArrayList<>();
|
||||
CountDownLatch latch = new CountDownLatch(albums.size());
|
||||
|
||||
for (AlbumID3 album : albums) {
|
||||
albumRepository.getAlbumTracks(album.getId()).observeForever(songs -> {
|
||||
if (songs != null) {
|
||||
allSongs.addAll(songs);
|
||||
}
|
||||
latch.countDown();
|
||||
|
||||
if (latch.getCount() == 0) {
|
||||
callback.onSongsCollected(allSongs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
albumRepository.removeObserver(this);
|
||||
}
|
||||
|
||||
private interface AlbumSongsCallback {
|
||||
void onSongsCollected(List<Child> songs);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue