playback: re-add play from genre
Re-add the "Play from genre" setting. It's much easier to implement this now than prior with the picker framework, so may as well retain consistency.
This commit is contained in:
parent
cce7b766d7
commit
195ea074ca
41 changed files with 306 additions and 131 deletions
|
@ -74,10 +74,9 @@ class AuxioApp : Application(), ImageLoaderFactory {
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/** The ID of the "Shuffle All" shortcut. */
|
|
||||||
const val SHORTCUT_SHUFFLE_ID = "shortcut_shuffle"
|
|
||||||
|
|
||||||
/** The [Intent] name for the "Shuffle All" shortcut. */
|
/** The [Intent] name for the "Shuffle All" shortcut. */
|
||||||
const val INTENT_KEY_SHORTCUT_SHUFFLE = BuildConfig.APPLICATION_ID + ".action.SHUFFLE_ALL"
|
const val INTENT_KEY_SHORTCUT_SHUFFLE = BuildConfig.APPLICATION_ID + ".action.SHUFFLE_ALL"
|
||||||
|
/** The ID of the "Shuffle All" shortcut. */
|
||||||
|
private const val SHORTCUT_SHUFFLE_ID = "shortcut_shuffle"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ object IntegerTable {
|
||||||
const val REPEAT_MODE_ALL = 0xA101
|
const val REPEAT_MODE_ALL = 0xA101
|
||||||
/** RepeatMode.TRACK */
|
/** RepeatMode.TRACK */
|
||||||
const val REPEAT_MODE_TRACK = 0xA102
|
const val REPEAT_MODE_TRACK = 0xA102
|
||||||
|
/** PlaybackMode.IN_GENRE */
|
||||||
|
const val PLAYBACK_MODE_IN_GENRE = 0xA103
|
||||||
/** PlaybackMode.IN_ARTIST */
|
/** PlaybackMode.IN_ARTIST */
|
||||||
const val PLAYBACK_MODE_IN_ARTIST = 0xA104
|
const val PLAYBACK_MODE_IN_ARTIST = 0xA104
|
||||||
/** PlaybackMode.IN_ALBUM */
|
/** PlaybackMode.IN_ALBUM */
|
||||||
|
|
|
@ -128,9 +128,10 @@ class MainFragment :
|
||||||
// --- VIEWMODEL SETUP ---
|
// --- VIEWMODEL SETUP ---
|
||||||
collect(navModel.mainNavigationAction, ::handleMainNavigation)
|
collect(navModel.mainNavigationAction, ::handleMainNavigation)
|
||||||
collect(navModel.exploreNavigationItem, ::handleExploreNavigation)
|
collect(navModel.exploreNavigationItem, ::handleExploreNavigation)
|
||||||
collect(navModel.exploreNavigationArtists, ::handleExplorePicker)
|
collect(navModel.exploreArtistNavigationItem, ::handleArtistNavigationPicker)
|
||||||
collectImmediately(playbackModel.song, ::updateSong)
|
collectImmediately(playbackModel.song, ::updateSong)
|
||||||
collect(playbackModel.artistPlaybackPickerSong, ::handlePlaybackArtistPicker)
|
collect(playbackModel.artistPickerSong, ::handlePlaybackArtistPicker)
|
||||||
|
collect(playbackModel.genrePickerSong, ::handlePlaybackGenrePicker)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -278,13 +279,11 @@ class MainFragment :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleExplorePicker(items: List<Artist>?) {
|
private fun handleArtistNavigationPicker(item: Music?) {
|
||||||
if (items != null) {
|
if (item != null) {
|
||||||
// Navigate to the analogous artist picker dialog.
|
|
||||||
navModel.mainNavigateTo(
|
navModel.mainNavigateTo(
|
||||||
MainNavigationAction.Directions(
|
MainNavigationAction.Directions(
|
||||||
MainFragmentDirections.actionPickNavigationArtist(
|
MainFragmentDirections.actionPickNavigationArtist(item.uid)))
|
||||||
items.map { it.uid }.toTypedArray())))
|
|
||||||
navModel.finishExploreNavigation()
|
navModel.finishExploreNavigation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +298,6 @@ class MainFragment :
|
||||||
|
|
||||||
private fun handlePlaybackArtistPicker(song: Song?) {
|
private fun handlePlaybackArtistPicker(song: Song?) {
|
||||||
if (song != null) {
|
if (song != null) {
|
||||||
// Navigate to the analogous artist picker dialog.
|
|
||||||
navModel.mainNavigateTo(
|
navModel.mainNavigateTo(
|
||||||
MainNavigationAction.Directions(
|
MainNavigationAction.Directions(
|
||||||
MainFragmentDirections.actionPickPlaybackArtist(song.uid)))
|
MainFragmentDirections.actionPickPlaybackArtist(song.uid)))
|
||||||
|
@ -307,6 +305,15 @@ class MainFragment :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handlePlaybackGenrePicker(song: Song?) {
|
||||||
|
if (song != null) {
|
||||||
|
navModel.mainNavigateTo(
|
||||||
|
MainNavigationAction.Directions(
|
||||||
|
MainFragmentDirections.actionPickPlaybackGenre(song.uid)))
|
||||||
|
playbackModel.finishPlaybackArtistPicker()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun tryExpandSheets() {
|
private fun tryExpandSheets() {
|
||||||
val binding = requireBinding()
|
val binding = requireBinding()
|
||||||
val playbackSheetBehavior =
|
val playbackSheetBehavior =
|
||||||
|
|
|
@ -128,14 +128,14 @@ class AlbumDetailFragment : ListFragment<FragmentDetailBinding>(), AlbumDetailAd
|
||||||
|
|
||||||
override fun onRealClick(music: Music) {
|
override fun onRealClick(music: Music) {
|
||||||
check(music is Song) { "Unexpected datatype: ${music::class.java}" }
|
check(music is Song) { "Unexpected datatype: ${music::class.java}" }
|
||||||
when (val mode = Settings(requireContext()).detailPlaybackMode) {
|
when (Settings(requireContext()).detailPlaybackMode) {
|
||||||
// "Play from shown item" and "Play from album" functionally have the same
|
// "Play from shown item" and "Play from album" functionally have the same
|
||||||
// behavior since a song can only have one album.
|
// behavior since a song can only have one album.
|
||||||
null,
|
null,
|
||||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
||||||
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
||||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
||||||
else -> error("Unexpected playback mode: $mode")
|
MusicMode.GENRES -> playbackModel.playFromGenre(music)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ class AlbumDetailFragment : ListFragment<FragmentDetailBinding>(), AlbumDetailAd
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNavigateToParentArtist() {
|
override fun onNavigateToParentArtist() {
|
||||||
navModel.exploreNavigateTo(unlikelyToBeNull(detailModel.currentAlbum.value).artists)
|
navModel.exploreNavigateToParentArtist(unlikelyToBeNull(detailModel.currentAlbum.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateAlbum(album: Album?) {
|
private fun updateAlbum(album: Album?) {
|
||||||
|
@ -180,7 +180,6 @@ class AlbumDetailFragment : ListFragment<FragmentDetailBinding>(), AlbumDetailAd
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
requireBinding().detailToolbar.title = album.resolveName(requireContext())
|
requireBinding().detailToolbar.title = album.resolveName(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,16 +124,16 @@ class ArtistDetailFragment : ListFragment<FragmentDetailBinding>(), DetailAdapte
|
||||||
override fun onRealClick(music: Music) {
|
override fun onRealClick(music: Music) {
|
||||||
when (music) {
|
when (music) {
|
||||||
is Song -> {
|
is Song -> {
|
||||||
when (val mode = Settings(requireContext()).detailPlaybackMode) {
|
when (Settings(requireContext()).detailPlaybackMode) {
|
||||||
// "Play from selected item" and "Play from artist" differ, as the latter
|
// When configured to play from the selected item, we already have an Artist
|
||||||
// actually should show a picker choice in the case of multiple artists.
|
// to play from.
|
||||||
null ->
|
null ->
|
||||||
playbackModel.playFromArtist(
|
playbackModel.playFromArtist(
|
||||||
music, unlikelyToBeNull(detailModel.currentArtist.value))
|
music, unlikelyToBeNull(detailModel.currentArtist.value))
|
||||||
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
||||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
||||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
||||||
else -> error("Unexpected playback mode: $mode")
|
MusicMode.GENRES -> playbackModel.playFromGenre(music)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Album -> navModel.exploreNavigateTo(music)
|
is Album -> navModel.exploreNavigateTo(music)
|
||||||
|
|
|
@ -124,15 +124,16 @@ class GenreDetailFragment : ListFragment<FragmentDetailBinding>(), DetailAdapter
|
||||||
when (music) {
|
when (music) {
|
||||||
is Artist -> navModel.exploreNavigateTo(music)
|
is Artist -> navModel.exploreNavigateTo(music)
|
||||||
is Song ->
|
is Song ->
|
||||||
when (val mode = Settings(requireContext()).detailPlaybackMode) {
|
when (Settings(requireContext()).detailPlaybackMode) {
|
||||||
// Only way to play from the genre is through "Play from selected item".
|
// When configured to play from the selected item, we already have a Genre
|
||||||
|
// to play from.
|
||||||
null ->
|
null ->
|
||||||
playbackModel.playFromGenre(
|
playbackModel.playFromGenre(
|
||||||
music, unlikelyToBeNull(detailModel.currentGenre.value))
|
music, unlikelyToBeNull(detailModel.currentGenre.value))
|
||||||
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
||||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
||||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
||||||
else -> error("Unexpected playback mode: $mode")
|
MusicMode.GENRES -> playbackModel.playFromGenre(music)
|
||||||
}
|
}
|
||||||
else -> error("Unexpected datatype: ${music::class.simpleName}")
|
else -> error("Unexpected datatype: ${music::class.simpleName}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
||||||
override fun onBindingCreated(binding: DialogSongDetailBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogSongDetailBinding, savedInstanceState: Bundle?) {
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
// DetailViewModel handles most initialization from the navigation argument.
|
// DetailViewModel handles most initialization from the navigation argument.
|
||||||
detailModel.setSongUid(args.songUid)
|
detailModel.setSongUid(args.itemUid)
|
||||||
collectImmediately(detailModel.currentSong, ::updateSong)
|
collectImmediately(detailModel.currentSong, ::updateSong)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,9 +155,7 @@ class HomeFragment :
|
||||||
collect(homeModel.shouldRecreate, ::handleRecreate)
|
collect(homeModel.shouldRecreate, ::handleRecreate)
|
||||||
collectImmediately(homeModel.currentTabMode, ::updateCurrentTab)
|
collectImmediately(homeModel.currentTabMode, ::updateCurrentTab)
|
||||||
collectImmediately(homeModel.songLists, homeModel.isFastScrolling, ::updateFab)
|
collectImmediately(homeModel.songLists, homeModel.isFastScrolling, ::updateFab)
|
||||||
|
|
||||||
collectImmediately(musicModel.indexerState, ::updateIndexerState)
|
collectImmediately(musicModel.indexerState, ::updateIndexerState)
|
||||||
|
|
||||||
collect(navModel.exploreNavigationItem, ::handleNavigation)
|
collect(navModel.exploreNavigationItem, ::handleNavigation)
|
||||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||||
}
|
}
|
||||||
|
@ -484,9 +482,7 @@ class HomeFragment :
|
||||||
fragmentManager: FragmentManager,
|
fragmentManager: FragmentManager,
|
||||||
lifecycleOwner: LifecycleOwner
|
lifecycleOwner: LifecycleOwner
|
||||||
) : FragmentStateAdapter(fragmentManager, lifecycleOwner.lifecycle) {
|
) : FragmentStateAdapter(fragmentManager, lifecycleOwner.lifecycle) {
|
||||||
|
|
||||||
override fun getItemCount() = tabs.size
|
override fun getItemCount() = tabs.size
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment =
|
override fun createFragment(position: Int): Fragment =
|
||||||
when (tabs[position]) {
|
when (tabs[position]) {
|
||||||
MusicMode.SONGS -> SongListFragment()
|
MusicMode.SONGS -> SongListFragment()
|
||||||
|
|
|
@ -132,11 +132,11 @@ class SongListFragment :
|
||||||
|
|
||||||
override fun onRealClick(music: Music) {
|
override fun onRealClick(music: Music) {
|
||||||
check(music is Song) { "Unexpected datatype: ${music::class.java}" }
|
check(music is Song) { "Unexpected datatype: ${music::class.java}" }
|
||||||
when (val mode = Settings(requireContext()).libPlaybackMode) {
|
when (Settings(requireContext()).libPlaybackMode) {
|
||||||
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
||||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
||||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
||||||
else -> error("Unexpected playback mode: $mode")
|
MusicMode.GENRES -> playbackModel.playFromGenre(music)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ abstract class ListFragment<VB : ViewBinding> : SelectionFragment<VB>(), Selecta
|
||||||
requireContext().showToast(R.string.lng_queue_added)
|
requireContext().showToast(R.string.lng_queue_added)
|
||||||
}
|
}
|
||||||
R.id.action_go_artist -> {
|
R.id.action_go_artist -> {
|
||||||
navModel.exploreNavigateTo(song.artists)
|
navModel.exploreNavigateToParentArtist(song)
|
||||||
}
|
}
|
||||||
R.id.action_go_album -> {
|
R.id.action_go_album -> {
|
||||||
navModel.exploreNavigateTo(song.album)
|
navModel.exploreNavigateTo(song.album)
|
||||||
|
@ -134,7 +134,7 @@ abstract class ListFragment<VB : ViewBinding> : SelectionFragment<VB>(), Selecta
|
||||||
requireContext().showToast(R.string.lng_queue_added)
|
requireContext().showToast(R.string.lng_queue_added)
|
||||||
}
|
}
|
||||||
R.id.action_go_artist -> {
|
R.id.action_go_artist -> {
|
||||||
navModel.exploreNavigateTo(album.artists)
|
navModel.exploreNavigateToParentArtist(album)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
error("Unexpected menu item selected")
|
error("Unexpected menu item selected")
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.util.context
|
||||||
import org.oxycblt.auxio.util.inflater
|
import org.oxycblt.auxio.util.inflater
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An adapter responsible for showing a list of [Artist] choices in [ArtistPickerDialog].
|
* An [RecyclerView.Adapter] that displays a list of [Artist] choices.
|
||||||
* @param listener A [ClickableListListener] to bind interactions to.
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
* @author OxygenCobalt.
|
* @author OxygenCobalt.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,12 +31,12 @@ import org.oxycblt.auxio.ui.NavigationViewModel
|
||||||
*/
|
*/
|
||||||
class ArtistNavigationPickerDialog : ArtistPickerDialog() {
|
class ArtistNavigationPickerDialog : ArtistPickerDialog() {
|
||||||
private val navModel: NavigationViewModel by activityViewModels()
|
private val navModel: NavigationViewModel by activityViewModels()
|
||||||
// Information about what artists to display is initially within the navigation arguments
|
// Information about what Song to show choices for is initially within the navigation arguments
|
||||||
// as a list of UIDs, as that is the only safe way to parcel an artist.
|
// as UIDs, as that is the only safe way to parcel a Song.
|
||||||
private val args: ArtistNavigationPickerDialogArgs by navArgs()
|
private val args: ArtistNavigationPickerDialogArgs by navArgs()
|
||||||
|
|
||||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
||||||
pickerModel.setArtistUids(args.artistUids)
|
pickerModel.setItemUid(args.itemUid)
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,11 +52,9 @@ abstract class ArtistPickerDialog :
|
||||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
||||||
binding.pickerRecycler.adapter = artistAdapter
|
binding.pickerRecycler.adapter = artistAdapter
|
||||||
|
|
||||||
collectImmediately(pickerModel.currentArtists) { artists ->
|
collectImmediately(pickerModel.artistChoices) { artists ->
|
||||||
if (!artists.isNullOrEmpty()) {
|
if (artists.isNotEmpty()) {
|
||||||
// Make sure the artist choices align with any changes in the music library.
|
// Make sure the artist choices align with any changes in the music library.
|
||||||
// TODO: I really don't think it makes sense to do this. I'd imagine it would
|
|
||||||
// be more productive to just exit this dialog rather than try to update it.
|
|
||||||
artistAdapter.submitList(artists)
|
artistAdapter.submitList(artists)
|
||||||
} else {
|
} else {
|
||||||
// Not showing any choices, navigate up.
|
// Not showing any choices, navigate up.
|
||||||
|
|
|
@ -22,6 +22,7 @@ import androidx.navigation.fragment.navArgs
|
||||||
import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
|
import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.util.androidActivityViewModels
|
import org.oxycblt.auxio.util.androidActivityViewModels
|
||||||
|
|
||||||
|
@ -31,19 +32,21 @@ import org.oxycblt.auxio.util.androidActivityViewModels
|
||||||
*/
|
*/
|
||||||
class ArtistPlaybackPickerDialog : ArtistPickerDialog() {
|
class ArtistPlaybackPickerDialog : ArtistPickerDialog() {
|
||||||
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
|
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
|
||||||
// Information about what artists to display is initially within the navigation arguments
|
// Information about what Song to show choices for is initially within the navigation arguments
|
||||||
// as a list of UIDs, as that is the only safe way to parcel an artist.
|
// as UIDs, as that is the only safe way to parcel a Song.
|
||||||
private val args: ArtistPlaybackPickerDialogArgs by navArgs()
|
private val args: ArtistPlaybackPickerDialogArgs by navArgs()
|
||||||
|
|
||||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
||||||
pickerModel.setSongUid(args.songUid)
|
pickerModel.setItemUid(args.itemUid)
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(item: Item) {
|
override fun onClick(item: Item) {
|
||||||
super.onClick(item)
|
super.onClick(item)
|
||||||
check(item is Artist) { "Unexpected datatype: ${item::class.simpleName}" }
|
|
||||||
// User made a choice, play the given song from that artist.
|
// User made a choice, play the given song from that artist.
|
||||||
pickerModel.currentSong.value?.let { song -> playbackModel.playFromArtist(song, item) }
|
check(item is Artist) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||||
|
val song = pickerModel.currentItem.value
|
||||||
|
check(song is Song) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||||
|
playbackModel.playFromArtist(song, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package org.oxycblt.auxio.music.picker
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.oxycblt.auxio.databinding.ItemPickerChoiceBinding
|
||||||
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
|
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
||||||
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
import org.oxycblt.auxio.util.context
|
||||||
|
import org.oxycblt.auxio.util.inflater
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An [RecyclerView.Adapter] that displays a list of [Genre] choices.
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
* @author OxygenCobalt.
|
||||||
|
*/
|
||||||
|
class GenreChoiceAdapter(private val listener: ClickableListListener) :
|
||||||
|
RecyclerView.Adapter<GenreChoiceViewHolder>() {
|
||||||
|
private var genres = listOf<Genre>()
|
||||||
|
|
||||||
|
override fun getItemCount() = genres.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
GenreChoiceViewHolder.new(parent)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: GenreChoiceViewHolder, position: Int) =
|
||||||
|
holder.bind(genres[position], listener)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immediately update the [Genre] choices.
|
||||||
|
* @param newGenres The new [Genre]s to show.
|
||||||
|
*/
|
||||||
|
fun submitList(newGenres: List<Genre>) {
|
||||||
|
if (newGenres != genres) {
|
||||||
|
genres = newGenres
|
||||||
|
@Suppress("NotifyDataSetChanged") notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [DialogRecyclerView.ViewHolder] that displays a smaller variant of a typical [Genre] item, for
|
||||||
|
* use with [GenreChoiceAdapter]. Use [new] to create an instance.
|
||||||
|
*/
|
||||||
|
class GenreChoiceViewHolder(private val binding: ItemPickerChoiceBinding) :
|
||||||
|
DialogRecyclerView.ViewHolder(binding.root) {
|
||||||
|
/**
|
||||||
|
* Bind new data to this instance.
|
||||||
|
* @param genre The new [Genre] to bind.
|
||||||
|
* @param listener A [ClickableListListener] to bind interactions to.
|
||||||
|
*/
|
||||||
|
fun bind(genre: Genre, listener: ClickableListListener) {
|
||||||
|
binding.root.setOnClickListener { listener.onClick(genre) }
|
||||||
|
binding.pickerImage.bind(genre)
|
||||||
|
binding.pickerName.text = genre.resolveName(binding.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
* @param parent The parent to inflate this instance from.
|
||||||
|
* @return A new instance.
|
||||||
|
*/
|
||||||
|
fun new(parent: View) =
|
||||||
|
GenreChoiceViewHolder(ItemPickerChoiceBinding.inflate(parent.context.inflater))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.oxycblt.auxio.music.picker
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import org.oxycblt.auxio.R
|
||||||
|
import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
|
||||||
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
|
import org.oxycblt.auxio.list.Item
|
||||||
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
import org.oxycblt.auxio.music.Song
|
||||||
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
|
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
||||||
|
import org.oxycblt.auxio.util.androidActivityViewModels
|
||||||
|
import org.oxycblt.auxio.util.collectImmediately
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A picker [ViewBindingDialogFragment] intended for when [Genre] playback is ambiguous.
|
||||||
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
|
*/
|
||||||
|
class GenrePlaybackPickerDialog : ViewBindingDialogFragment<DialogMusicPickerBinding>(), ClickableListListener {
|
||||||
|
private val pickerModel: PickerViewModel by viewModels()
|
||||||
|
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
|
||||||
|
// Information about what Song to show choices for is initially within the navigation arguments
|
||||||
|
// as UIDs, as that is the only safe way to parcel a Song.
|
||||||
|
private val args: GenrePlaybackPickerDialogArgs by navArgs()
|
||||||
|
// Okay to leak this since the Listener will not be called until after initialization.
|
||||||
|
private val genreAdapter = GenreChoiceAdapter(@Suppress("LeakingThis") this)
|
||||||
|
|
||||||
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
|
DialogMusicPickerBinding.inflate(inflater)
|
||||||
|
|
||||||
|
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
||||||
|
builder.setTitle(R.string.lbl_genres).setNegativeButton(R.string.lbl_cancel, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
||||||
|
binding.pickerRecycler.adapter = genreAdapter
|
||||||
|
|
||||||
|
pickerModel.setItemUid(args.itemUid)
|
||||||
|
collectImmediately(pickerModel.genreChoices) { genres ->
|
||||||
|
if (genres.isNotEmpty()) {
|
||||||
|
// Make sure the genre choices align with any changes in the music library.
|
||||||
|
genreAdapter.submitList(genres)
|
||||||
|
} else {
|
||||||
|
// Not showing any choices, navigate up.
|
||||||
|
findNavController().navigateUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyBinding(binding: DialogMusicPickerBinding) {
|
||||||
|
binding.pickerRecycler.adapter = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(item: Item) {
|
||||||
|
// User made a choice, play the given song from that genre.
|
||||||
|
check(item is Genre) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||||
|
val song = pickerModel.currentItem.value
|
||||||
|
check(song is Song) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||||
|
playbackModel.playFromGenre(song, item)
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,10 +20,7 @@ package org.oxycblt.auxio.music.picker
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.*
|
||||||
import org.oxycblt.auxio.music.Music
|
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
|
||||||
import org.oxycblt.auxio.music.Song
|
|
||||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,24 +29,21 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class PickerViewModel : ViewModel(), MusicStore.Callback {
|
class PickerViewModel : ViewModel(), MusicStore.Callback {
|
||||||
// TODO: Refactor
|
|
||||||
|
|
||||||
private val musicStore = MusicStore.getInstance()
|
private val musicStore = MusicStore.getInstance()
|
||||||
|
|
||||||
private val _currentSong = MutableStateFlow<Song?>(null)
|
private val _currentItem = MutableStateFlow<Music?>(null)
|
||||||
/**
|
/** The current item whose artists should be shown in the picker. Null if there is no item. */
|
||||||
* The current [Song] whose choices are being shown in the picker. Null if there is no [Song].
|
val currentItem: StateFlow<Music?> get() = _currentItem
|
||||||
*/
|
|
||||||
val currentSong: StateFlow<Song?>
|
|
||||||
get() = _currentSong
|
|
||||||
|
|
||||||
private val _currentArtists = MutableStateFlow<List<Artist>?>(null)
|
private val _artistChoices = MutableStateFlow<List<Artist>>(listOf())
|
||||||
/**
|
/** The current [Artist] choices. Empty if no item is shown in the picker. */
|
||||||
* The current [Artist] whose choices are being shown in the picker. Null/Empty if there is
|
val artistChoices: StateFlow<List<Artist>>
|
||||||
* none.
|
get() = _artistChoices
|
||||||
*/
|
|
||||||
val currentArtists: StateFlow<List<Artist>?>
|
private val _genreChoices = MutableStateFlow<List<Genre>>(listOf())
|
||||||
get() = _currentArtists
|
/** The current [Genre] choices. Empty if no item is shown in the picker. */
|
||||||
|
val genreChoices: StateFlow<List<Genre>>
|
||||||
|
get() = _genreChoices
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
musicStore.removeCallback(this)
|
musicStore.removeCallback(this)
|
||||||
|
@ -57,37 +51,29 @@ class PickerViewModel : ViewModel(), MusicStore.Callback {
|
||||||
|
|
||||||
override fun onLibraryChanged(library: MusicStore.Library?) {
|
override fun onLibraryChanged(library: MusicStore.Library?) {
|
||||||
if (library != null) {
|
if (library != null) {
|
||||||
// If we are showing any item right now, we will need to refresh it (and any information
|
refreshChoices()
|
||||||
// related to it) with the new library in order to prevent stale items from appearing
|
|
||||||
// in the UI.
|
|
||||||
val song = _currentSong.value
|
|
||||||
val artists = _currentArtists.value
|
|
||||||
if (song != null) {
|
|
||||||
_currentSong.value = library.sanitize(song)
|
|
||||||
_currentArtists.value = _currentSong.value?.artists
|
|
||||||
} else if (artists != null) {
|
|
||||||
_currentArtists.value = artists.mapNotNull { library.sanitize(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a new [currentSong] from it's [Music.UID].
|
* Set a new [currentItem] from it's [Music.UID].
|
||||||
* @param uid The [Music.UID] of the [Song] to update to.
|
* @param uid The [Music.UID] of the [Song] to update to.
|
||||||
*/
|
*/
|
||||||
fun setSongUid(uid: Music.UID) {
|
fun setItemUid(uid: Music.UID) {
|
||||||
val library = unlikelyToBeNull(musicStore.library)
|
val library = unlikelyToBeNull(musicStore.library)
|
||||||
_currentSong.value = library.find(uid)
|
_currentItem.value = library.find(uid)
|
||||||
_currentArtists.value = _currentSong.value?.artists
|
refreshChoices()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun refreshChoices() {
|
||||||
* Set a new [currentArtists] list from a list of [Music.UID]'s.
|
when (val item = _currentItem.value) {
|
||||||
* @param uids The [Music.UID]s of the [Artist]s to [currentArtists] to.
|
is Song -> {
|
||||||
*/
|
_artistChoices.value = item.artists
|
||||||
fun setArtistUids(uids: Array<Music.UID>) {
|
_genreChoices.value = item.genres
|
||||||
val library = unlikelyToBeNull(musicStore.library)
|
}
|
||||||
// Map the UIDs to artist instances and filter out the ones that can't be found.
|
is Album -> _artistChoices.value = item.artists
|
||||||
_currentArtists.value = uids.mapNotNull { library.find<Artist>(it) }.ifEmpty { null }
|
else -> {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,7 @@ class PlaybackPanelFragment :
|
||||||
/** Navigate to one of the currently playing [Song]'s Artists. */
|
/** Navigate to one of the currently playing [Song]'s Artists. */
|
||||||
private fun navigateToCurrentArtist() {
|
private fun navigateToCurrentArtist() {
|
||||||
val song = playbackModel.song.value ?: return
|
val song = playbackModel.song.value ?: return
|
||||||
navModel.exploreNavigateTo(song.artists)
|
navModel.exploreNavigateToParentArtist(song)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Navigate to the currently playing [Song]'s albums. */
|
/** Navigate to the currently playing [Song]'s albums. */
|
||||||
|
|
|
@ -70,13 +70,21 @@ class PlaybackViewModel(application: Application) :
|
||||||
|
|
||||||
private val _artistPlaybackPickerSong = MutableStateFlow<Song?>(null)
|
private val _artistPlaybackPickerSong = MutableStateFlow<Song?>(null)
|
||||||
/**
|
/**
|
||||||
* Flag signaling to open a picker dialog in order to resolve an ambiguous [Artist] choice when
|
* Flag signaling to open a picker dialog in order to resolve an ambiguous choice when
|
||||||
* playing a [Song] from one of it's [Artist]s.
|
* playing a [Song] from one of it's [Artist]s.
|
||||||
* @see playFromArtist
|
* @see playFromArtist
|
||||||
*/
|
*/
|
||||||
val artistPlaybackPickerSong: StateFlow<Song?>
|
val artistPickerSong: StateFlow<Song?>
|
||||||
get() = _artistPlaybackPickerSong
|
get() = _artistPlaybackPickerSong
|
||||||
|
|
||||||
|
private val _genrePlaybackPickerSong = MutableStateFlow<Song?>(null)
|
||||||
|
/**
|
||||||
|
* Flag signaling to open a picker dialog in order to resolve an ambiguous choice when playing
|
||||||
|
* a [Song] from one of it's [Genre]s.
|
||||||
|
*/
|
||||||
|
val genrePickerSong: StateFlow<Song?>
|
||||||
|
get() = _genrePlaybackPickerSong
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current audio session ID of the internal player. Null if no [InternalPlayer] is
|
* The current audio session ID of the internal player. Null if no [InternalPlayer] is
|
||||||
* available.
|
* available.
|
||||||
|
@ -178,11 +186,18 @@ class PlaybackViewModel(application: Application) :
|
||||||
/**
|
/**
|
||||||
* PLay a [Song] from one of it's [Genre]s.
|
* PLay a [Song] from one of it's [Genre]s.
|
||||||
* @param song The [Song] to play.
|
* @param song The [Song] to play.
|
||||||
* @param genre The [Genre] to play from. Must be linked to the [Song].
|
* @param genre The [Genre] to play from. Must be linked to the [Song]. If null, the user will
|
||||||
|
* be prompted on what artist to play. Defaults to null.
|
||||||
*/
|
*/
|
||||||
fun playFromGenre(song: Song, genre: Genre) {
|
fun playFromGenre(song: Song, genre: Genre? = null) {
|
||||||
check(genre.songs.contains(song)) { "Invalid input: Genre is not linked to song" }
|
if (genre != null) {
|
||||||
playbackManager.play(song, genre, settings)
|
check(genre.songs.contains(song)) { "Invalid input: Genre is not linked to song" }
|
||||||
|
playbackManager.play(song, genre, settings)
|
||||||
|
} else if (song.genres.size == 1) {
|
||||||
|
playbackManager.play(song, song.genres[0], settings)
|
||||||
|
} else {
|
||||||
|
_genrePlaybackPickerSong.value = song
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -137,11 +137,11 @@ class SearchFragment : ListFragment<FragmentSearchBinding>() {
|
||||||
override fun onRealClick(music: Music) {
|
override fun onRealClick(music: Music) {
|
||||||
when (music) {
|
when (music) {
|
||||||
is Song ->
|
is Song ->
|
||||||
when (val mode = Settings(requireContext()).libPlaybackMode) {
|
when (Settings(requireContext()).libPlaybackMode) {
|
||||||
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
MusicMode.SONGS -> playbackModel.playFromAll(music)
|
||||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
MusicMode.ALBUMS -> playbackModel.playFromAlbum(music)
|
||||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
MusicMode.ARTISTS -> playbackModel.playFromArtist(music)
|
||||||
else -> error("Unexpected playback mode: $mode")
|
MusicMode.GENRES -> playbackModel.playFromGenre(music)
|
||||||
}
|
}
|
||||||
is MusicParent -> navModel.exploreNavigateTo(music)
|
is MusicParent -> navModel.exploreNavigateTo(music)
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,10 +113,11 @@ class Settings(private val context: Context, private val callback: Callback? = n
|
||||||
|
|
||||||
fun Int.migratePlaybackMode() =
|
fun Int.migratePlaybackMode() =
|
||||||
when (this) {
|
when (this) {
|
||||||
// Genre playback mode was removed in 3.0.0
|
// Convert PlaybackMode into MusicMode
|
||||||
IntegerTable.PLAYBACK_MODE_ALL_SONGS -> MusicMode.SONGS
|
IntegerTable.PLAYBACK_MODE_ALL_SONGS -> MusicMode.SONGS
|
||||||
IntegerTable.PLAYBACK_MODE_IN_ARTIST -> MusicMode.ARTISTS
|
IntegerTable.PLAYBACK_MODE_IN_ARTIST -> MusicMode.ARTISTS
|
||||||
IntegerTable.PLAYBACK_MODE_IN_ALBUM -> MusicMode.ALBUMS
|
IntegerTable.PLAYBACK_MODE_IN_ALBUM -> MusicMode.ALBUMS
|
||||||
|
IntegerTable.PLAYBACK_MODE_IN_GENRE -> MusicMode.GENRES
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,10 @@ import androidx.lifecycle.ViewModel
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
|
|
||||||
/** A [ViewModel] that handles complicated navigation functionality. */
|
/** A [ViewModel] that handles complicated navigation functionality. */
|
||||||
|
@ -42,14 +44,14 @@ class NavigationViewModel : ViewModel() {
|
||||||
val exploreNavigationItem: StateFlow<Music?>
|
val exploreNavigationItem: StateFlow<Music?>
|
||||||
get() = _exploreNavigationItem
|
get() = _exploreNavigationItem
|
||||||
|
|
||||||
private val _exploreNavigationArtists = MutableStateFlow<List<Artist>?>(null)
|
private val _exploreArtistNavigationItem = MutableStateFlow<Music?>(null)
|
||||||
/**
|
/**
|
||||||
* Variation of [exploreNavigationItem] for situations where the choice of [Artist] to navigate
|
* Variation of [exploreNavigationItem] for situations where the choice of parent [Artist] to
|
||||||
* to is ambiguous. Only intended for use by MainFragment, as the resolved choice will
|
* navigate to is ambiguous. Only intended for use by MainFragment, as the resolved choice will
|
||||||
* eventually be assigned to [exploreNavigationItem].
|
* eventually be assigned to [exploreNavigationItem].
|
||||||
*/
|
*/
|
||||||
val exploreNavigationArtists: StateFlow<List<Artist>?>
|
val exploreArtistNavigationItem: StateFlow<Music?>
|
||||||
get() = _exploreNavigationArtists
|
get() = _exploreArtistNavigationItem
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to something in the main navigation graph. This can be used by UIs in the explore
|
* Navigate to something in the main navigation graph. This can be used by UIs in the explore
|
||||||
|
@ -89,12 +91,25 @@ class NavigationViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to an [Artist] out of a list of [Artist]s, like [exploreNavigateTo].
|
* Navigate to one of the parent [Artist]'s of the given [Song].
|
||||||
* @param artists The [Artist]s to navigate to. In the case of multiple artists, the user will
|
* @param song The [Song] to navigate with. If there are multiple parent [Artist]s,
|
||||||
* be prompted with a choice on which [Artist] to navigate to.
|
* a picker dialog will be shown.
|
||||||
*/
|
*/
|
||||||
fun exploreNavigateTo(artists: List<Artist>) {
|
fun exploreNavigateToParentArtist(song: Song) {
|
||||||
if (_exploreNavigationArtists.value != null) {
|
exploreNavigateToParentArtistImpl(song, song.artists)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to one of the parent [Artist]'s of the given [Album].
|
||||||
|
* @param album The [Album] to navigate with. If there are multiple parent [Artist]s,
|
||||||
|
* a picker dialog will be shown.
|
||||||
|
*/
|
||||||
|
fun exploreNavigateToParentArtist(album: Album) {
|
||||||
|
exploreNavigateToParentArtistImpl(album, album.artists)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exploreNavigateToParentArtistImpl(item: Music, artists: List<Artist>) {
|
||||||
|
if (_exploreArtistNavigationItem.value != null) {
|
||||||
logD("Already navigating, not doing explore action")
|
logD("Already navigating, not doing explore action")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -103,7 +118,7 @@ class NavigationViewModel : ViewModel() {
|
||||||
exploreNavigateTo(artists[0])
|
exploreNavigateTo(artists[0])
|
||||||
} else {
|
} else {
|
||||||
logD("Navigating to a choice of ${artists.map { it.rawName }}")
|
logD("Navigating to a choice of ${artists.map { it.rawName }}")
|
||||||
_exploreNavigationArtists.value = artists
|
_exploreArtistNavigationItem.value = item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +129,7 @@ class NavigationViewModel : ViewModel() {
|
||||||
fun finishExploreNavigation() {
|
fun finishExploreNavigation() {
|
||||||
logD("Finishing explore navigation process")
|
logD("Finishing explore navigation process")
|
||||||
_exploreNavigationItem.value = null
|
_exploreNavigationItem.value = null
|
||||||
_exploreNavigationArtists.value = null
|
_exploreArtistNavigationItem.value = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_pick_navigation_artist"
|
android:id="@+id/action_pick_navigation_artist"
|
||||||
app:destination="@id/artist_navigation_picker_dialog" />
|
app:destination="@id/artist_navigation_picker_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_pick_playback_genre"
|
||||||
|
app:destination="@id/genre_playback_picker_dialog" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<dialog
|
<dialog
|
||||||
|
@ -31,7 +34,7 @@
|
||||||
android:label="artist_playback_picker_dialog"
|
android:label="artist_playback_picker_dialog"
|
||||||
tools:layout="@layout/dialog_music_picker">
|
tools:layout="@layout/dialog_music_picker">
|
||||||
<argument
|
<argument
|
||||||
android:name="songUid"
|
android:name="itemUid"
|
||||||
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
|
@ -41,8 +44,18 @@
|
||||||
android:label="artist_navigation_picker_dialog"
|
android:label="artist_navigation_picker_dialog"
|
||||||
tools:layout="@layout/dialog_music_picker">
|
tools:layout="@layout/dialog_music_picker">
|
||||||
<argument
|
<argument
|
||||||
android:name="artistUids"
|
android:name="itemUid"
|
||||||
app:argType="org.oxycblt.auxio.music.Music$UID[]" />
|
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog
|
||||||
|
android:id="@+id/genre_playback_picker_dialog"
|
||||||
|
android:name="org.oxycblt.auxio.music.picker.GenrePlaybackPickerDialog"
|
||||||
|
android:label="genre_playback_picker_dialog"
|
||||||
|
tools:layout="@layout/dialog_music_picker">
|
||||||
|
<argument
|
||||||
|
android:name="itemUid"
|
||||||
|
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<dialog
|
<dialog
|
||||||
|
@ -51,7 +64,7 @@
|
||||||
android:label="song_detail_dialog"
|
android:label="song_detail_dialog"
|
||||||
tools:layout="@layout/dialog_song_detail">
|
tools:layout="@layout/dialog_song_detail">
|
||||||
<argument
|
<argument
|
||||||
android:name="songUid"
|
android:name="itemUid"
|
||||||
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<string name="lbl_playback">يعمل الآن</string>
|
<string name="lbl_playback">يعمل الآن</string>
|
||||||
<string name="lbl_play">تشغيل</string>
|
<string name="lbl_play">تشغيل</string>
|
||||||
<string name="lbl_shuffle">خلط</string>
|
<string name="lbl_shuffle">خلط</string>
|
||||||
<string name="set_playback_mode_all">تشغيل من جميع الاغاني</string>
|
<string name="set_playback_mode_songs">تشغيل من جميع الاغاني</string>
|
||||||
<string name="set_playback_mode_album">تشغيل من البوم</string>
|
<string name="set_playback_mode_album">تشغيل من البوم</string>
|
||||||
<string name="set_playback_mode_artist">تشغيل من فنان</string>
|
<string name="set_playback_mode_artist">تشغيل من فنان</string>
|
||||||
<string name="lbl_queue">طابور</string>
|
<string name="lbl_queue">طابور</string>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
<string name="lbl_playback">Právě hraje</string>
|
<string name="lbl_playback">Právě hraje</string>
|
||||||
<string name="lbl_play">Přehrát</string>
|
<string name="lbl_play">Přehrát</string>
|
||||||
<string name="lbl_shuffle">Náhodně</string>
|
<string name="lbl_shuffle">Náhodně</string>
|
||||||
<string name="set_playback_mode_all">Přehrát ze všech skladeb</string>
|
<string name="set_playback_mode_songs">Přehrát ze všech skladeb</string>
|
||||||
<string name="set_playback_mode_album">Přehrát z alba</string>
|
<string name="set_playback_mode_album">Přehrát z alba</string>
|
||||||
<string name="set_playback_mode_artist">Přehrát od umělce</string>
|
<string name="set_playback_mode_artist">Přehrát od umělce</string>
|
||||||
<string name="lbl_queue">Fronta</string>
|
<string name="lbl_queue">Fronta</string>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<string name="lbl_sort_asc">Aufsteigend</string>
|
<string name="lbl_sort_asc">Aufsteigend</string>
|
||||||
<string name="lbl_play">Abspielen</string>
|
<string name="lbl_play">Abspielen</string>
|
||||||
<string name="lbl_shuffle">Zufällig</string>
|
<string name="lbl_shuffle">Zufällig</string>
|
||||||
<string name="set_playback_mode_all">Von allen Lieder abspielen</string>
|
<string name="set_playback_mode_songs">Von allen Lieder abspielen</string>
|
||||||
<string name="set_playback_mode_album">Von Album abspielen</string>
|
<string name="set_playback_mode_album">Von Album abspielen</string>
|
||||||
<string name="lbl_playback">Aktuelle Wiedergabe</string>
|
<string name="lbl_playback">Aktuelle Wiedergabe</string>
|
||||||
<string name="lbl_queue">Warteschlange</string>
|
<string name="lbl_queue">Warteschlange</string>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<string name="lbl_playback">En reproducción</string>
|
<string name="lbl_playback">En reproducción</string>
|
||||||
<string name="lbl_play">Reproducir</string>
|
<string name="lbl_play">Reproducir</string>
|
||||||
<string name="lbl_shuffle">Mezcla</string>
|
<string name="lbl_shuffle">Mezcla</string>
|
||||||
<string name="set_playback_mode_all">Reproducir todo</string>
|
<string name="set_playback_mode_songs">Reproducir todo</string>
|
||||||
<string name="set_playback_mode_album">Reproducir por álbum</string>
|
<string name="set_playback_mode_album">Reproducir por álbum</string>
|
||||||
<string name="set_playback_mode_artist">Reproducir por artista</string>
|
<string name="set_playback_mode_artist">Reproducir por artista</string>
|
||||||
<string name="lbl_queue">Cola</string>
|
<string name="lbl_queue">Cola</string>
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
<string name="set_pre_amp_warning">Upozorenje: Postavljanje pretpojačala na visoke razine može uzrokovati vrhunce tonova u nekim zvučnim zapisima.</string>
|
<string name="set_pre_amp_warning">Upozorenje: Postavljanje pretpojačala na visoke razine može uzrokovati vrhunce tonova u nekim zvučnim zapisima.</string>
|
||||||
<string name="set_library_song_playback_mode">Kada se reproducira iz zbirke</string>
|
<string name="set_library_song_playback_mode">Kada se reproducira iz zbirke</string>
|
||||||
<string name="set_detail_song_playback_mode">Kada se reproducira iz detalja o predmetu</string>
|
<string name="set_detail_song_playback_mode">Kada se reproducira iz detalja o predmetu</string>
|
||||||
<string name="set_playback_mode_all">Reproduciraj od svih pjesama</string>
|
<string name="set_playback_mode_songs">Reproduciraj od svih pjesama</string>
|
||||||
<string name="set_reindex">Aktualiziraj glazbu</string>
|
<string name="set_reindex">Aktualiziraj glazbu</string>
|
||||||
<string name="set_reindex_desc">Ponovo učitaj glazbenu biblioteku, koristeći predmemorirane oznake kada je to moguće</string>
|
<string name="set_reindex_desc">Ponovo učitaj glazbenu biblioteku, koristeći predmemorirane oznake kada je to moguće</string>
|
||||||
<string name="set_dirs">Mape glazbe</string>
|
<string name="set_dirs">Mape glazbe</string>
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
<string name="set_pre_amp_with">Penyesuaian dengan tag</string>
|
<string name="set_pre_amp_with">Penyesuaian dengan tag</string>
|
||||||
<string name="set_pre_amp_warning">Peringatan: Mengubah pre-amp ke nilai positif yang tinggi dapat mengakibatkan puncak pada beberapa trek audio.</string>
|
<string name="set_pre_amp_warning">Peringatan: Mengubah pre-amp ke nilai positif yang tinggi dapat mengakibatkan puncak pada beberapa trek audio.</string>
|
||||||
<string name="set_playback_mode_none">Putar dari item yang ditampilkan</string>
|
<string name="set_playback_mode_none">Putar dari item yang ditampilkan</string>
|
||||||
<string name="set_playback_mode_all">Putar dari semua lagu</string>
|
<string name="set_playback_mode_songs">Putar dari semua lagu</string>
|
||||||
<string name="set_keep_shuffle_desc">Tetap mengacak saat memutar lagu baru</string>
|
<string name="set_keep_shuffle_desc">Tetap mengacak saat memutar lagu baru</string>
|
||||||
<string name="set_repeat_pause">Jeda pada pengulangan</string>
|
<string name="set_repeat_pause">Jeda pada pengulangan</string>
|
||||||
<string name="set_rewind_prev">Putar balik sebelum melompat ke belakang</string>
|
<string name="set_rewind_prev">Putar balik sebelum melompat ke belakang</string>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<string name="lbl_playback">Ora in riproduzione</string>
|
<string name="lbl_playback">Ora in riproduzione</string>
|
||||||
<string name="lbl_play">Riproduci</string>
|
<string name="lbl_play">Riproduci</string>
|
||||||
<string name="lbl_shuffle">Mescola</string>
|
<string name="lbl_shuffle">Mescola</string>
|
||||||
<string name="set_playback_mode_all">Riproduci da tutte le canzoni</string>
|
<string name="set_playback_mode_songs">Riproduci da tutte le canzoni</string>
|
||||||
<string name="set_playback_mode_album">Riproduci dal disco</string>
|
<string name="set_playback_mode_album">Riproduci dal disco</string>
|
||||||
<string name="set_playback_mode_artist">Riproduci dall\'artista</string>
|
<string name="set_playback_mode_artist">Riproduci dall\'artista</string>
|
||||||
<string name="lbl_queue">Coda</string>
|
<string name="lbl_queue">Coda</string>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<string name="lbl_playback">지금 재생 중</string>
|
<string name="lbl_playback">지금 재생 중</string>
|
||||||
<string name="lbl_play">재생</string>
|
<string name="lbl_play">재생</string>
|
||||||
<string name="lbl_shuffle">셔플</string>
|
<string name="lbl_shuffle">셔플</string>
|
||||||
<string name="set_playback_mode_all">모든 곡에서 재생</string>
|
<string name="set_playback_mode_songs">모든 곡에서 재생</string>
|
||||||
<string name="set_playback_mode_album">앨범에서 재생</string>
|
<string name="set_playback_mode_album">앨범에서 재생</string>
|
||||||
<string name="set_playback_mode_artist">아티스트에서 재생</string>
|
<string name="set_playback_mode_artist">아티스트에서 재생</string>
|
||||||
<string name="lbl_queue">대기열</string>
|
<string name="lbl_queue">대기열</string>
|
||||||
|
|
|
@ -176,7 +176,7 @@
|
||||||
<string name="set_dirs_mode_exclude_desc">Muzika <b>nebus</b> įkeliama iš pridėtų aplankų jūs pridėsite.</string>
|
<string name="set_dirs_mode_exclude_desc">Muzika <b>nebus</b> įkeliama iš pridėtų aplankų jūs pridėsite.</string>
|
||||||
<string name="set_dirs_mode_include">Įtraukti</string>
|
<string name="set_dirs_mode_include">Įtraukti</string>
|
||||||
<string name="desc_clear_queue_item">Pašalinti šią eilės dainą</string>
|
<string name="desc_clear_queue_item">Pašalinti šią eilės dainą</string>
|
||||||
<string name="set_playback_mode_all">Groti iš visų dainų</string>
|
<string name="set_playback_mode_songs">Groti iš visų dainų</string>
|
||||||
<string name="set_playback_mode_none">Groti iš parodyto elemento</string>
|
<string name="set_playback_mode_none">Groti iš parodyto elemento</string>
|
||||||
<string name="set_playback_mode_album">Groti iš albumo</string>
|
<string name="set_playback_mode_album">Groti iš albumo</string>
|
||||||
<string name="set_playback_mode_artist">Groti iš atlikėjo</string>
|
<string name="set_playback_mode_artist">Groti iš atlikėjo</string>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<string name="lbl_sort_asc">Oplopend</string>
|
<string name="lbl_sort_asc">Oplopend</string>
|
||||||
<string name="lbl_play">Afspelen</string>
|
<string name="lbl_play">Afspelen</string>
|
||||||
<string name="lbl_shuffle">Shuffle</string>
|
<string name="lbl_shuffle">Shuffle</string>
|
||||||
<string name="set_playback_mode_all">Speel van alle nummers </string>
|
<string name="set_playback_mode_songs">Speel van alle nummers </string>
|
||||||
<string name="set_playback_mode_album">Speel af van album </string>
|
<string name="set_playback_mode_album">Speel af van album </string>
|
||||||
<string name="set_playback_mode_artist">Speel van artiest </string>
|
<string name="set_playback_mode_artist">Speel van artiest </string>
|
||||||
<string name="lbl_playback">Afspeelscherm</string>
|
<string name="lbl_playback">Afspeelscherm</string>
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
<string name="lbl_equalizer">Equalizer</string>
|
<string name="lbl_equalizer">Equalizer</string>
|
||||||
<string name="lbl_size">Rozmiar</string>
|
<string name="lbl_size">Rozmiar</string>
|
||||||
<string name="err_no_dirs">Brak folderów</string>
|
<string name="err_no_dirs">Brak folderów</string>
|
||||||
<string name="set_playback_mode_all">Odtwórz wszystkie utwory</string>
|
<string name="set_playback_mode_songs">Odtwórz wszystkie utwory</string>
|
||||||
<string name="set_playback_mode_album">Odtwórz album</string>
|
<string name="set_playback_mode_album">Odtwórz album</string>
|
||||||
<string name="set_headset_autoplay_desc">Zacznij odtawrzanie po podłączeniu słuchawek (może nie działać na wszystkich urządzeniach)</string>
|
<string name="set_headset_autoplay_desc">Zacznij odtawrzanie po podłączeniu słuchawek (może nie działać na wszystkich urządzeniach)</string>
|
||||||
<string name="set_reindex">Załaduj ponownie bibliotekę</string>
|
<string name="set_reindex">Załaduj ponownie bibliotekę</string>
|
||||||
|
|
|
@ -166,7 +166,7 @@
|
||||||
<string name="set_round_mode_desc">Ativar cantos arredondados em elementos adicionais da interface do usuário (requer que as capas dos álbuns sejam arredondadas)</string>
|
<string name="set_round_mode_desc">Ativar cantos arredondados em elementos adicionais da interface do usuário (requer que as capas dos álbuns sejam arredondadas)</string>
|
||||||
<string name="set_replay_gain">Modo de normalização de volume (ReplayGain)</string>
|
<string name="set_replay_gain">Modo de normalização de volume (ReplayGain)</string>
|
||||||
<string name="set_playback_mode_none">Reproduzir a partir do item mostrado</string>
|
<string name="set_playback_mode_none">Reproduzir a partir do item mostrado</string>
|
||||||
<string name="set_playback_mode_all">Reproduzir de todas as músicas</string>
|
<string name="set_playback_mode_songs">Reproduzir de todas as músicas</string>
|
||||||
<string name="set_replay_gain_album">Preferir álbum</string>
|
<string name="set_replay_gain_album">Preferir álbum</string>
|
||||||
<string name="set_replay_gain_dynamic">Prefira o álbum se estiver tocando</string>
|
<string name="set_replay_gain_dynamic">Prefira o álbum se estiver tocando</string>
|
||||||
<string name="set_observing">Recarregamento automático</string>
|
<string name="set_observing">Recarregamento automático</string>
|
||||||
|
|
|
@ -189,7 +189,7 @@
|
||||||
<string name="set_replay_gain">Estratégia do ganho de repetição</string>
|
<string name="set_replay_gain">Estratégia do ganho de repetição</string>
|
||||||
<string name="set_replay_gain_album">Preferir álbum</string>
|
<string name="set_replay_gain_album">Preferir álbum</string>
|
||||||
<string name="set_pre_amp_desc">O pré-amplificador é aplicado ao ajuste existente durante a reprodução</string>
|
<string name="set_pre_amp_desc">O pré-amplificador é aplicado ao ajuste existente durante a reprodução</string>
|
||||||
<string name="set_playback_mode_all">Reproduzir de todas as músicas</string>
|
<string name="set_playback_mode_songs">Reproduzir de todas as músicas</string>
|
||||||
<string name="set_repeat_pause_desc">Pausa quando uma música se repete</string>
|
<string name="set_repeat_pause_desc">Pausa quando uma música se repete</string>
|
||||||
<string name="set_wipe_desc">Limpe o estado de reprodução salvo anteriormente (se houver)</string>
|
<string name="set_wipe_desc">Limpe o estado de reprodução salvo anteriormente (se houver)</string>
|
||||||
<string name="set_restore_state">Restaurar o estado de reprodução</string>
|
<string name="set_restore_state">Restaurar o estado de reprodução</string>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<string name="lbl_playback">Сейчас играет</string>
|
<string name="lbl_playback">Сейчас играет</string>
|
||||||
<string name="lbl_play">Играть</string>
|
<string name="lbl_play">Играть</string>
|
||||||
<string name="lbl_shuffle">Перемешать</string>
|
<string name="lbl_shuffle">Перемешать</string>
|
||||||
<string name="set_playback_mode_all">Играть все треки</string>
|
<string name="set_playback_mode_songs">Играть все треки</string>
|
||||||
<string name="set_playback_mode_album">Играть альбом</string>
|
<string name="set_playback_mode_album">Играть альбом</string>
|
||||||
<string name="set_playback_mode_artist">Играть исполнителя</string>
|
<string name="set_playback_mode_artist">Играть исполнителя</string>
|
||||||
<string name="lbl_queue">Очередь</string>
|
<string name="lbl_queue">Очередь</string>
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
<string name="set_pre_amp_with">Etiket ile ayarla</string>
|
<string name="set_pre_amp_with">Etiket ile ayarla</string>
|
||||||
<string name="set_pre_amp_warning">Uyarı: Ön amfinin yüksek bir pozitif değere değiştirilmesi bazı ses parçalarında pik yapmaya neden olabilir.</string>
|
<string name="set_pre_amp_warning">Uyarı: Ön amfinin yüksek bir pozitif değere değiştirilmesi bazı ses parçalarında pik yapmaya neden olabilir.</string>
|
||||||
<string name="set_playback_mode_none">Gösterilen öğeden çal</string>
|
<string name="set_playback_mode_none">Gösterilen öğeden çal</string>
|
||||||
<string name="set_playback_mode_all">Tüm şarkılardan çal</string>
|
<string name="set_playback_mode_songs">Tüm şarkılardan çal</string>
|
||||||
<string name="set_playback_mode_album">Albümden çal</string>
|
<string name="set_playback_mode_album">Albümden çal</string>
|
||||||
<string name="set_dirs">Müzik klasörleri</string>
|
<string name="set_dirs">Müzik klasörleri</string>
|
||||||
<string name="set_dirs_mode_include_desc">Müzik <b>yalnızca</b> eklediğiniz klasörlerden yüklenecektir.</string>
|
<string name="set_dirs_mode_include_desc">Müzik <b>yalnızca</b> eklediğiniz klasörlerden yüklenecektir.</string>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<string name="lbl_playback">正在播放</string>
|
<string name="lbl_playback">正在播放</string>
|
||||||
<string name="lbl_play">播放</string>
|
<string name="lbl_play">播放</string>
|
||||||
<string name="lbl_shuffle">随机</string>
|
<string name="lbl_shuffle">随机</string>
|
||||||
<string name="set_playback_mode_all">从全部歌曲开始播放</string>
|
<string name="set_playback_mode_songs">从全部歌曲开始播放</string>
|
||||||
<string name="set_playback_mode_album">从专辑开始播放</string>
|
<string name="set_playback_mode_album">从专辑开始播放</string>
|
||||||
<string name="set_playback_mode_artist">从艺术家播放</string>
|
<string name="set_playback_mode_artist">从艺术家播放</string>
|
||||||
<string name="lbl_queue">播放队列</string>
|
<string name="lbl_queue">播放队列</string>
|
||||||
|
|
|
@ -99,22 +99,25 @@
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="entries_library_song_playback_mode">
|
<string-array name="entries_library_song_playback_mode">
|
||||||
<item>@string/set_playback_mode_all</item>
|
<item>@string/set_playback_mode_songs</item>
|
||||||
<item>@string/set_playback_mode_artist</item>
|
<item>@string/set_playback_mode_artist</item>
|
||||||
<item>@string/set_playback_mode_album</item>
|
<item>@string/set_playback_mode_album</item>
|
||||||
|
<item>@string/set_playback_mode_genre</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<integer-array name="values_library_song_playback_mode">
|
<integer-array name="values_library_song_playback_mode">
|
||||||
<item>@integer/music_mode_songs</item>
|
<item>@integer/music_mode_songs</item>
|
||||||
<item>@integer/music_mode_artist</item>
|
<item>@integer/music_mode_artist</item>
|
||||||
<item>@integer/music_mode_album</item>
|
<item>@integer/music_mode_album</item>
|
||||||
|
<item>@integer/music_mode_genre</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="entries_detail_song_playback_mode">
|
<string-array name="entries_detail_song_playback_mode">
|
||||||
<item>@string/set_playback_mode_none</item>
|
<item>@string/set_playback_mode_none</item>
|
||||||
<item>@string/set_playback_mode_all</item>
|
<item>@string/set_playback_mode_songs</item>
|
||||||
<item>@string/set_playback_mode_artist</item>
|
<item>@string/set_playback_mode_artist</item>
|
||||||
<item>@string/set_playback_mode_album</item>
|
<item>@string/set_playback_mode_album</item>
|
||||||
|
<item>@string/set_playback_mode_genre</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<integer-array name="values_detail_song_playback_mode">
|
<integer-array name="values_detail_song_playback_mode">
|
||||||
|
@ -122,6 +125,7 @@
|
||||||
<item>@integer/music_mode_songs</item>
|
<item>@integer/music_mode_songs</item>
|
||||||
<item>@integer/music_mode_artist</item>
|
<item>@integer/music_mode_artist</item>
|
||||||
<item>@integer/music_mode_album</item>
|
<item>@integer/music_mode_album</item>
|
||||||
|
<item>@integer/music_mode_genre</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="entries_replay_gain">
|
<string-array name="entries_replay_gain">
|
||||||
|
@ -141,6 +145,7 @@
|
||||||
<integer name="theme_dark">2</integer>
|
<integer name="theme_dark">2</integer>
|
||||||
|
|
||||||
<integer name="music_mode_none">-2147483648</integer>
|
<integer name="music_mode_none">-2147483648</integer>
|
||||||
|
<integer name="music_mode_genre">0xA108</integer>
|
||||||
<integer name="music_mode_artist">0xA109</integer>
|
<integer name="music_mode_artist">0xA109</integer>
|
||||||
<integer name="music_mode_album">0xA10A</integer>
|
<integer name="music_mode_album">0xA10A</integer>
|
||||||
<integer name="music_mode_songs">0xA10B</integer>
|
<integer name="music_mode_songs">0xA10B</integer>
|
||||||
|
|
|
@ -202,9 +202,10 @@
|
||||||
<string name="set_library_song_playback_mode">When playing from the library</string>
|
<string name="set_library_song_playback_mode">When playing from the library</string>
|
||||||
<string name="set_detail_song_playback_mode">When playing from item details</string>
|
<string name="set_detail_song_playback_mode">When playing from item details</string>
|
||||||
<string name="set_playback_mode_none">Play from shown item</string>
|
<string name="set_playback_mode_none">Play from shown item</string>
|
||||||
<string name="set_playback_mode_all">Play from all songs</string>
|
<string name="set_playback_mode_songs">Play from all songs</string>
|
||||||
<string name="set_playback_mode_album">Play from album</string>
|
<string name="set_playback_mode_album">Play from album</string>
|
||||||
<string name="set_playback_mode_artist">Play from artist</string>
|
<string name="set_playback_mode_artist">Play from artist</string>
|
||||||
|
<string name="set_playback_mode_genre">Play from genre</string>
|
||||||
<string name="set_keep_shuffle">Remember shuffle</string>
|
<string name="set_keep_shuffle">Remember shuffle</string>
|
||||||
<string name="set_keep_shuffle_desc">Keep shuffle on when playing a new song</string>
|
<string name="set_keep_shuffle_desc">Keep shuffle on when playing a new song</string>
|
||||||
<string name="set_rewind_prev">Rewind before skipping back</string>
|
<string name="set_rewind_prev">Rewind before skipping back</string>
|
||||||
|
|
Loading…
Reference in a new issue