Code refactor

This commit is contained in:
Hemanth S 2020-08-31 18:00:07 +05:30
parent c379342f6a
commit 6881e9a4c1
32 changed files with 411 additions and 173 deletions

View file

@ -68,7 +68,7 @@ favorite songs. No other music player has this feature.
We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features. We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features.
### FAQ ### FAQ
Please read the FAQ here: https://del.dog/RetroFaq Please read the FAQ here: https://del.dog/RetroFaq
In any case, you find or notice any bugs please report them by In any case, you find or notice any bugs please report them by

View file

@ -3,8 +3,8 @@ package code.name.monkey.retromusic
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import code.name.monkey.retromusic.db.BlackListStoreDao
import code.name.monkey.retromusic.db.BlackListStoreEntity import code.name.monkey.retromusic.db.BlackListStoreEntity
import code.name.monkey.retromusic.db.PlaylistDao
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.RetroDatabase import code.name.monkey.retromusic.db.RetroDatabase
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
@ -13,6 +13,7 @@ import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel
import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel
import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel
import code.name.monkey.retromusic.fragments.search.SearchViewModel import code.name.monkey.retromusic.fragments.search.SearchViewModel
import code.name.monkey.retromusic.fragments.songs.SongsViewModel
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.network.networkModule import code.name.monkey.retromusic.network.networkModule
import code.name.monkey.retromusic.repository.* import code.name.monkey.retromusic.repository.*
@ -35,7 +36,7 @@ private val roomModule = module {
super.onOpen(db) super.onOpen(db)
GlobalScope.launch(IO) { GlobalScope.launch(IO) {
FilePathUtil.blacklistFilePaths().map { FilePathUtil.blacklistFilePaths().map {
get<PlaylistDao>().insertBlacklistPath(BlackListStoreEntity(it)) get<BlackListStoreDao>().insertBlacklistPath(BlackListStoreEntity(it))
} }
} }
} }
@ -48,9 +49,17 @@ private val roomModule = module {
get<RetroDatabase>().playlistDao() get<RetroDatabase>().playlistDao()
} }
factory {
get<RetroDatabase>().blackListStore()
}
factory {
get<RetroDatabase>().playCountDao()
}
single { single {
RealRoomRepository(get()) RealRoomRepository(get(), get(), get())
} bind RoomPlaylistRepository::class } bind RoomRepository::class
} }
private val mainModule = module { private val mainModule = module {
single { single {
@ -143,6 +152,10 @@ private val viewModules = module {
viewModel { viewModel {
SearchViewModel(get()) SearchViewModel(get())
} }
viewModel {
SongsViewModel(get())
}
} }
val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule) val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule)

View file

@ -34,7 +34,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
} }
private val repository by inject<Repository>() private val repository by inject<Repository>()
private var blockRequestPermissions = false private var blockRequestPermissions = false
override fun createContentView(): View { override fun createContentView(): View {
@ -133,7 +132,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
if (id >= 0) { if (id >= 0) {
lifecycleScope.launch(Dispatchers.Main) { lifecycleScope.launch(Dispatchers.Main) {
val position = intent.getIntExtra("position", 0) val position = intent.getIntExtra("position", 0)
openQueue(repository.albumById(id).songs!!, position, true) openQueue(repository.albumByIdAsync(id).songs!!, position, true)
handled = true handled = true
} }
} }

View file

@ -4,17 +4,23 @@ import android.Manifest
import android.content.* import android.content.*
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.db.toPlayCount
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService.* import code.name.monkey.retromusic.service.MusicService.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener { abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>() private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
private val repository: RealRepository by inject()
private var serviceToken: MusicPlayerRemote.ServiceToken? = null private var serviceToken: MusicPlayerRemote.ServiceToken? = null
private var musicStateReceiver: MusicStateReceiver? = null private var musicStateReceiver: MusicStateReceiver? = null
private var receiverRegistered: Boolean = false private var receiverRegistered: Boolean = false
@ -93,6 +99,22 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventLis
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onPlayingMetaChanged() listener.onPlayingMetaChanged()
} }
lifecycleScope.launch(Dispatchers.IO) {
val entity = repository.songPresentInHistory(MusicPlayerRemote.currentSong)
if (entity != null) {
repository.updateHistorySong(MusicPlayerRemote.currentSong)
} else {
repository.addSongToHistory(MusicPlayerRemote.currentSong)
}
val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
if (songs.isNotEmpty()) {
repository.updateSongInPlayCount(songs.first().apply {
playCount += 1
})
} else {
repository.insertSongInPlayCount(MusicPlayerRemote.currentSong.toPlayCount())
}
}
} }
override fun onQueueChanged() { override fun onQueueChanged() {

View file

@ -73,7 +73,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
setContentView(createContentView()) setContentView(createContentView())
chooseFragmentForTheme() chooseFragmentForTheme()
setupSlidingUpPanel() setupSlidingUpPanel()
addMusicServiceEventListener(libraryViewModel)
setupBottomSheet() setupBottomSheet()

View file

@ -14,7 +14,6 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.animation.OvershootInterpolator import android.view.animation.OvershootInterpolator
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.ColorUtil
@ -182,11 +181,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
saveFab = findViewById(R.id.saveTags) saveFab = findViewById(R.id.saveTags)
getIntentExtras() getIntentExtras()
lifecycleScope.launchWhenCreated { songPaths = getSongPaths()
songPaths = getSongPaths() if (songPaths!!.isEmpty()) {
if (songPaths!!.isEmpty()) { finish()
finish()
}
} }
setUpViews() setUpViews()
} }
@ -258,7 +255,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
} }
} }
protected abstract suspend fun getSongPaths(): List<String> protected abstract fun getSongPaths(): List<String>
protected fun searchWebFor(vararg keys: String) { protected fun searchWebFor(vararg keys: String) {
val stringBuilder = StringBuilder() val stringBuilder = StringBuilder()

View file

@ -167,7 +167,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
) )
} }
override suspend fun getSongPaths(): List<String> { override fun getSongPaths(): List<String> {
val songs = repository.albumById(id).songs val songs = repository.albumById(id).songs
val paths = ArrayList<String>(songs!!.size) val paths = ArrayList<String>(songs!!.size)
for (song in songs) { for (song in songs) {

View file

@ -88,7 +88,7 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
writeValuesToFiles(fieldKeyValueMap, null) writeValuesToFiles(fieldKeyValueMap, null)
} }
override suspend fun getSongPaths(): List<String> { override fun getSongPaths(): List<String> {
val paths = ArrayList<String>(1) val paths = ArrayList<String>(1)
paths.add(songRepository.song(id).data) paths.add(songRepository.song(id).data)
return paths return paths

View file

@ -154,13 +154,11 @@ class PlaylistAdapter(
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
image?.apply { image?.apply {
val iconPadding = val iconPadding =
activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding) activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding)
setPadding(iconPadding, iconPadding, iconPadding, iconPadding) setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
} }
menu?.setOnClickListener { view -> menu?.setOnClickListener { view ->
val popupMenu = PopupMenu(activity, view) val popupMenu = PopupMenu(activity, view)
popupMenu.inflate(R.menu.menu_item_playlist) popupMenu.inflate(R.menu.menu_item_playlist)

View file

@ -0,0 +1,21 @@
package code.name.monkey.retromusic.db
import androidx.room.*
@Dao
interface BlackListStoreDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
@Delete
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
@Query("DELETE FROM BlackListStoreEntity")
suspend fun clearBlacklist()
@Query("SELECT * FROM BlackListStoreEntity")
fun blackListPaths(): List<BlackListStoreEntity>
}

View file

@ -0,0 +1,21 @@
package code.name.monkey.retromusic.db
import androidx.room.*
@Dao
interface PlayCountDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
@Update
fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
@Delete
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
@Query("SELECT * FROM PlayCountEntity WHERE id =:songId")
fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
@Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
fun playCountSongs(): List<PlayCountEntity>
}

View file

@ -63,30 +63,6 @@ interface PlaylistDao {
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId") @Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
fun favoritesSongs(playlistId: Int): List<SongEntity> fun favoritesSongs(playlistId: Int): List<SongEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
@Update
fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
@Delete
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
@Query("SELECT * FROM PlayCountEntity WHERE id =:songId")
fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
@Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
fun playCountSongs(): List<PlayCountEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
@Delete
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
@Query("DELETE FROM BlackListStoreEntity")
suspend fun clearBlacklist()
} }

View file

@ -5,9 +5,11 @@ import androidx.room.RoomDatabase
@Database( @Database(
entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class], entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class],
version = 18, version = 19,
exportSchema = false exportSchema = false
) )
abstract class RetroDatabase : RoomDatabase() { abstract class RetroDatabase : RoomDatabase() {
abstract fun playlistDao(): PlaylistDao abstract fun playlistDao(): PlaylistDao
abstract fun blackListStore(): BlackListStoreDao
abstract fun playCountDao(): PlayCountDao
} }

