Merge pull request #658 from Dejvino/bugfix/615

Fix #615: Use a locale-aware Collator for sorting Checklists
This commit is contained in:
Tibor Kaputa 2023-08-02 15:38:00 +02:00 committed by GitHub
commit 16229704ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 2 deletions

View File

@ -0,0 +1,79 @@
package com.simplemobiletools.notes.pro.helpers
import java.text.Collator
/**
* Collator-based string comparator
*
* Adapted from AlphanumericComparator to support numerical collation.
*/
class CollatorBasedComparator: Comparator<String> {
override fun compare(string1: String, string2: String): Int {
val collator = getCollator()
var thisMarker = 0
var thatMarker = 0
while (thisMarker < string1.length && thatMarker < string2.length) {
val thisChunk = getChunk(string1, string1.length, thisMarker)
thisMarker += thisChunk.length
val thatChunk = getChunk(string2, string2.length, thatMarker)
thatMarker += thatChunk.length
val result = if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
collateNumerically(thisChunk, thatChunk)
} else {
collator.compare(thisChunk, thatChunk)
}
if (result != 0) {
return coerceResult(result)
}
}
return coerceResult(string1.length - string2.length)
}
private fun collateNumerically(string1: String, string2: String): Int {
var result: Int
result = string1.length - string2.length
if (result == 0) {
// equal length, the first different number counts
for (i in string1.indices) {
result = string1[i] - string2[i]
if (result != 0) {
break
}
}
}
return result
}
private fun getChunk(string: String, length: Int, marker: Int): String {
var current = marker
var c = string[current]
val chunk = StringBuilder(c.toString())
current++
val chunkOfDigits = isDigit(c)
while (current < length) {
c = string[current]
if (isDigit(c) != chunkOfDigits) {
break
}
chunk.append(c)
current++
}
return chunk.toString()
}
private fun isDigit(ch: Char) = ch in '0'..'9'
private fun coerceResult(compareToResult: Int) = compareToResult.coerceIn(-1, 1)
private fun getCollator(): Collator {
val collator = Collator.getInstance()
collator.strength = Collator.PRIMARY
collator.decomposition = Collator.CANONICAL_DECOMPOSITION
return collator
}
}

View File

@ -1,8 +1,8 @@
package com.simplemobiletools.notes.pro.models
import com.simplemobiletools.commons.helpers.AlphanumericComparator
import com.simplemobiletools.commons.helpers.SORT_BY_TITLE
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
import com.simplemobiletools.notes.pro.helpers.CollatorBasedComparator
import kotlinx.serialization.Serializable
@Serializable
@ -19,7 +19,7 @@ data class ChecklistItem(
override fun compareTo(other: ChecklistItem): Int {
var result = when {
sorting and SORT_BY_TITLE != 0 -> AlphanumericComparator().compare(title.lowercase(), other.title.lowercase())
sorting and SORT_BY_TITLE != 0 -> CollatorBasedComparator().compare(title, other.title)
else -> dateCreated.compareTo(other.dateCreated)
}