music: add picker dialog
Add a dialog for picking a genre from several choices. This basically completes multi-genre support in Auxio, save more internal reworks. Note that it is extremely likely that the "Play from genre" setting will be removed soon. This feature has made me realize that such does not many any real sense, as genres are more semantically similar to playlists than artists or albums. This implementation only exists to make multi-artist support an easy plug-and-play operation. Resolves #201
This commit is contained in:
parent
2aa540c29a
commit
717f49fc20
37 changed files with 451 additions and 106 deletions
|
@ -29,16 +29,20 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
||||
import org.oxycblt.auxio.detail.recycler.AlbumDetailAdapter
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.picker.PickerMode
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.util.canScroll
|
||||
|
@ -125,11 +129,19 @@ class AlbumDetailFragment :
|
|||
|
||||
override fun onItemClick(item: Item) {
|
||||
check(item is Song) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||
val playbackMode = settings.detailPlaybackMode
|
||||
if (playbackMode != null) {
|
||||
playbackModel.play(item, playbackMode)
|
||||
} else {
|
||||
playbackModel.playFromAlbum(item)
|
||||
when (settings.detailPlaybackMode) {
|
||||
null, MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
navModel.mainNavigateTo(
|
||||
MainNavigationAction.Directions(
|
||||
MainFragmentDirections.showGenrePickerDialog(item.uid, PickerMode.PLAY)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
playbackModel.playFromGenre(item, item.genres[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import androidx.fragment.app.activityViewModels
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
||||
import org.oxycblt.auxio.detail.recycler.ArtistDetailAdapter
|
||||
|
@ -33,10 +34,13 @@ import org.oxycblt.auxio.detail.recycler.DetailAdapter
|
|||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.picker.PickerMode
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.util.collect
|
||||
|
@ -117,11 +121,19 @@ class ArtistDetailFragment :
|
|||
override fun onItemClick(item: Item) {
|
||||
when (item) {
|
||||
is Song -> {
|
||||
val playbackMode = settings.detailPlaybackMode
|
||||
if (playbackMode != null) {
|
||||
playbackModel.play(item, playbackMode)
|
||||
} else {
|
||||
playbackModel.playFromArtist(item)
|
||||
when (settings.detailPlaybackMode) {
|
||||
null, MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
navModel.mainNavigateTo(
|
||||
MainNavigationAction.Directions(
|
||||
MainFragmentDirections.showGenrePickerDialog(item.uid, PickerMode.PLAY)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
playbackModel.playFromGenre(item, item.genres[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
is Album -> navModel.exploreNavigateTo(item)
|
||||
|
|
|
@ -38,7 +38,7 @@ import org.oxycblt.auxio.music.Music
|
|||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.ReleaseType
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
|
|
|
@ -26,6 +26,7 @@ import androidx.fragment.app.activityViewModels
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
||||
import org.oxycblt.auxio.detail.recycler.DetailAdapter
|
||||
|
@ -34,10 +35,13 @@ import org.oxycblt.auxio.music.Album
|
|||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.picker.PickerMode
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.util.collect
|
||||
|
@ -117,11 +121,20 @@ class GenreDetailFragment :
|
|||
|
||||
override fun onItemClick(item: Item) {
|
||||
check(item is Song) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||
val playbackMode = settings.detailPlaybackMode
|
||||
if (playbackMode != null) {
|
||||
playbackModel.play(item, playbackMode)
|
||||
} else {
|
||||
playbackModel.playFromGenre(item, unlikelyToBeNull(detailModel.currentGenre.value))
|
||||
when (settings.detailPlaybackMode) {
|
||||
null -> playbackModel.playFromGenre(item, unlikelyToBeNull(detailModel.currentGenre.value))
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
navModel.mainNavigateTo(
|
||||
MainNavigationAction.Directions(
|
||||
MainFragmentDirections.showGenrePickerDialog(item.uid, PickerMode.PLAY)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
playbackModel.playFromGenre(item, item.genres[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import android.content.Context
|
|||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,11 +48,11 @@ import org.oxycblt.auxio.music.Album
|
|||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.system.Indexer
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
|
|
|
@ -26,10 +26,10 @@ import org.oxycblt.auxio.home.tabs.Tab
|
|||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.application
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
|
|
@ -24,11 +24,11 @@ import android.view.ViewGroup
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.formatDurationMs
|
||||
import org.oxycblt.auxio.music.secsToMs
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.ui.recycler.AlbumViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.IndicatorAdapter
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
|
|
|
@ -23,10 +23,10 @@ import android.view.ViewGroup
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.formatDurationMs
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.ui.recycler.ArtistViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.IndicatorAdapter
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
|
|
|
@ -23,10 +23,10 @@ import android.view.ViewGroup
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.formatDurationMs
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.ui.recycler.GenreViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.IndicatorAdapter
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
|
|
|
@ -21,15 +21,18 @@ import android.os.Bundle
|
|||
import android.text.format.DateUtils
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.formatDurationMs
|
||||
import org.oxycblt.auxio.music.picker.PickerMode
|
||||
import org.oxycblt.auxio.music.secsToMs
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||
import org.oxycblt.auxio.ui.recycler.IndicatorAdapter
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.ui.recycler.MenuItemListener
|
||||
|
@ -109,7 +112,20 @@ class SongListFragment : HomeListFragment<Song>() {
|
|||
|
||||
override fun onItemClick(item: Item) {
|
||||
check(item is Song) { "Unexpected datatype: ${item::class.java}" }
|
||||
playbackModel.play(item, settings.libPlaybackMode)
|
||||
when (settings.libPlaybackMode) {
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
navModel.mainNavigateTo(
|
||||
MainNavigationAction.Directions(
|
||||
MainFragmentDirections.showGenrePickerDialog(item.uid, PickerMode.PLAY)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
playbackModel.playFromGenre(item, item.genres[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOpenMenu(item: Item, anchor: View) {
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.oxycblt.auxio.home.tabs.Tab.Companion.fromSequence
|
|||
import org.oxycblt.auxio.home.tabs.Tab.Companion.toSequence
|
||||
import org.oxycblt.auxio.home.tabs.Tab.Invisible
|
||||
import org.oxycblt.auxio.home.tabs.Tab.Visible
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.util.logE
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,7 @@ import android.view.ViewGroup
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.ItemTabBinding
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.ui.recycler.DialogViewHolder
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import org.oxycblt.auxio.BuildConfig
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.DialogTabsBinding
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.fragment.ViewBindingDialogFragment
|
||||
import org.oxycblt.auxio.util.context
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import kotlin.math.min
|
||||
|
||||
/** A basic keyer for music data. */
|
||||
|
|
|
@ -26,8 +26,6 @@ import kotlinx.parcelize.Parcelize
|
|||
import org.oxycblt.auxio.BuildConfig
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.Date.Companion.from
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.util.inRangeOrNull
|
||||
import org.oxycblt.auxio.util.nonZeroOrNull
|
||||
|
@ -105,43 +103,34 @@ sealed class Music : Item {
|
|||
*/
|
||||
@Parcelize
|
||||
class UID private constructor(
|
||||
private val isMusicBrainz: Boolean,
|
||||
private val format: Format,
|
||||
private val mode: MusicMode,
|
||||
private val uuid: UUID
|
||||
) : Parcelable {
|
||||
// Cache the hashCode for speed
|
||||
@IgnoredOnParcel private val hashCode: Int
|
||||
@IgnoredOnParcel private var hashCode = format.hashCode()
|
||||
|
||||
init {
|
||||
var result = isMusicBrainz.hashCode()
|
||||
result = 31 * result + mode.hashCode()
|
||||
result = 31 * result + uuid.hashCode()
|
||||
hashCode = result
|
||||
hashCode = 31 * hashCode + mode.hashCode()
|
||||
hashCode = 31 * hashCode + uuid.hashCode()
|
||||
}
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) = other is UID &&
|
||||
isMusicBrainz == other.isMusicBrainz &&
|
||||
format == other.format &&
|
||||
mode == other.mode && uuid == other.uuid
|
||||
|
||||
override fun toString(): String {
|
||||
// Format comes first, delimited by a ":".
|
||||
val format = if (isMusicBrainz) {
|
||||
FORMAT_MUSICBRAINZ
|
||||
} else {
|
||||
FORMAT_AUXIO
|
||||
}
|
||||
// UID string format is roughly:
|
||||
// format_namespace:music_mode_int-uuid
|
||||
override fun toString() = "${format.namespace}:${mode.intCode.toString(16)}-$uuid"
|
||||
|
||||
// Instead of making new string values for the mode, be lazy and just append it's
|
||||
// intCode in front of the UUID.
|
||||
return "$format:${mode.intCode.toString(16)}-$uuid"
|
||||
private enum class Format(val namespace: String) {
|
||||
AUXIO("org.oxycblt.auxio"),
|
||||
MUSICBRAINZ("org.musicbrainz")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FORMAT_AUXIO = "org.oxycblt.auxio"
|
||||
private const val FORMAT_MUSICBRAINZ = "org.musicbrainz"
|
||||
|
||||
/** Parse a [UID] from the string [uid]. Returns null if not valid. */
|
||||
fun fromString(uid: String): UID? {
|
||||
val split = uid.split(':', limit = 2)
|
||||
|
@ -149,9 +138,9 @@ sealed class Music : Item {
|
|||
return null
|
||||
}
|
||||
|
||||
val isMusicBrainz = when (split[0]) {
|
||||
FORMAT_MUSICBRAINZ -> true
|
||||
FORMAT_AUXIO -> false
|
||||
val format = when (split[0]) {
|
||||
Format.AUXIO.namespace -> Format.AUXIO
|
||||
Format.MUSICBRAINZ.namespace -> Format.MUSICBRAINZ
|
||||
else -> return null
|
||||
}
|
||||
|
||||
|
@ -163,7 +152,7 @@ sealed class Music : Item {
|
|||
val mode = MusicMode.fromInt(ids[0].toIntOrNull(16) ?: return null) ?: return null
|
||||
val uuid = UUID.fromString(ids[1])
|
||||
|
||||
return UID(isMusicBrainz, mode, uuid)
|
||||
return UID(format, mode, uuid)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,7 +167,7 @@ sealed class Music : Item {
|
|||
val digest = MessageDigest.getInstance("MD5")
|
||||
updates(digest)
|
||||
val uuid = digest.digest().toUuid()
|
||||
return UID(false, mode, uuid)
|
||||
return UID(Format.AUXIO, mode, uuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.ui
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import org.oxycblt.auxio.IntegerTable
|
||||
|
|
@ -26,7 +26,6 @@ import android.provider.MediaStore
|
|||
import android.text.format.DateUtils
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import java.util.UUID
|
||||
|
||||
/** Shortcut for making a [ContentResolver] query with less superfluous arguments. */
|
||||
fun ContentResolver.queryCursor(
|
||||
|
|
|
@ -15,18 +15,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.ui
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import androidx.annotation.IdRes
|
||||
import org.oxycblt.auxio.IntegerTable
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Date
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.Sort.Mode
|
||||
import org.oxycblt.auxio.music.Sort.Mode
|
||||
|
||||
/**
|
||||
* Represents the sort modes used in Auxio.
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.settings
|
||||
package org.oxycblt.auxio.music.dirs
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.settings
|
||||
package org.oxycblt.auxio.music.dirs
|
||||
|
||||
import org.oxycblt.auxio.music.Directory
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.settings
|
||||
package org.oxycblt.auxio.music.dirs
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Auxio Project
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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.music.Genre
|
||||
import org.oxycblt.auxio.ui.recycler.DialogViewHolder
|
||||
import org.oxycblt.auxio.ui.recycler.ItemClickListener
|
||||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
|
||||
/**
|
||||
* The adapter that displays a list of genre choices in the picker UI.
|
||||
*/
|
||||
class GenreChoiceAdapter(private val listener: ItemClickListener) : 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)
|
||||
|
||||
fun submitList(newGenres: List<Genre>) {
|
||||
if (newGenres != genres) {
|
||||
genres = newGenres
|
||||
|
||||
@Suppress("NotifyDataSetChanged")
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The ViewHolder that displays a genre choice. Smaller than other parent items due to dialog
|
||||
* constraints.
|
||||
*/
|
||||
class GenreChoiceViewHolder(private val binding: ItemPickerChoiceBinding) : DialogViewHolder(binding.root) {
|
||||
fun bind(genre: Genre, listener: ItemClickListener) {
|
||||
binding.pickerImage.bind(genre)
|
||||
binding.pickerName.text = genre.resolveName(binding.context)
|
||||
binding.root.setOnClickListener {
|
||||
listener.onItemClick(genre)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun new(parent: View) =
|
||||
GenreChoiceViewHolder(ItemPickerChoiceBinding.inflate(parent.context.inflater))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Auxio Project
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.picker
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.activityViewModels
|
||||
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.music.Genre
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
import org.oxycblt.auxio.ui.fragment.ViewBindingDialogFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.ui.recycler.ItemClickListener
|
||||
import org.oxycblt.auxio.util.androidActivityViewModels
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
* A dialog that shows several genre options if the result of an genre-reliant operation is
|
||||
* ambiguous.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class GenrePickerDialog : ViewBindingDialogFragment<DialogMusicPickerBinding>(), ItemClickListener {
|
||||
private val pickerModel: PickerViewModel by viewModels()
|
||||
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
|
||||
private val navModel: NavigationViewModel by activityViewModels()
|
||||
|
||||
private val args: GenrePickerDialogArgs by navArgs()
|
||||
private val adapter = GenreChoiceAdapter(this)
|
||||
|
||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||
DialogMusicPickerBinding.inflate(inflater)
|
||||
|
||||
override fun onConfigDialog(builder: AlertDialog.Builder) {
|
||||
builder
|
||||
.setTitle(
|
||||
when (args.pickerMode) {
|
||||
PickerMode.GO -> R.string.lbl_go_genre
|
||||
PickerMode.PLAY -> R.string.lbl_play_genre
|
||||
}
|
||||
)
|
||||
.setNegativeButton(R.string.lbl_cancel, null)
|
||||
}
|
||||
|
||||
override fun onBindingCreated(binding: DialogMusicPickerBinding, savedInstanceState: Bundle?) {
|
||||
pickerModel.setSongUid(args.songUid)
|
||||
|
||||
binding.pickerRecycler.adapter = adapter
|
||||
|
||||
collectImmediately(pickerModel.currentSong) { song ->
|
||||
if (song != null) {
|
||||
adapter.submitList(song.genres)
|
||||
} else {
|
||||
findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyBinding(binding: DialogMusicPickerBinding) {
|
||||
binding.pickerRecycler.adapter = null
|
||||
}
|
||||
|
||||
override fun onItemClick(item: Item) {
|
||||
check(item is Genre) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||
findNavController().navigateUp()
|
||||
when (args.pickerMode) {
|
||||
PickerMode.GO -> navModel.exploreNavigateTo(item)
|
||||
PickerMode.PLAY -> {
|
||||
val song = unlikelyToBeNull(pickerModel.currentSong.value)
|
||||
playbackModel.playFromGenre(song, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Auxio Project
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.picker
|
||||
|
||||
/**
|
||||
* Represents the actions available to the picker UI.
|
||||
*/
|
||||
enum class PickerMode {
|
||||
PLAY,
|
||||
GO
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Auxio Project
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.picker
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
* A small ViewModel holding and updating the current song being shown in the picker UI.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class PickerViewModel : ViewModel(), MusicStore.Callback {
|
||||
private val musicStore = MusicStore.getInstance()
|
||||
|
||||
private val _currentSong = MutableStateFlow<Song?>(null)
|
||||
val currentSong: StateFlow<Song?> get() = _currentSong
|
||||
|
||||
fun setSongUid(uid: Music.UID) {
|
||||
if (_currentSong.value?.uid == uid) return
|
||||
val library = unlikelyToBeNull(musicStore.library)
|
||||
_currentSong.value = requireNotNull(library.find(uid)) { "Invalid song id provided" }
|
||||
}
|
||||
|
||||
override fun onLibraryChanged(library: MusicStore.Library?) {
|
||||
if (library != null) {
|
||||
val song = _currentSong.value
|
||||
if (song != null) {
|
||||
_currentSong.value = library.sanitize(song)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,14 +15,13 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.settings
|
||||
package org.oxycblt.auxio.music.separators
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.children
|
||||
import com.google.android.material.checkbox.MaterialCheckBox
|
||||
import org.oxycblt.auxio.BuildConfig
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.DialogSeparatorsBinding
|
||||
import org.oxycblt.auxio.settings.Settings
|
|
@ -32,12 +32,12 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.extractor.Api21MediaStoreLayer
|
||||
import org.oxycblt.auxio.music.extractor.Api29MediaStoreLayer
|
||||
import org.oxycblt.auxio.music.extractor.Api30MediaStoreLayer
|
||||
import org.oxycblt.auxio.music.extractor.CacheLayer
|
||||
import org.oxycblt.auxio.music.extractor.MetadataLayer
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.logW
|
||||
|
|
|
@ -32,7 +32,6 @@ import org.oxycblt.auxio.music.MusicParent
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.dsToMs
|
||||
import org.oxycblt.auxio.music.msToDs
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.playback.state.InternalPlayer
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateDatabase
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
|
@ -92,19 +91,9 @@ class PlaybackViewModel(application: Application) :
|
|||
|
||||
// --- PLAYING FUNCTIONS ---
|
||||
|
||||
/** Play a [song] with the [mode] specified, */
|
||||
fun play(song: Song, mode: MusicMode) {
|
||||
// TODO: Remove this function when selection is implemented
|
||||
|
||||
val parent =
|
||||
when (mode) {
|
||||
MusicMode.GENRES -> song.album
|
||||
MusicMode.ARTISTS -> song.album.artist
|
||||
MusicMode.ALBUMS -> song.genres.maxBy { it.songs.size }
|
||||
MusicMode.SONGS -> null
|
||||
}
|
||||
|
||||
playbackManager.play(song, parent, settings)
|
||||
/** Play a [song] from all songs. */
|
||||
fun play(song: Song) {
|
||||
playbackManager.play(song, null, settings)
|
||||
}
|
||||
|
||||
/** Play a song from it's album. */
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import org.oxycblt.auxio.BuildConfig
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.DialogPreAmpBinding
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
|
|
|
@ -29,16 +29,19 @@ import androidx.core.widget.addTextChangedListener
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentSearchBinding
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.picker.PickerMode
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
import org.oxycblt.auxio.ui.recycler.MenuItemListener
|
||||
|
@ -147,7 +150,20 @@ class SearchFragment :
|
|||
|
||||
override fun onItemClick(item: Item) {
|
||||
when (item) {
|
||||
is Song -> playbackModel.play(item, settings.libPlaybackMode)
|
||||
is Song -> when (settings.libPlaybackMode) {
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
navModel.mainNavigateTo(
|
||||
MainNavigationAction.Directions(
|
||||
MainFragmentDirections.showGenrePickerDialog(item.uid, PickerMode.PLAY)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
playbackModel.playFromGenre(item, item.genres[0])
|
||||
}
|
||||
}
|
||||
is MusicParent -> navModel.exploreNavigateTo(item)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,10 @@ import org.oxycblt.auxio.music.Album
|
|||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.ui.recycler.Header
|
||||
import org.oxycblt.auxio.ui.recycler.Item
|
||||
|
|
|
@ -28,9 +28,9 @@ import org.oxycblt.auxio.IntegerTable
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.home.tabs.Tab
|
||||
import org.oxycblt.auxio.music.Directory
|
||||
import org.oxycblt.auxio.music.settings.MusicDirs
|
||||
import org.oxycblt.auxio.music.ui.MusicMode
|
||||
import org.oxycblt.auxio.music.ui.Sort
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.dirs.MusicDirs
|
||||
import org.oxycblt.auxio.playback.BarAction
|
||||
import org.oxycblt.auxio.playback.replaygain.ReplayGainMode
|
||||
import org.oxycblt.auxio.playback.replaygain.ReplayGainPreAmp
|
||||
|
|
9
app/src/main/res/layout/dialog_music_picker.xml
Normal file
9
app/src/main/res/layout/dialog_music_picker.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.oxycblt.auxio.ui.recycler.DialogRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/picker_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_picker_choice" />
|
35
app/src/main/res/layout/item_picker_choice.xml
Normal file
35
app/src/main/res/layout/item_picker_choice.xml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingStart="@dimen/spacing_mid_large"
|
||||
android:paddingTop="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_mid_large"
|
||||
android:paddingBottom="@dimen/spacing_medium">
|
||||
|
||||
<org.oxycblt.auxio.image.ImageGroup
|
||||
android:id="@+id/picker_image"
|
||||
style="@style/Widget.Auxio.Image.Small"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:staticIcon="@drawable/ic_song_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/picker_name"
|
||||
style="@style/Widget.Auxio.TextView.Item.Primary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/spacing_mid_medium"
|
||||
android:textColor="@color/sel_accented_primary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/picker_image"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Artist" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -17,8 +17,24 @@
|
|||
<action
|
||||
android:id="@+id/action_show_details"
|
||||
app:destination="@id/song_detail_dialog" />
|
||||
<action
|
||||
android:id="@+id/show_genre_picker_dialog"
|
||||
app:destination="@id/genre_picker_dialog" />
|
||||
</fragment>
|
||||
|
||||
<dialog
|
||||
android:id="@+id/genre_picker_dialog"
|
||||
android:name="org.oxycblt.auxio.music.picker.GenrePickerDialog"
|
||||
android:label="genre_picker_dialog"
|
||||
tools:layout="@layout/dialog_music_picker">
|
||||
<argument
|
||||
android:name="songUid"
|
||||
app:argType="org.oxycblt.auxio.music.Music$UID" />
|
||||
<argument
|
||||
android:name="pickerMode"
|
||||
app:argType="org.oxycblt.auxio.music.picker.PickerMode" />
|
||||
</dialog>
|
||||
|
||||
<dialog
|
||||
android:id="@+id/song_detail_dialog"
|
||||
android:name="org.oxycblt.auxio.detail.SongDetailDialog"
|
||||
|
@ -67,12 +83,12 @@
|
|||
tools:layout="@layout/dialog_pre_amp" />
|
||||
<dialog
|
||||
android:id="@+id/music_dirs_dialog"
|
||||
android:name="org.oxycblt.auxio.music.settings.MusicDirsDialog"
|
||||
android:name="org.oxycblt.auxio.music.dirs.MusicDirsDialog"
|
||||
android:label="music_dirs_dialog"
|
||||
tools:layout="@layout/dialog_music_dirs" />
|
||||
<dialog
|
||||
android:id="@+id/separators_dialog"
|
||||
android:name="org.oxycblt.auxio.music.settings.SeparatorsDialog"
|
||||
android:name="org.oxycblt.auxio.music.separators.SeparatorsDialog"
|
||||
android:label="music_dirs_dialog"
|
||||
tools:layout="@layout/dialog_separators" />
|
||||
|
||||
|
|
|
@ -102,8 +102,11 @@
|
|||
<string name="lbl_play_next">Play next</string>
|
||||
<string name="lbl_queue_add">Add to queue</string>
|
||||
|
||||
<string name="lbl_go_genre">Go to genre</string>
|
||||
<string name="lbl_go_artist">Go to artist</string>
|
||||
<string name="lbl_go_album">Go to album</string>
|
||||
<string name="lbl_play_genre">Play from genre</string>
|
||||
<string name="lbl_play_artist">Play from artist</string>
|
||||
<string name="lbl_song_detail">View properties</string>
|
||||
|
||||
<string name="lbl_props">Song properties</string>
|
||||
|
@ -203,8 +206,8 @@
|
|||
<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_album">Play from album</string>
|
||||
<string name="set_playback_mode_artist">Play from artist</string>
|
||||
<string name="set_playback_mode_genre">Play from genre</string>
|
||||
<string name="set_playback_mode_artist">@string/lbl_play_artist</string>
|
||||
<string name="set_playback_mode_genre">@string/lbl_play_genre</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_rewind_prev">Rewind before skipping back</string>
|
||||
|
|
Loading…
Reference in a new issue