mirror of
https://github.com/antebudimir/tempus.git
synced 2026-01-01 18:03:33 +00:00
Merge branch 'development' into skip-duplicates
This commit is contained in:
commit
717f95a04a
87 changed files with 6098 additions and 428 deletions
|
|
@ -1,17 +1,25 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.repository.FavoriteRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.util.NetworkUtil;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.List;
|
||||
|
||||
public class ArtistBottomSheetViewModel extends AndroidViewModel {
|
||||
private final ArtistRepository artistRepository;
|
||||
|
|
@ -34,7 +42,7 @@ public class ArtistBottomSheetViewModel extends AndroidViewModel {
|
|||
this.artist = artist;
|
||||
}
|
||||
|
||||
public void setFavorite() {
|
||||
public void setFavorite(Context context) {
|
||||
if (artist.getStarred() != null) {
|
||||
if (NetworkUtil.isOffline()) {
|
||||
removeFavoriteOffline();
|
||||
|
|
@ -43,9 +51,9 @@ public class ArtistBottomSheetViewModel extends AndroidViewModel {
|
|||
}
|
||||
} else {
|
||||
if (NetworkUtil.isOffline()) {
|
||||
setFavoriteOffline();
|
||||
setFavoriteOffline(context);
|
||||
} else {
|
||||
setFavoriteOnline();
|
||||
setFavoriteOnline(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +67,6 @@ public class ArtistBottomSheetViewModel extends AndroidViewModel {
|
|||
favoriteRepository.unstar(null, null, artist.getId(), new StarCallback() {
|
||||
@Override
|
||||
public void onError() {
|
||||
// artist.setStarred(new Date());
|
||||
favoriteRepository.starLater(null, null, artist.getId(), false);
|
||||
}
|
||||
});
|
||||
|
|
@ -67,20 +74,45 @@ public class ArtistBottomSheetViewModel extends AndroidViewModel {
|
|||
artist.setStarred(null);
|
||||
}
|
||||
|
||||
private void setFavoriteOffline() {
|
||||
private void setFavoriteOffline(Context context) {
|
||||
favoriteRepository.starLater(null, null, artist.getId(), true);
|
||||
artist.setStarred(new Date());
|
||||
}
|
||||
|
||||
private void setFavoriteOnline() {
|
||||
private void setFavoriteOnline(Context context) {
|
||||
favoriteRepository.star(null, null, artist.getId(), new StarCallback() {
|
||||
@Override
|
||||
public void onError() {
|
||||
// artist.setStarred(null);
|
||||
favoriteRepository.starLater(null, null, artist.getId(), true);
|
||||
}
|
||||
});
|
||||
|
||||
artist.setStarred(new Date());
|
||||
|
||||
Log.d("ArtistSync", "Checking preference: " + Preferences.isStarredArtistsSyncEnabled());
|
||||
|
||||
if (Preferences.isStarredArtistsSyncEnabled()) {
|
||||
Log.d("ArtistSync", "Starting artist sync for: " + artist.getName());
|
||||
|
||||
artistRepository.getArtistAllSongs(artist.getId(), new ArtistRepository.ArtistSongsCallback() {
|
||||
@Override
|
||||
public void onSongsCollected(List<Child> songs) {
|
||||
Log.d("ArtistSync", "Callback triggered with songs: " + (songs != null ? songs.size() : 0));
|
||||
if (songs != null && !songs.isEmpty()) {
|
||||
Log.d("ArtistSync", "Starting download of " + songs.size() + " songs");
|
||||
DownloadUtil.getDownloadTracker(context).download(
|
||||
MappingUtil.mapDownloads(songs),
|
||||
songs.stream().map(Download::new).collect(Collectors.toList())
|
||||
);
|
||||
Log.d("ArtistSync", "Download started successfully");
|
||||
} else {
|
||||
Log.d("ArtistSync", "No songs to download");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.d("ArtistSync", "Artist sync preference is disabled");
|
||||
}
|
||||
}
|
||||
///
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import android.app.Application;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -8,10 +9,13 @@ import androidx.lifecycle.AndroidViewModel;
|
|||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.model.DownloadStack;
|
||||
import com.cappielloantonio.tempo.repository.DownloadRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.util.ExternalAudioReader;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -25,6 +29,7 @@ public class DownloadViewModel extends AndroidViewModel {
|
|||
|
||||
private final MutableLiveData<List<Child>> downloadedTrackSample = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<ArrayList<DownloadStack>> viewStack = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<Integer> refreshResult = new MutableLiveData<>();
|
||||
|
||||
public DownloadViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
|
@ -43,6 +48,10 @@ public class DownloadViewModel extends AndroidViewModel {
|
|||
return viewStack;
|
||||
}
|
||||
|
||||
public LiveData<Integer> getRefreshResult() {
|
||||
return refreshResult;
|
||||
}
|
||||
|
||||
public void initViewStack(DownloadStack level) {
|
||||
ArrayList<DownloadStack> stack = new ArrayList<>();
|
||||
stack.add(level);
|
||||
|
|
@ -60,4 +69,59 @@ public class DownloadViewModel extends AndroidViewModel {
|
|||
stack.remove(stack.size() - 1);
|
||||
viewStack.setValue(stack);
|
||||
}
|
||||
|
||||
public void refreshExternalDownloads() {
|
||||
new Thread(() -> {
|
||||
String directoryUri = Preferences.getDownloadDirectoryUri();
|
||||
if (directoryUri == null) {
|
||||
refreshResult.postValue(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Download> downloads = downloadRepository.getAllDownloads();
|
||||
if (downloads == null || downloads.isEmpty()) {
|
||||
refreshResult.postValue(0);
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<Download> toRemove = new ArrayList<>();
|
||||
|
||||
for (Download download : downloads) {
|
||||
String uriString = download.getDownloadUri();
|
||||
if (uriString == null || uriString.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(uriString);
|
||||
if (uri.getScheme() == null || !uri.getScheme().equalsIgnoreCase("content")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DocumentFile file;
|
||||
try {
|
||||
file = DocumentFile.fromSingleUri(getApplication(), uri);
|
||||
} catch (SecurityException exception) {
|
||||
file = null;
|
||||
}
|
||||
|
||||
if (file == null || !file.exists()) {
|
||||
toRemove.add(download);
|
||||
}
|
||||
}
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
ArrayList<String> ids = new ArrayList<>();
|
||||
for (Download download : toRemove) {
|
||||
ids.add(download.getId());
|
||||
ExternalAudioReader.removeMetadata(download);
|
||||
}
|
||||
|
||||
downloadRepository.delete(ids);
|
||||
ExternalAudioReader.refreshCache();
|
||||
refreshResult.postValue(ids.size());
|
||||
} else {
|
||||
refreshResult.postValue(0);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
private final SharingRepository sharingRepository;
|
||||
|
||||
private final StarredAlbumsSyncViewModel albumsSyncViewModel;
|
||||
private final StarredArtistsSyncViewModel artistSyncViewModel;
|
||||
|
||||
private final MutableLiveData<List<Child>> dicoverSongSample = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<AlbumID3>> newReleasedAlbum = new MutableLiveData<>(null);
|
||||
|
|
@ -85,6 +86,7 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
sharingRepository = new SharingRepository();
|
||||
|
||||
albumsSyncViewModel = new StarredAlbumsSyncViewModel(application);
|
||||
artistSyncViewModel = new StarredArtistsSyncViewModel(application);
|
||||
|
||||
setOfflineFavorite();
|
||||
}
|
||||
|
|
@ -174,6 +176,10 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
return albumsSyncViewModel.getAllStarredAlbumSongs();
|
||||
}
|
||||
|
||||
public LiveData<List<Child>> getAllStarredArtistSongs() {
|
||||
return artistSyncViewModel.getAllStarredArtistSongs();
|
||||
}
|
||||
|
||||
public LiveData<List<ArtistID3>> getStarredArtists(LifecycleOwner owner) {
|
||||
if (starredArtists.getValue() == null) {
|
||||
artistRepository.getStarredArtists(true, 20).observe(owner, starredArtists::postValue);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.cappielloantonio.tempo.viewmodel;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class PlaybackViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<String> currentSongId = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<Boolean> isPlaying = new MutableLiveData<>(false);
|
||||
|
||||
public LiveData<String> getCurrentSongId() {
|
||||
return currentSongId;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getIsPlaying() {
|
||||
return isPlaying;
|
||||
}
|
||||
|
||||
public void update(String songId, boolean playing) {
|
||||
if (!Objects.equals(currentSongId.getValue(), songId)) {
|
||||
currentSongId.postValue(songId);
|
||||
}
|
||||
if (!Objects.equals(isPlaying.getValue(), playing)) {
|
||||
isPlaying.postValue(playing);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
currentSongId.postValue(null);
|
||||
isPlaying.postValue(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.cappielloantonio.tempo.viewmodel;
|
|||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.OptIn;
|
||||
|
|
@ -9,14 +10,17 @@ import androidx.lifecycle.AndroidViewModel;
|
|||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.tempo.interfaces.StarCallback;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.model.LyricsCache;
|
||||
import com.cappielloantonio.tempo.model.Queue;
|
||||
import com.cappielloantonio.tempo.repository.AlbumRepository;
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.repository.FavoriteRepository;
|
||||
import com.cappielloantonio.tempo.repository.LyricsRepository;
|
||||
import com.cappielloantonio.tempo.repository.OpenRepository;
|
||||
import com.cappielloantonio.tempo.repository.QueueRepository;
|
||||
import com.cappielloantonio.tempo.repository.SongRepository;
|
||||
|
|
@ -31,6 +35,7 @@ import com.cappielloantonio.tempo.util.MappingUtil;
|
|||
import com.cappielloantonio.tempo.util.NetworkUtil;
|
||||
import com.cappielloantonio.tempo.util.OpenSubsonicExtensionsUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
|
@ -47,14 +52,20 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
|||
private final QueueRepository queueRepository;
|
||||
private final FavoriteRepository favoriteRepository;
|
||||
private final OpenRepository openRepository;
|
||||
private final LyricsRepository lyricsRepository;
|
||||
private final MutableLiveData<String> lyricsLiveData = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<LyricsList> lyricsListLiveData = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<Boolean> lyricsCachedLiveData = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<String> descriptionLiveData = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<Child> liveMedia = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<AlbumID3> liveAlbum = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<ArtistID3> liveArtist = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> instantMix = new MutableLiveData<>(null);
|
||||
private final Gson gson = new Gson();
|
||||
private boolean lyricsSyncState = true;
|
||||
private LiveData<LyricsCache> cachedLyricsSource;
|
||||
private String currentSongId;
|
||||
private final Observer<LyricsCache> cachedLyricsObserver = this::onCachedLyricsChanged;
|
||||
|
||||
|
||||
public PlayerBottomSheetViewModel(@NonNull Application application) {
|
||||
|
|
@ -66,6 +77,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
|||
queueRepository = new QueueRepository();
|
||||
favoriteRepository = new FavoriteRepository();
|
||||
openRepository = new OpenRepository();
|
||||
lyricsRepository = new LyricsRepository();
|
||||
}
|
||||
|
||||
public LiveData<List<Queue>> getQueueSong() {
|
||||
|
|
@ -122,7 +134,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
|||
|
||||
media.setStarred(new Date());
|
||||
|
||||
if (Preferences.isStarredSyncEnabled()) {
|
||||
if (Preferences.isStarredSyncEnabled() && Preferences.getDownloadDirectoryUri() == null) {
|
||||
DownloadUtil.getDownloadTracker(context).download(
|
||||
MappingUtil.mapDownload(media),
|
||||
new Download(media)
|
||||
|
|
@ -139,12 +151,49 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
|||
}
|
||||
|
||||
public void refreshMediaInfo(LifecycleOwner owner, Child media) {
|
||||
lyricsLiveData.postValue(null);
|
||||
lyricsListLiveData.postValue(null);
|
||||
lyricsCachedLiveData.postValue(false);
|
||||
|
||||
clearCachedLyricsObserver();
|
||||
|
||||
String songId = media != null ? media.getId() : currentSongId;
|
||||
|
||||
if (TextUtils.isEmpty(songId) || owner == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentSongId = songId;
|
||||
|
||||
observeCachedLyrics(owner, songId);
|
||||
|
||||
LyricsCache cachedLyrics = lyricsRepository.getLyrics(songId);
|
||||
if (cachedLyrics != null) {
|
||||
onCachedLyricsChanged(cachedLyrics);
|
||||
}
|
||||
|
||||
if (NetworkUtil.isOffline() || media == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenSubsonicExtensionsUtil.isSongLyricsExtensionAvailable()) {
|
||||
openRepository.getLyricsBySongId(media.getId()).observe(owner, lyricsListLiveData::postValue);
|
||||
lyricsLiveData.postValue(null);
|
||||
openRepository.getLyricsBySongId(media.getId()).observe(owner, lyricsList -> {
|
||||
lyricsListLiveData.postValue(lyricsList);
|
||||
lyricsLiveData.postValue(null);
|
||||
|
||||
if (shouldAutoDownloadLyrics() && hasStructuredLyrics(lyricsList)) {
|
||||
saveLyricsToCache(media, null, lyricsList);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
songRepository.getSongLyrics(media).observe(owner, lyricsLiveData::postValue);
|
||||
lyricsListLiveData.postValue(null);
|
||||
songRepository.getSongLyrics(media).observe(owner, lyrics -> {
|
||||
lyricsLiveData.postValue(lyrics);
|
||||
lyricsListLiveData.postValue(null);
|
||||
|
||||
if (shouldAutoDownloadLyrics() && !TextUtils.isEmpty(lyrics)) {
|
||||
saveLyricsToCache(media, lyrics, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +202,17 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
|||
}
|
||||
|
||||
public void setLiveMedia(LifecycleOwner owner, String mediaType, String mediaId) {
|
||||
currentSongId = mediaId;
|
||||
|
||||
if (!TextUtils.isEmpty(mediaId)) {
|
||||
refreshMediaInfo(owner, null);
|
||||
} else {
|
||||
clearCachedLyricsObserver();
|
||||
lyricsLiveData.postValue(null);
|
||||
lyricsListLiveData.postValue(null);
|
||||
lyricsCachedLiveData.postValue(false);
|
||||
}
|
||||
|
||||
if (mediaType != null) {
|
||||
switch (mediaType) {
|
||||
case Constants.MEDIA_TYPE_MUSIC:
|
||||
|
|
@ -162,7 +222,12 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
|||
case Constants.MEDIA_TYPE_PODCAST:
|
||||
liveMedia.postValue(null);
|
||||
break;
|
||||
default:
|
||||
liveMedia.postValue(null);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
liveMedia.postValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +298,105 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void observeCachedLyrics(LifecycleOwner owner, String songId) {
|
||||
if (TextUtils.isEmpty(songId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cachedLyricsSource = lyricsRepository.observeLyrics(songId);
|
||||
cachedLyricsSource.observe(owner, cachedLyricsObserver);
|
||||
}
|
||||
|
||||
private void clearCachedLyricsObserver() {
|
||||
if (cachedLyricsSource != null) {
|
||||
cachedLyricsSource.removeObserver(cachedLyricsObserver);
|
||||
cachedLyricsSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void onCachedLyricsChanged(LyricsCache lyricsCache) {
|
||||
if (lyricsCache == null) {
|
||||
lyricsCachedLiveData.postValue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
lyricsCachedLiveData.postValue(true);
|
||||
|
||||
if (!TextUtils.isEmpty(lyricsCache.getStructuredLyrics())) {
|
||||
try {
|
||||
LyricsList cachedList = gson.fromJson(lyricsCache.getStructuredLyrics(), LyricsList.class);
|
||||
lyricsListLiveData.postValue(cachedList);
|
||||
lyricsLiveData.postValue(null);
|
||||
} catch (Exception exception) {
|
||||
lyricsListLiveData.postValue(null);
|
||||
lyricsLiveData.postValue(lyricsCache.getLyrics());
|
||||
}
|
||||
} else {
|
||||
lyricsListLiveData.postValue(null);
|
||||
lyricsLiveData.postValue(lyricsCache.getLyrics());
|
||||
}
|
||||
}
|
||||
|
||||
private void saveLyricsToCache(Child media, String lyrics, LyricsList lyricsList) {
|
||||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((lyricsList == null || !hasStructuredLyrics(lyricsList)) && TextUtils.isEmpty(lyrics)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LyricsCache lyricsCache = new LyricsCache(media.getId());
|
||||
lyricsCache.setArtist(media.getArtist());
|
||||
lyricsCache.setTitle(media.getTitle());
|
||||
lyricsCache.setUpdatedAt(System.currentTimeMillis());
|
||||
|
||||
if (lyricsList != null && hasStructuredLyrics(lyricsList)) {
|
||||
lyricsCache.setStructuredLyrics(gson.toJson(lyricsList));
|
||||
lyricsCache.setLyrics(null);
|
||||
} else {
|
||||
lyricsCache.setLyrics(lyrics);
|
||||
lyricsCache.setStructuredLyrics(null);
|
||||
}
|
||||
|
||||
lyricsRepository.insert(lyricsCache);
|
||||
lyricsCachedLiveData.postValue(true);
|
||||
}
|
||||
|
||||
private boolean hasStructuredLyrics(LyricsList lyricsList) {
|
||||
return lyricsList != null
|
||||
&& lyricsList.getStructuredLyrics() != null
|
||||
&& !lyricsList.getStructuredLyrics().isEmpty()
|
||||
&& lyricsList.getStructuredLyrics().get(0) != null
|
||||
&& lyricsList.getStructuredLyrics().get(0).getLine() != null
|
||||
&& !lyricsList.getStructuredLyrics().get(0).getLine().isEmpty();
|
||||
}
|
||||
|
||||
private boolean shouldAutoDownloadLyrics() {
|
||||
return Preferences.isAutoDownloadLyricsEnabled();
|
||||
}
|
||||
|
||||
public boolean downloadCurrentLyrics() {
|
||||
Child media = getLiveMedia().getValue();
|
||||
if (media == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LyricsList lyricsList = lyricsListLiveData.getValue();
|
||||
String lyrics = lyricsLiveData.getValue();
|
||||
|
||||
if ((lyricsList == null || !hasStructuredLyrics(lyricsList)) && TextUtils.isEmpty(lyrics)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
saveLyricsToCache(media, lyrics, lyricsList);
|
||||
return true;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getLyricsCachedState() {
|
||||
return lyricsCachedLiveData;
|
||||
}
|
||||
|
||||
public void changeSyncLyricsState() {
|
||||
lyricsSyncState = !lyricsSyncState;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public class SongBottomSheetViewModel extends AndroidViewModel {
|
|||
|
||||
media.setStarred(new Date());
|
||||
|
||||
if (Preferences.isStarredSyncEnabled()) {
|
||||
if (Preferences.isStarredSyncEnabled() && Preferences.getDownloadDirectoryUri() == null) {
|
||||
DownloadUtil.getDownloadTracker(context).download(
|
||||
MappingUtil.mapDownload(media),
|
||||
new Download(media)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
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.Observer;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class StarredArtistsSyncViewModel extends AndroidViewModel {
|
||||
private final ArtistRepository artistRepository;
|
||||
|
||||
private final MutableLiveData<List<ArtistID3>> starredArtists = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> starredArtistSongs = new MutableLiveData<>(null);
|
||||
|
||||
public StarredArtistsSyncViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
artistRepository = new ArtistRepository();
|
||||
}
|
||||
|
||||
public LiveData<List<ArtistID3>> getStarredArtists(LifecycleOwner owner) {
|
||||
artistRepository.getStarredArtists(false, -1).observe(owner, starredArtists::postValue);
|
||||
return starredArtists;
|
||||
}
|
||||
|
||||
public LiveData<List<Child>> getAllStarredArtistSongs() {
|
||||
artistRepository.getStarredArtists(false, -1).observeForever(new Observer<List<ArtistID3>>() {
|
||||
@Override
|
||||
public void onChanged(List<ArtistID3> artists) {
|
||||
if (artists != null && !artists.isEmpty()) {
|
||||
collectAllArtistSongs(artists, starredArtistSongs::postValue);
|
||||
} else {
|
||||
starredArtistSongs.postValue(new ArrayList<>());
|
||||
}
|
||||
artistRepository.getStarredArtists(false, -1).removeObserver(this);
|
||||
}
|
||||
});
|
||||
|
||||
return starredArtistSongs;
|
||||
}
|
||||
|
||||
public LiveData<List<Child>> getStarredArtistSongs(Activity activity) {
|
||||
artistRepository.getStarredArtists(false, -1).observe((LifecycleOwner) activity, artists -> {
|
||||
if (artists != null && !artists.isEmpty()) {
|
||||
collectAllArtistSongs(artists, starredArtistSongs::postValue);
|
||||
} else {
|
||||
starredArtistSongs.postValue(new ArrayList<>());
|
||||
}
|
||||
});
|
||||
return starredArtistSongs;
|
||||
}
|
||||
|
||||
private void collectAllArtistSongs(List<ArtistID3> artists, ArtistSongsCallback callback) {
|
||||
if (artists == null || artists.isEmpty()) {
|
||||
callback.onSongsCollected(new ArrayList<>());
|
||||
return;
|
||||
}
|
||||
|
||||
List<Child> allSongs = new ArrayList<>();
|
||||
AtomicInteger remainingArtists = new AtomicInteger(artists.size());
|
||||
|
||||
for (ArtistID3 artist : artists) {
|
||||
artistRepository.getArtistAllSongs(artist.getId(), new ArtistRepository.ArtistSongsCallback() {
|
||||
@Override
|
||||
public void onSongsCollected(List<Child> songs) {
|
||||
if (songs != null) {
|
||||
allSongs.addAll(songs);
|
||||
}
|
||||
|
||||
int remaining = remainingArtists.decrementAndGet();
|
||||
if (remaining == 0) {
|
||||
callback.onSongsCollected(allSongs);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private interface ArtistSongsCallback {
|
||||
void onSongsCollected(List<Child> songs);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue