Skip to content

Commit 1ccf1a9

Browse files
authored
Merge pull request #578 from ryacub/codex/r571-theme-ci-gate-backfill
ci: add theme instrumentation gate and theming backfill (R571)
2 parents d88cd2b + 1b2f438 commit 1ccf1a9

5 files changed

Lines changed: 197 additions & 0 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
name: Theme instrumentation gate
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'app/src/main/java/eu/kanade/domain/ui/**'
7+
- 'app/src/main/java/eu/kanade/domain/ui/model/**'
8+
- 'app/src/main/java/eu/kanade/presentation/theme/**'
9+
- 'app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt'
10+
- 'app/src/main/java/eu/kanade/presentation/more/settings/widget/AppThemePreferenceWidget.kt'
11+
- 'app/src/main/java/eu/kanade/presentation/more/onboarding/ThemeStep.kt'
12+
- 'app/src/androidTest/**'
13+
- '.github/workflows/theme_instrumentation_pr.yml'
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
17+
cancel-in-progress: true
18+
19+
permissions:
20+
contents: read
21+
22+
env:
23+
SQLDELIGHT_AGP9_FIX_SHA: c8f6011c014368544c71f5e490ef0409bb2f4705
24+
SQM2_PATH: ${{ env.HOME }}/.m2/repository/app/cash
25+
26+
jobs:
27+
prepare_sqldelight:
28+
name: Prepare SqlDelight artifacts
29+
runs-on: ubuntu-24.04
30+
31+
steps:
32+
- name: Restore SqlDelight local Maven cache
33+
id: sqldelight-cache
34+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.2.3
35+
with:
36+
path: ${{ env.SQM2_PATH }}
37+
key: sqldelight-m2-${{ env.SQLDELIGHT_AGP9_FIX_SHA }}
38+
39+
- name: Set up JDK
40+
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
41+
with:
42+
java-version: 17
43+
distribution: temurin
44+
45+
- name: Build SqlDelight AGP 9 fix
46+
if: steps.sqldelight-cache.outputs.cache-hit != 'true'
47+
run: |
48+
set -euxo pipefail
49+
50+
git clone --filter=blob:none https://github.com/cashapp/sqldelight.git /tmp/sqldelight
51+
cd /tmp/sqldelight
52+
git checkout --detach "$SQLDELIGHT_AGP9_FIX_SHA"
53+
54+
./gradlew publishToMavenLocal -x test --no-daemon
55+
56+
- name: Upload SqlDelight local Maven artifacts
57+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
58+
with:
59+
name: sqldelight-m2-${{ env.SQLDELIGHT_AGP9_FIX_SHA }}
60+
path: ${{ env.SQM2_PATH }}
61+
62+
theme_android_test:
63+
name: Theme instrumentation tests
64+
runs-on: ubuntu-24.04
65+
needs: prepare_sqldelight
66+
67+
steps:
68+
- name: Clone repo
69+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
70+
71+
- name: Set up JDK
72+
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
73+
with:
74+
java-version: 17
75+
distribution: temurin
76+
77+
- name: Set up gradle
78+
uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
79+
with:
80+
cache-read-only: false
81+
82+
- name: Download SqlDelight local Maven artifacts
83+
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
84+
with:
85+
name: sqldelight-m2-${{ env.SQLDELIGHT_AGP9_FIX_SHA }}
86+
path: ${{ env.SQM2_PATH }}
87+
88+
- name: Build instrumentation APKs
89+
run: ./gradlew :app:assembleDebug :app:assembleDebugAndroidTest --build-cache
90+
91+
- name: Run theming instrumentation tests
92+
uses: reactivecircus/android-emulator-runner@v2
93+
with:
94+
api-level: 35
95+
arch: x86_64
96+
target: google_apis
97+
profile: pixel_7
98+
script: |
99+
set +e
100+
./gradlew :app:connectedDebugAndroidTest \
101+
-Pandroid.testInstrumentationRunnerArguments.class=eu.kanade.presentation.theme.ThemePreferencesInstrumentationTest,eu.kanade.presentation.more.settings.widget.ThemeAppearanceFlowAndroidTest \
102+
--build-cache
103+
status=$?
104+
adb logcat -d > app/build/reports/androidTests/theme-logcat.txt || true
105+
exit $status
106+
107+
- name: Upload instrumentation reports
108+
if: always()
109+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
110+
with:
111+
name: theme-instrumentation-reports-${{ github.sha }}
112+
path: |
113+
app/build/reports/androidTests
114+
app/build/outputs/androidTest-results
115+
app/build/reports/androidTests/theme-logcat.txt
116+
if-no-files-found: warn

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
1717
- **Custom accent color theme** — Material 3 app-wide theming from a user-selected accent seed; generates light/dark color schemes with Android 14 contrast-awareness and readability guardrails (contrast clamp + fallback)
1818
- **Download crash notification** — notifies the user when the anime or manga download job crashes repeatedly (threshold: 3 consecutive crashes), with a tap-to-open link to the download manager
1919
- **Custom app theme accent controls** — custom app theme is now selectable in Appearance settings with curated accent swatches and one-tap reset to default palette
20+
- **Theme instrumentation coverage** — added Android instrumentation tests for custom accent persistence, reset behavior, and unset-seed fallback to default `TachiyomiColorScheme`
2021
- **LightNovelPluginManager unit tests** — 37 tests covering install flow, manifest validation, update policy, APK download/checksum verification, install launch, in-flight mutex deduplication, error recovery, and orphaned APK cleanup
2122
- **Persist dialog/form state across rotation** — PIN setup, PIN change (step/value/error), and enrichment chooser source selection now survive configuration changes via `rememberSaveable`
2223
- **PIN error feedback** — shows an error message when saving a new PIN fails (e.g., storage write error), instead of silently closing the dialog
@@ -43,6 +44,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
4344

