* Enhance Cloud TTS with navigation controls and shared UI overlay in desktop app * Refactor Cloud TTS voice settings and remove standalone settings overlay on desktop app * Persist reader window state and improve slider interaction in desktop app * Improve PDF page transitions and refine focus management in desktop app * Refactor scrollbar interaction and adjust desktop modal focus handling * Improve PDF sidecar synchronization and cross-platform metadata compatibility * Refactor PDF annotation comment logic to shared module and implement Desktop UI * Refactor reader screen to use tap-to-toggle and full-width styling in desktop app * Refactor reader workspace layout and chrome-panel interactions * Implement global search keyboard shortcuts and focusable chrome layers * Implement flavor-specific legal links and update the About UI * Refactor reader UI controls on desktop app * Enhance desktop folder sync with background metadata extraction and improved error handling * Refactor Library UI and remove redundant Home tab in desktop app * Add custom tooltips to reader icon buttons in desktop app * Integrate app theme controls into reader interfaces on desktop * Add right-to-left pagination support and improve focus restoration on desktop app * Improve EPUB pagination geometry and diagnostic logging for layout cutoffs on desktop app * Update desktop reader defaults and implement settings migration * Implement block-based position tracking in ReaderLocator * Enhance EPUB highlighting reliability in desktop app * Add support for custom reader themes and update highlight palette logic in desktop app * Replace the Tools panel with a "More" dropdown menu and refactor account UI * Implement account profile header in desktop sidebar * Implement cloud sync reliability improvements and sidebar toggle on desktop app * Improve EPUB annotation synchronization and highlight mapping accuracy in desktop app * Integrate WebView2 for EPUB vertical rendering on Windows * Refactor reader layout logic and enhance WebView2 diagnostics * Improve vertical reading layout and WebView2 resizing on Desktop * Refine vertical reading mode layout and margin handling * Enhance reader locator precision and Desktop mode-switching reliability * Implement chapter-level caching and warm-start pagination in desktop app * Replace bundled KCEF with native system webviews via SWT * Refactor EPUB page info bar visibility and layout logic * Improve PDF toolbar persistence and fix tab reactivation logic * Enable multi-selection and bulk operations for custom fonts * Refactor instrumentation tests * Add EPUB UI test fixture and initial instrumentation tests * Expand EpubReader UI tests and improve accessibility * Add instrumentation tests and test tags for library and reader screens * Enhance OPDS parser logic and catalog integration * Add support for toggling local synchronization on a per-folder basis. * Implement tri-state sizing for the TTS overlay * Persist TTS overlay size across sessions * Refactor reader brightness control and add incremental step buttons * Improve CSS support, pagination control, and style-aware semantic caching * Improve link handling, interaction, and diagnostics in the paginated reader * crash fixes * Implement persistent pending removal for external files * Implement book-specific word replacements * Add native vertical reading mode with custom renderer * Implement text selection and navigation improvements for the native vertical reader * Implement locator-based navigation and improved vertical scrolling in native vertical mode in epub * Implement lazy loading and chapter prefetching for native vertical reader * Improve window lifecycle and disposal handling on Desktop * Optimize vertical reading performance in desktop app * Enhance TTS start accuracy and diagnostic logging on desktop * Refactor AI settings visibility on desktop * Improve pagination height measurement and enhance cutoff diagnostics * Implement lifecycle management and improve justified text splitting for pagination * Refine AI usage tracking and force AI feature visibility on Desktop * Add descriptive context comments and usage examples to string and plural resources. * Optimize performance and memory usage in search and state mapping * Replace reader page sliders with minimal slider and navigation controls * Add support for CBT comic archives * Harden file path validation and XML parsing to prevent security vulnerabilities * Implement local account profile caching and optimize desktop performance * Improve desktop persistence reliability and add Linux secure storage support * Improved PDF zoom stability and layout prediction during zoom commits * Improved PDF spread layout prediction, reader focus restoration, and account profile caching * Enhance highlight precision and scoping using block-local offsets and CFIs * Enhance cloud book content synchronization and background downloads * Implement granular timestamp tracking for reading positions and PDF annotations * Restrict diagnostic logging and stack traces to debug builds * Refine PDF page gaps and reader chrome interaction logic * Refactor PDF highlight rendering and overhaul Desktop sidebar UI * Implement a new interaction dock and undo/redo history for PDF annotations in desktop * Enhance PDF color picker and improve navigation scroll restoration * Add highlight palette customization and improve selection menu UI in desktop app epub reader * Enhance desktop shelf management and library organization
161 lines
6.7 KiB
Kotlin
161 lines
6.7 KiB
Kotlin
package com.aryan.reader
|
|
|
|
import java.io.File
|
|
import javax.xml.parsers.DocumentBuilderFactory
|
|
import org.junit.Assert.assertEquals
|
|
import org.junit.Assert.assertFalse
|
|
import org.junit.Assert.assertTrue
|
|
import org.junit.Test
|
|
import org.w3c.dom.Element
|
|
|
|
class AppLanguageOptionsTest {
|
|
|
|
@Test
|
|
fun `supported app languages expose configured locale order`() {
|
|
assertEquals(
|
|
listOf(
|
|
"en", "ar", "de", "nl", "tr", "fr", "ru", "uk", "be", "es", "pt-BR", "it", "pl",
|
|
"id", "vi", "ja", "ko", "hi", "zh-CN"
|
|
),
|
|
supportedAppLanguageOptions.mapNotNull { it.tag }
|
|
)
|
|
assertEquals(R.string.language_chinese_simplified, supportedAppLanguageOptions.last().labelRes)
|
|
}
|
|
|
|
@Test
|
|
fun `app language selection defaults to system before explicit overrides`() {
|
|
assertEquals(null, appLanguageSelectionOptions.first().tag)
|
|
assertEquals(R.string.language_system_default, appLanguageSelectionOptions.first().labelRes)
|
|
assertEquals(supportedAppLanguageOptions, appLanguageSelectionOptions.drop(1))
|
|
}
|
|
|
|
@Test
|
|
fun `app language search matches labels tags and aliases`() {
|
|
val chinese = supportedAppLanguageOptions.first { it.tag == "zh-CN" }
|
|
|
|
assertTrue(chinese.matchesLanguageSearch(label = "简体中文(简体中文)", query = "zh cn"))
|
|
assertTrue(chinese.matchesLanguageSearch(label = "简体中文(简体中文)", query = "mandarin"))
|
|
assertTrue(chinese.matchesLanguageSearch(label = "简体中文(简体中文)", query = "简体"))
|
|
assertTrue(systemAppLanguageOption.matchesLanguageSearch(label = "System default", query = "device"))
|
|
assertFalse(chinese.matchesLanguageSearch(label = "简体中文(简体中文)", query = "korean"))
|
|
}
|
|
|
|
@Test
|
|
fun `app language search normalizes accents`() {
|
|
val turkish = supportedAppLanguageOptions.first { it.tag == "tr" }
|
|
val dutch = supportedAppLanguageOptions.first { it.tag == "nl" }
|
|
val ukrainian = supportedAppLanguageOptions.first { it.tag == "uk" }
|
|
val belarusian = supportedAppLanguageOptions.first { it.tag == "be" }
|
|
val portugueseBrazilian = supportedAppLanguageOptions.first { it.tag == "pt-BR" }
|
|
val indonesian = supportedAppLanguageOptions.first { it.tag == "id" }
|
|
val vietnamese = supportedAppLanguageOptions.first { it.tag == "vi" }
|
|
val japanese = supportedAppLanguageOptions.first { it.tag == "ja" }
|
|
val korean = supportedAppLanguageOptions.first { it.tag == "ko" }
|
|
|
|
assertTrue(turkish.matchesLanguageSearch(label = "Türkçe (Turkish)", query = "turkce"))
|
|
assertTrue(dutch.matchesLanguageSearch(label = "Nederlands", query = "dutch"))
|
|
assertTrue(ukrainian.matchesLanguageSearch(label = "Українська", query = "ukrayinska"))
|
|
assertTrue(belarusian.matchesLanguageSearch(label = "Беларуская", query = "belarusian"))
|
|
assertTrue(
|
|
portugueseBrazilian.matchesLanguageSearch(
|
|
label = "Português (Brasil)",
|
|
query = "portugues brasileiro"
|
|
)
|
|
)
|
|
assertTrue(indonesian.matchesLanguageSearch(label = "Bahasa Indonesia", query = "bahasa"))
|
|
assertTrue(vietnamese.matchesLanguageSearch(label = "Tiếng Việt", query = "tieng viet"))
|
|
assertTrue(japanese.matchesLanguageSearch(label = "日本語", query = "nihongo"))
|
|
assertTrue(korean.matchesLanguageSearch(label = "한국어", query = "hangul"))
|
|
}
|
|
|
|
@Test
|
|
fun `supported app language tags are unique`() {
|
|
val tags = supportedAppLanguageOptions.mapNotNull { it.tag }
|
|
|
|
assertEquals(tags.distinct(), tags)
|
|
}
|
|
|
|
@Test
|
|
fun `supported app languages match Android locale config`() {
|
|
assertEquals(readLocaleConfigTags(), supportedAppLanguageOptions.map { it.tag })
|
|
}
|
|
|
|
@Test
|
|
fun `android manifest enables AppCompat language persistence`() {
|
|
val manifest = readAndroidManifest()
|
|
val service = manifest.getElementsByTagName("service").asElements()
|
|
.singleOrNull {
|
|
it.androidAttribute("name") == "androidx.appcompat.app.AppLocalesMetadataHolderService"
|
|
}
|
|
|
|
assertTrue(service != null)
|
|
assertEquals("false", service!!.androidAttribute("enabled"))
|
|
assertEquals("false", service.androidAttribute("exported"))
|
|
|
|
val autoStoreLocales = service.getElementsByTagName("meta-data").asElements()
|
|
.singleOrNull { it.androidAttribute("name") == "autoStoreLocales" }
|
|
|
|
assertTrue(autoStoreLocales != null)
|
|
assertEquals("true", autoStoreLocales!!.androidAttribute("value"))
|
|
}
|
|
|
|
@Test
|
|
fun `android manifest exposes cbt comic archive mime types`() {
|
|
val mimeTypes = readAndroidManifest()
|
|
.getElementsByTagName("data")
|
|
.asElements()
|
|
.mapNotNull { it.androidAttribute("mimeType") }
|
|
|
|
assertTrue("application/x-cbt" in mimeTypes)
|
|
assertTrue("application/vnd.comicbook+tar" in mimeTypes)
|
|
assertTrue("application/x-tar" in mimeTypes)
|
|
assertTrue("application/tar" in mimeTypes)
|
|
}
|
|
|
|
private fun readLocaleConfigTags(): List<String> {
|
|
val localeConfig = listOf(
|
|
File("src/main/res/xml/locales_config.xml"),
|
|
File("app/src/main/res/xml/locales_config.xml")
|
|
).first { it.isFile }
|
|
val document = DocumentBuilderFactory.newInstance()
|
|
.apply { isNamespaceAware = true }
|
|
.newDocumentBuilder()
|
|
.parse(localeConfig)
|
|
val localeNodes = document.getElementsByTagName("locale")
|
|
|
|
return buildList {
|
|
for (index in 0 until localeNodes.length) {
|
|
add(
|
|
localeNodes.item(index)
|
|
.attributes
|
|
.getNamedItemNS("http://schemas.android.com/apk/res/android", "name")
|
|
.nodeValue
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun readAndroidManifest(): org.w3c.dom.Document {
|
|
val manifest = listOf(
|
|
File("src/main/AndroidManifest.xml"),
|
|
File("app/src/main/AndroidManifest.xml")
|
|
).first { it.isFile }
|
|
return DocumentBuilderFactory.newInstance()
|
|
.apply { isNamespaceAware = true }
|
|
.newDocumentBuilder()
|
|
.parse(manifest)
|
|
}
|
|
|
|
private fun org.w3c.dom.NodeList.asElements(): List<Element> =
|
|
buildList {
|
|
for (index in 0 until length) {
|
|
val element = item(index) as? Element
|
|
if (element != null) add(element)
|
|
}
|
|
}
|
|
|
|
private fun Element.androidAttribute(name: String): String? =
|
|
attributes
|
|
?.getNamedItemNS("http://schemas.android.com/apk/res/android", name)
|
|
?.nodeValue
|
|
}
|