[Android] Add comparator to sort media identically to the android auto keyboard
Robert Stone
git at videolan.org
Fri Jul 9 09:12:04 UTC 2021
vlc-android | branch: master | Robert Stone <rhstone at gmail.com> | Tue Jul 6 22:15:09 2021 -0700| [3592eb89ed077872a06e8505659fa1a1c392509f] | committer: Nicolas Pomepuy
Add comparator to sort media identically to the android auto keyboard
> https://code.videolan.org/videolan/vlc-android/commit/3592eb89ed077872a06e8505659fa1a1c392509f
---
.../videolan/vlc/gui/helpers/MediaComparators.kt | 71 ++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/helpers/MediaComparators.kt b/application/vlc-android/src/org/videolan/vlc/gui/helpers/MediaComparators.kt
index b9684e025..b78acd9a1 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/helpers/MediaComparators.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/helpers/MediaComparators.kt
@@ -20,10 +20,20 @@
package org.videolan.vlc.gui.helpers
import org.videolan.medialibrary.interfaces.media.MediaWrapper
+import org.videolan.medialibrary.media.MediaLibraryItem
+import java.text.Normalizer
import java.util.*
object MediaComparators {
+ private val englishArticles by lazy { arrayOf("a ", "an ", "the ") }
+ private val asciiAlphaNumeric by lazy {
+ BitSet().also { b -> "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray().forEach { c -> b.set(c.toInt(), true) } }
+ }
+ private val asciiPunctuation by lazy {
+ BitSet().also { b -> "\t !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".toCharArray().forEach { c -> b.set(c.toInt(), true) } }
+ }
+
val BY_TRACK_NUMBER: Comparator<MediaWrapper> = Comparator { m1, m2 ->
if (m1.discNumber < m2.discNumber) return at Comparator -1
if (m1.discNumber > m2.discNumber) return at Comparator 1
@@ -34,4 +44,65 @@ object MediaComparators {
0
}
+ val ANDROID_AUTO: Comparator<MediaLibraryItem> = Comparator { item1, item2 ->
+ buildComparableTitle(item1.title).compareTo(buildComparableTitle(item2.title))
+ }
+
+ private fun buildComparableTitle(origTitle: String): String {
+ val tTitle = origTitle.trim()
+ if (tTitle.isEmpty()) return tTitle
+ /* Remove invalid leading characters and articles */
+ val invCharTitle = removeLeadingPunctuation(tTitle).toLowerCase(Locale.US)
+ val scrubbedTitle = formatArticles(invCharTitle, false).ifEmpty { invCharTitle }
+ /* Decompose the first letter to handle ä, ç, é, ô, etc. This yields two chars: an a-z letter, and
+ * a unicode combining character representing the diacritic mark. The combining character is dropped.
+ */
+ val nChars = Normalizer.normalize(scrubbedTitle[0].toString(), Normalizer.Form.NFD)
+ val firstChar = removeNonAlphaNumeric(nChars).ifEmpty { nChars }
+ /* Assemble the title */
+ return "${firstChar[0]}${scrubbedTitle.substring(1)}"
+ }
+
+ /**
+ * Functionally identical to "^(?i)(the|an|a)\\s+(.*)", and either returning "$2" or "$2, $1"
+ */
+ fun formatArticles(title: String, appendPrefix: Boolean): String {
+ for (article in englishArticles)
+ if (title.startsWith(article, true)) {
+ val suffix = title.substring(article.length).trim()
+ return if (appendPrefix) {
+ val prefix = title.substring(0, article.length).trim()
+ listOf(suffix, prefix).filter { it.isNotEmpty() }.joinToString(", ") { it }
+ } else suffix
+ }
+ return title
+ }
+
+ /**
+ * Remove all non-lowercase alphanumeric characters.
+ * Functionally identical to replaceAll("[^a-z0-9]+", "")
+ */
+ private fun removeNonAlphaNumeric(title: String): String {
+ return if (title.length == 1 && asciiAlphaNumeric.get(title[0].toInt())) title
+ else buildString {
+ for (c in title.toCharArray())
+ if (asciiAlphaNumeric.get(c.toInt()))
+ append(c)
+ }
+ }
+
+ /**
+ * Find the first occurrence of non-punctuation characters.
+ * Functionally identical to replaceAll("^[\t\\x20-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7E]+", "")
+ * "[On Android]...Unicode character classes are always used." (see Pattern.UNICODE_CHARACTER_CLASS)
+ * therefore "^[\\p{Blank}\\p{Punct}]+" is not a direct substitute.
+ */
+ private fun removeLeadingPunctuation(title: String): String {
+ title.forEachIndexed { i, c ->
+ if (!asciiPunctuation.get(c.toInt()))
+ return title.substring(i)
+ }
+ return title
+ }
}
+
More information about the Android
mailing list