Merge branch 'room-playlist' of https://github.com/h4h13/RetroMusicPlayer into room-playlist
This commit is contained in:
commit
54b037c0c1
32 changed files with 1032 additions and 158 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
@ -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() {
|
||||||
|
|
|
@ -73,7 +73,6 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
setContentView(createContentView())
|
setContentView(createContentView())
|
||||||
chooseFragmentForTheme()
|
chooseFragmentForTheme()
|
||||||
setupSlidingUpPanel()
|
setupSlidingUpPanel()
|
||||||
addMusicServiceEventListener(libraryViewModel)
|
|
||||||
|
|
||||||
setupBottomSheet()
|
setupBottomSheet()
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
}
|
|
@ -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>
|
||||||
|
}
|
|
@ -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()
|
|
||||||
}
|
}
|
|
@ -10,4 +10,6 @@ import androidx.room.RoomDatabase
|
||||||
)
|
)
|
||||||
abstract class RetroDatabase : RoomDatabase() {
|
abstract class RetroDatabase : RoomDatabase() {
|
||||||
abstract fun playlistDao(): PlaylistDao
|
abstract fun playlistDao(): PlaylistDao
|
||||||
|
abstract fun blackListStore(): BlackListStoreDao
|
||||||
|
abstract fun playCountDao(): PlayCountDao
|
||||||
}
|
}
|
|
@ -51,7 +51,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])
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import androidx.lifecycle.viewModelScope
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
import code.name.monkey.retromusic.db.SongEntity
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
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.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||||
|
@ -88,7 +87,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()
|
||||||
|
@ -123,22 +121,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() {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package code.name.monkey.retromusic.fragments.albums
|
package code.name.monkey.retromusic.fragments.albums
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.*
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
|
@ -12,7 +12,11 @@ import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
||||||
import code.name.monkey.retromusic.extensions.findActivityNavController
|
import code.name.monkey.retromusic.extensions.findActivityNavController
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder.AlbumSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
|
||||||
|
|
||||||
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
||||||
AlbumClickListener {
|
AlbumClickListener {
|
||||||
|
@ -103,6 +107,181 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
|
||||||
|
if (RetroUtil.isLandscape()) {
|
||||||
|
gridSizeItem.setTitle(R.string.action_grid_size_land)
|
||||||
|
}
|
||||||
|
setUpGridSizeMenu(gridSizeItem.subMenu)
|
||||||
|
val layoutItem = menu.findItem(R.id.action_layout_type)
|
||||||
|
setupLayoutMenu(layoutItem.subMenu)
|
||||||
|
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpSortOrderMenu(
|
||||||
|
sortOrderMenu: SubMenu
|
||||||
|
) {
|
||||||
|
val currentSortOrder: String? = getSortOrder()
|
||||||
|
sortOrderMenu.clear()
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_asc,
|
||||||
|
0,
|
||||||
|
R.string.sort_order_a_z
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_A_Z)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_desc,
|
||||||
|
1,
|
||||||
|
R.string.sort_order_z_a
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_Z_A)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_artist,
|
||||||
|
2,
|
||||||
|
R.string.sort_order_artist
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_ARTIST)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_album_sort_order_year,
|
||||||
|
3,
|
||||||
|
R.string.sort_order_year
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_YEAR)
|
||||||
|
|
||||||
|
sortOrderMenu.setGroupCheckable(0, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLayoutMenu(
|
||||||
|
subMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (itemLayoutRes()) {
|
||||||
|
R.layout.item_card -> subMenu.findItem(R.id.action_layout_card).isChecked = true
|
||||||
|
R.layout.item_grid -> subMenu.findItem(R.id.action_layout_normal).isChecked = true
|
||||||
|
R.layout.item_card_color ->
|
||||||
|
subMenu.findItem(R.id.action_layout_colored_card).isChecked = true
|
||||||
|
R.layout.item_grid_circle ->
|
||||||
|
subMenu.findItem(R.id.action_layout_circular).isChecked = true
|
||||||
|
R.layout.image -> subMenu.findItem(R.id.action_layout_image).isChecked = true
|
||||||
|
R.layout.item_image_gradient ->
|
||||||
|
subMenu.findItem(R.id.action_layout_gradient_image).isChecked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpGridSizeMenu(
|
||||||
|
gridSizeMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (getGridSize()) {
|
||||||
|
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked =
|
||||||
|
true
|
||||||
|
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
|
||||||
|
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
|
||||||
|
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
|
||||||
|
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
|
||||||
|
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
|
||||||
|
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
|
||||||
|
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
|
||||||
|
}
|
||||||
|
val gridSize: Int = maxGridSize
|
||||||
|
if (gridSize < 8) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 7) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 6) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 5) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 4) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 3) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (handleGridSizeMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleLayoutResType(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleSortOrderMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSortOrderMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var sortOrder: String? = null
|
||||||
|
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_album_sort_order_asc -> sortOrder = AlbumSortOrder.ALBUM_A_Z
|
||||||
|
R.id.action_album_sort_order_desc -> sortOrder = AlbumSortOrder.ALBUM_Z_A
|
||||||
|
R.id.action_album_sort_order_artist -> sortOrder = AlbumSortOrder.ALBUM_ARTIST
|
||||||
|
R.id.action_album_sort_order_year -> sortOrder = AlbumSortOrder.ALBUM_YEAR
|
||||||
|
}
|
||||||
|
if (sortOrder != null) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveSortOrder(sortOrder)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLayoutResType(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var layoutRes = -1
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_layout_normal -> layoutRes = R.layout.item_grid
|
||||||
|
R.id.action_layout_card -> layoutRes = R.layout.item_card
|
||||||
|
R.id.action_layout_colored_card -> layoutRes = R.layout.item_card_color
|
||||||
|
R.id.action_layout_circular -> layoutRes = R.layout.item_grid_circle
|
||||||
|
R.id.action_layout_image -> layoutRes = R.layout.image
|
||||||
|
R.id.action_layout_gradient_image -> layoutRes = R.layout.item_image_gradient
|
||||||
|
}
|
||||||
|
if (layoutRes != -1) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveLayoutRes(layoutRes)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleGridSizeMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var gridSize = 0
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_grid_size_1 -> gridSize = 1
|
||||||
|
R.id.action_grid_size_2 -> gridSize = 2
|
||||||
|
R.id.action_grid_size_3 -> gridSize = 3
|
||||||
|
R.id.action_grid_size_4 -> gridSize = 4
|
||||||
|
R.id.action_grid_size_5 -> gridSize = 5
|
||||||
|
R.id.action_grid_size_6 -> gridSize = 6
|
||||||
|
R.id.action_grid_size_7 -> gridSize = 7
|
||||||
|
R.id.action_grid_size_8 -> gridSize = 8
|
||||||
|
}
|
||||||
|
if (gridSize > 0) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveGridSize(gridSize)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AlbumClickListener {
|
interface AlbumClickListener {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package code.name.monkey.retromusic.fragments.artists
|
package code.name.monkey.retromusic.fragments.artists
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.*
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
@ -12,7 +12,10 @@ import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
||||||
import code.name.monkey.retromusic.extensions.findActivityNavController
|
import code.name.monkey.retromusic.extensions.findActivityNavController
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder.ArtistSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
|
||||||
|
|
||||||
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
||||||
ArtistClickListener {
|
ArtistClickListener {
|
||||||
|
@ -97,6 +100,161 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
||||||
val controller = findActivityNavController(R.id.fragment_container)
|
val controller = findActivityNavController(R.id.fragment_container)
|
||||||
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
|
||||||
|
if (RetroUtil.isLandscape()) {
|
||||||
|
gridSizeItem.setTitle(R.string.action_grid_size_land)
|
||||||
|
}
|
||||||
|
setUpGridSizeMenu(gridSizeItem.subMenu)
|
||||||
|
val layoutItem = menu.findItem(R.id.action_layout_type)
|
||||||
|
setupLayoutMenu(layoutItem.subMenu)
|
||||||
|
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpSortOrderMenu(
|
||||||
|
sortOrderMenu: SubMenu
|
||||||
|
) {
|
||||||
|
val currentSortOrder: String? = getSortOrder()
|
||||||
|
sortOrderMenu.clear()
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_artist_sort_order_asc,
|
||||||
|
0,
|
||||||
|
R.string.sort_order_a_z
|
||||||
|
).isChecked = currentSortOrder.equals(ArtistSortOrder.ARTIST_A_Z)
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_artist_sort_order_desc,
|
||||||
|
1,
|
||||||
|
R.string.sort_order_z_a
|
||||||
|
).isChecked = currentSortOrder.equals(ArtistSortOrder.ARTIST_Z_A)
|
||||||
|
sortOrderMenu.setGroupCheckable(0, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLayoutMenu(
|
||||||
|
subMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (itemLayoutRes()) {
|
||||||
|
R.layout.item_card -> subMenu.findItem(R.id.action_layout_card).isChecked = true
|
||||||
|
R.layout.item_grid -> subMenu.findItem(R.id.action_layout_normal).isChecked = true
|
||||||
|
R.layout.item_card_color ->
|
||||||
|
subMenu.findItem(R.id.action_layout_colored_card).isChecked = true
|
||||||
|
R.layout.item_grid_circle ->
|
||||||
|
subMenu.findItem(R.id.action_layout_circular).isChecked = true
|
||||||
|
R.layout.image -> subMenu.findItem(R.id.action_layout_image).isChecked = true
|
||||||
|
R.layout.item_image_gradient ->
|
||||||
|
subMenu.findItem(R.id.action_layout_gradient_image).isChecked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpGridSizeMenu(
|
||||||
|
gridSizeMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (getGridSize()) {
|
||||||
|
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked =
|
||||||
|
true
|
||||||
|
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
|
||||||
|
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
|
||||||
|
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
|
||||||
|
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
|
||||||
|
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
|
||||||
|
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
|
||||||
|
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
|
||||||
|
}
|
||||||
|
val gridSize: Int = maxGridSize
|
||||||
|
if (gridSize < 8) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 7) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 6) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 5) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 4) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 3) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (handleGridSizeMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleLayoutResType(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleSortOrderMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSortOrderMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var sortOrder: String? = null
|
||||||
|
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_artist_sort_order_asc -> sortOrder = ArtistSortOrder.ARTIST_A_Z
|
||||||
|
R.id.action_artist_sort_order_desc -> sortOrder = ArtistSortOrder.ARTIST_Z_A
|
||||||
|
}
|
||||||
|
if (sortOrder != null) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveSortOrder(sortOrder)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLayoutResType(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var layoutRes = -1
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_layout_normal -> layoutRes = R.layout.item_grid
|
||||||
|
R.id.action_layout_card -> layoutRes = R.layout.item_card
|
||||||
|
R.id.action_layout_colored_card -> layoutRes = R.layout.item_card_color
|
||||||
|
R.id.action_layout_circular -> layoutRes = R.layout.item_grid_circle
|
||||||
|
R.id.action_layout_image -> layoutRes = R.layout.image
|
||||||
|
R.id.action_layout_gradient_image -> layoutRes = R.layout.item_image_gradient
|
||||||
|
}
|
||||||
|
if (layoutRes != -1) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveLayoutRes(layoutRes)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleGridSizeMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var gridSize = 0
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_grid_size_1 -> gridSize = 1
|
||||||
|
R.id.action_grid_size_2 -> gridSize = 2
|
||||||
|
R.id.action_grid_size_3 -> gridSize = 3
|
||||||
|
R.id.action_grid_size_4 -> gridSize = 4
|
||||||
|
R.id.action_grid_size_5 -> gridSize = 5
|
||||||
|
R.id.action_grid_size_6 -> gridSize = 6
|
||||||
|
R.id.action_grid_size_7 -> gridSize = 7
|
||||||
|
R.id.action_grid_size_8 -> gridSize = 8
|
||||||
|
}
|
||||||
|
if (gridSize > 0) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveGridSize(gridSize)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ArtistClickListener {
|
interface ArtistClickListener {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package code.name.monkey.retromusic.fragments.base
|
||||||
|
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -21,6 +22,7 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
||||||
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
|
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
import code.name.monkey.retromusic.db.SongEntity
|
||||||
import code.name.monkey.retromusic.dialogs.*
|
import code.name.monkey.retromusic.dialogs.*
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.whichFragment
|
import code.name.monkey.retromusic.extensions.whichFragment
|
||||||
|
@ -85,7 +87,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
|
||||||
}
|
}
|
||||||
|
@ -182,29 +184,33 @@ 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 = libraryViewModel.favoritePlaylist().first()
|
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||||
val songEntity = song.toSongEntity(playlist.playListId)
|
if (playlist != null) {
|
||||||
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
|
val songEntity = song.toSongEntity(playlist.playListId)
|
||||||
if (isFavorite) {
|
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
|
||||||
libraryViewModel.removeSongFromPlaylist(songEntity)
|
if (isFavorite) {
|
||||||
} else {
|
libraryViewModel.removeSongFromPlaylist(songEntity)
|
||||||
libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
|
} else {
|
||||||
libraryViewModel.forceReload(ReloadType.Playlists)
|
libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||||
requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
|
requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateIsFavorite() {
|
fun updateIsFavorite() {
|
||||||
lifecycleScope.launch(IO) {
|
lifecycleScope.launch(IO) {
|
||||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist().firstOrNull()
|
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||||
if (playlist != null) {
|
if (playlist != null) {
|
||||||
val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
val song: SongEntity =
|
||||||
val isFavorite = libraryViewModel.isFavoriteSong(song).isNotEmpty()
|
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
||||||
|
val isFavorite: Boolean = libraryViewModel.isFavoriteSong(song).isNotEmpty()
|
||||||
withContext(Main) {
|
withContext(Main) {
|
||||||
val icon =
|
val icon =
|
||||||
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
||||||
val drawable =
|
val drawable: Drawable? =
|
||||||
|
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
icon,
|
icon,
|
||||||
|
|
|
@ -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) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package code.name.monkey.retromusic.fragments.songs
|
package code.name.monkey.retromusic.fragments.songs
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.*
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
@ -9,9 +9,13 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
|
import code.name.monkey.retromusic.helper.SortOrder.SongSortOrder
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
|
||||||
|
|
||||||
class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>() {
|
class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>() {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer {
|
libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer {
|
||||||
|
@ -34,7 +38,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
|
||||||
return SongAdapter(
|
return SongAdapter(
|
||||||
requireActivity(),
|
requireActivity(),
|
||||||
dataSet,
|
dataSet,
|
||||||
R.layout.item_list,
|
itemLayoutRes(),
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -80,6 +84,213 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
|
||||||
libraryViewModel.forceReload(ReloadType.Songs)
|
libraryViewModel.forceReload(ReloadType.Songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
|
||||||
|
if (RetroUtil.isLandscape()) {
|
||||||
|
gridSizeItem.setTitle(R.string.action_grid_size_land)
|
||||||
|
}
|
||||||
|
setUpGridSizeMenu(gridSizeItem.subMenu)
|
||||||
|
val layoutItem = menu.findItem(R.id.action_layout_type)
|
||||||
|
setupLayoutMenu(layoutItem.subMenu)
|
||||||
|
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpSortOrderMenu(
|
||||||
|
sortOrderMenu: SubMenu
|
||||||
|
) {
|
||||||
|
val currentSortOrder: String? = getSortOrder()
|
||||||
|
sortOrderMenu.clear()
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_asc,
|
||||||
|
0,
|
||||||
|
R.string.sort_order_a_z
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.SONG_A_Z
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_desc,
|
||||||
|
1,
|
||||||
|
R.string.sort_order_z_a
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.SONG_Z_A
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_artist,
|
||||||
|
2,
|
||||||
|
R.string.sort_order_artist
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.SONG_ARTIST
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_album,
|
||||||
|
3,
|
||||||
|
R.string.sort_order_album
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.SONG_ALBUM
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_year,
|
||||||
|
4,
|
||||||
|
R.string.sort_order_year
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.SONG_YEAR
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_date,
|
||||||
|
5,
|
||||||
|
R.string.sort_order_date
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.SONG_DATE
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_date_modified,
|
||||||
|
6,
|
||||||
|
R.string.sort_order_date_modified
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.SONG_DATE_MODIFIED
|
||||||
|
sortOrderMenu.add(
|
||||||
|
0,
|
||||||
|
R.id.action_song_sort_order_composer,
|
||||||
|
7,
|
||||||
|
R.string.sort_order_composer
|
||||||
|
).isChecked =
|
||||||
|
currentSortOrder == SongSortOrder.COMPOSER
|
||||||
|
|
||||||
|
sortOrderMenu.setGroupCheckable(0, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLayoutMenu(
|
||||||
|
subMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (itemLayoutRes()) {
|
||||||
|
R.layout.item_card -> subMenu.findItem(R.id.action_layout_card).isChecked = true
|
||||||
|
R.layout.item_grid -> subMenu.findItem(R.id.action_layout_normal).isChecked = true
|
||||||
|
R.layout.item_card_color ->
|
||||||
|
subMenu.findItem(R.id.action_layout_colored_card).isChecked = true
|
||||||
|
R.layout.item_grid_circle ->
|
||||||
|
subMenu.findItem(R.id.action_layout_circular).isChecked = true
|
||||||
|
R.layout.image -> subMenu.findItem(R.id.action_layout_image).isChecked = true
|
||||||
|
R.layout.item_image_gradient ->
|
||||||
|
subMenu.findItem(R.id.action_layout_gradient_image).isChecked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpGridSizeMenu(
|
||||||
|
gridSizeMenu: SubMenu
|
||||||
|
) {
|
||||||
|
when (getGridSize()) {
|
||||||
|
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked =
|
||||||
|
true
|
||||||
|
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
|
||||||
|
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
|
||||||
|
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
|
||||||
|
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
|
||||||
|
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
|
||||||
|
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
|
||||||
|
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
|
||||||
|
}
|
||||||
|
val gridSize: Int = maxGridSize
|
||||||
|
if (gridSize < 8) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 7) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 6) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 5) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 4) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 3) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (handleGridSizeMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleLayoutResType(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (handleSortOrderMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSortOrderMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var sortOrder: String? = null
|
||||||
|
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_song_sort_order_asc -> sortOrder = SongSortOrder.SONG_A_Z
|
||||||
|
R.id.action_song_sort_order_desc -> sortOrder = SongSortOrder.SONG_Z_A
|
||||||
|
R.id.action_song_sort_order_artist -> sortOrder = SongSortOrder.SONG_ARTIST
|
||||||
|
R.id.action_song_sort_order_album -> sortOrder = SongSortOrder.SONG_ALBUM
|
||||||
|
R.id.action_song_sort_order_year -> sortOrder = SongSortOrder.SONG_YEAR
|
||||||
|
R.id.action_song_sort_order_date -> sortOrder = SongSortOrder.SONG_DATE
|
||||||
|
R.id.action_song_sort_order_composer -> sortOrder = SongSortOrder.COMPOSER
|
||||||
|
R.id.action_song_sort_order_date_modified -> sortOrder =
|
||||||
|
SongSortOrder.SONG_DATE_MODIFIED
|
||||||
|
}
|
||||||
|
if (sortOrder != null) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveSortOrder(sortOrder)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLayoutResType(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var layoutRes = -1
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_layout_normal -> layoutRes = R.layout.item_grid
|
||||||
|
R.id.action_layout_card -> layoutRes = R.layout.item_card
|
||||||
|
R.id.action_layout_colored_card -> layoutRes = R.layout.item_card_color
|
||||||
|
R.id.action_layout_circular -> layoutRes = R.layout.item_grid_circle
|
||||||
|
R.id.action_layout_image -> layoutRes = R.layout.image
|
||||||
|
R.id.action_layout_gradient_image -> layoutRes = R.layout.item_image_gradient
|
||||||
|
}
|
||||||
|
if (layoutRes != -1) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveLayoutRes(layoutRes)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleGridSizeMenuItem(
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
var gridSize = 0
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_grid_size_1 -> gridSize = 1
|
||||||
|
R.id.action_grid_size_2 -> gridSize = 2
|
||||||
|
R.id.action_grid_size_3 -> gridSize = 3
|
||||||
|
R.id.action_grid_size_4 -> gridSize = 4
|
||||||
|
R.id.action_grid_size_5 -> gridSize = 5
|
||||||
|
R.id.action_grid_size_6 -> gridSize = 6
|
||||||
|
R.id.action_grid_size_7 -> gridSize = 7
|
||||||
|
R.id.action_grid_size_8 -> gridSize = 8
|
||||||
|
}
|
||||||
|
if (gridSize > 0) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveGridSize(gridSize)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
var TAG: String = SongsFragment::class.java.simpleName
|
var TAG: String = SongsFragment::class.java.simpleName
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,10 +16,82 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:context=".DrawerActivity">
|
tools:context=".DrawerActivity">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size"
|
||||||
|
android:icon="@drawable/ic_grid_size"
|
||||||
|
android:title="@string/action_grid_size"
|
||||||
|
app:showAsAction="never">
|
||||||
|
<menu>
|
||||||
|
<group
|
||||||
|
android:id="@+id/group_grid_size"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_1"
|
||||||
|
android:title="@string/grid_size_1" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_2"
|
||||||
|
android:title="@string/grid_size_2" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_3"
|
||||||
|
android:title="@string/grid_size_3" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_4"
|
||||||
|
android:title="@string/grid_size_4" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_5"
|
||||||
|
android:title="@string/grid_size_5" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_6"
|
||||||
|
android:title="@string/grid_size_6" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_7"
|
||||||
|
android:title="@string/grid_size_7" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_grid_size_8"
|
||||||
|
android:title="@string/grid_size_8" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_layout_type"
|
||||||
|
android:icon="@drawable/ic_dashboard"
|
||||||
|
android:title="@string/grid_style_label"
|
||||||
|
app:showAsAction="never">
|
||||||
|
<menu>
|
||||||
|
<group
|
||||||
|
android:id="@+id/group_layout_type"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_layout_normal"
|
||||||
|
android:title="@string/normal" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_layout_card"
|
||||||
|
android:title="@string/card" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_layout_colored_card"
|
||||||
|
android:title="@string/card_color_style" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_layout_circular"
|
||||||
|
android:title="@string/circular" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_layout_image"
|
||||||
|
android:title="@string/image" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_layout_gradient_image"
|
||||||
|
android:title="@string/image_gradient" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_order"
|
||||||
|
android:icon="@drawable/ic_sort"
|
||||||
|
android:title="@string/action_sort_order"
|
||||||
|
app:showAsAction="never">
|
||||||
|
<menu></menu>
|
||||||
|
</item>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_settings"
|
android:id="@+id/action_settings"
|
||||||
android:icon="@drawable/ic_settings"
|
android:icon="@drawable/ic_settings"
|
||||||
android:title="@string/action_settings"
|
android:title="@string/action_settings"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in a new issue