4445
- Add `workflow_dispatch` trigger to build workflow for manual release runs when automatic tag-triggered CI is blocked by workflow-file security restrictions
4546
- Replace `[skip ci]` auto-bump strategy with actor-based job condition to unblock tag-triggered release builds
47+
- Add path-scoped PR theme instrumentation workflow running `:app:connectedDebugAndroidTest` on emulator with test-report/logcat artifact upload on failure
4648

4749
### Other
4850

@@ -58,6 +60,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
5860
- Pin real SHA-256 certificate fingerprint (`f3565300…`) for LightNovel plugin trust verification; removes placeholder fingerprints
5961
- Remove unused `CoroutineScope` parameter from `PlayerMpvInitializer` constructor
6062
- Remove dead `rollbackToLastGood()` stub and `ROLLBACK_NOT_AVAILABLE` error code from `LightNovelPluginManager`; converted 4 deferred TODO comments to tracked GitHub issues (#536#539)
63+
- Backfilled missing `Unreleased` entries from previously merged Codex PRs, deduped against existing changelog items
6164

6265
## [0.18.1.75] - 2026-03-13
6366

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Fork of Aniyomi with anime/manga/light novel tracking, reading, and watching.
4545
- If custom accent seed is unset, the app falls back to the default Tachiyomi color scheme.
4646
- Legacy lowercase theme-mode values are normalized during preference split migration.
4747
- Invalid stored theme-mode enum values safely fall back to the default (`SYSTEM`).
48+
- Theme-related pull requests run a dedicated instrumentation gate in CI with emulator artifacts/logcat attached for failure diagnosis.
4849

4950
## Contributing
5051

app/src/androidTest/java/eu/kanade/presentation/more/settings/widget/ThemeAppearanceFlowAndroidTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ class ThemeAppearanceFlowAndroidTest {
4242
AppThemePreferenceWidget(
4343
value = appTheme,
4444
amoled = false,
45+
customAccentSeed = selectedAccentSeed,
4546
onItemClick = { appTheme = it },
47+
onCustomAccentSeedChange = { selectedAccentSeed = it },
4648
)
4749

4850
if (appTheme == AppTheme.CUSTOM) {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package eu.kanade.presentation.theme
2+
3+
import android.content.Context
4+
import androidx.test.core.app.ApplicationProvider
5+
import androidx.test.ext.junit.runners.AndroidJUnit4
6+
import eu.kanade.domain.ui.UiPreferences
7+
import eu.kanade.domain.ui.model.AppTheme
8+
import eu.kanade.presentation.theme.colorscheme.CustomAccentColorScheme
9+
import eu.kanade.presentation.theme.colorscheme.TachiyomiColorScheme
10+
import org.junit.Assert.assertEquals
11+
import org.junit.Assert.assertSame
12+
import org.junit.Assert.assertTrue
13+
import org.junit.Before
14+
import org.junit.Test
15+
import org.junit.runner.RunWith
16+
import tachiyomi.core.common.preference.AndroidPreferenceStore
17+
18+
@RunWith(AndroidJUnit4::class)
19+
class ThemePreferencesInstrumentationTest {
20+
21+
private lateinit var context: Context
22+
private lateinit var uiPreferences: UiPreferences
23+
24+
@Before
25+
fun setUp() {
26+
context = ApplicationProvider.getApplicationContext()
27+
val sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
28+
sharedPreferences.edit().clear().commit()
29+
uiPreferences = UiPreferences(AndroidPreferenceStore(context, sharedPreferences))
30+
}
31+
32+
@Test
33+
fun customAccentSeedPersistsChosenValue() {
34+
val selectedAccent = 0xFF4285F4.toInt()
35+
36+
uiPreferences.customThemeAccentSeed().set(selectedAccent)
37+
38+
assertEquals(selectedAccent, uiPreferences.customThemeAccentSeed().get())
39+
}
40+
41+
@Test
42+
fun customAccentSeedResetUsesUnsetSentinel() {
43+
uiPreferences.customThemeAccentSeed().set(0xFF1E88E5.toInt())
44+
45+
uiPreferences.customThemeAccentSeed().set(UiPreferences.CUSTOM_THEME_ACCENT_SEED_UNSET)
46+
47+
assertEquals(UiPreferences.CUSTOM_THEME_ACCENT_SEED_UNSET, uiPreferences.customThemeAccentSeed().get())
48+
}
49+
50+
@Test
51+
fun customThemeFallbackUsesDefaultSchemeWhenAccentUnset() {
52+
val resolved = resolveBaseColorScheme(
53+
appTheme = AppTheme.CUSTOM,
54+
customAccentSeed = UiPreferences.CUSTOM_THEME_ACCENT_SEED_UNSET,
55+
context = context,
56+
)
57+
58+
assertSame(TachiyomiColorScheme, resolved)
59+
}
60+
61+
@Test
62+
fun customThemeWithSeedUsesGeneratedAccentScheme() {
63+
val resolved = resolveBaseColorScheme(
64+
appTheme = AppTheme.CUSTOM,
65+
customAccentSeed = 0xFF6750A4.toInt(),
66+
context = context,
67+
)
68+
69+
assertTrue(resolved is CustomAccentColorScheme)
70+
}
71+
72+
private companion object {
73+
const val PREFS_NAME = "theme_instrumentation_test_prefs"
74+
}
75+
}

0 commit comments

Comments
 (0)