Fix Album & Artist crash when no network
parent
e8549513bd
commit
5211890607
|
@ -38,6 +38,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.SortOrder
|
import code.name.monkey.retromusic.helper.SortOrder
|
||||||
import code.name.monkey.retromusic.model.Album
|
import code.name.monkey.retromusic.model.Album
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
@ -83,15 +84,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
startPostponedEnterTransition()
|
startPostponedEnterTransition()
|
||||||
showAlbum(it)
|
showAlbum(it)
|
||||||
})
|
})
|
||||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
|
||||||
loadArtistImage(it)
|
|
||||||
})
|
|
||||||
detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer {
|
|
||||||
moreAlbums(it)
|
|
||||||
})
|
|
||||||
detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, Observer {
|
|
||||||
aboutAlbum(it)
|
|
||||||
})
|
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
artistImage.setOnClickListener {
|
artistImage.setOnClickListener {
|
||||||
requireActivity().findNavController(R.id.fragment_container)
|
requireActivity().findNavController(R.id.fragment_container)
|
||||||
|
@ -172,8 +165,25 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
}
|
}
|
||||||
loadAlbumCover(album)
|
loadAlbumCover(album)
|
||||||
simpleSongAdapter.swapDataSet(album.songs)
|
simpleSongAdapter.swapDataSet(album.songs)
|
||||||
detailsViewModel.loadArtist(album.artistId)
|
detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer {
|
||||||
detailsViewModel.loadAlbumInfo(album)
|
loadArtistImage(it)
|
||||||
|
})
|
||||||
|
/*detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer {
|
||||||
|
moreAlbums(it)
|
||||||
|
})*/
|
||||||
|
detailsViewModel.getAlbumInfo(album).observe(viewLifecycleOwner, Observer { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> {
|
||||||
|
println("Loading")
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
println("Error")
|
||||||
|
}
|
||||||
|
is Result.Success -> {
|
||||||
|
aboutAlbum(result.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moreAlbums(albums: List<Album>) {
|
private fun moreAlbums(albums: List<Album>) {
|
||||||
|
|
|
@ -1,70 +1,44 @@
|
||||||
package code.name.monkey.retromusic.fragments.albums
|
package code.name.monkey.retromusic.fragments.albums
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.liveData
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
import code.name.monkey.retromusic.model.Album
|
import code.name.monkey.retromusic.model.Album
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class AlbumDetailsViewModel(
|
class AlbumDetailsViewModel(
|
||||||
private val realRepository: RealRepository,
|
private val realRepository: RealRepository,
|
||||||
private val albumId: Int
|
private val albumId: Int
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val _album = MutableLiveData<Album>()
|
|
||||||
private val _artist = MutableLiveData<Artist>()
|
|
||||||
private val _lastFmAlbum = MutableLiveData<LastFmAlbum>()
|
|
||||||
private val _moreAlbums = MutableLiveData<List<Album>>()
|
|
||||||
|
|
||||||
fun getAlbum(): LiveData<Album> = liveData(IO) {
|
fun getAlbum(): LiveData<Album> = liveData(IO) {
|
||||||
val album = realRepository.albumByIdAsync(albumId)
|
val album = realRepository.albumByIdAsync(albumId)
|
||||||
emit(album)
|
emit(album)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getArtist(): LiveData<Artist> = _artist
|
fun getArtist(artistId: Int): LiveData<Artist> = liveData(IO) {
|
||||||
fun getAlbumInfo(): LiveData<LastFmAlbum> = _lastFmAlbum
|
|
||||||
fun getMoreAlbums(): LiveData<List<Album>> = _moreAlbums
|
|
||||||
|
|
||||||
init {
|
|
||||||
loadAlbumDetails()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAlbum2() = liveData(context = viewModelScope.coroutineContext + IO) {
|
|
||||||
val album = realRepository.albumByIdAsync(albumId)
|
|
||||||
emit(album)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadAlbumDetails() = viewModelScope.launch(IO) {
|
|
||||||
val album = loadAlbumAsync.await() ?: throw NullPointerException("Album couldn't found")
|
|
||||||
_album.postValue(album)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadAlbumInfo(album: Album) = viewModelScope.launch(IO) {
|
|
||||||
val lastFmAlbum = realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-")
|
|
||||||
_lastFmAlbum.postValue(lastFmAlbum)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadArtist(artistId: Int) = viewModelScope.launch(IO) {
|
|
||||||
val artist = realRepository.artistById(artistId)
|
val artist = realRepository.artistById(artistId)
|
||||||
_artist.postValue(artist)
|
emit(artist)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAlbumInfo(album: Album): LiveData<Result<LastFmAlbum>> = liveData {
|
||||||
|
emit(Result.Loading)
|
||||||
|
emit( realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMoreAlbums(artist: Artist): LiveData<List<Album>> = liveData(IO) {
|
||||||
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
||||||
if (albums.isNotEmpty()) _moreAlbums.postValue(albums)
|
if (albums.isNotEmpty()) emit(albums)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val loadAlbumAsync: Deferred<Album?>
|
|
||||||
get() = viewModelScope.async(IO) {
|
|
||||||
realRepository.albumByIdAsync(albumId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
||||||
loadAlbumDetails()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {}
|
override fun onServiceConnected() {}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import code.name.monkey.retromusic.glide.ArtistGlideRequest
|
||||||
import code.name.monkey.retromusic.glide.SingleColorTarget
|
import code.name.monkey.retromusic.glide.SingleColorTarget
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmArtist
|
import code.name.monkey.retromusic.network.model.LastFmArtist
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
import code.name.monkey.retromusic.util.CustomArtistImageUtil
|
||||||
|
@ -77,9 +78,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
showArtist(it)
|
showArtist(it)
|
||||||
startPostponedEnterTransition()
|
startPostponedEnterTransition()
|
||||||
})
|
})
|
||||||
detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer {
|
|
||||||
artistInfo(it)
|
|
||||||
})
|
|
||||||
|
|
||||||
playAction.apply {
|
playAction.apply {
|
||||||
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
||||||
|
@ -140,6 +139,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
albumTitle.text = albumText
|
albumTitle.text = albumText
|
||||||
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
||||||
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadBiography(
|
private fun loadBiography(
|
||||||
|
@ -148,7 +148,14 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
||||||
) {
|
) {
|
||||||
biography = null
|
biography = null
|
||||||
this.lang = lang
|
this.lang = lang
|
||||||
detailsViewModel.loadBiography(name, lang, null)
|
detailsViewModel.getArtistInfo(name, lang, null)
|
||||||
|
.observe(viewLifecycleOwner, Observer { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> println("Loading")
|
||||||
|
is Result.Error -> println("Error")
|
||||||
|
is Result.Success -> artistInfo(result.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun artistInfo(lastFmArtist: LastFmArtist?) {
|
private fun artistInfo(lastFmArtist: LastFmArtist?) {
|
||||||
|
|
|
@ -1,51 +1,37 @@
|
||||||
package code.name.monkey.retromusic.fragments.artists
|
package code.name.monkey.retromusic.fragments.artists
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.liveData
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmArtist
|
import code.name.monkey.retromusic.network.model.LastFmArtist
|
||||||
import code.name.monkey.retromusic.repository.RealRepository
|
import code.name.monkey.retromusic.repository.RealRepository
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class ArtistDetailsViewModel(
|
class ArtistDetailsViewModel(
|
||||||
private val realRepository: RealRepository,
|
private val realRepository: RealRepository,
|
||||||
private val artistId: Int
|
private val artistId: Int
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val loadArtistDetailsAsync: Deferred<Artist?>
|
fun getArtist(): LiveData<Artist> = liveData(IO) {
|
||||||
get() = viewModelScope.async(Dispatchers.IO) {
|
val artist = realRepository.artistById(artistId)
|
||||||
realRepository.artistById(artistId)
|
emit(artist)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _artist = MutableLiveData<Artist>()
|
fun getArtistInfo(
|
||||||
private val _lastFmArtist = MutableLiveData<LastFmArtist>()
|
name: String,
|
||||||
|
lang: String?,
|
||||||
fun getArtist(): LiveData<Artist> = _artist
|
cache: String?
|
||||||
fun getArtistInfo(): LiveData<LastFmArtist> = _lastFmArtist
|
): LiveData<Result<LastFmArtist>> = liveData(IO) {
|
||||||
|
emit(Result.Loading)
|
||||||
init {
|
|
||||||
loadArtistDetails()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadArtistDetails() = viewModelScope.launch {
|
|
||||||
val artist =
|
|
||||||
loadArtistDetailsAsync.await() ?: throw NullPointerException("Album couldn't found")
|
|
||||||
_artist.postValue(artist)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadBiography(name: String, lang: String?, cache: String?) = viewModelScope.launch {
|
|
||||||
val info = realRepository.artistInfo(name, lang, cache)
|
val info = realRepository.artistInfo(name, lang, cache)
|
||||||
_lastFmArtist.postValue(info)
|
emit(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
||||||
loadArtistDetails()
|
getArtist()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {}
|
override fun onServiceConnected() {}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package code.name.monkey.retromusic
|
package code.name.monkey.retromusic.network
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic class that holds the network state
|
* Generic class that holds the network state
|
|
@ -21,6 +21,7 @@ import code.name.monkey.retromusic.db.*
|
||||||
import code.name.monkey.retromusic.model.*
|
import code.name.monkey.retromusic.model.*
|
||||||
import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist
|
import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist
|
||||||
import code.name.monkey.retromusic.network.LastFMService
|
import code.name.monkey.retromusic.network.LastFMService
|
||||||
|
import code.name.monkey.retromusic.network.Result
|
||||||
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
import code.name.monkey.retromusic.network.model.LastFmAlbum
|
||||||
import code.name.monkey.retromusic.network.model.LastFmArtist
|
import code.name.monkey.retromusic.network.model.LastFmArtist
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
@ -48,8 +49,8 @@ interface Repository {
|
||||||
suspend fun search(query: String?): MutableList<Any>
|
suspend fun search(query: String?): MutableList<Any>
|
||||||
suspend fun getPlaylistSongs(playlist: Playlist): List<Song>
|
suspend fun getPlaylistSongs(playlist: Playlist): List<Song>
|
||||||
suspend fun getGenre(genreId: Int): List<Song>
|
suspend fun getGenre(genreId: Int): List<Song>
|
||||||
suspend fun artistInfo(name: String, lang: String?, cache: String?): LastFmArtist
|
suspend fun artistInfo(name: String, lang: String?, cache: String?): Result<LastFmArtist>
|
||||||
suspend fun albumInfo(artist: String, album: String): LastFmAlbum
|
suspend fun albumInfo(artist: String, album: String): Result<LastFmAlbum>
|
||||||
suspend fun artistById(artistId: Int): Artist
|
suspend fun artistById(artistId: Int): Artist
|
||||||
suspend fun recentArtists(): List<Artist>
|
suspend fun recentArtists(): List<Artist>
|
||||||
suspend fun topArtists(): List<Artist>
|
suspend fun topArtists(): List<Artist>
|
||||||
|
@ -110,7 +111,9 @@ class RealRepository(
|
||||||
override suspend fun fetchAlbums(): List<Album> = albumRepository.albums()
|
override suspend fun fetchAlbums(): List<Album> = albumRepository.albums()
|
||||||
|
|
||||||
override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId)
|
override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId)
|
||||||
|
|
||||||
override fun albumById(albumId: Int): Album = albumRepository.album(albumId)
|
override fun albumById(albumId: Int): Album = albumRepository.album(albumId)
|
||||||
|
|
||||||
override suspend fun fetchArtists(): List<Artist> = artistRepository.artists()
|
override suspend fun fetchArtists(): List<Artist> = artistRepository.artists()
|
||||||
|
|
||||||
override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists()
|
override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists()
|
||||||
|
@ -147,17 +150,29 @@ class RealRepository(
|
||||||
name: String,
|
name: String,
|
||||||
lang: String?,
|
lang: String?,
|
||||||
cache: String?
|
cache: String?
|
||||||
): LastFmArtist = lastFMService.artistInfo(name, lang, cache)
|
): Result<LastFmArtist> {
|
||||||
|
return try {
|
||||||
|
Result.Success(lastFMService.artistInfo(name, lang, cache))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Result.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun albumInfo(
|
override suspend fun albumInfo(
|
||||||
artist: String,
|
artist: String,
|
||||||
album: String
|
album: String
|
||||||
): LastFmAlbum = lastFMService.albumInfo(artist, album)
|
): Result<LastFmAlbum> {
|
||||||
|
return try {
|
||||||
|
val lastFmAlbum = lastFMService.albumInfo(artist, album)
|
||||||
|
Result.Success(lastFmAlbum)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Result.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
override suspend fun homeSectionsFlow(): Flow<Result<List<Home>>> {
|
override suspend fun homeSectionsFlow(): Flow<Result<List<Home>>> {
|
||||||
val homes = MutableStateFlow<Result<List<Home>>>(value = Result.Loading)
|
val homes = MutableStateFlow<Result<List<Home>>>(value = Result.Loading)
|
||||||
println("homeSections:Loading")
|
|
||||||
val homeSections = mutableListOf<Home>()
|
val homeSections = mutableListOf<Home>()
|
||||||
val sections = listOf(
|
val sections = listOf(
|
||||||
topArtistsHome(),
|
topArtistsHome(),
|
||||||
|
|
Loading…
Reference in New Issue