diff --git a/app/build.gradle b/app/build.gradle
index d928d6935..4725b1d89 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -161,7 +161,6 @@ dependencies {
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r'
-
implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0'
implementation 'com.github.kabouzeid:recyclerview-fastscroll:1.9-kmod'
implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3'
@@ -169,7 +168,7 @@ dependencies {
implementation 'com.r0adkll:slidableactivity:2.1.0'
implementation 'com.heinrichreimersoftware:material-intro:1.6'
implementation 'com.github.dhaval2404:imagepicker:1.7.1'
-
+ implementation 'org.jsoup:jsoup:1.11.1'
implementation 'me.zhanghai.android.fastscroll:library:1.1.0'
implementation 'me.jorgecastillo:androidcolorx:0.2.0'
diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml
index 7f4fe30c3..c45bc56ae 100644
--- a/app/src/debug/res/values/styles.xml
+++ b/app/src/debug/res/values/styles.xml
@@ -60,20 +60,23 @@
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt
index aae0ed48e..fe513d50d 100644
--- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt
@@ -14,7 +14,7 @@ import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel
import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel
import code.name.monkey.retromusic.fragments.search.SearchViewModel
import code.name.monkey.retromusic.model.Genre
-import code.name.monkey.retromusic.network.networkModule
+import code.name.monkey.retromusic.network.*
import code.name.monkey.retromusic.repository.*
import code.name.monkey.retromusic.util.FilePathUtil
import kotlinx.coroutines.Dispatchers.IO
@@ -25,6 +25,28 @@ import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.bind
import org.koin.dsl.module
+val networkModule = module {
+
+ factory {
+ provideDefaultCache()
+ }
+ factory {
+ provideOkHttp(get(), get())
+ }
+ single {
+ provideLastFmRetrofit(get())
+ }
+ single {
+ provideDeezerRest(get())
+ }
+ single {
+ provideLastFmRest(get())
+ }
+ single {
+ provideLyrics(get())
+ }
+}
+
private val roomModule = module {
single {
@@ -56,8 +78,12 @@ private val roomModule = module {
get().playCountDao()
}
+ factory {
+ get().historyDao()
+ }
+
single {
- RealRoomRepository(get(), get(), get())
+ RealRoomRepository(get(), get(), get(), get())
} bind RoomRepository::class
}
private val mainModule = module {
@@ -68,7 +94,20 @@ private val mainModule = module {
}
private val dataModule = module {
single {
- RealRepository(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
+ RealRepository(
+ get(),
+ get(),
+ get(),
+ get(),
+ get(),
+ get(),
+ get(),
+ get(),
+ get(),
+ get(),
+ get(),
+ get()
+ )
} bind Repository::class
single {
diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt
index 039aa9fe2..8cd40e974 100644
--- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt
@@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.dialogs.LyricsDialog
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
@@ -90,14 +91,15 @@ class AlbumCoverPagerAdapter(
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
albumCover = view.findViewById(R.id.player_image)
albumCover.setOnClickListener {
- showLyricsDialog()
+ LyricsDialog().show(childFragmentManager, "LyricsDialog")
+ //showLyricsDialog()
}
return view
}
private fun showLyricsDialog() {
lifecycleScope.launch(Dispatchers.IO) {
- val data = MusicUtil.getLyrics(song)
+ val data: String = MusicUtil.getLyrics(song) ?: "No lyrics found"
withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder(
requireContext(),
diff --git a/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt
new file mode 100644
index 000000000..5ea731a2f
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/db/HistoryDao.kt
@@ -0,0 +1,26 @@
+package code.name.monkey.retromusic.db
+
+import androidx.lifecycle.LiveData
+import androidx.room.*
+
+@Dao
+interface HistoryDao {
+ companion object {
+ private const val HISTORY_LIMIT = 100
+ }
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insertSongInHistory(historyEntity: HistoryEntity)
+
+ @Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
+ suspend fun isSongPresentInHistory(songId: Int): HistoryEntity?
+
+ @Update
+ suspend fun updateHistorySong(historyEntity: HistoryEntity)
+
+ @Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
+ fun historySongs(): List
+
+ @Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC LIMIT $HISTORY_LIMIT")
+ fun observableHistorySongs(): LiveData>
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt
index c3b7f8016..0cfe2b8aa 100644
--- a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt
@@ -45,17 +45,6 @@ interface PlaylistDao {
@Delete
suspend fun deleteSongsInPlaylist(songs: List)
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- suspend fun insertSongInHistory(historyEntity: HistoryEntity)
-
- @Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
- suspend fun isSongPresentInHistory(songId: Int): HistoryEntity?
-
- @Update
- suspend fun updateHistorySong(historyEntity: HistoryEntity)
-
- @Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC")
- fun historySongs(): LiveData>
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongsLiveData(playlistId: Int): LiveData>
diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt
index 02cb65863..e9b99cca3 100644
--- a/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/db/RetroDatabase.kt
@@ -12,4 +12,5 @@ abstract class RetroDatabase : RoomDatabase() {
abstract fun playlistDao(): PlaylistDao
abstract fun blackListStore(): BlackListStoreDao
abstract fun playCountDao(): PlayCountDao
+ abstract fun historyDao(): HistoryDao
}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt
new file mode 100644
index 000000000..d1f5f0221
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/LyricsDialog.kt
@@ -0,0 +1,51 @@
+package code.name.monkey.retromusic.dialogs
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.DialogFragment
+import androidx.lifecycle.lifecycleScope
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.helper.MusicPlayerRemote
+import code.name.monkey.retromusic.network.Result
+import code.name.monkey.retromusic.repository.Repository
+import kotlinx.android.synthetic.main.lyrics_dialog.*
+import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.Dispatchers.Main
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import org.koin.android.ext.android.inject
+
+class LyricsDialog : DialogFragment() {
+ override fun getTheme(): Int {
+ return R.style.MaterialAlertDialogTheme
+ }
+
+ private val repository by inject()
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.lyrics_dialog, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ lifecycleScope.launch(IO) {
+ val result: Result = repository.lyrics(
+ MusicPlayerRemote.currentSong.artistName,
+ MusicPlayerRemote.currentSong.title
+ )
+ withContext(Main) {
+ when (result) {
+ is Result.Error -> println("Error")
+ is Result.Loading -> println("Loading")
+ is Result.Success -> lyricsText.text = result.data
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt
index d2c383101..c56a40459 100644
--- a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt
@@ -8,7 +8,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
fun DialogFragment.materialDialog(title: Int): MaterialAlertDialogBuilder {
return MaterialAlertDialogBuilder(
requireContext(),
- R.style.ThemeOverlay_MaterialComponents_Dialog_Alert
+ R.style.MaterialAlertDialogTheme
).setTitle(title)
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt
index c71bcceb9..6c7230a52 100644
--- a/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/fragments/DetailListFragment.kt
@@ -104,7 +104,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
adapter = songAdapter
layoutManager = linearLayoutManager()
}
- repository.historySong().observe(viewLifecycleOwner, Observer {
+ repository.observableHistorySongs().observe(viewLifecycleOwner, Observer {
val songs = it.map { historyEntity -> historyEntity.toSong() }
songAdapter.swapDataSet(songs)
})
diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt
index c047f6c35..055727485 100644
--- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt
@@ -38,6 +38,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.model.Album
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.repository.RealRepository
import code.name.monkey.retromusic.util.MusicUtil
@@ -83,15 +84,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
startPostponedEnterTransition()
showAlbum(it)
})
- detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
- loadArtistImage(it)
- })
- detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer {
- moreAlbums(it)
- })
- detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, Observer {
- aboutAlbum(it)
- })
+
setupRecyclerView()
artistImage.setOnClickListener {
requireActivity().findNavController(R.id.fragment_container)
@@ -172,8 +165,23 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
loadAlbumCover(album)
simpleSongAdapter.swapDataSet(album.songs)
- detailsViewModel.loadArtist(album.artistId)
- detailsViewModel.loadAlbumInfo(album)
+ detailsViewModel.getArtist(album.artistId).observe(viewLifecycleOwner, Observer {
+ loadArtistImage(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) {
@@ -214,6 +222,9 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
private fun loadArtistImage(artist: Artist) {
+ detailsViewModel.getMoreAlbums(artist).observe(viewLifecycleOwner, Observer {
+ moreAlbums(it)
+ })
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
.forceDownload(PreferenceUtil.isAllowedToDownloadMetadata())
.generatePalette(requireContext())
diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt
index f698f882b..3311046e4 100644
--- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt
@@ -1,70 +1,44 @@
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.model.Album
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.repository.RealRepository
-import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.async
-import kotlinx.coroutines.launch
class AlbumDetailsViewModel(
private val realRepository: RealRepository,
private val albumId: Int
) : ViewModel(), MusicServiceEventListener {
- private val _album = MutableLiveData()
- private val _artist = MutableLiveData()
- private val _lastFmAlbum = MutableLiveData()
- private val _moreAlbums = MutableLiveData>()
-
fun getAlbum(): LiveData = liveData(IO) {
val album = realRepository.albumByIdAsync(albumId)
emit(album)
}
- fun getArtist(): LiveData = _artist
- fun getAlbumInfo(): LiveData = _lastFmAlbum
- fun getMoreAlbums(): LiveData> = _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) {
+ fun getArtist(artistId: Int): LiveData = liveData(IO) {
val artist = realRepository.artistById(artistId)
- _artist.postValue(artist)
-
- artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
- if (albums.isNotEmpty()) _moreAlbums.postValue(albums)
- }
+ emit(artist)
}
- private val loadAlbumAsync: Deferred
- get() = viewModelScope.async(IO) {
- realRepository.albumByIdAsync(albumId)
+ fun getAlbumInfo(album: Album): LiveData> = liveData {
+ emit(Result.Loading)
+ emit( realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-"))
+ }
+
+ fun getMoreAlbums(artist: Artist): LiveData> = liveData(IO) {
+ artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
+ if (albums.isNotEmpty()) emit(albums)
}
+ }
override fun onMediaStoreChanged() {
- loadAlbumDetails()
+
}
override fun onServiceConnected() {}
diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt
index f9db60bf6..877def068 100644
--- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsFragment.kt
@@ -18,6 +18,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore
+import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
@@ -32,6 +33,7 @@ import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.SingleColorTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
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.repository.RealRepository
import code.name.monkey.retromusic.util.CustomArtistImageUtil
@@ -77,9 +79,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
showArtist(it)
startPostponedEnterTransition()
})
- detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer {
- artistInfo(it)
- })
+
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
@@ -140,6 +140,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
albumTitle.text = albumText
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
artist.albums?.let { albumAdapter.swapDataSet(it) }
+
}
private fun loadBiography(
@@ -148,7 +149,14 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
) {
biography = null
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?) {
@@ -201,7 +209,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
override fun onAlbumClick(albumId: Int, view: View) {
findNavController().navigate(
R.id.albumDetailsFragment,
- bundleOf("extra_album_id" to albumId),
+ bundleOf(EXTRA_ALBUM_ID to albumId),
null,
FragmentNavigatorExtras(
view to getString(R.string.transition_album_art)
diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt
index f2ee5fe67..890397359 100644
--- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistDetailsViewModel.kt
@@ -1,51 +1,37 @@
package code.name.monkey.retromusic.fragments.artists
import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
+import androidx.lifecycle.liveData
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
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.repository.RealRepository
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.async
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.Dispatchers.IO
class ArtistDetailsViewModel(
private val realRepository: RealRepository,
private val artistId: Int
) : ViewModel(), MusicServiceEventListener {
- private val loadArtistDetailsAsync: Deferred
- get() = viewModelScope.async(Dispatchers.IO) {
- realRepository.artistById(artistId)
- }
-
- private val _artist = MutableLiveData()
- private val _lastFmArtist = MutableLiveData()
-
- fun getArtist(): LiveData = _artist
- fun getArtistInfo(): LiveData = _lastFmArtist
-
- init {
- loadArtistDetails()
+ fun getArtist(): LiveData = liveData(IO) {
+ val artist = realRepository.artistById(artistId)
+ emit(artist)
}
- 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 {
+ fun getArtistInfo(
+ name: String,
+ lang: String?,
+ cache: String?
+ ): LiveData> = liveData(IO) {
+ emit(Result.Loading)
val info = realRepository.artistInfo(name, lang, cache)
- _lastFmArtist.postValue(info)
+ emit(info)
}
override fun onMediaStoreChanged() {
- loadArtistDetails()
+ getArtist()
}
override fun onServiceConnected() {}
diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt
index eecff933c..506810236 100644
--- a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchViewModel.kt
@@ -6,9 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import code.name.monkey.retromusic.repository.RealRepository
import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
class SearchViewModel(private val realRepository: RealRepository) : ViewModel() {
private val results = MutableLiveData>()
@@ -17,6 +15,6 @@ class SearchViewModel(private val realRepository: RealRepository) : ViewModel()
fun search(query: String?) = viewModelScope.launch(IO) {
val result = realRepository.search(query)
- withContext(Main) { results.postValue(result) }
+ results.value = result
}
}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt
index 398916cec..43d23120d 100644
--- a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageLoader.kt
@@ -15,8 +15,8 @@
package code.name.monkey.retromusic.glide.artistimage
import android.content.Context
-import code.name.monkey.retromusic.deezer.Data
-import code.name.monkey.retromusic.deezer.DeezerApiService
+import code.name.monkey.retromusic.model.Data
+import code.name.monkey.retromusic.network.DeezerService
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Priority
@@ -38,7 +38,7 @@ class ArtistImage(val artistName: String)
class ArtistImageFetcher(
private val context: Context,
- private val deezerApiService: DeezerApiService,
+ private val deezerService: DeezerService,
val model: ArtistImage,
val urlLoader: ModelLoader,
val width: Int,
@@ -66,7 +66,7 @@ class ArtistImageFetcher(
PreferenceUtil.isAllowedToDownloadMetadata()
) {
val artists = model.artistName.split(",")
- val response = deezerApiService.getArtistImage(artists[0]).execute()
+ val response = deezerService.getArtistImage(artists[0]).execute()
if (!response.isSuccessful) {
throw IOException("Request failed with code: " + response.code())
@@ -106,7 +106,7 @@ class ArtistImageFetcher(
class ArtistImageLoader(
val context: Context,
- private val deezerApiService: DeezerApiService,
+ private val deezerService: DeezerService,
private val urlLoader: ModelLoader
) : StreamModelLoader {
@@ -115,7 +115,7 @@ class ArtistImageLoader(
width: Int,
height: Int
): DataFetcher {
- return ArtistImageFetcher(context, deezerApiService, model, urlLoader, width, height)
+ return ArtistImageFetcher(context, deezerService, model, urlLoader, width, height)
}
}
@@ -123,7 +123,7 @@ class Factory(
val context: Context
) : ModelLoaderFactory {
- private var deezerApiService: DeezerApiService
+ private var deezerService: DeezerService
private var okHttpFactory: OkHttpUrlLoader.Factory
init {
@@ -134,8 +134,8 @@ class Factory(
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.build()
)
- deezerApiService = DeezerApiService.invoke(
- DeezerApiService.createDefaultOkHttpClient(context)
+ deezerService = DeezerService.invoke(
+ DeezerService.createDefaultOkHttpClient(context)
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
@@ -156,7 +156,7 @@ class Factory(
): ModelLoader {
return ArtistImageLoader(
context!!,
- deezerApiService,
+ deezerService,
okHttpFactory.build(context, factories)
)
}
diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt b/app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt
similarity index 94%
rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt
rename to app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt
index b029ab535..929a9d131 100644
--- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerResponse.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/model/DeezerResponse.kt
@@ -1,4 +1,4 @@
-package code.name.monkey.retromusic.deezer
+package code.name.monkey.retromusic.model
import com.google.gson.annotations.SerializedName
diff --git a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt b/app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt
similarity index 92%
rename from app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt
rename to app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt
index fd107234c..1ea0c16ce 100644
--- a/app/src/main/java/code/name/monkey/retromusic/deezer/DeezerApiService.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/network/DeezerService.kt
@@ -1,6 +1,7 @@
-package code.name.monkey.retromusic.deezer
+package code.name.monkey.retromusic.network
import android.content.Context
+import code.name.monkey.retromusic.model.DeezerResponse
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.OkHttpClient
@@ -16,7 +17,7 @@ import java.util.*
private const val BASE_QUERY_ARTIST = "search/artist"
private const val BASE_URL = "https://api.deezer.com/"
-interface DeezerApiService {
+interface DeezerService {
@GET("$BASE_QUERY_ARTIST&limit=1")
fun getArtistImage(
@@ -26,7 +27,7 @@ interface DeezerApiService {
companion object {
operator fun invoke(
client: okhttp3.Call.Factory
- ): DeezerApiService {
+ ): DeezerService {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.callFactory(client)
diff --git a/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt b/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt
new file mode 100644
index 000000000..0a0e04904
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/network/LyricsService.kt
@@ -0,0 +1,12 @@
+package code.name.monkey.retromusic.network
+
+import retrofit2.http.GET
+import retrofit2.http.Headers
+import retrofit2.http.Query
+
+interface LyricsRestService {
+
+ @Headers("Cache-Control: public")
+ @GET("/lyrics")
+ suspend fun getLyrics(@Query("artist") artist: String, @Query("title") title: String): String
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/Result.kt b/app/src/main/java/code/name/monkey/retromusic/network/Result.kt
similarity index 94%
rename from app/src/main/java/code/name/monkey/retromusic/Result.kt
rename to app/src/main/java/code/name/monkey/retromusic/network/Result.kt
index 4c241a143..05211fd39 100644
--- a/app/src/main/java/code/name/monkey/retromusic/Result.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/network/Result.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package code.name.monkey.retromusic
+package code.name.monkey.retromusic.network
/**
* Generic class that holds the network state
diff --git a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt
index affb38230..df75072d3 100644
--- a/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/network/RetrofitClient.kt
@@ -1,67 +1,19 @@
package code.name.monkey.retromusic.network
+import android.content.Context
import code.name.monkey.retromusic.App
-import code.name.monkey.retromusic.Constants.AUDIO_SCROBBLER_URL
+import code.name.monkey.retromusic.BuildConfig
+import code.name.monkey.retromusic.network.conversion.LyricsConverterFactory
import com.google.gson.Gson
import okhttp3.Cache
-import okhttp3.ConnectionPool
import okhttp3.Interceptor
import okhttp3.OkHttpClient
-import org.koin.dsl.module
+import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.util.concurrent.TimeUnit
-private const val TIMEOUT: Long = 700
-
-val networkModule = module {
- factory {
- provideHttpClient(get(), get())
- }
- factory {
- provideCacheControlInterceptor()
- }
- factory {
- provideDefaultCache()
- }
- factory {
- provideLastFmService(get())
- }
- single {
- providerRetrofit(get())
- }
-}
-
-fun provideLastFmService(retrofit: Retrofit): LastFMService =
- retrofit.create(LastFMService::class.java)
-
-fun providerRetrofit(okHttpClient: OkHttpClient.Builder): Retrofit = Retrofit.Builder()
- .baseUrl(AUDIO_SCROBBLER_URL)
- .callFactory(okHttpClient.build())
- .addConverterFactory(GsonConverterFactory.create(Gson()))
- .build()
-
-fun provideHttpClient(
- cache: Cache,
- interceptor: Interceptor
-): OkHttpClient.Builder = OkHttpClient.Builder()
- .connectionPool(ConnectionPool(0, 1, TimeUnit.NANOSECONDS))
- .retryOnConnectionFailure(true)
- .connectTimeout(TIMEOUT, TimeUnit.MINUTES)
- .writeTimeout(TIMEOUT, TimeUnit.MINUTES)
- .readTimeout(TIMEOUT, TimeUnit.MINUTES)
- .cache(cache)
- .addInterceptor(interceptor)
-
-
-fun provideCacheControlInterceptor(): Interceptor = Interceptor { chain: Interceptor.Chain ->
- val modifiedRequest = chain.request().newBuilder()
- .addHeader("Cache-Control", "max-age=31536000, max-stale=31536000")
- .build()
- chain.proceed(modifiedRequest)
-}
-
fun provideDefaultCache(): Cache? {
val cacheDir = File(App.getContext().cacheDir.absolutePath, "/okhttp-lastfm/")
if (cacheDir.mkdirs() || cacheDir.isDirectory) {
@@ -69,3 +21,63 @@ fun provideDefaultCache(): Cache? {
}
return null
}
+
+fun logInterceptor(): Interceptor {
+ val loggingInterceptor = HttpLoggingInterceptor()
+ if (BuildConfig.DEBUG) {
+ loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
+ } else {
+ // disable retrofit log on release
+ loggingInterceptor.level = HttpLoggingInterceptor.Level.NONE
+ }
+ return loggingInterceptor
+}
+
+fun headerInterceptor(context: Context): Interceptor {
+ return Interceptor {
+ val original = it.request()
+ val request = original.newBuilder()
+ .header("User-Agent", context.packageName)
+ .addHeader("Content-Type", "application/json; charset=utf-8")
+ .method(original.method(), original.body())
+ .build()
+ it.proceed(request)
+ }
+}
+
+fun provideOkHttp(context: Context, cache: Cache): OkHttpClient {
+ return OkHttpClient.Builder()
+ .addNetworkInterceptor(logInterceptor())
+ .addInterceptor(headerInterceptor(context))
+ .connectTimeout(1, TimeUnit.SECONDS)
+ .readTimeout(1, TimeUnit.SECONDS)
+ .cache(cache)
+ .build()
+}
+
+fun provideLastFmRetrofit(client: OkHttpClient): Retrofit {
+ return Retrofit.Builder()
+ .baseUrl("https://ws.audioscrobbler.com/2.0/")
+ .addConverterFactory(GsonConverterFactory.create(Gson()))
+ .callFactory { request -> client.newCall(request) }
+ .build()
+}
+
+fun provideLastFmRest(retrofit: Retrofit): LastFMService {
+ return retrofit.create(LastFMService::class.java)
+}
+
+fun provideDeezerRest(retrofit: Retrofit): DeezerService {
+ val newBuilder = retrofit.newBuilder()
+ .baseUrl("https://api.deezer.com/")
+ .build()
+ return newBuilder.create(DeezerService::class.java)
+}
+
+fun provideLyrics(retrofit: Retrofit): LyricsRestService {
+ val newBuilder = retrofit.newBuilder()
+ .baseUrl("https://makeitpersonal.co")
+ .addConverterFactory(LyricsConverterFactory())
+ .build()
+ return newBuilder.create(LyricsRestService::class.java)
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt
new file mode 100644
index 000000000..474e81c99
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 Naman Dwivedi.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ */
+package code.name.monkey.retromusic.network.conversion
+
+import okhttp3.MediaType
+import okhttp3.RequestBody
+import okhttp3.ResponseBody
+import retrofit2.Converter
+import retrofit2.Retrofit
+import java.lang.reflect.Type
+
+class LyricsConverterFactory : Converter.Factory() {
+
+ override fun responseBodyConverter(
+ type: Type?,
+ annotations: Array?,
+ retrofit: Retrofit?
+ ): Converter? {
+ return if (String::class.java == type) {
+ Converter { value -> value.string() }
+ } else null
+ }
+
+ override fun requestBodyConverter(
+ type: Type?,
+ parameterAnnotations: Array?,
+ methodAnnotations: Array?,
+ retrofit: Retrofit?
+ ): Converter<*, RequestBody>? {
+
+ return if (String::class.java == type) {
+ Converter { value -> RequestBody.create(MEDIA_TYPE, value) }
+ } else null
+ }
+
+ companion object {
+ private val MEDIA_TYPE = MediaType.parse("text/plain")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt
index 06478f490..32ca1ffe1 100644
--- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt
@@ -21,6 +21,9 @@ import code.name.monkey.retromusic.db.*
import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist
import code.name.monkey.retromusic.network.LastFMService
+import code.name.monkey.retromusic.network.LyricsRestService
+import code.name.monkey.retromusic.network.Result
+import code.name.monkey.retromusic.network.Result.*
import code.name.monkey.retromusic.network.model.LastFmAlbum
import code.name.monkey.retromusic.network.model.LastFmArtist
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -35,11 +38,12 @@ interface Repository {
fun artistsFlow(): Flow>>
fun playlistsFlow(): Flow>>
fun genresFlow(): Flow>>
- fun historySong(): LiveData>
+ fun historySong(): List
fun favorites(): LiveData>
+ fun observableHistorySongs(): LiveData>
+ fun albumById(albumId: Int): Album
suspend fun fetchAlbums(): List
suspend fun albumByIdAsync(albumId: Int): Album
- fun albumById(albumId: Int): Album
suspend fun allSongs(): List
suspend fun fetchArtists(): List
suspend fun albumArtists(): List
@@ -48,8 +52,8 @@ interface Repository {
suspend fun search(query: String?): MutableList
suspend fun getPlaylistSongs(playlist: Playlist): List
suspend fun getGenre(genreId: Int): List
- suspend fun artistInfo(name: String, lang: String?, cache: String?): LastFmArtist
- suspend fun albumInfo(artist: String, album: String): LastFmAlbum
+ suspend fun artistInfo(name: String, lang: String?, cache: String?): Result
+ suspend fun albumInfo(artist: String, album: String): Result
suspend fun artistById(artistId: Int): Artist
suspend fun recentArtists(): List
suspend fun topArtists(): List
@@ -91,6 +95,7 @@ interface Repository {
suspend fun checkSongExistInPlayCount(songId: Int): List
suspend fun playCountSongs(): List
suspend fun blackListPaths(): List
+ suspend fun lyrics(artist: String, title: String): Result
}
class RealRepository(
@@ -104,13 +109,22 @@ class RealRepository(
private val playlistRepository: PlaylistRepository,
private val searchRepository: RealSearchRepository,
private val topPlayedRepository: TopPlayedRepository,
- private val roomRepository: RoomRepository
+ private val roomRepository: RoomRepository,
+ private val lyricsRestService: LyricsRestService
) : Repository {
+ override suspend fun lyrics(artist: String, title: String): Result = try {
+ Success(lyricsRestService.getLyrics(artist, title))
+ } catch (e: Exception) {
+ Error
+ }
+
override suspend fun fetchAlbums(): List = albumRepository.albums()
override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId)
+
override fun albumById(albumId: Int): Album = albumRepository.album(albumId)
+
override suspend fun fetchArtists(): List = artistRepository.artists()
override suspend fun albumArtists(): List = artistRepository.albumArtists()
@@ -147,17 +161,31 @@ class RealRepository(
name: String,
lang: String?,
cache: String?
- ): LastFmArtist = lastFMService.artistInfo(name, lang, cache)
+ ): Result {
+ return try {
+ Success(lastFMService.artistInfo(name, lang, cache))
+ } catch (e: Exception) {
+ println(e)
+ Error
+ }
+ }
override suspend fun albumInfo(
artist: String,
album: String
- ): LastFmAlbum = lastFMService.albumInfo(artist, album)
+ ): Result {
+ return try {
+ val lastFmAlbum = lastFMService.albumInfo(artist, album)
+ Success(lastFmAlbum)
+ } catch (e: Exception) {
+ println(e)
+ Error
+ }
+ }
@ExperimentalCoroutinesApi
override suspend fun homeSectionsFlow(): Flow>> {
- val homes = MutableStateFlow>>(value = Result.Loading)
- println("homeSections:Loading")
+ val homes = MutableStateFlow>>(value = Loading)
val homeSections = mutableListOf()
val sections = listOf(
topArtistsHome(),
@@ -175,9 +203,9 @@ class RealRepository(
}
}
if (homeSections.isEmpty()) {
- homes.value = Result.Error
+ homes.value = Error
} else {
- homes.value = Result.Success(homeSections)
+ homes.value = Success(homeSections)
}
return homes
}
@@ -279,7 +307,10 @@ class RealRepository(
override suspend fun blackListPaths(): List =
roomRepository.blackListPaths()
- override fun historySong(): LiveData> =
+ override fun observableHistorySongs(): LiveData> =
+ roomRepository.observableHistorySongs()
+
+ override fun historySong(): List =
roomRepository.historySongs()
override fun favorites(): LiveData> =
@@ -331,52 +362,52 @@ class RealRepository(
}
override fun songsFlow(): Flow>> = flow {
- emit(Result.Loading)
+ emit(Loading)
val data = songRepository.songs()
if (data.isEmpty()) {
- emit(Result.Error)
+ emit(Error)
} else {
- emit(Result.Success(data))
+ emit(Success(data))
}
}
override fun albumsFlow(): Flow>> = flow {
- emit(Result.Loading)
+ emit(Loading)
val data = albumRepository.albums()
if (data.isEmpty()) {
- emit(Result.Error)
+ emit(Error)
} else {
- emit(Result.Success(data))
+ emit(Success(data))
}
}
override fun artistsFlow(): Flow>> = flow {
- emit(Result.Loading)
+ emit(Loading)
val data = artistRepository.artists()
if (data.isEmpty()) {
- emit(Result.Error)
+ emit(Error)
} else {
- emit(Result.Success(data))
+ emit(Success(data))
}
}
override fun playlistsFlow(): Flow>> = flow {
- emit(Result.Loading)
+ emit(Loading)
val data = playlistRepository.playlists()
if (data.isEmpty()) {
- emit(Result.Error)
+ emit(Error)
} else {
- emit(Result.Success(data))
+ emit(Success(data))
}
}
override fun genresFlow(): Flow>> = flow {
- emit(Result.Loading)
+ emit(Loading)
val data = genreRepository.genres()
if (data.isEmpty()) {
- emit(Result.Error)
+ emit(Error)
} else {
- emit(Result.Success(data))
+ emit(Success(data))
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt
index a523883d4..8267b36ae 100644
--- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt
@@ -7,9 +7,10 @@ import code.name.monkey.retromusic.model.Song
interface RoomRepository {
- fun historySongs(): LiveData>
+ fun historySongs(): List
fun favoritePlaylistLiveData(favorite: String): LiveData>
fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
+ fun observableHistorySongs(): LiveData>
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
suspend fun checkPlaylistExists(playlistName: String): List
suspend fun playlists(): List
@@ -42,7 +43,8 @@ interface RoomRepository {
class RealRoomRepository(
private val playlistDao: PlaylistDao,
private val blackListStoreDao: BlackListStoreDao,
- private val playCountDao: PlayCountDao
+ private val playCountDao: PlayCountDao,
+ private val historyDao: HistoryDao
) : RoomRepository {
@WorkerThread
override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long =
@@ -59,12 +61,6 @@ class RealRoomRepository(
override suspend fun playlistWithSongs(): List =
playlistDao.playlistsWithSongs()
- /* val tempList = ArrayList(songs)
- val existingSongs = songs.map {
- playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId)
- }.first()
- println("Existing ${existingSongs.size}")
- tempList.removeAll(existingSongs)*/
@WorkerThread
override suspend fun insertSongs(songs: List) =
playlistDao.insertSongsToPlaylist(songs)
@@ -96,7 +92,6 @@ class RealRoomRepository(
}
}
-
override suspend fun isFavoriteSong(songEntity: SongEntity): List =
playlistDao.isSongExistsInPlaylist(
songEntity.playlistCreatorId,
@@ -107,17 +102,18 @@ class RealRoomRepository(
playlistDao.removeSongFromPlaylist(songEntity.playlistCreatorId, songEntity.id)
override suspend fun addSongToHistory(currentSong: Song) =
- playlistDao.insertSongInHistory(currentSong.toHistoryEntity(System.currentTimeMillis()))
+ historyDao.insertSongInHistory(currentSong.toHistoryEntity(System.currentTimeMillis()))
override suspend fun songPresentInHistory(song: Song): HistoryEntity? =
- playlistDao.isSongPresentInHistory(song.id)
+ historyDao.isSongPresentInHistory(song.id)
override suspend fun updateHistorySong(song: Song) =
- playlistDao.updateHistorySong(song.toHistoryEntity(System.currentTimeMillis()))
+ historyDao.updateHistorySong(song.toHistoryEntity(System.currentTimeMillis()))
- override fun historySongs(): LiveData> {
- return playlistDao.historySongs()
- }
+ override fun observableHistorySongs(): LiveData> =
+ historyDao.observableHistorySongs()
+
+ override fun historySongs(): List = historyDao.historySongs()
override fun favoritePlaylistLiveData(favorite: String): LiveData> =
playlistDao.favoritesSongsLiveData(
diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt
index a3bbf7766..8659a0ba9 100644
--- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt
+++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt
@@ -111,7 +111,7 @@ object MusicUtil : KoinComponent {
}
fun getLyrics(song: Song): String? {
- var lyrics: String? = null
+ var lyrics: String? = "No lyrics found"
val file = File(song.data)
try {
lyrics = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS)
@@ -151,7 +151,7 @@ object MusicUtil : KoinComponent {
}
false
}
- if (files != null && files.size > 0) {
+ if (files != null && files.isNotEmpty()) {
for (f in files) {
try {
val newLyrics =
diff --git a/app/src/main/res/layout/item_contributor.xml b/app/src/main/res/layout/item_contributor.xml
index ef73b468b..d7ba88328 100644
--- a/app/src/main/res/layout/item_contributor.xml
+++ b/app/src/main/res/layout/item_contributor.xml
@@ -32,6 +32,7 @@
android:scaleType="centerCrop"
app:civ_border="false"
app:civ_shadow="false"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:retroCornerSize="21dp"
diff --git a/app/src/main/res/layout/lyrics_dialog.xml b/app/src/main/res/layout/lyrics_dialog.xml
new file mode 100644
index 000000000..27fa8a957
--- /dev/null
+++ b/app/src/main/res/layout/lyrics_dialog.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index c0eb21c3e..3c37bd749 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -215,14 +215,16 @@