View file

@ -54,7 +54,7 @@ class AddToRetroPlaylist : BottomSheetDialogFragment() {
return materialDialog(R.string.add_playlist_title) return materialDialog(R.string.add_playlist_title)
.setItems(playlistNames.toTypedArray()) { _, which -> .setItems(playlistNames.toTypedArray()) { _, which ->
if (which == 0) { if (which == 0) {
CreateRetroPlaylist().show(requireActivity().supportFragmentManager, "Dialog") CreateRetroPlaylist.create(songs).show(requireActivity().supportFragmentManager, "Dialog")
} else { } else {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val songEntities = songs.toSongEntity(playlistEntities[which - 1]) val songEntities = songs.toSongEntity(playlistEntities[which - 1])

View file

@ -5,14 +5,18 @@ import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.Toast import android.widget.Toast
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.EXTRA_SONG
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType.Playlists import code.name.monkey.retromusic.fragments.ReloadType.Playlists
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
@ -25,8 +29,24 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class CreateRetroPlaylist : DialogFragment() { class CreateRetroPlaylist : DialogFragment() {
private val repository by inject<RealRepository>() private val repository by inject<RealRepository>()
private val libraryViewModel by sharedViewModel<LibraryViewModel>() private val libraryViewModel by sharedViewModel<LibraryViewModel>()
companion object {
fun create(song: Song): CreateRetroPlaylist {
val list = mutableListOf<Song>()
list.add(song)
return create(list)
}
fun create(songs: List<Song>): CreateRetroPlaylist {
return CreateRetroPlaylist().apply {
arguments = bundleOf(EXTRA_SONG to songs)
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null) val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null)
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
val playlistView: TextInputEditText = view.actionNewPlaylist val playlistView: TextInputEditText = view.actionNewPlaylist
val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer
return materialDialog(R.string.new_playlist_title) return materialDialog(R.string.new_playlist_title)
@ -38,13 +58,14 @@ class CreateRetroPlaylist : DialogFragment() {
if (!TextUtils.isEmpty(playlistName)) { if (!TextUtils.isEmpty(playlistName)) {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
if (repository.checkPlaylistExists(playlistName).isEmpty()) { if (repository.checkPlaylistExists(playlistName).isEmpty()) {
repository.createPlaylist(PlaylistEntity(playlistName)) val playlistId = repository.createPlaylist(PlaylistEntity(playlistName))
println(playlistId)
repository.insertSongs(songs.map { it.toSongEntity(playlistId.toInt()) })
libraryViewModel.forceReload(Playlists) libraryViewModel.forceReload(Playlists)
} else { } else {
Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT) Toast.makeText(requireContext(), "Playlist exists", Toast.LENGTH_SHORT)
.show() .show()
} }
} }
} else { } else {
playlistContainer.error = "Playlist is can't be empty" playlistContainer.error = "Playlist is can't be empty"

View file

@ -35,7 +35,6 @@ import code.name.monkey.retromusic.R
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
fun Int.ripAlpha(): Int { fun Int.ripAlpha(): Int {
@ -145,10 +144,6 @@ fun TextInputLayout.accentColor() {
isHintAnimationEnabled = true isHintAnimationEnabled = true
} }
fun TextInputEditText.accentColor() {
}
fun AppCompatImageView.accentColor(): Int { fun AppCompatImageView.accentColor(): Int {
return ThemeStore.accentColor(context) return ThemeStore.accentColor(context)
} }

View file

@ -0,0 +1,23 @@
package code.name.monkey.retromusic.fragments
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
open class CoroutineViewModel(
private val mainDispatcher: CoroutineDispatcher
) : ViewModel() {
private val job = Job()
protected val scope = CoroutineScope(job + mainDispatcher)
protected fun launch(
context: CoroutineContext = mainDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
) = scope.launch(context, start, block)
override fun onCleared() {
super.onCleared()
job.cancel()
}
}

View file

@ -85,7 +85,9 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
layoutManager = linearLayoutManager() layoutManager = linearLayoutManager()
} }
lifecycleScope.launch(IO) { lifecycleScope.launch(IO) {
val songs = repository.recentSongs() val songs = repository.playCountSongs().map {
it.toSong()
}
withContext(Main) { songAdapter.swapDataSet(songs) } withContext(Main) { songAdapter.swapDataSet(songs) }
} }
} }

View file

@ -5,9 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toPlayCount
import code.name.monkey.retromusic.fragments.ReloadType.* import code.name.monkey.retromusic.fragments.ReloadType.*
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
@ -51,7 +49,7 @@ class LibraryViewModel(
artists.value = loadArtists.await() artists.value = loadArtists.await()
playlists.value = loadPlaylists.await() playlists.value = loadPlaylists.await()
roomPlaylists.value = loadPlaylistsWithSongs.await() roomPlaylists.value = loadPlaylistsWithSongs.await()
genres.value = loadGenres.await() //genres.value = loadGenres.await()
} }
private val loadHome: Deferred<List<Home>> private val loadHome: Deferred<List<Home>>
@ -86,7 +84,6 @@ class LibraryViewModel(
fun forceReload(reloadType: ReloadType) = viewModelScope.launch { fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
println(reloadType)
when (reloadType) { when (reloadType) {
Songs -> songs.value = loadSongs.await() Songs -> songs.value = loadSongs.await()
Albums -> albums.value = loadAlbums.await() Albums -> albums.value = loadAlbums.await()
@ -121,22 +118,7 @@ class LibraryViewModel(
override fun onPlayingMetaChanged() { override fun onPlayingMetaChanged() {
println("onPlayingMetaChanged") println("onPlayingMetaChanged")
viewModelScope.launch(IO) {
val entity = repository.songPresentInHistory(MusicPlayerRemote.currentSong)
if (entity != null) {
repository.updateHistorySong(MusicPlayerRemote.currentSong)
} else {
repository.addSongToHistory(MusicPlayerRemote.currentSong)
}
val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
if (songs.isNotEmpty()) {
repository.updateSongInPlayCount(songs.first().apply {
playCount += playCount + 1
})
} else {
repository.insertSongInPlayCount(MusicPlayerRemote.currentSong.toPlayCount())
}
}
} }
override fun onPlayStateChanged() { override fun onPlayStateChanged() {

View file

@ -14,6 +14,7 @@ import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.EXTRA_ALBUM_ID
@ -32,6 +33,7 @@ import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.AlbumGlideRequest import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
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.helper.SortOrder import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
@ -77,9 +79,9 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
toolbar.title = null toolbar.title = null
postponeEnterTransition() postponeEnterTransition()
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer { detailsViewModel.getAlbum2().observe(viewLifecycleOwner, Observer {
showAlbum(it)
startPostponedEnterTransition() startPostponedEnterTransition()
showAlbum(it)
}) })
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer { detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
loadArtistImage(it) loadArtistImage(it)
@ -232,16 +234,18 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
.build() .build()
.dontAnimate() .dontAnimate()
.dontTransform() .dontTransform()
.into(object : RetroMusicColoredTarget(image) { .into(object : SingleColorTarget(image) {
override fun onColorReady(colors: MediaNotificationProcessor) { override fun onColorReady(color: Int) {
setColors(colors) setColors(color)
} }
}) })
} }
private fun setColors(color: MediaNotificationProcessor) { private fun setColors(color: Int) {
shuffleAction.applyColor(color.backgroundColor) val finalColor =
playAction.applyOutlineColor(color.backgroundColor) if (PreferenceUtil.isAdaptiveColor) color else ThemeStore.accentColor(requireContext())
shuffleAction.applyColor(finalColor)
playAction.applyOutlineColor(finalColor)
} }
override fun onAlbumClick(albumId: Int, view: View) { override fun onAlbumClick(albumId: Int, view: View) {

View file

@ -1,16 +1,13 @@
package code.name.monkey.retromusic.fragments.albums package code.name.monkey.retromusic.fragments.albums
import androidx.lifecycle.LiveData import androidx.lifecycle.*
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
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.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.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -24,7 +21,11 @@ class AlbumDetailsViewModel(
private val _lastFmAlbum = MutableLiveData<LastFmAlbum>() private val _lastFmAlbum = MutableLiveData<LastFmAlbum>()
private val _moreAlbums = MutableLiveData<List<Album>>() private val _moreAlbums = MutableLiveData<List<Album>>()
fun getAlbum(): LiveData<Album> = _album fun getAlbum(): LiveData<Album> = liveData(IO) {
val album = realRepository.albumByIdAsync(albumId)
emit(album)
}
fun getArtist(): LiveData<Artist> = _artist fun getArtist(): LiveData<Artist> = _artist
fun getAlbumInfo(): LiveData<LastFmAlbum> = _lastFmAlbum fun getAlbumInfo(): LiveData<LastFmAlbum> = _lastFmAlbum
fun getMoreAlbums(): LiveData<List<Album>> = _moreAlbums fun getMoreAlbums(): LiveData<List<Album>> = _moreAlbums
@ -33,17 +34,22 @@ class AlbumDetailsViewModel(
loadAlbumDetails() loadAlbumDetails()
} }
private fun loadAlbumDetails() = viewModelScope.launch { 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") val album = loadAlbumAsync.await() ?: throw NullPointerException("Album couldn't found")
_album.postValue(album) _album.postValue(album)
} }
fun loadAlbumInfo(album: Album) = viewModelScope.launch(Dispatchers.IO) { fun loadAlbumInfo(album: Album) = viewModelScope.launch(IO) {
val lastFmAlbum = realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-") val lastFmAlbum = realRepository.albumInfo(album.artistName ?: "-", album.title ?: "-")
_lastFmAlbum.postValue(lastFmAlbum) _lastFmAlbum.postValue(lastFmAlbum)
} }
fun loadArtist(artistId: Int) = viewModelScope.launch(Dispatchers.IO) { fun loadArtist(artistId: Int) = viewModelScope.launch(IO) {
val artist = realRepository.artistById(artistId) val artist = realRepository.artistById(artistId)
_artist.postValue(artist) _artist.postValue(artist)
@ -53,8 +59,8 @@ class AlbumDetailsViewModel(
} }
private val loadAlbumAsync: Deferred<Album?> private val loadAlbumAsync: Deferred<Album?>
get() = viewModelScope.async(Dispatchers.IO) { get() = viewModelScope.async(IO) {
realRepository.albumById(albumId) realRepository.albumByIdAsync(albumId)
} }
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {

View file

@ -17,6 +17,7 @@ import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
@ -28,15 +29,15 @@ import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget 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.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
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.fragment_artist_content.* import kotlinx.android.synthetic.main.fragment_artist_content.*
import kotlinx.android.synthetic.main.fragment_artist_details.* import kotlinx.android.synthetic.main.fragment_artist_details.*
@ -181,19 +182,22 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
private fun loadArtistImage(artist: Artist) { private fun loadArtistImage(artist: Artist) {
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist) ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
.generatePalette(requireContext()).build() .generatePalette(requireContext()).build()
.dontAnimate().into(object : RetroMusicColoredTarget(image) { .dontAnimate()
override fun onColorReady(colors: MediaNotificationProcessor) { .into(object : SingleColorTarget(image) {
startPostponedEnterTransition() override fun onColorReady(color: Int) {
setColors(colors) setColors(color)
} }
}) })
} }
private fun setColors(color: MediaNotificationProcessor) { private fun setColors(color: Int) {
shuffleAction.applyColor(color.backgroundColor) val finalColor = if (PreferenceUtil.isAdaptiveColor) color
playAction.applyOutlineColor(color.backgroundColor) else ThemeStore.accentColor(requireContext())
shuffleAction.applyColor(finalColor)
playAction.applyOutlineColor(finalColor)
} }
override fun onAlbumClick(albumId: Int, view: View) { override fun onAlbumClick(albumId: Int, view: View) {
findNavController().navigate( findNavController().navigate(
R.id.albumDetailsFragment, R.id.albumDetailsFragment,

View file

@ -35,7 +35,6 @@ import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.* import code.name.monkey.retromusic.util.*
import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.* import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -75,7 +74,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
R.id.action_add_to_playlist -> { R.id.action_add_to_playlist -> {
lifecycleScope.launch(IO) { lifecycleScope.launch(IO) {
val playlists = get<RealRepository>().roomPlaylists() val playlists = get<RealRepository>().roomPlaylists()
withContext(Dispatchers.Main) { withContext(Main) {
AddToRetroPlaylist.create(playlists, song) AddToRetroPlaylist.create(playlists, song)
.show(childFragmentManager, "ADD_PLAYLIST") .show(childFragmentManager, "ADD_PLAYLIST")
} }
@ -87,7 +86,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
return true return true
} }
R.id.action_save_playing_queue -> { R.id.action_save_playing_queue -> {
CreatePlaylistDialog.create(ArrayList(MusicPlayerRemote.playingQueue)) CreateRetroPlaylist.create(ArrayList(MusicPlayerRemote.playingQueue))
.show(childFragmentManager, "ADD_TO_PLAYLIST") .show(childFragmentManager, "ADD_TO_PLAYLIST")
return true return true
} }
@ -163,15 +162,17 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
protected open fun toggleFavorite(song: Song) { protected open fun toggleFavorite(song: Song) {
lifecycleScope.launch(IO) { lifecycleScope.launch(IO) {
val playlist: PlaylistEntity = repository.favoritePlaylist().first() val playlist: PlaylistEntity? = repository.favoritePlaylist()
val songEntity = song.toSongEntity(playlist.playListId) if (playlist != null) {
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty() val songEntity = song.toSongEntity(playlist.playListId)
if (isFavorite) { val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
repository.removeSongFromPlaylist(songEntity) if (isFavorite) {
} else { repository.removeSongFromPlaylist(songEntity)
repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) } else {
libraryViewModel.forceReload(Playlists) repository.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
}
} }
libraryViewModel.forceReload(Playlists)
requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED)) requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
} }
} }
@ -198,13 +199,18 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
fun updateIsFavorite() { fun updateIsFavorite() {
lifecycleScope.launch(IO) { lifecycleScope.launch(IO) {
val playlist: PlaylistEntity = repository.favoritePlaylist().first() val playlist: PlaylistEntity = repository.favoritePlaylist()
val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId) val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
val isFavorite = repository.isFavoriteSong(song).isNotEmpty() val isFavorite = repository.isFavoriteSong(song).isNotEmpty()
withContext(Dispatchers.Main) { withContext(Main) {
val icon = if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border val icon = if (isFavorite) R.drawable.ic_favorite
else R.drawable.ic_favorite_border
val drawable = val drawable =
RetroUtil.getTintedVectorDrawable(requireContext(), icon, toolbarIconColor()) RetroUtil.getTintedVectorDrawable(
requireContext(),
icon,
toolbarIconColor()
)
if (playerToolbar() != null) { if (playerToolbar() != null) {
playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite) playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite)
?.setIcon(drawable)?.title = ?.setIcon(drawable)?.title =

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.fragments.home
import android.app.ActivityOptions import android.app.ActivityOptions
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics
import android.view.View import android.view.View
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
@ -50,13 +49,6 @@ class HomeFragment :
private val repository by inject<Repository>() private val repository by inject<Repository>()
private val libraryViewModel: LibraryViewModel by sharedViewModel() private val libraryViewModel: LibraryViewModel by sharedViewModel()
private val displayMetrics: DisplayMetrics
get() {
val display = mainActivity.windowManager.defaultDisplay
val metrics = DisplayMetrics()
display.getMetrics(metrics)
return metrics
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)

View file

@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toSongs
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.repository.RealRepository
@ -33,7 +34,7 @@ class PlaylistDetailsViewModel(
private fun loadPlaylistSongs(playlist: PlaylistWithSongs) = private fun loadPlaylistSongs(playlist: PlaylistWithSongs) =
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val songs: List<Song> = realRepository.playlistSongs(playlist) val songs: List<Song> = playlist.songs.toSongs()
withContext(Main) { _playListSongs.postValue(songs) } withContext(Main) { _playListSongs.postValue(songs) }
} }

View file

@ -15,7 +15,6 @@ import code.name.monkey.retromusic.util.PreferenceUtil
class SongsFragment : class SongsFragment :
AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>(), AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>(),
MainActivityFragmentCallbacks { MainActivityFragmentCallbacks {
override fun handleBackPress(): Boolean { override fun handleBackPress(): Boolean {
return false return false
} }

View file

@ -0,0 +1,31 @@
package code.name.monkey.retromusic.fragments.songs
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.SongRepository
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
class SongsViewModel(
private val songRepository: SongRepository
) : ViewModel() {
init {
update()
}
private val songsData = MutableLiveData<List<Song>>().apply { value = mutableListOf() }
fun getSongList(): LiveData<List<Song>> {
return songsData
}
fun update() {
viewModelScope.launch(IO) {
val songs = songRepository.songs()
songsData.postValue(songs)
}
}
}

View file

@ -0,0 +1,39 @@
package code.name.monkey.retromusic.glide
import android.graphics.drawable.Drawable
import android.widget.ImageView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.util.ColorUtil
import com.bumptech.glide.request.animation.GlideAnimation
abstract class SingleColorTarget(view: ImageView) : BitmapPaletteTarget(view) {
protected val defaultFooterColor: Int
get() = ATHUtil.resolveColor(view.context, R.attr.colorControlNormal)
abstract fun onColorReady(color: Int)
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable)
onColorReady(defaultFooterColor)
}
override fun onResourceReady(
resource: BitmapPaletteWrapper?,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
) {
super.onResourceReady(resource, glideAnimation)
resource?.let {
onColorReady(
ColorUtil.getColor(
it.palette,
ATHUtil.resolveColor(view.context, R.attr.colorPrimary)
)
)
}
}
}

View file

@ -35,9 +35,11 @@ interface Repository {
fun artistsFlow(): Flow<Result<List<Artist>>> fun artistsFlow(): Flow<Result<List<Artist>>>
fun playlistsFlow(): Flow<Result<List<Playlist>>> fun playlistsFlow(): Flow<Result<List<Playlist>>>
fun genresFlow(): Flow<Result<List<Genre>>> fun genresFlow(): Flow<Result<List<Genre>>>
fun historySong(): LiveData<List<HistoryEntity>>
fun favorites(): LiveData<List<SongEntity>>
suspend fun allAlbums(): List<Album> suspend fun allAlbums(): List<Album>
suspend fun albumById(albumId: Int): Album suspend fun albumByIdAsync(albumId: Int): Album
fun albumById(albumId: Int): Album
suspend fun allSongs(): List<Song> suspend fun allSongs(): List<Song>
suspend fun allArtists(): List<Artist> suspend fun allArtists(): List<Artist>
suspend fun albumArtists(): List<Artist> suspend fun albumArtists(): List<Artist>
@ -75,7 +77,7 @@ interface Repository {
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
suspend fun removeSongFromPlaylist(songEntity: SongEntity) suspend fun removeSongFromPlaylist(songEntity: SongEntity)
suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>)
suspend fun favoritePlaylist(): List<PlaylistEntity> suspend fun favoritePlaylist(): PlaylistEntity
suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity>
suspend fun addSongToHistory(currentSong: Song) suspend fun addSongToHistory(currentSong: Song)
suspend fun songPresentInHistory(currentSong: Song): HistoryEntity? suspend fun songPresentInHistory(currentSong: Song): HistoryEntity?
@ -88,8 +90,7 @@ interface Repository {
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
suspend fun playCountSongs(): List<PlayCountEntity> suspend fun playCountSongs(): List<PlayCountEntity>
fun historySong(): LiveData<List<HistoryEntity>> suspend fun blackListPaths(): List<BlackListStoreEntity>
fun favorites(): LiveData<List<SongEntity>>
} }
class RealRepository( class RealRepository(
@ -103,13 +104,13 @@ class RealRepository(
private val playlistRepository: PlaylistRepository, private val playlistRepository: PlaylistRepository,
private val searchRepository: RealSearchRepository, private val searchRepository: RealSearchRepository,
private val topPlayedRepository: TopPlayedRepository, private val topPlayedRepository: TopPlayedRepository,
private val roomRepository: RoomPlaylistRepository private val roomRepository: RoomRepository
) : Repository { ) : Repository {
override suspend fun allAlbums(): List<Album> = albumRepository.albums() override suspend fun allAlbums(): List<Album> = albumRepository.albums()
override suspend fun albumById(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 suspend fun allArtists(): List<Artist> = artistRepository.artists() override suspend fun allArtists(): List<Artist> = artistRepository.artists()
override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists() override suspend fun albumArtists(): List<Artist> = artistRepository.albumArtists()
@ -130,28 +131,24 @@ class RealRepository(
override suspend fun allSongs(): List<Song> = songRepository.songs() override suspend fun allSongs(): List<Song> = songRepository.songs()
override suspend fun search(query: String?): MutableList<Any> = override suspend fun search(query: String?): MutableList<Any> =
searchRepository.searchAll(context, query) searchRepository.searchAll(context, query)
override suspend fun getPlaylistSongs(playlist: Playlist): List<Song> { override suspend fun getPlaylistSongs(playlist: Playlist): List<Song> =
return if (playlist is AbsCustomPlaylist) { if (playlist is AbsCustomPlaylist) {
playlist.songs() playlist.songs()
} else { } else {
PlaylistSongsLoader.getPlaylistSongList(context, playlist.id) PlaylistSongsLoader.getPlaylistSongList(context, playlist.id)
} }
}
override suspend fun getGenre(genreId: Int): List<Song> = genreRepository.songs(genreId) override suspend fun getGenre(genreId: Int): List<Song> = genreRepository.songs(genreId)
override suspend fun artistInfo( override suspend fun artistInfo(
name: String, name: String,
lang: String?, lang: String?,
cache: String? cache: String?
): LastFmArtist = lastFMService.artistInfo(name, lang, cache) ): LastFmArtist = lastFMService.artistInfo(name, lang, cache)
override suspend fun albumInfo( override suspend fun albumInfo(
artist: String, artist: String,
album: String album: String
@ -193,8 +190,8 @@ class RealRepository(
topAlbumsHome(), topAlbumsHome(),
recentArtistsHome(), recentArtistsHome(),
recentAlbumsHome(), recentAlbumsHome(),
favoritePlaylistHome(), favoritePlaylistHome()
genresHome() // genresHome()
) )
for (section in sections) { for (section in sections) {
if (section.arrayList.isNotEmpty()) { if (section.arrayList.isNotEmpty()) {
@ -211,11 +208,10 @@ class RealRepository(
override suspend fun playlistWithSongs(): List<PlaylistWithSongs> = override suspend fun playlistWithSongs(): List<PlaylistWithSongs> =
roomRepository.playlistWithSongs() roomRepository.playlistWithSongs()
override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song> { override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song> =
return playlistWithSongs.songs.map { playlistWithSongs.songs.map {
it.toSong() it.toSong()
} }
}
override suspend fun insertSongs(songs: List<SongEntity>) = override suspend fun insertSongs(songs: List<SongEntity>) =
roomRepository.insertSongs(songs) roomRepository.insertSongs(songs)
@ -243,7 +239,7 @@ class RealRepository(
override suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) = override suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) =
roomRepository.deleteSongsFromPlaylist(playlists) roomRepository.deleteSongsFromPlaylist(playlists)
override suspend fun favoritePlaylist(): List<PlaylistEntity> = override suspend fun favoritePlaylist(): PlaylistEntity =
roomRepository.favoritePlaylist(context.getString(R.string.favorites)) roomRepository.favoritePlaylist(context.getString(R.string.favorites))
override suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> = override suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> =
@ -280,6 +276,9 @@ class RealRepository(
override suspend fun playCountSongs(): List<PlayCountEntity> = override suspend fun playCountSongs(): List<PlayCountEntity> =
roomRepository.playCountSongs() roomRepository.playCountSongs()
override suspend fun blackListPaths(): List<BlackListStoreEntity> =
roomRepository.blackListPaths()
override fun historySong(): LiveData<List<HistoryEntity>> = override fun historySong(): LiveData<List<HistoryEntity>> =
roomRepository.historySongs() roomRepository.historySongs()
@ -328,7 +327,6 @@ class RealRepository(
val songs = favoritePlaylistSongs().map { val songs = favoritePlaylistSongs().map {
it.toSong() it.toSong()
} }
println(songs.size)
return Home(songs, FAVOURITES, R.string.favorites) return Home(songs, FAVOURITES, R.string.favorites)
} }

View file

@ -6,7 +6,10 @@ import code.name.monkey.retromusic.db.*
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
interface RoomPlaylistRepository { interface RoomRepository {
fun historySongs(): LiveData<List<HistoryEntity>>
fun favoritePlaylistLiveData(favorite: String): LiveData<List<SongEntity>>
fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
suspend fun checkPlaylistExists(playlistName: String): List<PlaylistEntity> suspend fun checkPlaylistExists(playlistName: String): List<PlaylistEntity>
suspend fun playlists(): List<PlaylistEntity> suspend fun playlists(): List<PlaylistEntity>
@ -17,7 +20,7 @@ interface RoomPlaylistRepository {
suspend fun renamePlaylistEntity(playlistId: Int, name: String) suspend fun renamePlaylistEntity(playlistId: Int, name: String)
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>)
suspend fun favoritePlaylist(favorite: String): List<PlaylistEntity> suspend fun favoritePlaylist(favorite: String): PlaylistEntity
suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity>
suspend fun removeSongFromPlaylist(songEntity: SongEntity) suspend fun removeSongFromPlaylist(songEntity: SongEntity)
suspend fun addSongToHistory(currentSong: Song) suspend fun addSongToHistory(currentSong: Song)
@ -29,13 +32,18 @@ interface RoomPlaylistRepository {
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
suspend fun playCountSongs(): List<PlayCountEntity> suspend fun playCountSongs(): List<PlayCountEntity>
fun historySongs(): LiveData<List<HistoryEntity>> suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
fun favoritePlaylistLiveData(favorite: String): LiveData<List<SongEntity>> suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
suspend fun clearBlacklist()
suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity)
suspend fun blackListPaths(): List<BlackListStoreEntity>
} }
class RealRoomRepository( class RealRoomRepository(
private val playlistDao: PlaylistDao private val playlistDao: PlaylistDao,
) : RoomPlaylistRepository { private val blackListStoreDao: BlackListStoreDao,
private val playCountDao: PlayCountDao
) : RoomRepository {
@WorkerThread @WorkerThread
override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long =
playlistDao.createPlaylist(playlistEntity) playlistDao.createPlaylist(playlistEntity)
@ -51,20 +59,18 @@ class RealRoomRepository(
override suspend fun playlistWithSongs(): List<PlaylistWithSongs> = override suspend fun playlistWithSongs(): List<PlaylistWithSongs> =
playlistDao.playlistsWithSongs() playlistDao.playlistsWithSongs()
@WorkerThread /* val tempList = ArrayList<SongEntity>(songs)
override suspend fun insertSongs(songs: List<SongEntity>) {
/* val tempList = ArrayList<SongEntity>(songs)
val existingSongs = songs.map { val existingSongs = songs.map {
playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId) playlistDao.checkSongExistsWithPlaylistName(it.playlistCreatorName, it.songId)
}.first() }.first()
println("Existing ${existingSongs.size}") println("Existing ${existingSongs.size}")
tempList.removeAll(existingSongs)*/ tempList.removeAll(existingSongs)*/
@WorkerThread
override suspend fun insertSongs(songs: List<SongEntity>) =
playlistDao.insertSongsToPlaylist(songs) playlistDao.insertSongsToPlaylist(songs)
}
override suspend fun getSongs(playlistEntity: PlaylistEntity): List<SongEntity> { override suspend fun getSongs(playlistEntity: PlaylistEntity): List<SongEntity> =
return playlistDao.songsFromPlaylist(playlistEntity.playListId) playlistDao.songsFromPlaylist(playlistEntity.playListId)
}
override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) = override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) =
playlistDao.deletePlaylists(playlistEntities) playlistDao.deletePlaylists(playlistEntities)
@ -75,14 +81,21 @@ class RealRoomRepository(
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) = override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) =
playlistDao.deleteSongsInPlaylist(songs) playlistDao.deleteSongsInPlaylist(songs)
override suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) { override suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) =
playlists.forEach { playlists.forEach {
playlistDao.deleteSongsInPlaylist(it.playListId) playlistDao.deleteSongsInPlaylist(it.playListId)
} }
override suspend fun favoritePlaylist(favorite: String): PlaylistEntity {
val playlist: PlaylistEntity? = playlistDao.isPlaylistExists(favorite).firstOrNull()
return if (playlist != null) {
playlist
} else {
createPlaylist(PlaylistEntity(favorite))
playlistDao.isPlaylistExists(favorite).first()
}
} }
override suspend fun favoritePlaylist(favorite: String): List<PlaylistEntity> =
playlistDao.isPlaylistExists(favorite)
override suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> = override suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> =
playlistDao.isSongExistsInPlaylist( playlistDao.isSongExistsInPlaylist(
@ -111,25 +124,41 @@ class RealRoomRepository(
playlistDao.isPlaylistExists(favorite).first().playListId playlistDao.isPlaylistExists(favorite).first().playListId
) )
override suspend fun favoritePlaylistSongs(favorite: String): List<SongEntity> { override suspend fun favoritePlaylistSongs(favorite: String): List<SongEntity> =
return if (playlistDao.isPlaylistExists(favorite).isNotEmpty()) if (playlistDao.isPlaylistExists(favorite).isNotEmpty())
playlistDao.favoritesSongs( playlistDao.favoritesSongs(
playlistDao.isPlaylistExists(favorite).first().playListId playlistDao.isPlaylistExists(favorite).first().playListId
) else emptyList() ) else emptyList()
}
override suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) = override suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) =
playlistDao.insertSongInPlayCount(playCountEntity) playCountDao.insertSongInPlayCount(playCountEntity)
override suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) = override suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) =
playlistDao.updateSongInPlayCount(playCountEntity) playCountDao.updateSongInPlayCount(playCountEntity)
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) = override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
playlistDao.deleteSongInPlayCount(playCountEntity) playCountDao.deleteSongInPlayCount(playCountEntity)
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> = override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> =
playlistDao.checkSongExistInPlayCount(songId) playCountDao.checkSongExistInPlayCount(songId)
override suspend fun playCountSongs(): List<PlayCountEntity> = override suspend fun playCountSongs(): List<PlayCountEntity> =
playlistDao.playCountSongs() playCountDao.playCountSongs()
override fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity) =
blackListStoreDao.insertBlacklistPath(blackListStoreEntity)
override suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>) =
blackListStoreDao.insertBlacklistPath(blackListStoreEntities)
override suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity) =
blackListStoreDao.insertBlacklistPath(blackListStoreEntity)
override suspend fun blackListPaths(): List<BlackListStoreEntity> =
blackListStoreDao.blackListPaths()
override suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) =
blackListStoreDao.deleteBlacklistPath(blackListStoreEntity)
override suspend fun clearBlacklist() = blackListStoreDao.clearBlacklist()
} }

View file

@ -0,0 +1,58 @@
package code.name.monkey.retromusic.util;
import android.graphics.Bitmap;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.palette.graphics.Palette;
import java.util.Collections;
import java.util.Comparator;
public class ColorUtil {
@Nullable
public static Palette generatePalette(Bitmap bitmap) {
if (bitmap == null) return null;
return Palette.from(bitmap).generate();
}
@ColorInt
public static int getColor(@Nullable Palette palette, int fallback) {
if (palette != null) {
if (palette.getVibrantSwatch() != null) {
return palette.getVibrantSwatch().getRgb();
} else if (palette.getMutedSwatch() != null) {
return palette.getMutedSwatch().getRgb();
} else if (palette.getDarkVibrantSwatch() != null) {
return palette.getDarkVibrantSwatch().getRgb();
} else if (palette.getDarkMutedSwatch() != null) {
return palette.getDarkMutedSwatch().getRgb();
} else if (palette.getLightVibrantSwatch() != null) {
return palette.getLightVibrantSwatch().getRgb();
} else if (palette.getLightMutedSwatch() != null) {
return palette.getLightMutedSwatch().getRgb();
} else if (!palette.getSwatches().isEmpty()) {
return Collections.max(palette.getSwatches(), SwatchComparator.getInstance()).getRgb();
}
}
return fallback;
}
private static class SwatchComparator implements Comparator<Palette.Swatch> {
private static SwatchComparator sInstance;
static SwatchComparator getInstance() {
if (sInstance == null) {
sInstance = new SwatchComparator();
}
return sInstance;
}
@Override
public int compare(Palette.Swatch lhs, Palette.Swatch rhs) {
return lhs.getPopulation() - rhs.getPopulation();
}
}
}

View file

@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx2048M org.gradle.jvmargs=-Xmx4608m
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.parallel=true org.gradle.parallel=true
jvmArgs='-Xmx2048m' jvmArgs='-Xmx2048m'