all: cleanup
Routine code inspection and cleanup, this time with the new lints from android studio giraffe.
This commit is contained in:
parent
842677fab4
commit
d6d1071535
49 changed files with 98 additions and 168 deletions
|
@ -36,8 +36,8 @@ import org.oxycblt.auxio.detail.list.SortHeader
|
||||||
import org.oxycblt.auxio.list.BasicHeader
|
import org.oxycblt.auxio.list.BasicHeader
|
||||||
import org.oxycblt.auxio.list.Divider
|
import org.oxycblt.auxio.list.Divider
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||||
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
|
|
@ -111,9 +111,7 @@ sealed interface ArtistShowChoices {
|
||||||
newLibrary.findSong(uid)?.let { FromSong(it) }
|
newLibrary.findSong(uid)?.let { FromSong(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Backing implementation of [ArtistShowChoices] that is based on an [Album]. */
|
||||||
* Backing implementation of [ArtistShowChoices] that is based on an [AlbumArtistShowChoices].
|
|
||||||
*/
|
|
||||||
data class FromAlbum(val album: Album) : ArtistShowChoices {
|
data class FromAlbum(val album: Album) : ArtistShowChoices {
|
||||||
override val uid = album.uid
|
override val uid = album.uid
|
||||||
override val choices = album.artists
|
override val choices = album.artists
|
||||||
|
|
|
@ -24,7 +24,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.databinding.DialogSortBinding
|
import org.oxycblt.auxio.databinding.DialogSortBinding
|
||||||
import org.oxycblt.auxio.detail.DetailViewModel
|
import org.oxycblt.auxio.detail.DetailViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.util.collectImmediately
|
import org.oxycblt.auxio.util.collectImmediately
|
||||||
|
|
|
@ -24,7 +24,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.databinding.DialogSortBinding
|
import org.oxycblt.auxio.databinding.DialogSortBinding
|
||||||
import org.oxycblt.auxio.detail.DetailViewModel
|
import org.oxycblt.auxio.detail.DetailViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.util.collectImmediately
|
import org.oxycblt.auxio.util.collectImmediately
|
||||||
|
|
|
@ -24,7 +24,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.databinding.DialogSortBinding
|
import org.oxycblt.auxio.databinding.DialogSortBinding
|
||||||
import org.oxycblt.auxio.detail.DetailViewModel
|
import org.oxycblt.auxio.detail.DetailViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.util.collectImmediately
|
import org.oxycblt.auxio.util.collectImmediately
|
||||||
|
|
|
@ -24,7 +24,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.databinding.DialogSortBinding
|
import org.oxycblt.auxio.databinding.DialogSortBinding
|
||||||
import org.oxycblt.auxio.detail.DetailViewModel
|
import org.oxycblt.auxio.detail.DetailViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
import org.oxycblt.auxio.music.Playlist
|
import org.oxycblt.auxio.music.Playlist
|
||||||
import org.oxycblt.auxio.util.collectImmediately
|
import org.oxycblt.auxio.util.collectImmediately
|
||||||
|
|
|
@ -24,8 +24,8 @@ import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.oxycblt.auxio.home.tabs.Tab
|
import org.oxycblt.auxio.home.tabs.Tab
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||||
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
@ -312,7 +312,7 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface Outer {
|
sealed interface Outer {
|
||||||
object Settings : Outer
|
data object Settings : Outer
|
||||||
|
|
||||||
object About : Outer
|
data object About : Outer
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.ListViewModel
|
import org.oxycblt.auxio.list.ListViewModel
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
|
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
|
||||||
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
|
|
|
@ -31,9 +31,9 @@ import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.ListViewModel
|
import org.oxycblt.auxio.list.ListViewModel
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.ArtistViewHolder
|
import org.oxycblt.auxio.list.recycler.ArtistViewHolder
|
||||||
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
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.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
|
|
|
@ -31,9 +31,9 @@ import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.ListViewModel
|
import org.oxycblt.auxio.list.ListViewModel
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.GenreViewHolder
|
import org.oxycblt.auxio.list.recycler.GenreViewHolder
|
||||||
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
|
|
|
@ -30,9 +30,9 @@ import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.ListViewModel
|
import org.oxycblt.auxio.list.ListViewModel
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.PlaylistViewHolder
|
import org.oxycblt.auxio.list.recycler.PlaylistViewHolder
|
||||||
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
|
|
|
@ -32,9 +32,9 @@ import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.ListViewModel
|
import org.oxycblt.auxio.list.ListViewModel
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.SongViewHolder
|
import org.oxycblt.auxio.list.recycler.SongViewHolder
|
||||||
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.MusicViewModel
|
import org.oxycblt.auxio.music.MusicViewModel
|
||||||
|
|
|
@ -21,7 +21,7 @@ package org.oxycblt.auxio.home.sort
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.home.HomeViewModel
|
import org.oxycblt.auxio.home.HomeViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,7 +21,7 @@ package org.oxycblt.auxio.home.sort
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.home.HomeViewModel
|
import org.oxycblt.auxio.home.HomeViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,7 +21,7 @@ package org.oxycblt.auxio.home.sort
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.home.HomeViewModel
|
import org.oxycblt.auxio.home.HomeViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,7 +21,7 @@ package org.oxycblt.auxio.home.sort
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.home.HomeViewModel
|
import org.oxycblt.auxio.home.HomeViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,7 +21,7 @@ package org.oxycblt.auxio.home.sort
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.home.HomeViewModel
|
import org.oxycblt.auxio.home.HomeViewModel
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.list.sort.SortDialog
|
import org.oxycblt.auxio.list.sort.SortDialog
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -50,7 +50,7 @@ import okio.buffer
|
||||||
import okio.source
|
import okio.source
|
||||||
import org.oxycblt.auxio.image.CoverMode
|
import org.oxycblt.auxio.image.CoverMode
|
||||||
import org.oxycblt.auxio.image.ImageSettings
|
import org.oxycblt.auxio.image.ImageSettings
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.util.logE
|
import org.oxycblt.auxio.util.logE
|
||||||
|
|
|
@ -70,7 +70,7 @@ abstract class FlexibleListAdapter<T, VH : RecyclerView.ViewHolder>(
|
||||||
*/
|
*/
|
||||||
sealed interface UpdateInstructions {
|
sealed interface UpdateInstructions {
|
||||||
/** Use an asynchronous diff. Useful for unpredictable updates, but looks chaotic and janky. */
|
/** Use an asynchronous diff. Useful for unpredictable updates, but looks chaotic and janky. */
|
||||||
object Diff : UpdateInstructions
|
data object Diff : UpdateInstructions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visually replace all items from a given point. More visually coherent than [Diff].
|
* Visually replace all items from a given point. More visually coherent than [Diff].
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021 Auxio Project
|
* Copyright (c) 2023 Auxio Project
|
||||||
* Sort.kt is part of Auxio.
|
* Sort.kt is part of Auxio.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.oxycblt.auxio.list
|
package org.oxycblt.auxio.list.sort
|
||||||
|
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import org.oxycblt.auxio.IntegerTable
|
import org.oxycblt.auxio.IntegerTable
|
||||||
|
@ -25,7 +25,6 @@ import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
|
||||||
import org.oxycblt.auxio.music.Playlist
|
import org.oxycblt.auxio.music.Playlist
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.music.info.Date
|
import org.oxycblt.auxio.music.info.Date
|
||||||
|
@ -41,22 +40,6 @@ import org.oxycblt.auxio.music.info.Disc
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
data class Sort(val mode: Mode, val direction: Direction) {
|
data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
/**
|
|
||||||
* Create a new [Sort] with the same [mode], but a different [Direction].
|
|
||||||
*
|
|
||||||
* @param direction The new [Direction] to sort in.
|
|
||||||
* @return A new sort with the same mode, but with the new [Direction] value applied.
|
|
||||||
*/
|
|
||||||
fun withDirection(direction: Direction) = Sort(mode, direction)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new [Sort] with the same [direction] value, but different [mode] value.
|
|
||||||
*
|
|
||||||
* @param mode Tbe new mode to use for the Sort.
|
|
||||||
* @return A new sort with the same [direction] value, but with the new [mode] applied.
|
|
||||||
*/
|
|
||||||
fun withMode(mode: Mode) = Sort(mode, direction)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort a list of [Song]s.
|
* Sort a list of [Song]s.
|
||||||
*
|
*
|
||||||
|
@ -215,7 +198,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
*
|
*
|
||||||
* @see Music.name
|
* @see Music.name
|
||||||
*/
|
*/
|
||||||
object ByName : Mode {
|
data object ByName : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_NAME
|
get() = IntegerTable.SORT_BY_NAME
|
||||||
|
|
||||||
|
@ -243,7 +226,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
*
|
*
|
||||||
* @see Album.name
|
* @see Album.name
|
||||||
*/
|
*/
|
||||||
object ByAlbum : Mode {
|
data object ByAlbum : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_ALBUM
|
get() = IntegerTable.SORT_BY_ALBUM
|
||||||
|
|
||||||
|
@ -263,7 +246,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
*
|
*
|
||||||
* @see Artist.name
|
* @see Artist.name
|
||||||
*/
|
*/
|
||||||
object ByArtist : Mode {
|
data object ByArtist : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_ARTIST
|
get() = IntegerTable.SORT_BY_ARTIST
|
||||||
|
|
||||||
|
@ -292,7 +275,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
* @see Song.date
|
* @see Song.date
|
||||||
* @see Album.dates
|
* @see Album.dates
|
||||||
*/
|
*/
|
||||||
object ByDate : Mode {
|
data object ByDate : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_YEAR
|
get() = IntegerTable.SORT_BY_YEAR
|
||||||
|
|
||||||
|
@ -314,7 +297,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sort by the duration of an item. */
|
/** Sort by the duration of an item. */
|
||||||
object ByDuration : Mode {
|
data object ByDuration : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_DURATION
|
get() = IntegerTable.SORT_BY_DURATION
|
||||||
|
|
||||||
|
@ -344,12 +327,8 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
compareBy(BasicComparator.PLAYLIST))
|
compareBy(BasicComparator.PLAYLIST))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sort by the amount of songs an item contains. Only available for MusicParents. */
|
||||||
* Sort by the amount of songs an item contains. Only available for [MusicParent]s.
|
data object ByCount : Mode {
|
||||||
*
|
|
||||||
* @see MusicParent.songs
|
|
||||||
*/
|
|
||||||
object ByCount : Mode {
|
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_COUNT
|
get() = IntegerTable.SORT_BY_COUNT
|
||||||
|
|
||||||
|
@ -380,7 +359,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
*
|
*
|
||||||
* @see Song.disc
|
* @see Song.disc
|
||||||
*/
|
*/
|
||||||
object ByDisc : Mode {
|
data object ByDisc : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_DISC
|
get() = IntegerTable.SORT_BY_DISC
|
||||||
|
|
||||||
|
@ -399,7 +378,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
*
|
*
|
||||||
* @see Song.track
|
* @see Song.track
|
||||||
*/
|
*/
|
||||||
object ByTrack : Mode {
|
data object ByTrack : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_TRACK
|
get() = IntegerTable.SORT_BY_TRACK
|
||||||
|
|
||||||
|
@ -419,7 +398,7 @@ data class Sort(val mode: Mode, val direction: Direction) {
|
||||||
* @see Song.dateAdded
|
* @see Song.dateAdded
|
||||||
* @see Album.dates
|
* @see Album.dates
|
||||||
*/
|
*/
|
||||||
object ByDateAdded : Mode {
|
data object ByDateAdded : Mode {
|
||||||
override val intCode: Int
|
override val intCode: Int
|
||||||
get() = IntegerTable.SORT_BY_DATE_ADDED
|
get() = IntegerTable.SORT_BY_DATE_ADDED
|
||||||
|
|
|
@ -26,7 +26,6 @@ import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.DialogSortBinding
|
import org.oxycblt.auxio.databinding.DialogSortBinding
|
||||||
import org.oxycblt.auxio.list.ClickableListListener
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||||
import org.oxycblt.auxio.ui.ViewBindingBottomSheetDialogFragment
|
import org.oxycblt.auxio.ui.ViewBindingBottomSheetDialogFragment
|
||||||
import org.oxycblt.auxio.util.systemBarInsetsCompat
|
import org.oxycblt.auxio.util.systemBarInsetsCompat
|
||||||
|
@ -35,7 +34,7 @@ abstract class SortDialog :
|
||||||
ViewBindingBottomSheetDialogFragment<DialogSortBinding>(),
|
ViewBindingBottomSheetDialogFragment<DialogSortBinding>(),
|
||||||
ClickableListListener<Sort.Mode>,
|
ClickableListListener<Sort.Mode>,
|
||||||
MaterialButtonToggleGroup.OnButtonCheckedListener {
|
MaterialButtonToggleGroup.OnButtonCheckedListener {
|
||||||
private val modeAdapter = SortModeAdapter(this)
|
private val modeAdapter = SortModeAdapter(@Suppress("LeakingThis") this)
|
||||||
|
|
||||||
abstract fun getInitialSort(): Sort?
|
abstract fun getInitialSort(): Sort?
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import org.oxycblt.auxio.databinding.ItemSortModeBinding
|
import org.oxycblt.auxio.databinding.ItemSortModeBinding
|
||||||
import org.oxycblt.auxio.list.ClickableListListener
|
import org.oxycblt.auxio.list.ClickableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
|
||||||
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
||||||
import org.oxycblt.auxio.util.context
|
import org.oxycblt.auxio.util.context
|
||||||
|
|
|
@ -57,7 +57,7 @@ sealed interface IndexingState {
|
||||||
*/
|
*/
|
||||||
sealed interface IndexingProgress {
|
sealed interface IndexingProgress {
|
||||||
/** Other work is being done that does not have a defined progress. */
|
/** Other work is being done that does not have a defined progress. */
|
||||||
object Indeterminate : IndexingProgress
|
data object Indeterminate : IndexingProgress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Songs are currently being loaded.
|
* Songs are currently being loaded.
|
||||||
|
|
|
@ -24,7 +24,7 @@ import androidx.core.content.edit
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.fs.Directory
|
import org.oxycblt.auxio.music.fs.Directory
|
||||||
import org.oxycblt.auxio.music.fs.MusicDirectories
|
import org.oxycblt.auxio.music.fs.MusicDirectories
|
||||||
import org.oxycblt.auxio.settings.Settings
|
import org.oxycblt.auxio.settings.Settings
|
||||||
|
@ -178,20 +178,11 @@ class MusicSettingsImpl @Inject constructor(@ApplicationContext context: Context
|
||||||
}
|
}
|
||||||
|
|
||||||
override var albumSongSort: Sort
|
override var albumSongSort: Sort
|
||||||
get() {
|
get() =
|
||||||
var sort =
|
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(
|
||||||
getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE))
|
getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE))
|
||||||
?: Sort(Sort.Mode.ByDisc, Sort.Direction.ASCENDING)
|
?: Sort(Sort.Mode.ByDisc, Sort.Direction.ASCENDING)
|
||||||
|
|
||||||
// Correct legacy album sort modes to Disc
|
|
||||||
if (sort.mode is Sort.Mode.ByName) {
|
|
||||||
sort = sort.withMode(Sort.Mode.ByDisc)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sort
|
|
||||||
}
|
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putInt(getString(R.string.set_key_album_songs_sort), value.intCode)
|
putInt(getString(R.string.set_key_album_songs_sort), value.intCode)
|
||||||
|
|
|
@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicRepository
|
import org.oxycblt.auxio.music.MusicRepository
|
||||||
import org.oxycblt.auxio.music.Playlist
|
import org.oxycblt.auxio.music.Playlist
|
||||||
|
@ -260,9 +260,9 @@ sealed interface ChosenName {
|
||||||
/** The current name already exists. */
|
/** The current name already exists. */
|
||||||
data class AlreadyExists(val prior: String) : ChosenName
|
data class AlreadyExists(val prior: String) : ChosenName
|
||||||
/** The current name is empty. */
|
/** The current name is empty. */
|
||||||
object Empty : ChosenName
|
data object Empty : ChosenName
|
||||||
/** The current name only consists of whitespace. */
|
/** The current name only consists of whitespace. */
|
||||||
object Blank : ChosenName
|
data object Blank : ChosenName
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,7 @@ package org.oxycblt.auxio.music.device
|
||||||
|
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.image.extractor.CoverUri
|
import org.oxycblt.auxio.image.extractor.CoverUri
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
|
|
@ -83,7 +83,7 @@ inline fun <reified R> ContentResolver.useQuery(
|
||||||
) = safeQuery(uri, projection, selector, args).use(block)
|
) = safeQuery(uri, projection, selector, args).use(block)
|
||||||
|
|
||||||
/** Album art [MediaStore] database is not a built-in constant, have to define it ourselves. */
|
/** Album art [MediaStore] database is not a built-in constant, have to define it ourselves. */
|
||||||
private val EXTERNAL_COVERS_URI = Uri.parse("content://media/external/audio/albumart")
|
private val externalCoversUri = Uri.parse("content://media/external/audio/albumart")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a [MediaStore] Song ID into a [Uri] to it's audio file.
|
* Convert a [MediaStore] Song ID into a [Uri] to it's audio file.
|
||||||
|
@ -102,21 +102,11 @@ fun Long.toAudioUri() =
|
||||||
* @return An external storage image [Uri]. May not exist.
|
* @return An external storage image [Uri]. May not exist.
|
||||||
* @see ContentUris.withAppendedId
|
* @see ContentUris.withAppendedId
|
||||||
*/
|
*/
|
||||||
fun Long.toCoverUri() = ContentUris.withAppendedId(EXTERNAL_COVERS_URI, this)
|
fun Long.toCoverUri() = ContentUris.withAppendedId(externalCoversUri, this)
|
||||||
|
|
||||||
// --- STORAGEMANAGER UTILITIES ---
|
// --- STORAGEMANAGER UTILITIES ---
|
||||||
// Largely derived from Material Files: https://github.com/zhanghai/MaterialFiles
|
// Largely derived from Material Files: https://github.com/zhanghai/MaterialFiles
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the analogous method to [StorageManager.getStorageVolumes] method that is usable from
|
|
||||||
* API 21 to API 23, in which the [StorageManager] API was hidden and differed greatly.
|
|
||||||
*
|
|
||||||
* @see StorageManager.getStorageVolumes
|
|
||||||
*/
|
|
||||||
@Suppress("NewApi")
|
|
||||||
private val SM_API21_GET_VOLUME_LIST_METHOD: Method by
|
|
||||||
lazyReflectedMethod(StorageManager::class, "getVolumeList")
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the analogous method to [StorageVolume.getDirectory] method that is usable from API 21
|
* Provides the analogous method to [StorageVolume.getDirectory] method that is usable from API 21
|
||||||
* to API 23, in which the [StorageVolume] API was hidden and differed greatly.
|
* to API 23, in which the [StorageVolume] API was hidden and differed greatly.
|
||||||
|
@ -124,7 +114,7 @@ private val SM_API21_GET_VOLUME_LIST_METHOD: Method by
|
||||||
* @see StorageVolume.getDirectory
|
* @see StorageVolume.getDirectory
|
||||||
*/
|
*/
|
||||||
@Suppress("NewApi")
|
@Suppress("NewApi")
|
||||||
private val SV_API21_GET_PATH_METHOD: Method by lazyReflectedMethod(StorageVolume::class, "getPath")
|
private val svApi21GetPathMethod: Method by lazyReflectedMethod(StorageVolume::class, "getPath")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [StorageVolume] considered the "primary" volume by the system, obtained in a
|
* The [StorageVolume] considered the "primary" volume by the system, obtained in a
|
||||||
|
@ -143,13 +133,7 @@ val StorageManager.primaryStorageVolumeCompat: StorageVolume
|
||||||
* @see StorageManager.getStorageVolumes
|
* @see StorageManager.getStorageVolumes
|
||||||
*/
|
*/
|
||||||
val StorageManager.storageVolumesCompat: List<StorageVolume>
|
val StorageManager.storageVolumesCompat: List<StorageVolume>
|
||||||
get() =
|
get() = storageVolumes.toList()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
storageVolumes.toList()
|
|
||||||
} else {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
(SM_API21_GET_VOLUME_LIST_METHOD.invoke(this) as Array<StorageVolume>).toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The the absolute path to this [StorageVolume]'s directory within the file-system, in a
|
* The the absolute path to this [StorageVolume]'s directory within the file-system, in a
|
||||||
|
@ -166,8 +150,7 @@ val StorageVolume.directoryCompat: String?
|
||||||
// Replicate API: Analogous method if mounted, null if not
|
// Replicate API: Analogous method if mounted, null if not
|
||||||
when (stateCompat) {
|
when (stateCompat) {
|
||||||
Environment.MEDIA_MOUNTED,
|
Environment.MEDIA_MOUNTED,
|
||||||
Environment.MEDIA_MOUNTED_READ_ONLY ->
|
Environment.MEDIA_MOUNTED_READ_ONLY -> svApi21GetPathMethod.invoke(this) as String
|
||||||
SV_API21_GET_PATH_METHOD.invoke(this) as String
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,8 +145,8 @@ sealed interface Name : Comparable<Name> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val COLLATOR: Collator = Collator.getInstance().apply { strength = Collator.PRIMARY }
|
private val collator: Collator = Collator.getInstance().apply { strength = Collator.PRIMARY }
|
||||||
private val PUNCT_REGEX by lazy { Regex("[\\p{Punct}+]") }
|
private val punctRegex by lazy { Regex("[\\p{Punct}+]") }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plain [Name.Known] implementation that is internationalization-safe.
|
* Plain [Name.Known] implementation that is internationalization-safe.
|
||||||
|
@ -159,8 +159,8 @@ private data class SimpleKnownName(override val raw: String, override val sort:
|
||||||
|
|
||||||
private fun parseToken(name: String): SortToken {
|
private fun parseToken(name: String): SortToken {
|
||||||
// Remove excess punctuation from the string, as those usually aren't considered in sorting.
|
// Remove excess punctuation from the string, as those usually aren't considered in sorting.
|
||||||
val stripped = name.replace(PUNCT_REGEX, "").ifEmpty { name }
|
val stripped = name.replace(punctRegex, "").ifEmpty { name }
|
||||||
val collationKey = COLLATOR.getCollationKey(stripped)
|
val collationKey = collator.getCollationKey(stripped)
|
||||||
// Always use lexicographic mode since we aren't parsing any numeric components
|
// Always use lexicographic mode since we aren't parsing any numeric components
|
||||||
return SortToken(collationKey, SortToken.Type.LEXICOGRAPHIC)
|
return SortToken(collationKey, SortToken.Type.LEXICOGRAPHIC)
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ private data class IntelligentKnownName(override val raw: String, override val s
|
||||||
val stripped =
|
val stripped =
|
||||||
name
|
name
|
||||||
// Remove excess punctuation from the string, as those u
|
// Remove excess punctuation from the string, as those u
|
||||||
.replace(PUNCT_REGEX, "")
|
.replace(punctRegex, "")
|
||||||
.ifEmpty { name }
|
.ifEmpty { name }
|
||||||
.run {
|
.run {
|
||||||
// Strip any english articles like "the" or "an" from the start, as music
|
// Strip any english articles like "the" or "an" from the start, as music
|
||||||
|
@ -208,10 +208,10 @@ private data class IntelligentKnownName(override val raw: String, override val s
|
||||||
val digits =
|
val digits =
|
||||||
token.trimStart { Character.getNumericValue(it) == 0 }.ifEmpty { token }
|
token.trimStart { Character.getNumericValue(it) == 0 }.ifEmpty { token }
|
||||||
// Other languages have other types of digit strings, still use collation keys
|
// Other languages have other types of digit strings, still use collation keys
|
||||||
collationKey = COLLATOR.getCollationKey(digits)
|
collationKey = collator.getCollationKey(digits)
|
||||||
type = SortToken.Type.NUMERIC
|
type = SortToken.Type.NUMERIC
|
||||||
} else {
|
} else {
|
||||||
collationKey = COLLATOR.getCollationKey(token)
|
collationKey = collator.getCollationKey(token)
|
||||||
type = SortToken.Type.LEXICOGRAPHIC
|
type = SortToken.Type.LEXICOGRAPHIC
|
||||||
}
|
}
|
||||||
SortToken(collationKey, type)
|
SortToken(collationKey, type)
|
||||||
|
|
|
@ -111,7 +111,7 @@ sealed interface ReleaseType {
|
||||||
* A soundtrack. Similar to a [Compilation], but created for a specific piece of (usually
|
* A soundtrack. Similar to a [Compilation], but created for a specific piece of (usually
|
||||||
* visual) media.
|
* visual) media.
|
||||||
*/
|
*/
|
||||||
object Soundtrack : ReleaseType {
|
data object Soundtrack : ReleaseType {
|
||||||
override val refinement: Refinement?
|
override val refinement: Refinement?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ sealed interface ReleaseType {
|
||||||
* A (DJ) Mix. These are usually one large track consisting of the artist playing several
|
* A (DJ) Mix. These are usually one large track consisting of the artist playing several
|
||||||
* sub-tracks with smooth transitions between them.
|
* sub-tracks with smooth transitions between them.
|
||||||
*/
|
*/
|
||||||
object Mix : ReleaseType {
|
data object Mix : ReleaseType {
|
||||||
override val refinement: Refinement?
|
override val refinement: Refinement?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ sealed interface ReleaseType {
|
||||||
* A Mix-tape. These are usually [EP]-sized releases of music made to promote an Artist or a
|
* A Mix-tape. These are usually [EP]-sized releases of music made to promote an Artist or a
|
||||||
* future release.
|
* future release.
|
||||||
*/
|
*/
|
||||||
object Mixtape : ReleaseType {
|
data object Mixtape : ReleaseType {
|
||||||
override val refinement: Refinement?
|
override val refinement: Refinement?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
||||||
|
|
|
@ -204,14 +204,14 @@ private fun String.parseId3v1Genre(): String? {
|
||||||
"RX" -> "Remix"
|
"RX" -> "Remix"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
return GENRE_TABLE.getOrNull(numeric)
|
return genreTable.getOrNull(numeric)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [Regex] that implements parsing for ID3v2's genre format. Derived from mutagen:
|
* A [Regex] that implements parsing for ID3v2's genre format. Derived from mutagen:
|
||||||
* https://github.com/quodlibet/mutagen
|
* https://github.com/quodlibet/mutagen
|
||||||
*/
|
*/
|
||||||
private val ID3V2_GENRE_RE by lazy { Regex("((?:\\((\\d+|RX|CR)\\))*)(.+)?") }
|
private val id3v2GenreRe by lazy { Regex("((?:\\((\\d+|RX|CR)\\))*)(.+)?") }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an ID3v2 integer genre field, which has support for multiple genre values and combined
|
* Parse an ID3v2 integer genre field, which has support for multiple genre values and combined
|
||||||
|
@ -220,7 +220,7 @@ private val ID3V2_GENRE_RE by lazy { Regex("((?:\\((\\d+|RX|CR)\\))*)(.+)?") }
|
||||||
* @return A list of one or more genres, or null if the field is not a valid ID3v2 integer genre.
|
* @return A list of one or more genres, or null if the field is not a valid ID3v2 integer genre.
|
||||||
*/
|
*/
|
||||||
private fun String.parseId3v2Genre(): List<String>? {
|
private fun String.parseId3v2Genre(): List<String>? {
|
||||||
val groups = (ID3V2_GENRE_RE.matchEntire(this) ?: return null).groupValues
|
val groups = (id3v2GenreRe.matchEntire(this) ?: return null).groupValues
|
||||||
val genres = mutableSetOf<String>()
|
val genres = mutableSetOf<String>()
|
||||||
|
|
||||||
// ID3v2.3 genres are far more complex and require string grokking to properly implement.
|
// ID3v2.3 genres are far more complex and require string grokking to properly implement.
|
||||||
|
@ -260,7 +260,7 @@ private fun String.parseId3v2Genre(): List<String>? {
|
||||||
* A table of the "conventional" mapping between ID3v1 integer genres and their named counterparts.
|
* A table of the "conventional" mapping between ID3v1 integer genres and their named counterparts.
|
||||||
* Includes non-standard extensions.
|
* Includes non-standard extensions.
|
||||||
*/
|
*/
|
||||||
private val GENRE_TABLE =
|
private val genreTable =
|
||||||
arrayOf(
|
arrayOf(
|
||||||
// ID3 Standard
|
// ID3 Standard
|
||||||
"Blues",
|
"Blues",
|
||||||
|
|
|
@ -36,7 +36,7 @@ import org.oxycblt.auxio.util.newMainPendingIntent
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class IndexingNotification(private val context: Context) :
|
class IndexingNotification(private val context: Context) :
|
||||||
ForegroundServiceNotification(context, INDEXER_CHANNEL) {
|
ForegroundServiceNotification(context, indexerChannel) {
|
||||||
private var lastUpdateTime = -1L
|
private var lastUpdateTime = -1L
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -98,7 +98,7 @@ class IndexingNotification(private val context: Context) :
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class ObservingNotification(context: Context) :
|
class ObservingNotification(context: Context) :
|
||||||
ForegroundServiceNotification(context, INDEXER_CHANNEL) {
|
ForegroundServiceNotification(context, indexerChannel) {
|
||||||
init {
|
init {
|
||||||
setSmallIcon(R.drawable.ic_indexer_24)
|
setSmallIcon(R.drawable.ic_indexer_24)
|
||||||
setCategory(NotificationCompat.CATEGORY_SERVICE)
|
setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||||
|
@ -115,6 +115,6 @@ class ObservingNotification(context: Context) :
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notification channel shared by [IndexingNotification] and [ObservingNotification]. */
|
/** Notification channel shared by [IndexingNotification] and [ObservingNotification]. */
|
||||||
private val INDEXER_CHANNEL =
|
private val indexerChannel =
|
||||||
ForegroundServiceNotification.ChannelInfo(
|
ForegroundServiceNotification.ChannelInfo(
|
||||||
id = BuildConfig.APPLICATION_ID + ".channel.INDEXER", nameRes = R.string.lbl_indexer)
|
id = BuildConfig.APPLICATION_ID + ".channel.INDEXER", nameRes = R.string.lbl_indexer)
|
||||||
|
|
|
@ -51,7 +51,7 @@ abstract class UserMusicDatabase : RoomDatabase() {
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
@Dao
|
@Dao
|
||||||
abstract class PlaylistDao() {
|
abstract class PlaylistDao {
|
||||||
/**
|
/**
|
||||||
* Read out all playlists stored in the database.
|
* Read out all playlists stored in the database.
|
||||||
*
|
*
|
||||||
|
|
|
@ -44,12 +44,12 @@ sealed interface PlaySong {
|
||||||
val intCode: Int
|
val intCode: Int
|
||||||
|
|
||||||
/** Play a Song from the entire library of songs. */
|
/** Play a Song from the entire library of songs. */
|
||||||
object FromAll : PlaySong {
|
data object FromAll : PlaySong {
|
||||||
override val intCode = IntegerTable.PLAY_SONG_FROM_ALL
|
override val intCode = IntegerTable.PLAY_SONG_FROM_ALL
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Play a song from it's album. */
|
/** Play a song from it's album. */
|
||||||
object FromAlbum : PlaySong {
|
data object FromAlbum : PlaySong {
|
||||||
override val intCode = IntegerTable.PLAY_SONG_FROM_ALBUM
|
override val intCode = IntegerTable.PLAY_SONG_FROM_ALBUM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ sealed interface PlaySong {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Only play the given song, include nothing else in the queue. */
|
/** Only play the given song, include nothing else in the queue. */
|
||||||
object ByItself : PlaySong {
|
data object ByItself : PlaySong {
|
||||||
override val intCode = IntegerTable.PLAY_SONG_BY_ITSELF
|
override val intCode = IntegerTable.PLAY_SONG_BY_ITSELF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,13 +77,13 @@ interface InternalPlayer {
|
||||||
/** Possible long-running background tasks handled by the background playback task. */
|
/** Possible long-running background tasks handled by the background playback task. */
|
||||||
sealed interface Action {
|
sealed interface Action {
|
||||||
/** Restore the previously saved playback state. */
|
/** Restore the previously saved playback state. */
|
||||||
object RestoreState : Action
|
data object RestoreState : Action
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start shuffled playback of the entire music library. Analogous to the "Shuffle All"
|
* Start shuffled playback of the entire music library. Analogous to the "Shuffle All"
|
||||||
* shortcut.
|
* shortcut.
|
||||||
*/
|
*/
|
||||||
object ShuffleAll : Action
|
data object ShuffleAll : Action
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start playing an audio file at the given [Uri].
|
* Start playing an audio file at the given [Uri].
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.oxycblt.auxio.util.logD
|
||||||
class MediaButtonReceiver : BroadcastReceiver() {
|
class MediaButtonReceiver : BroadcastReceiver() {
|
||||||
@Inject lateinit var playbackManager: PlaybackStateManager
|
@Inject lateinit var playbackManager: PlaybackStateManager
|
||||||
|
|
||||||
|
// TODO: Figure this out
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
if (playbackManager.queue.currentSong != null) {
|
if (playbackManager.queue.currentSong != null) {
|
||||||
// We have a song, so we can assume that the service will start a foreground state.
|
// We have a song, so we can assume that the service will start a foreground state.
|
||||||
|
|
|
@ -25,8 +25,8 @@ import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.media.audiofx.AudioEffect
|
import android.media.audiofx.AudioEffect
|
||||||
import android.os.Build
|
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.media3.common.AudioAttributes
|
import androidx.media3.common.AudioAttributes
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
|
@ -165,18 +165,8 @@ class PlaybackService :
|
||||||
addAction(WidgetProvider.ACTION_WIDGET_UPDATE)
|
addAction(WidgetProvider.ACTION_WIDGET_UPDATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
ContextCompat.registerReceiver(
|
||||||
registerReceiver(
|
this, systemReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED)
|
||||||
systemReceiver,
|
|
||||||
intentFilter,
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
RECEIVER_NOT_EXPORTED
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
registerReceiver(systemReceiver, intentFilter)
|
|
||||||
}
|
|
||||||
|
|
||||||
logD("Service created")
|
logD("Service created")
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.list.BasicHeader
|
import org.oxycblt.auxio.list.BasicHeader
|
||||||
import org.oxycblt.auxio.list.Divider
|
import org.oxycblt.auxio.list.Divider
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.MusicRepository
|
import org.oxycblt.auxio.music.MusicRepository
|
||||||
import org.oxycblt.auxio.music.MusicType
|
import org.oxycblt.auxio.music.MusicType
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
|
|
@ -121,7 +121,6 @@ class AboutFragment : ViewBindingFragment<FragmentAboutBinding>() {
|
||||||
// case, we will try to manually handle these cases before we try to launch the
|
// case, we will try to manually handle these cases before we try to launch the
|
||||||
// browser.
|
// browser.
|
||||||
logD("Resolving browser activity for chooser")
|
logD("Resolving browser activity for chooser")
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
val pkgName =
|
val pkgName =
|
||||||
context.packageManager
|
context.packageManager
|
||||||
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
|
.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
|
||||||
|
|
|
@ -22,7 +22,7 @@ import android.os.Build
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.util.logW
|
import org.oxycblt.auxio.util.logW
|
||||||
|
|
||||||
private val ACCENT_NAMES =
|
private val accentNames =
|
||||||
intArrayOf(
|
intArrayOf(
|
||||||
R.string.clr_red,
|
R.string.clr_red,
|
||||||
R.string.clr_pink,
|
R.string.clr_pink,
|
||||||
|
@ -42,7 +42,7 @@ private val ACCENT_NAMES =
|
||||||
R.string.clr_grey,
|
R.string.clr_grey,
|
||||||
R.string.clr_dynamic)
|
R.string.clr_dynamic)
|
||||||
|
|
||||||
private val ACCENT_THEMES =
|
private val accentThemes =
|
||||||
intArrayOf(
|
intArrayOf(
|
||||||
R.style.Theme_Auxio_Red,
|
R.style.Theme_Auxio_Red,
|
||||||
R.style.Theme_Auxio_Pink,
|
R.style.Theme_Auxio_Pink,
|
||||||
|
@ -63,7 +63,7 @@ private val ACCENT_THEMES =
|
||||||
R.style.Theme_Auxio_App // Dynamic colors are on the base theme
|
R.style.Theme_Auxio_App // Dynamic colors are on the base theme
|
||||||
)
|
)
|
||||||
|
|
||||||
private val ACCENT_BLACK_THEMES =
|
private val accentBlackThemes =
|
||||||
intArrayOf(
|
intArrayOf(
|
||||||
R.style.Theme_Auxio_Black_Red,
|
R.style.Theme_Auxio_Black_Red,
|
||||||
R.style.Theme_Auxio_Black_Pink,
|
R.style.Theme_Auxio_Black_Pink,
|
||||||
|
@ -84,7 +84,7 @@ private val ACCENT_BLACK_THEMES =
|
||||||
R.style.Theme_Auxio_Black // Dynamic colors are on the base theme
|
R.style.Theme_Auxio_Black // Dynamic colors are on the base theme
|
||||||
)
|
)
|
||||||
|
|
||||||
private val ACCENT_PRIMARY_COLORS =
|
private val accentPrimaryColors =
|
||||||
intArrayOf(
|
intArrayOf(
|
||||||
R.color.red_primary,
|
R.color.red_primary,
|
||||||
R.color.pink_primary,
|
R.color.pink_primary,
|
||||||
|
@ -115,18 +115,18 @@ private val ACCENT_PRIMARY_COLORS =
|
||||||
class Accent private constructor(val index: Int) {
|
class Accent private constructor(val index: Int) {
|
||||||
/** The name of this [Accent]. */
|
/** The name of this [Accent]. */
|
||||||
val name: Int
|
val name: Int
|
||||||
get() = ACCENT_NAMES[index]
|
get() = accentNames[index]
|
||||||
/** The theme resource for this accent. */
|
/** The theme resource for this accent. */
|
||||||
val theme: Int
|
val theme: Int
|
||||||
get() = ACCENT_THEMES[index]
|
get() = accentThemes[index]
|
||||||
/**
|
/**
|
||||||
* The black theme resource for this accent. Identical to [theme], but with a black background.
|
* The black theme resource for this accent. Identical to [theme], but with a black background.
|
||||||
*/
|
*/
|
||||||
val blackTheme: Int
|
val blackTheme: Int
|
||||||
get() = ACCENT_BLACK_THEMES[index]
|
get() = accentBlackThemes[index]
|
||||||
/** The accent's primary color. */
|
/** The accent's primary color. */
|
||||||
val primary: Int
|
val primary: Int
|
||||||
get() = ACCENT_PRIMARY_COLORS[index]
|
get() = accentPrimaryColors[index]
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is Accent && index == other.index
|
override fun equals(other: Any?) = other is Accent && index == other.index
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ class Accent private constructor(val index: Int) {
|
||||||
val DEFAULT =
|
val DEFAULT =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
// Use dynamic coloring on devices that support it.
|
// Use dynamic coloring on devices that support it.
|
||||||
ACCENT_THEMES.lastIndex
|
accentThemes.lastIndex
|
||||||
} else {
|
} else {
|
||||||
// Use blue everywhere else.
|
// Use blue everywhere else.
|
||||||
5
|
5
|
||||||
|
@ -161,10 +161,10 @@ class Accent private constructor(val index: Int) {
|
||||||
/** The amount of valid accents. */
|
/** The amount of valid accents. */
|
||||||
val MAX =
|
val MAX =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
ACCENT_THEMES.size
|
accentThemes.size
|
||||||
} else {
|
} else {
|
||||||
// Disable the option for a dynamic accent on unsupported devices.
|
// Disable the option for a dynamic accent on unsupported devices.
|
||||||
ACCENT_THEMES.size - 1
|
accentThemes.size - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="@dimen/spacing_medium"
|
android:layout_marginHorizontal="@dimen/spacing_medium"
|
||||||
android:text="Sort By"
|
android:text="@string/lbl_sort_mode"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
style="@style/Widget.Auxio.TextView.Header"
|
style="@style/Widget.Auxio.TextView.Header"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Direction"
|
android:text="@string/lbl_sort_direction"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface"
|
android:background="?attr/colorSurface"
|
||||||
|
@ -28,7 +27,6 @@
|
||||||
android:id="@android:id/list_container"
|
android:id="@android:id/list_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||||
tools:targetApi="n" />
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout 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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_play"
|
android:id="@+id/action_play"
|
||||||
android:title="@string/lbl_play"
|
android:title="@string/lbl_play"
|
||||||
|
|
|
@ -469,10 +469,4 @@
|
||||||
android:name="parcel"
|
android:name="parcel"
|
||||||
app:argType="org.oxycblt.auxio.list.Menu$ForPlaylist$Parcel" />
|
app:argType="org.oxycblt.auxio.list.Menu$ForPlaylist$Parcel" />
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<dialog
|
|
||||||
android:id="@+id/sort_dialog"
|
|
||||||
android:name="org.oxycblt.auxio.list.sort.SortDialog"
|
|
||||||
android:label="sort_dialog"
|
|
||||||
tools:layout="@layout/dialog_sort" />
|
|
||||||
</navigation>
|
</navigation>
|
|
@ -1,2 +1,2 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources />
|
|
@ -172,7 +172,7 @@
|
||||||
<string name="set_separators">मल्टी-मूल्य विभाजक</string>
|
<string name="set_separators">मल्टी-मूल्य विभाजक</string>
|
||||||
<string name="fmt_lib_genre_count">लोड की गई शैलियाँ: %d</string>
|
<string name="fmt_lib_genre_count">लोड की गई शैलियाँ: %d</string>
|
||||||
<string name="fmt_lib_album_count">लोड किए गए एल्बम: %d</string>
|
<string name="fmt_lib_album_count">लोड किए गए एल्बम: %d</string>
|
||||||
<string name="fmt_indexing">आपकी संगीत लाइब्रेरी लोड कर रहे हैं... (%1$d/%2$d)</string>
|
<string name="fmt_indexing">आपकी संगीत लाइब्रेरी लोड कर रहे हैं… (%1$d/%2$d)</string>
|
||||||
<string name="fmt_bitrate">%d kbps</string>
|
<string name="fmt_bitrate">%d kbps</string>
|
||||||
<string name="lng_indexing">आपकी संगीत लाइब्रेरी लोड कर रहे हैं…</string>
|
<string name="lng_indexing">आपकी संगीत लाइब्रेरी लोड कर रहे हैं…</string>
|
||||||
<string name="lng_playlist_created">प्लेलिस्ट बनाई गई</string>
|
<string name="lng_playlist_created">प्लेलिस्ट बनाई गई</string>
|
||||||
|
|
|
@ -161,7 +161,6 @@
|
||||||
<integer name="play_song_from_album">0xA120</integer>
|
<integer name="play_song_from_album">0xA120</integer>
|
||||||
<integer name="play_song_from_artist">0xA121</integer>
|
<integer name="play_song_from_artist">0xA121</integer>
|
||||||
<integer name="play_song_from_genre">0xA122</integer>
|
<integer name="play_song_from_genre">0xA122</integer>
|
||||||
<integer name="play_song_from_playlist">0xA123</integer>
|
|
||||||
<integer name="play_song_by_itself">0xA124</integer>
|
<integer name="play_song_by_itself">0xA124</integer>
|
||||||
|
|
||||||
<integer name="replay_gain_track">0xA111</integer>
|
<integer name="replay_gain_track">0xA111</integer>
|
||||||
|
|
|
@ -104,6 +104,8 @@
|
||||||
<string name="lbl_date_added">Date added</string>
|
<string name="lbl_date_added">Date added</string>
|
||||||
|
|
||||||
<string name="lbl_sort">Sort</string>
|
<string name="lbl_sort">Sort</string>
|
||||||
|
<string name="lbl_sort_mode">Sort by</string>
|
||||||
|
<string name="lbl_sort_direction">Direction</string>
|
||||||
<string name="lbl_sort_asc">Ascending</string>
|
<string name="lbl_sort_asc">Ascending</string>
|
||||||
<string name="lbl_sort_dsc">Descending</string>
|
<string name="lbl_sort_dsc">Descending</string>
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.music
|
package org.oxycblt.auxio.music
|
||||||
|
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.fs.MusicDirectories
|
import org.oxycblt.auxio.music.fs.MusicDirectories
|
||||||
|
|
||||||
open class FakeMusicSettings : MusicSettings {
|
open class FakeMusicSettings : MusicSettings {
|
||||||
|
|
Loading…
Reference in a new issue