recycler: use article sort everywhere

Use the native MediaStore sort of using the characters after an article
[if present] everywhere when sorting is done. Yes, this is still dumb
and non-local, but if I want to add fast-scrolling to the library view
I will have to keep consistency across each sort.
This commit is contained in:
OxygenCobalt 2021-06-18 14:55:01 -06:00
parent e7d3dd0a98
commit 2f29950725
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 59 additions and 35 deletions

View file

@ -101,7 +101,7 @@ class MusicLoader(private val context: Context) {
Albums._ID, // 0
Albums.ALBUM, // 1
Albums.ARTIST, // 2
Albums.FIRST_YEAR, // 4
Albums.LAST_YEAR, // 4
),
null, null,
Albums.DEFAULT_SORT_ORDER
@ -114,7 +114,7 @@ class MusicLoader(private val context: Context) {
val idIndex = cursor.getColumnIndexOrThrow(Albums._ID)
val nameIndex = cursor.getColumnIndexOrThrow(Albums.ALBUM)
val artistNameIndex = cursor.getColumnIndexOrThrow(Albums.ARTIST)
val yearIndex = cursor.getColumnIndexOrThrow(Albums.FIRST_YEAR)
val yearIndex = cursor.getColumnIndexOrThrow(Albums.LAST_YEAR)
while (cursor.moveToNext()) {
val id = cursor.getLong(idIndex)

View file

@ -15,6 +15,7 @@ import org.oxycblt.auxio.music.Song
* off the given sorting mode.
* @property iconRes The icon for this [SortMode]
* @author OxygenCobalt
* TODO: Make SortMode use title case [skip the/a(n)]
*/
enum class SortMode(@DrawableRes val iconRes: Int) {
// Icons for each mode are assigned to the enums themselves
@ -32,11 +33,15 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
fun getSortedGenreList(genres: List<Genre>): List<Genre> {
return when (this) {
ALPHA_UP -> genres.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.resolvedName }
compareByDescending(String.CASE_INSENSITIVE_ORDER) {
it.resolvedName.sliceArticle()
}
)
ALPHA_DOWN -> genres.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.resolvedName }
compareBy(String.CASE_INSENSITIVE_ORDER) {
it.resolvedName.sliceArticle()
}
)
else -> genres
@ -51,11 +56,15 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
fun getSortedArtistList(artists: List<Artist>): List<Artist> {
return when (this) {
ALPHA_UP -> artists.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
compareByDescending(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
ALPHA_DOWN -> artists.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
compareBy(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
else -> artists
@ -70,11 +79,15 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
fun getSortedAlbumList(albums: List<Album>): List<Album> {
return when (this) {
ALPHA_UP -> albums.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
compareByDescending(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
ALPHA_DOWN -> albums.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
compareBy(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
NUMERIC_UP -> albums.sortedBy { it.year }
@ -92,11 +105,15 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
fun getSortedSongList(songs: List<Song>): List<Song> {
return when (this) {
ALPHA_UP -> songs.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
compareByDescending(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
ALPHA_DOWN -> songs.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
compareBy(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
NUMERIC_UP -> songs.sortedWith(compareByDescending { it.track })
@ -114,11 +131,15 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
fun getSortedArtistSongList(songs: List<Song>): List<Song> {
return when (this) {
ALPHA_UP -> songs.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
compareByDescending(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
ALPHA_DOWN -> songs.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
compareBy(String.CASE_INSENSITIVE_ORDER) {
it.name.sliceArticle()
}
)
NUMERIC_UP -> {
@ -130,6 +151,7 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
list
}
NUMERIC_DOWN -> {
val list = mutableListOf<Song>()
@ -205,3 +227,24 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
fun ImageButton.bindSortIcon(mode: SortMode) {
setImageResource(mode.iconRes)
}
/**
* Slice a string so that any preceding articles like The/A(n) are truncated.
* This is hilariously anglo-centric, but its mostly for MediaStore compat and hopefully
* shouldn't run with other languages.
*/
fun String.sliceArticle(): String {
if (length > 5 && startsWith("the ", true)) {
return slice(4..lastIndex)
}
if (length > 4 && startsWith("an ", true)) {
return slice(3..lastIndex)
}
if (length > 3 && startsWith("a ", true)) {
return slice(2..lastIndex)
}
return this
}

View file

@ -31,6 +31,7 @@ import kotlin.math.roundToInt
* fast-scrollers, this one displays indicators and a thumb instead of simply a scroll bar.
* This code is fundamentally an adaptation of Reddit's IndicatorFastScroll, albeit specialized
* towards Auxio. The original library is here: https://github.com/reddit/IndicatorFastScroll/
* TODO: Make this update with data.
* @author OxygenCobalt
*/
class FastScrollView @JvmOverloads constructor(

View file

@ -12,6 +12,7 @@ import org.oxycblt.auxio.databinding.FragmentSongsBinding
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.sliceArticle
import org.oxycblt.auxio.ui.getSpans
import org.oxycblt.auxio.ui.newMenu
@ -56,7 +57,8 @@ class SongsFragment : Fragment() {
}
binding.songFastScroll.setup(binding.songRecycler) { pos ->
val char = musicStore.songs[pos].name.first
// Get the first character [respecting articles]
val char = musicStore.songs[pos].name.sliceArticle().first().uppercaseChar()
if (char.isDigit()) '#' else char
}
@ -65,26 +67,4 @@ class SongsFragment : Fragment() {
return binding.root
}
/**
* Dumb shortcut for getting the first letter in a string, while regarding certain
* semantics when it comes to articles.
*/
private val String.first: Char get() {
// If the name actually starts with "The"/"A"/"An", get the character *after* that word.
// Yes, this is stupidly english centric but it wont run with other languages.
if (length > 5 && startsWith("the ", true)) {
return get(4).uppercaseChar()
}
if (length > 3 && startsWith("a ", true)) {
return get(2).uppercaseChar()
}
if (length > 4 && startsWith("an ", true)) {
return get(3).uppercaseChar()
}
return get(0).uppercaseChar()
}
}