Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/android-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Android CI Unit Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
unit-tests:
runs-on: ubuntu-latest

steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

# Cache Gradle dependencies to speed up subsequent builds
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Make Gradlew Executable
run: chmod +x ./gradlew

- name: Run Unit Tests
run: ./gradlew test

Binary file removed Images/feature-graphic (1).png
Binary file not shown.
Binary file removed Images/feature-graphic.jpg
Binary file not shown.
Binary file removed Images/feature-graphic.png
Binary file not shown.
Binary file added Images/foldable-browse-detail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/foldable-browse-grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/foldable-browse-screen-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/foldable-reading-dictionary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/foldable-reading-toc-pane.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/foldable-reading-translation-pane.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/foldable-reading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Images/gk-library-view-translations.png
Binary file not shown.
Binary file removed Images/gk-library-view.png
Binary file not shown.
Binary file removed Images/gk-reading-view-translation.png
Binary file not shown.
Binary file removed Images/gk-reading-view.png
Binary file not shown.
Binary file added Images/launcher-3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Images/library-lazy-cards.png
Binary file not shown.
Binary file removed Images/library-view-translations.png
Binary file not shown.
Binary file added Images/phone-browse-grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/phone-browse-screen-detail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/phone-browse-screen-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/phone-reading-screen-dictionary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/phone-reading-screen-main.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/phone-reading-screen-toc-pane.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/phone-reading-screen-translation-pane.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Images/reading-view-dictionary.png
Binary file not shown.
Binary file removed Images/reading-view-list.png
Diff not rendered.
Binary file removed Images/reading-view.png
Diff not rendered.
Binary file added Images/tablet-browse-detail.png
Binary file added Images/tablet-browse-grid.png
Binary file added Images/tablet-browse-list.png
Binary file added Images/tablet-reading-dictionary.png
Binary file added Images/tablet-reading-toc-pane.png
Binary file added Images/tablet-reading-translation-pane.png
Binary file added Images/tablet-reading.png
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ fun ReaderTopAppBar(
contentDescription = null
)
},
trailingIcon = {
if (searchText.isNotEmpty()) {
IconButton(onClick = onClearSearch) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = stringResource(R.string.cd_clear_search)
)
}
}
},
modifier = Modifier.width(IntrinsicSize.Max)
.align(Alignment.CenterHorizontally)
.testTag("SearchField"),
Expand Down Expand Up @@ -108,14 +118,6 @@ fun ReaderTopAppBar(
}
},
actions = {
if (searchText.isNotEmpty()) {
IconButton(onClick = onClearSearch) { // Use the new callback
Icon(
imageVector = Icons.Default.Close,
contentDescription = stringResource(R.string.cd_clear_search)
)
}
}
if (actions.isNotEmpty()) {
var showMenu by remember { mutableStateOf(false) }
Box {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.ericmschmidt.classicsreader.data

import com.ericmschmidt.classicsreader.MyApplication
import com.ericmschmidt.classicsreader.utilities.getEntry
import com.ericmschmidt.classicsreader.utilities.getResourceStream
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import java.io.ByteArrayInputStream

class DictionaryTest {

private lateinit var libraryMock: Library
private lateinit var workInfoMock: WorkInfo
private lateinit var appInstanceMock: MyApplication.ApplicationInstance

private val dictionaryEntriesXmlString = """
<?xml version="1.0" encoding="UTF-8"?>
<entries>
<entry>A1</entry>
<entry>a2</entry>
<entry>abactus</entry>
<entry>abacus</entry>
<entry>abalienatio</entry>
<entry>abalieno</entry>
</entries>
""".trimIndent()

@Before
fun setUp() {
// Mock static objects/functions
mockkObject(MyApplication.Factory)
mockkStatic("com.ericmschmidt.classicsreader.utilities.ResourceHelpersKt")

libraryMock = mockk()
workInfoMock = WorkInfo(id = "dict", location = 123)

every { libraryMock.getDictionaryInfo() } returns workInfoMock
every { libraryMock.getDictionaryEntryResource() } returns 456

appInstanceMock = MyApplication.ApplicationInstance(
context = mockk(),
library = libraryMock,
isNonRomanChar = false,
textConverter = null
)

every { MyApplication.applicationInstance() } returns appInstanceMock

// Mock getResourceStream for entry headers resource (456)
every { getResourceStream(456) } answers {
ByteArrayInputStream(dictionaryEntriesXmlString.toByteArray(Charsets.UTF_8))
}
// Mock getResourceStream for dictionary raw content resource (123)
every { getResourceStream(123) } answers {
ByteArrayInputStream("".toByteArray(Charsets.UTF_8))
}

// Mock the top-level getEntry function to bypass Android's XmlPullParser on JVM unit tests
every { getEntry(any(), any(), any()) } returns "driven away, driven off"
}

@After
fun tearDown() {
unmockkAll()
}

@Test
fun testDictionary_init() {
val dictionary = Dictionary()
assertNotNull(dictionary)
assertEquals(6, dictionary.entryCount())
}

@Test
fun testDictionary_isInDictionary() {
val dictionary = Dictionary()
assertTrue(dictionary.isInDictionary("abactus"))
assertTrue(dictionary.isInDictionary("abacus"))
assertFalse(dictionary.isInDictionary("nonexistent"))
}

@Test
fun testDictionary_getEntry() {
val dictionary = Dictionary()
val entry = dictionary.getEntry("abactus")
assertNotNull(entry)
assertTrue(entry!!.contains("driven away, driven off"))
}

@Test
fun testDictionary_getEntry_nonexistent_returnsEmptyString() {
val dictionary = Dictionary()
val entry = dictionary.getEntry("nonexistent")
assertEquals("", entry)
}

@Test
fun testDictionary_getRandomEntry() {
val dictionary = Dictionary()
val randomEntry = dictionary.getRandomEntry()
assertNotNull(randomEntry)
assertTrue(randomEntry!!.isNotEmpty())
}
}
28 changes: 14 additions & 14 deletions LatinReader/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
[versions]
activity-compose = "1.13.0"
adaptive = "1.2.0"
agp = "9.2.0-alpha05"
androidx-ui-tooling = "1.10.6"
agp = "9.2.1"
androidx-ui-tooling = "1.11.2"
appcompat = "1.7.1"
compose-bom = "2026.03.01"
compose-bom = "2026.05.01"
core = "1.7.0"
core-ktx = "1.18.0"
datastore-preferences = "1.2.1"
espresso-core = "3.7.0"
espresso-core-version = "3.0.2"
espresso-device = "1.1.0"
foundation = "1.10.6"
jetbrains-kotlin-android = "2.3.20"
foundation = "1.11.2"
jetbrains-kotlin-android = "2.3.21"
junit = "1.3.0"
junit-version = "4.13.2"
kxml2 = "2.3.0"
Expand All @@ -21,26 +21,26 @@ lifecycle-runtime-ktx = "2.10.0"
markdownview-android = "2.0.0"
#noinspection GradleDependency
markdownview-android-v1110 = "1.1.1"
material = "1.13.0"
material-ripple = "1.10.6"
material = "1.14.0"
material-ripple = "1.11.2"
mockito-core = "5.23.0"
mockito-kotlin = "6.3.0"
mockk = "1.14.9"
mockk-android = "1.14.9"
navigation-compose = "2.9.7"
navigation-fragment-ktx = "2.9.7"
navigation-safe-args-gradle-plugin = "2.9.7"
navigation-ui-ktx = "2.9.7"
navigation-compose = "2.9.8"
navigation-fragment-ktx = "2.9.8"
navigation-safe-args-gradle-plugin = "2.9.8"
navigation-ui-ktx = "2.9.8"
preference-ktx = "1.2.1"
recyclerview = "1.4.0"
robolectric = "4.16.1"
runner = "1.0.2"
truth = "1.4.5"
material3-adaptive-navigation-suite = "1.4.0"
material3-window-size-class1 = "1.4.0"
ui-test-junit4 = "1.10.6"
ui-text-google-fonts = "1.10.6"
junit-jupiter = "6.0.3"
ui-test-junit4 = "1.11.2"
ui-text-google-fonts = "1.11.2"
junit-jupiter = "6.1.0"

[libraries]
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" }
Expand Down
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
10 changes: 5 additions & 5 deletions LatinReader/latinreader-compose/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ plugins {
android {
namespace="com.ericmschmidt.classicsreader.latin.compose"
compileSdk {
version = release(36)
version = release(37)
}

defaultConfig {
applicationId "com.ericmschmidt.classicsreader.latin.compose"
applicationId "com.ericmschmidt.latinreader"
minSdk 24
targetSdk 36
versionCode(21)
versionName("2.1.0")
targetSdk 37
versionCode(22)
versionName("3.0.0")

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
2 changes: 1 addition & 1 deletion LatinReader/latinreader-views/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<application
android:name="com.ericmschmidt.latin.LatinReaderApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_2"
android:icon="@mipmap/ic_launcher_3"
android:label="@string/latinreader_app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import androidx.compose.ui.graphics.Color

val primaryLight = Color(0xFF804D78)
val onPrimaryLight = Color(0xFFFFFFFF)
val primaryContainerLight = Color(0xFFFFD7F4)
val primaryContainerLight = Color(0xFFFFD7FF)
val onPrimaryContainerLight = Color(0xFF66355F)
val secondaryLight = Color(0xFF6E5868)
val onSecondaryLight = Color(0xFFFFFFFF)
val secondaryContainerLight = Color(0xFFF8DAEE)
val secondaryContainerLight = Color(0xFFF8DAFF)
val onSecondaryContainerLight = Color(0xFF554050)
val tertiaryLight = Color(0xFF815344)
val onTertiaryLight = Color(0xFFFFFFFF)
Expand Down Expand Up @@ -111,11 +111,11 @@ val surfaceContainerHighestLightHighContrast = Color(0xFFCFC3C9)

val primaryDark = Color(0xFFF2B3E5)
val onPrimaryDark = Color(0xFF4C1F48)
val primaryContainerDark = Color(0xFF66355F)
val primaryContainerDark = Color(0xFF66357F)
val onPrimaryContainerDark = Color(0xFFFFD7F4)
val secondaryDark = Color(0xFFDBBED2)
val onSecondaryDark = Color(0xFF3D2A39)
val secondaryContainerDark = Color(0xFF554050)
val secondaryContainerDark = Color(0xFF554068)
val onSecondaryContainerDark = Color(0xFFF8DAEE)
val tertiaryDark = Color(0xFFF5B8A6)
val onTertiaryDark = Color(0xFF4C261A)
Expand Down
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.

This file was deleted.

This file was deleted.

Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Loading