UI/TTS improvements

This commit is contained in:
sergeych committed 2026-05-23 21:55:34 +03:00
1 parent 0eba07b594
commit ed66ea0d55
13 files changed
+250 -57

No files matched your search

@@ -702,21 +702,14 @@ private class JdbcBookFileRepository(private val connection: Connection) : BookF
FROM book_files f
LEFT JOIN books b ON b.id = f.book_id
WHERE f.duplicate_of_file_id IS NULL
ORDER BY
CASE
WHEN f.reading_status = 'READING' THEN 0
WHEN f.reading_status = 'NOT_INTERESTED' THEN 2
ELSE 1
END,
CASE WHEN f.reading_status = 'READING' THEN f.last_read_at END DESC NULLS LAST,
LOWER(COALESCE(NULLIF(b.title, ''), NULLIF(f.original_filename, ''), f.id)),
f.id
LIMIT ? OFFSET ?
""".trimIndent()
).use { statement ->
statement.setInt(1, limit)
statement.setInt(2, offset)
statement.executeQuery().use { resultSet -> resultSet.mapRows { it.toLibraryFileRecord() } }
statement.executeQuery().use { resultSet ->
resultSet.mapRows { it.toLibraryFileRecord() }
.sortedWith(LibraryFileNaturalTitleComparator)
.drop(offset)
.take(limit)
}
}
}
@@ -1097,6 +1090,50 @@ private fun String?.matchPositions(prefixes: List<String>, fieldOffset: Int): Li
private val SearchWordRegex = Regex("""[\p{L}\p{N}]+""")
private val LibraryFileNaturalTitleComparator = Comparator<LibraryFileRecord> { left, right ->
val titleCompare = naturalCompare(left.sortTitle(), right.sortTitle())
if (titleCompare != 0) titleCompare else left.fileId.compareTo(right.fileId)
}
private fun LibraryFileRecord.sortTitle(): String =
title?.takeIf(String::isNotBlank)
?: originalFilename?.takeIf(String::isNotBlank)
?: fileId
private fun naturalCompare(left: String, right: String): Int {
var leftIndex = 0
var rightIndex = 0
var exactFallback = 0
while (leftIndex < left.length && rightIndex < right.length) {
val leftChar = left[leftIndex]
val rightChar = right[rightIndex]
if (leftChar.isDigit() && rightChar.isDigit()) {
val leftStart = leftIndex
val rightStart = rightIndex
while (leftIndex < left.length && left[leftIndex].isDigit()) leftIndex += 1
while (rightIndex < right.length && right[rightIndex].isDigit()) rightIndex += 1
val leftDigits = left.substring(leftStart, leftIndex).trimStart('0')
val rightDigits = right.substring(rightStart, rightIndex).trimStart('0')
val leftNumber = leftDigits.ifEmpty { "0" }
val rightNumber = rightDigits.ifEmpty { "0" }
val lengthCompare = leftNumber.length.compareTo(rightNumber.length)
if (lengthCompare != 0) return lengthCompare
val numberCompare = leftNumber.compareTo(rightNumber)
if (numberCompare != 0) return numberCompare
val rawLengthCompare = (leftIndex - leftStart).compareTo(rightIndex - rightStart)
if (rawLengthCompare != 0) return rawLengthCompare
} else {
val foldedCompare = leftChar.lowercaseChar().compareTo(rightChar.lowercaseChar())
if (foldedCompare != 0) return foldedCompare
if (exactFallback == 0) exactFallback = leftChar.compareTo(rightChar)
leftIndex += 1
rightIndex += 1
}
}
return left.length.compareTo(right.length).takeIf { it != 0 } ?: exactFallback
}
private fun ResultSet.toLibraryFileRecord() = LibraryFileRecord(
fileId = getString("file_id"),
bookId = getString("book_id"),
@@ -161,17 +161,16 @@ class H2LibraryDatabaseTest {
}
@Test
fun listsReadingBooksFirstNotInterestedLastThenSortsByTitle() {
val db = H2LibraryDatabase.openMemory("listsReadingBooksFirstNotInterestedLastThenSortsByTitle")
fun listsLibraryFilesByNaturalTitle() {
val db = H2LibraryDatabase.openMemory("listsLibraryFilesByNaturalTitle")
val now = 1_700_000_000_000L
db.transaction {
listOf(
Triple("book-beta", "Beta", BookReadingStatus.NEW),
Triple("book-10", "Book 10", BookReadingStatus.READING),
Triple("book-alpha", "Alpha", BookReadingStatus.READ),
Triple("book-gamma", "Gamma", BookReadingStatus.READING),
Triple("book-aardvark", "Aardvark", BookReadingStatus.READING),
Triple("book-omega", "Omega", BookReadingStatus.NOT_INTERESTED),
Triple("book-2", "Book 2", BookReadingStatus.NEW),
Triple("book-beta", "Beta", BookReadingStatus.NOT_INTERESTED),
).forEachIndexed { index, (bookId, title, status) ->
books.upsert(
BookRecord(
@@ -189,7 +188,7 @@ class H2LibraryDatabaseTest {
originalFilename = "$title.fb2",
storageKind = BookFileStorageKind.EXTERNAL_URI,
readingStatus = status,
lastReadAt = if (title == "Aardvark") now + 500 else now + 100,
lastReadAt = now + index,
createdAt = now + index,
updatedAt = now + index,
)
@@ -198,7 +197,7 @@ class H2LibraryDatabaseTest {
}
assertEquals(
listOf("Aardvark", "Gamma", "Alpha", "Beta", "Omega"),
listOf("Alpha", "Beta", "Book 2", "Book 10"),
db.files.listLibraryFiles().map { it.title },
)
db.close()