diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5714937d..0bc0af533 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@
#### What's Improved
- Auxio will now accept zeroed track/disc numbers in the presence of non-zero total
track/disc fields
+- Music loading has been made slightly faster
+- Improved sort menu usability
#### What's Fixed
- Fixed non-functioning "repeat all" repeat mode
diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt
index 59d7e6846..7fce9482e 100644
--- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt
@@ -40,7 +40,7 @@ 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.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.*
@@ -151,14 +151,19 @@ class AlbumDetailFragment :
openMenu(anchor, R.menu.menu_album_sort) {
val sort = detailModel.albumSongSort
unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true
- unlikelyToBeNull(menu.findItem(R.id.option_sort_asc)).isChecked = sort.isAscending
+ val directionItemId =
+ when (sort.direction) {
+ Sort.Direction.ASCENDING -> R.id.option_sort_asc
+ Sort.Direction.DESCENDING -> R.id.option_sort_dec
+ }
+ unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true
setOnMenuItemClickListener { item ->
item.isChecked = !item.isChecked
detailModel.albumSongSort =
- if (item.itemId == R.id.option_sort_asc) {
- sort.withAscending(item.isChecked)
- } else {
- sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
+ when (item.itemId) {
+ R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING)
+ R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING)
+ else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
}
true
}
diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt
index 30affc13b..7875642ce 100644
--- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt
@@ -39,7 +39,7 @@ import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.collect
@@ -167,15 +167,20 @@ class ArtistDetailFragment :
openMenu(anchor, R.menu.menu_artist_sort) {
val sort = detailModel.artistSongSort
unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true
- unlikelyToBeNull(menu.findItem(R.id.option_sort_asc)).isChecked = sort.isAscending
+ val directionItemId =
+ when (sort.direction) {
+ Sort.Direction.ASCENDING -> R.id.option_sort_asc
+ Sort.Direction.DESCENDING -> R.id.option_sort_dec
+ }
+ unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true
setOnMenuItemClickListener { item ->
item.isChecked = !item.isChecked
detailModel.artistSongSort =
- if (item.itemId == R.id.option_sort_asc) {
- sort.withAscending(item.isChecked)
- } else {
- sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
+ when (item.itemId) {
+ R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING)
+ R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING)
+ else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
}
true
diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt
index d352bcdec..5f354baa1 100644
--- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt
+++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt
@@ -34,7 +34,7 @@ import org.oxycblt.auxio.list.BasicHeader
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Library
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.metadata.AudioInfo
import org.oxycblt.auxio.music.metadata.Disc
import org.oxycblt.auxio.music.metadata.ReleaseType
@@ -280,7 +280,7 @@ constructor(
private fun refreshArtistList(artist: Artist) {
logD("Refreshing artist data")
val data = mutableListOf- (artist)
- val albums = Sort(Sort.Mode.ByDate, false).albums(artist.albums)
+ val albums = Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING).albums(artist.albums)
val byReleaseGroup =
albums.groupBy {
diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt
index d8b28f5a4..5d65cf42c 100644
--- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt
@@ -40,7 +40,7 @@ import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.collect
@@ -166,14 +166,19 @@ class GenreDetailFragment :
openMenu(anchor, R.menu.menu_genre_sort) {
val sort = detailModel.genreSongSort
unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true
- unlikelyToBeNull(menu.findItem(R.id.option_sort_asc)).isChecked = sort.isAscending
+ val directionItemId =
+ when (sort.direction) {
+ Sort.Direction.ASCENDING -> R.id.option_sort_asc
+ Sort.Direction.DESCENDING -> R.id.option_sort_dec
+ }
+ unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true
setOnMenuItemClickListener { item ->
item.isChecked = !item.isChecked
detailModel.genreSongSort =
- if (item.itemId == R.id.option_sort_asc) {
- sort.withAscending(item.isChecked)
- } else {
- sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
+ when (item.itemId) {
+ R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING)
+ R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING)
+ else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
}
true
}
diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt
index f18d98c3b..a3dbc87ac 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt
@@ -23,6 +23,7 @@ import android.view.MenuItem
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.view.MenuCompat
import androidx.core.view.isVisible
import androidx.core.view.iterator
import androidx.core.view.updatePadding
@@ -53,7 +54,7 @@ import org.oxycblt.auxio.list.selection.SelectionFragment
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Library
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.system.Indexer
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.MainNavigationAction
@@ -104,7 +105,10 @@ class HomeFragment :
// --- UI SETUP ---
binding.homeAppbar.addOnOffsetChangedListener(this)
- binding.homeToolbar.setOnMenuItemClickListener(this)
+ binding.homeToolbar.apply {
+ setOnMenuItemClickListener(this@HomeFragment)
+ MenuCompat.setGroupDividerEnabled(menu, true)
+ }
// Load the track color in manually as it's unclear whether the track actually supports
// using a ColorStateList in the resources
@@ -213,11 +217,18 @@ class HomeFragment :
// Junk click event when opening the menu
}
R.id.option_sort_asc -> {
- item.isChecked = !item.isChecked
+ item.isChecked = true
homeModel.setSortForCurrentTab(
homeModel
.getSortForTab(homeModel.currentTabMode.value)
- .withAscending(item.isChecked))
+ .withDirection(Sort.Direction.ASCENDING))
+ }
+ R.id.option_sort_dec -> {
+ item.isChecked = true
+ homeModel.setSortForCurrentTab(
+ homeModel
+ .getSortForTab(homeModel.currentTabMode.value)
+ .withDirection(Sort.Direction.DESCENDING))
}
else -> {
// Sorting option was selected, mark it as selected and update the mode
@@ -270,6 +281,7 @@ class HomeFragment :
// Only allow sorting by name, count, and duration for artists
MusicMode.ARTISTS -> { id ->
id == R.id.option_sort_asc ||
+ id == R.id.option_sort_dec ||
id == R.id.option_sort_name ||
id == R.id.option_sort_count ||
id == R.id.option_sort_duration
@@ -277,6 +289,7 @@ class HomeFragment :
// Only allow sorting by name, count, and duration for genres
MusicMode.GENRES -> { id ->
id == R.id.option_sort_asc ||
+ id == R.id.option_sort_dec ||
id == R.id.option_sort_name ||
id == R.id.option_sort_count ||
id == R.id.option_sort_duration
@@ -292,7 +305,10 @@ class HomeFragment :
// Check the ascending option and corresponding sort option to align with
// the current sort of the tab.
if (option.itemId == toHighlight.mode.itemId ||
- (option.itemId == R.id.option_sort_asc && toHighlight.isAscending)) {
+ (option.itemId == R.id.option_sort_asc &&
+ toHighlight.direction == Sort.Direction.ASCENDING) ||
+ (option.itemId == R.id.option_sort_dec &&
+ toHighlight.direction == Sort.Direction.DESCENDING)) {
option.isChecked = true
}
diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt
index 8ca8c35be..e6dc8c8bb 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt
@@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Library
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.logD
diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt
index a5e887a75..acea4f078 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt
@@ -37,7 +37,7 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.*
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.secsToMs
diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt
index 5850cbf73..fb6bc59f6 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt
@@ -38,7 +38,7 @@ 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.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.ui.NavigationViewModel
diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt
index fd612cc03..7ff2233e0 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt
@@ -38,7 +38,7 @@ 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.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.ui.NavigationViewModel
diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt
index 8d3af659a..64391e721 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt
@@ -40,7 +40,7 @@ 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.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.secsToMs
diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt
index a324690a2..1ce04fc46 100644
--- a/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt
+++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt
@@ -35,7 +35,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.library.Sort
+import org.oxycblt.auxio.list.Sort
/**
* A [Keyer] implementation for [Music] data.
@@ -91,7 +91,7 @@ private constructor(
) : Fetcher {
override suspend fun fetch(): FetchResult? {
// Pick the "most prominent" albums (i.e albums with the most songs) to show in the image.
- val albums = Sort(Sort.Mode.ByCount, false).albums(artist.albums)
+ val albums = Sort(Sort.Mode.ByCount, Sort.Direction.DESCENDING).albums(artist.albums)
val results = albums.mapAtMostNotNull(4) { album -> Covers.fetch(context, album) }
return Images.createMosaic(context, results, size)
}
diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt
index e8290cff5..2363fc059 100644
--- a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt
@@ -21,6 +21,8 @@ import android.view.MenuItem
import android.view.View
import androidx.annotation.MenuRes
import androidx.appcompat.widget.PopupMenu
+import androidx.core.internal.view.SupportMenu
+import androidx.core.view.MenuCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.MainFragmentDirections
@@ -237,6 +239,8 @@ abstract class ListFragment :
currentMenu =
PopupMenu(requireContext(), anchor).apply {
inflate(menuRes)
+ logD(menu is SupportMenu)
+ MenuCompat.setGroupDividerEnabled(menu, true)
block()
setOnDismissListener { currentMenu = null }
show()
diff --git a/app/src/main/java/org/oxycblt/auxio/music/library/Sort.kt b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt
similarity index 77%
rename from app/src/main/java/org/oxycblt/auxio/music/library/Sort.kt
rename to app/src/main/java/org/oxycblt/auxio/list/Sort.kt
index 64bfd846a..9ea6afaa2 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/library/Sort.kt
+++ b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt
@@ -15,14 +15,14 @@
* along with this program. If not, see .
*/
-package org.oxycblt.auxio.music.library
+package org.oxycblt.auxio.list
import androidx.annotation.IdRes
import kotlin.math.max
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.*
-import org.oxycblt.auxio.music.library.Sort.Mode
+import org.oxycblt.auxio.list.Sort.Mode
import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.metadata.Disc
@@ -32,23 +32,23 @@ import org.oxycblt.auxio.music.metadata.Disc
* This can be used not only to sort items, but also represent a sorting mode within the UI.
*
* @param mode A [Mode] dictating how to sort the list.
- * @param isAscending Whether to sort in ascending or descending order.
+ * @param direction The [Direction] to sort in.
* @author Alexander Capehart (OxygenCobalt)
*/
-data class Sort(val mode: Mode, val isAscending: Boolean) {
+data class Sort(val mode: Mode, val direction: Direction) {
/**
- * Create a new [Sort] with the same [mode], but different [isAscending] value.
- * @param isAscending Whether the new sort should be in ascending order or not.
- * @return A new sort with the same mode, but with the new [isAscending] value applied.
+ * 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 withAscending(isAscending: Boolean) = Sort(mode, isAscending)
+ fun withDirection(direction: Direction) = Sort(mode, direction)
/**
- * Create a new [Sort] with the same [isAscending] value, but different [mode] value.
+ * 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 [isAscending] value, but with the new [mode] applied.
+ * @return A new sort with the same [direction] value, but with the new [mode] applied.
*/
- fun withMode(mode: Mode) = Sort(mode, isAscending)
+ fun withMode(mode: Mode) = Sort(mode, direction)
/**
* Sort a list of [Song]s.
@@ -99,7 +99,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
* @param songs The [Song]s to sort.
*/
private fun songsInPlace(songs: MutableList) {
- songs.sortWith(mode.getSongComparator(isAscending))
+ songs.sortWith(mode.getSongComparator(direction))
}
/**
@@ -107,7 +107,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
* @param albums The [Album]s to sort.
*/
private fun albumsInPlace(albums: MutableList) {
- albums.sortWith(mode.getAlbumComparator(isAscending))
+ albums.sortWith(mode.getAlbumComparator(direction))
}
/**
@@ -115,7 +115,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
* @param artists The [Album]s to sort.
*/
private fun artistsInPlace(artists: MutableList) {
- artists.sortWith(mode.getArtistComparator(isAscending))
+ artists.sortWith(mode.getArtistComparator(direction))
}
/**
@@ -123,7 +123,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
* @param genres The [Genre]s to sort.
*/
private fun genresInPlace(genres: MutableList) {
- genres.sortWith(mode.getGenreComparator(isAscending))
+ genres.sortWith(mode.getGenreComparator(direction))
}
/**
@@ -134,8 +134,14 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
// Sort's integer representation is formatted as AMMMM, where A is a bitflag
// representing if the sort is in ascending or descending order, and M is the
// integer representation of the sort mode.
- get() = mode.intCode.shl(1) or if (isAscending) 1 else 0
+ get() =
+ mode.intCode.shl(1) or
+ when (direction) {
+ Direction.ASCENDING -> 1
+ Direction.DESCENDING -> 0
+ }
+ /** Describes the type of data to sort with. */
sealed class Mode {
/** The integer representation of this sort mode. */
abstract val intCode: Int
@@ -144,37 +150,37 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
/**
* Get a [Comparator] that sorts [Song]s according to this [Mode].
- * @param isAscending Whether to sort in ascending or descending order.
+ * @param direction The direction to sort in.
* @return A [Comparator] that can be used to sort a [Song] list according to this [Mode].
*/
- open fun getSongComparator(isAscending: Boolean): Comparator {
+ open fun getSongComparator(direction: Direction): Comparator {
throw UnsupportedOperationException()
}
/**
* Get a [Comparator] that sorts [Album]s according to this [Mode].
- * @param isAscending Whether to sort in ascending or descending order.
+ * @param direction The direction to sort in.
* @return A [Comparator] that can be used to sort a [Album] list according to this [Mode].
*/
- open fun getAlbumComparator(isAscending: Boolean): Comparator {
+ open fun getAlbumComparator(direction: Direction): Comparator {
throw UnsupportedOperationException()
}
/**
* Return a [Comparator] that sorts [Artist]s according to this [Mode].
- * @param isAscending Whether to sort in ascending or descending order.
+ * @param direction The direction to sort in.
* @return A [Comparator] that can be used to sort a [Artist] list according to this [Mode].
*/
- open fun getArtistComparator(isAscending: Boolean): Comparator {
+ open fun getArtistComparator(direction: Direction): Comparator {
throw UnsupportedOperationException()
}
/**
* Return a [Comparator] that sorts [Genre]s according to this [Mode].
- * @param isAscending Whether to sort in ascending or descending order.
+ * @param direction The direction to sort in.
* @return A [Comparator] that can be used to sort a [Genre] list according to this [Mode].
*/
- open fun getGenreComparator(isAscending: Boolean): Comparator {
+ open fun getGenreComparator(direction: Direction): Comparator {
throw UnsupportedOperationException()
}
@@ -189,17 +195,17 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_name
- override fun getSongComparator(isAscending: Boolean) =
- compareByDynamic(isAscending, BasicComparator.SONG)
+ override fun getSongComparator(direction: Direction) =
+ compareByDynamic(direction, BasicComparator.SONG)
- override fun getAlbumComparator(isAscending: Boolean) =
- compareByDynamic(isAscending, BasicComparator.ALBUM)
+ override fun getAlbumComparator(direction: Direction) =
+ compareByDynamic(direction, BasicComparator.ALBUM)
- override fun getArtistComparator(isAscending: Boolean) =
- compareByDynamic(isAscending, BasicComparator.ARTIST)
+ override fun getArtistComparator(direction: Direction) =
+ compareByDynamic(direction, BasicComparator.ARTIST)
- override fun getGenreComparator(isAscending: Boolean) =
- compareByDynamic(isAscending, BasicComparator.GENRE)
+ override fun getGenreComparator(direction: Direction) =
+ compareByDynamic(direction, BasicComparator.GENRE)
}
/**
@@ -213,9 +219,9 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_album
- override fun getSongComparator(isAscending: Boolean): Comparator =
+ override fun getSongComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, BasicComparator.ALBUM) { it.album },
+ compareByDynamic(direction, BasicComparator.ALBUM) { it.album },
compareBy(NullableComparator.DISC) { it.disc },
compareBy(NullableComparator.INT) { it.track },
compareBy(BasicComparator.SONG))
@@ -232,18 +238,18 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_artist
- override fun getSongComparator(isAscending: Boolean): Comparator =
+ override fun getSongComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, ListComparator.ARTISTS) { it.artists },
+ compareByDynamic(direction, ListComparator.ARTISTS) { it.artists },
compareByDescending(NullableComparator.DATE_RANGE) { it.album.dates },
compareByDescending(BasicComparator.ALBUM) { it.album },
compareBy(NullableComparator.DISC) { it.disc },
compareBy(NullableComparator.INT) { it.track },
compareBy(BasicComparator.SONG))
- override fun getAlbumComparator(isAscending: Boolean): Comparator =
+ override fun getAlbumComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, ListComparator.ARTISTS) { it.artists },
+ compareByDynamic(direction, ListComparator.ARTISTS) { it.artists },
compareByDescending(NullableComparator.DATE_RANGE) { it.dates },
compareBy(BasicComparator.ALBUM))
}
@@ -260,17 +266,17 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_year
- override fun getSongComparator(isAscending: Boolean): Comparator =
+ override fun getSongComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, NullableComparator.DATE_RANGE) { it.album.dates },
+ compareByDynamic(direction, NullableComparator.DATE_RANGE) { it.album.dates },
compareByDescending(BasicComparator.ALBUM) { it.album },
compareBy(NullableComparator.DISC) { it.disc },
compareBy(NullableComparator.INT) { it.track },
compareBy(BasicComparator.SONG))
- override fun getAlbumComparator(isAscending: Boolean): Comparator =
+ override fun getAlbumComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, NullableComparator.DATE_RANGE) { it.dates },
+ compareByDynamic(direction, NullableComparator.DATE_RANGE) { it.dates },
compareBy(BasicComparator.ALBUM))
}
@@ -282,25 +288,22 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_duration
- override fun getSongComparator(isAscending: Boolean): Comparator =
+ override fun getSongComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending) { it.durationMs },
- compareBy(BasicComparator.SONG))
+ compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.SONG))
- override fun getAlbumComparator(isAscending: Boolean): Comparator =
+ override fun getAlbumComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending) { it.durationMs },
- compareBy(BasicComparator.ALBUM))
+ compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.ALBUM))
- override fun getArtistComparator(isAscending: Boolean): Comparator =
+ override fun getArtistComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, NullableComparator.LONG) { it.durationMs },
+ compareByDynamic(direction, NullableComparator.LONG) { it.durationMs },
compareBy(BasicComparator.ARTIST))
- override fun getGenreComparator(isAscending: Boolean): Comparator =
+ override fun getGenreComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending) { it.durationMs },
- compareBy(BasicComparator.GENRE))
+ compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.GENRE))
}
/**
@@ -314,20 +317,18 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_count
- override fun getAlbumComparator(isAscending: Boolean): Comparator =
+ override fun getAlbumComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending) { it.songs.size },
- compareBy(BasicComparator.ALBUM))
+ compareByDynamic(direction) { it.songs.size }, compareBy(BasicComparator.ALBUM))
- override fun getArtistComparator(isAscending: Boolean): Comparator =
+ override fun getArtistComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, NullableComparator.INT) { it.songs.size },
+ compareByDynamic(direction, NullableComparator.INT) { it.songs.size },
compareBy(BasicComparator.ARTIST))
- override fun getGenreComparator(isAscending: Boolean): Comparator =
+ override fun getGenreComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending) { it.songs.size },
- compareBy(BasicComparator.GENRE))
+ compareByDynamic(direction) { it.songs.size }, compareBy(BasicComparator.GENRE))
}
/**
@@ -341,9 +342,9 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_disc
- override fun getSongComparator(isAscending: Boolean): Comparator =
+ override fun getSongComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending, NullableComparator.DISC) { it.disc },
+ compareByDynamic(direction, NullableComparator.DISC) { it.disc },
compareBy(NullableComparator.INT) { it.track },
compareBy(BasicComparator.SONG))
}
@@ -359,10 +360,10 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_track
- override fun getSongComparator(isAscending: Boolean): Comparator =
+ override fun getSongComparator(direction: Direction): Comparator =
MultiComparator(
compareBy(NullableComparator.DISC) { it.disc },
- compareByDynamic(isAscending, NullableComparator.INT) { it.track },
+ compareByDynamic(direction, NullableComparator.INT) { it.track },
compareBy(BasicComparator.SONG))
}
@@ -378,48 +379,47 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
override val itemId: Int
get() = R.id.option_sort_date_added
- override fun getSongComparator(isAscending: Boolean): Comparator =
+ override fun getSongComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending) { it.dateAdded }, compareBy(BasicComparator.SONG))
+ compareByDynamic(direction) { it.dateAdded }, compareBy(BasicComparator.SONG))
- override fun getAlbumComparator(isAscending: Boolean): Comparator =
+ override fun getAlbumComparator(direction: Direction): Comparator =
MultiComparator(
- compareByDynamic(isAscending) { album -> album.dateAdded },
+ compareByDynamic(direction) { album -> album.dateAdded },
compareBy(BasicComparator.ALBUM))
}
/**
- * Utility function to create a [Comparator] in a dynamic way determined by [isAscending].
- * @param isAscending Whether to sort in ascending or descending order.
+ * Utility function to create a [Comparator] in a dynamic way determined by [direction].
+ * @param direction The [Direction] to sort in.
* @see compareBy
* @see compareByDescending
*/
protected inline fun > compareByDynamic(
- isAscending: Boolean,
+ direction: Direction,
crossinline selector: (T) -> K
) =
- if (isAscending) {
- compareBy(selector)
- } else {
- compareByDescending(selector)
+ when (direction) {
+ Direction.ASCENDING -> compareBy(selector)
+ Direction.DESCENDING -> compareByDescending(selector)
}
/**
- * Utility function to create a [Comparator] in a dynamic way determined by [isAscending]
- * @param isAscending Whether to sort in ascending or descending order.
+ * Utility function to create a [Comparator] in a dynamic way determined by [direction]
+ * @param direction The [Direction] to sort in.
* @param comparator A [Comparator] to wrap.
* @return A new [Comparator] with the specified configuration.
* @see compareBy
* @see compareByDescending
*/
protected fun compareByDynamic(
- isAscending: Boolean,
+ direction: Direction,
comparator: Comparator
- ): Comparator = compareByDynamic(isAscending, comparator) { it }
+ ): Comparator = compareByDynamic(direction, comparator) { it }
/**
- * Utility function to create a [Comparator] a dynamic way determined by [isAscending]
- * @param isAscending Whether to sort in ascending or descending order.
+ * Utility function to create a [Comparator] a dynamic way determined by [direction]
+ * @param direction The [Direction] to sort in.
* @param comparator A [Comparator] to wrap.
* @param selector Called to obtain a specific attribute to sort by.
* @return A new [Comparator] with the specified configuration.
@@ -427,14 +427,13 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
* @see compareByDescending
*/
protected inline fun compareByDynamic(
- isAscending: Boolean,
+ direction: Direction,
comparator: Comparator,
crossinline selector: (T) -> K
) =
- if (isAscending) {
- compareBy(comparator, selector)
- } else {
- compareByDescending(comparator, selector)
+ when (direction) {
+ Direction.ASCENDING -> compareBy(comparator, selector)
+ Direction.DESCENDING -> compareByDescending(comparator, selector)
}
/**
@@ -596,6 +595,12 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
}
}
+ /** The direction to sort items in. */
+ enum class Direction {
+ ASCENDING,
+ DESCENDING
+ }
+
companion object {
/**
* Convert a [Sort] integer representation into an instance.
@@ -607,9 +612,9 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
// Sort's integer representation is formatted as AMMMM, where A is a bitflag
// representing on if the mode is ascending or descending, and M is the integer
// representation of the sort mode.
- val isAscending = (intCode and 1) == 1
+ val direction = if ((intCode and 1) == 1) Direction.ASCENDING else Direction.DESCENDING
val mode = Mode.fromIntCode(intCode.shr(1)) ?: return null
- return Sort(mode, isAscending)
+ return Sort(mode, direction)
}
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt
index 330a6e4c8..df432e612 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt
@@ -21,7 +21,7 @@ import android.content.Context
import android.os.storage.StorageManager
import androidx.core.content.edit
import org.oxycblt.auxio.R
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.storage.Directory
import org.oxycblt.auxio.music.storage.MusicDirectories
import org.oxycblt.auxio.settings.Settings
@@ -116,7 +116,7 @@ private class RealMusicSettings(context: Context) :
get() =
Sort.fromIntCode(
sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE))
- ?: Sort(Sort.Mode.ByName, true)
+ ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
set(value) {
sharedPreferences.edit {
putInt(getString(R.string.set_key_songs_sort), value.intCode)
@@ -128,7 +128,7 @@ private class RealMusicSettings(context: Context) :
get() =
Sort.fromIntCode(
sharedPreferences.getInt(getString(R.string.set_key_albums_sort), Int.MIN_VALUE))
- ?: Sort(Sort.Mode.ByName, true)
+ ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
set(value) {
sharedPreferences.edit {
putInt(getString(R.string.set_key_albums_sort), value.intCode)
@@ -140,7 +140,7 @@ private class RealMusicSettings(context: Context) :
get() =
Sort.fromIntCode(
sharedPreferences.getInt(getString(R.string.set_key_artists_sort), Int.MIN_VALUE))
- ?: Sort(Sort.Mode.ByName, true)
+ ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
set(value) {
sharedPreferences.edit {
putInt(getString(R.string.set_key_artists_sort), value.intCode)
@@ -152,7 +152,7 @@ private class RealMusicSettings(context: Context) :
get() =
Sort.fromIntCode(
sharedPreferences.getInt(getString(R.string.set_key_genres_sort), Int.MIN_VALUE))
- ?: Sort(Sort.Mode.ByName, true)
+ ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
set(value) {
sharedPreferences.edit {
putInt(getString(R.string.set_key_genres_sort), value.intCode)
@@ -166,7 +166,7 @@ private class RealMusicSettings(context: Context) :
Sort.fromIntCode(
sharedPreferences.getInt(
getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE))
- ?: Sort(Sort.Mode.ByDisc, true)
+ ?: Sort(Sort.Mode.ByDisc, Sort.Direction.ASCENDING)
// Correct legacy album sort modes to Disc
if (sort.mode is Sort.Mode.ByName) {
@@ -187,7 +187,7 @@ private class RealMusicSettings(context: Context) :
Sort.fromIntCode(
sharedPreferences.getInt(
getString(R.string.set_key_artist_songs_sort), Int.MIN_VALUE))
- ?: Sort(Sort.Mode.ByDate, false)
+ ?: Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING)
set(value) {
sharedPreferences.edit {
putInt(getString(R.string.set_key_artist_songs_sort), value.intCode)
@@ -200,7 +200,7 @@ private class RealMusicSettings(context: Context) :
Sort.fromIntCode(
sharedPreferences.getInt(
getString(R.string.set_key_genre_songs_sort), Int.MIN_VALUE))
- ?: Sort(Sort.Mode.ByName, true)
+ ?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
set(value) {
sharedPreferences.edit {
putInt(getString(R.string.set_key_genre_songs_sort), value.intCode)
diff --git a/app/src/main/java/org/oxycblt/auxio/music/library/Library.kt b/app/src/main/java/org/oxycblt/auxio/music/library/Library.kt
index 8c9a515fd..2d4663afe 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/library/Library.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/library/Library.kt
@@ -20,6 +20,7 @@ package org.oxycblt.auxio.music.library
import android.content.Context
import android.net.Uri
import android.provider.OpenableColumns
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.storage.contentResolverSafe
import org.oxycblt.auxio.music.storage.useQuery
@@ -76,7 +77,7 @@ interface Library {
companion object {
/**
- * Create a library-backed instance of [Library].
+ * Create an instance of [Library].
* @param rawSongs [RawSong]s to create the library out of.
* @param settings [MusicSettings] required.
*/
@@ -93,10 +94,10 @@ private class RealLibrary(rawSongs: List, settings: MusicSettings) : Li
// Use a mapping to make finding information based on it's UID much faster.
private val uidMap = buildMap {
- songs.forEach { this[it.uid] = it.finalize() }
- albums.forEach { this[it.uid] = it.finalize() }
- artists.forEach { this[it.uid] = it.finalize() }
- genres.forEach { this[it.uid] = it.finalize() }
+ songs.forEach { put(it.uid, it.finalize()) }
+ albums.forEach { put(it.uid, it.finalize()) }
+ artists.forEach { put(it.uid, it.finalize()) }
+ genres.forEach { put(it.uid, it.finalize()) }
}
/**
@@ -131,7 +132,8 @@ private class RealLibrary(rawSongs: List, settings: MusicSettings) : Li
* grouping.
*/
private fun buildSongs(rawSongs: List, settings: MusicSettings) =
- Sort(Sort.Mode.ByName, true).songs(rawSongs.map { RealSong(it, settings) }.distinct())
+ Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
+ .songs(rawSongs.map { RealSong(it, settings) }.distinct())
/**
* Build a list of [Album]s from the given [Song]s.
diff --git a/app/src/main/java/org/oxycblt/auxio/music/library/RealMusic.kt b/app/src/main/java/org/oxycblt/auxio/music/library/RealMusic.kt
index 8b43cbbbc..595edb98f 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/library/RealMusic.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/library/RealMusic.kt
@@ -24,6 +24,7 @@ import java.text.CollationKey
import java.text.Collator
import kotlin.math.max
import org.oxycblt.auxio.R
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
@@ -418,7 +419,7 @@ class RealArtist(private val rawArtist: RawArtist, songAlbums: List) : Ar
fun finalize(): Artist {
check(songs.isNotEmpty() || albums.isNotEmpty()) { "Malformed artist: Empty" }
genres =
- Sort(Sort.Mode.ByName, true)
+ Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
.genres(songs.flatMapTo(mutableSetOf()) { it.genres })
.sortedByDescending { genre -> songs.count { it.genres.contains(genre) } }
return this
@@ -458,10 +459,10 @@ class RealGenre(private val rawGenre: RawGenre, override val songs: List
- album.songs.count { it.genres.contains(this) }
- }
- artists = Sort(Sort.Mode.ByName, true).artists(distinctArtists)
+ Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
+ .albums(distinctAlbums)
+ .sortedByDescending { album -> album.songs.count { it.genres.contains(this) } }
+ artists = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).artists(distinctArtists)
durationMs = totalDuration
}
diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt
index 3e747c3ad..f858b1722 100644
--- a/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt
+++ b/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt
@@ -32,7 +32,7 @@ import org.oxycblt.auxio.list.BasicHeader
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Library
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.logD
@@ -176,6 +176,6 @@ constructor(
}
private companion object {
- val SORT = Sort(Sort.Mode.ByName, true)
+ val SORT = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
}
}
diff --git a/app/src/main/res/menu/menu_album_sort.xml b/app/src/main/res/menu/menu_album_sort.xml
index 749c77b90..0b0af5d1d 100644
--- a/app/src/main/res/menu/menu_album_sort.xml
+++ b/app/src/main/res/menu/menu_album_sort.xml
@@ -1,6 +1,7 @@
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_artist_sort.xml b/app/src/main/res/menu/menu_artist_sort.xml
index ae3fd9d97..c3055096d 100644
--- a/app/src/main/res/menu/menu_artist_sort.xml
+++ b/app/src/main/res/menu/menu_artist_sort.xml
@@ -1,6 +1,7 @@
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_genre_sort.xml b/app/src/main/res/menu/menu_genre_sort.xml
index fe0080134..daf303fdf 100644
--- a/app/src/main/res/menu/menu_genre_sort.xml
+++ b/app/src/main/res/menu/menu_genre_sort.xml
@@ -1,6 +1,7 @@
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_home.xml b/app/src/main/res/menu/menu_home.xml
index 75863b85e..f63266c9c 100644
--- a/app/src/main/res/menu/menu_home.xml
+++ b/app/src/main/res/menu/menu_home.xml
@@ -14,7 +14,8 @@
android:title="@string/lbl_sort"
app:showAsAction="ifRoom">
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index dd0937b67..6ae4291c5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -92,6 +92,7 @@
Track
Date added
Ascending
+ Descending
Now playing
Equalizer
diff --git a/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt b/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt
index 946595096..2e632fb84 100644
--- a/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt
+++ b/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt
@@ -17,7 +17,7 @@
package org.oxycblt.auxio.music
-import org.oxycblt.auxio.music.library.Sort
+import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.storage.MusicDirectories
interface FakeMusicSettings : MusicSettings {