fix: use saveable repository list keys
This commit is contained in:
parent
5778dc9b2a
commit
5e414a663a
@ -223,7 +223,7 @@ private fun RepositoryContent(
|
||||
if (state.mode == RepositoryListMode.ALL && state.organizations.isNotEmpty()) {
|
||||
item { OrganizationFilterRow(state.organization, state.organizations, onSelectOrganization) }
|
||||
}
|
||||
items(state.repositories, key = { it.coordinates }) { repository ->
|
||||
items(state.repositories, key = { repositoryLazyListKey(it.coordinates) }) { repository ->
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
@ -265,6 +265,9 @@ private fun RepositoryContent(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun repositoryLazyListKey(coordinates: RepositoryCoordinates): String =
|
||||
"${coordinates.owner}/${coordinates.name}"
|
||||
|
||||
@Composable
|
||||
private fun OrganizationFilterRow(
|
||||
selected: String?,
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package com.ubisam.ubgitea.feature.repositories
|
||||
|
||||
import com.ubisam.ubgitea.domain.model.RepositoryCoordinates
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Test
|
||||
|
||||
class RepositoryListScreenTest {
|
||||
@Test
|
||||
fun `lazy list key is a stable saveable string`() {
|
||||
val coordinates = RepositoryCoordinates.of("team", "mobile")
|
||||
|
||||
assertEquals("team/mobile", repositoryLazyListKey(coordinates))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `lazy list keys distinguish the same repository name under different owners`() {
|
||||
val first = repositoryLazyListKey(RepositoryCoordinates.of("team-a", "mobile"))
|
||||
val second = repositoryLazyListKey(RepositoryCoordinates.of("team-b", "mobile"))
|
||||
|
||||
assertNotEquals(first, second)
|
||||
}
|
||||
}
|
||||
@ -305,3 +305,11 @@ This is the append-only implementation and handoff record shared by Codex and Cl
|
||||
- Known limitations: Physical-device callback verification is still required. Gitea star/unstar mutation is intentionally unavailable with the restored read-only token.
|
||||
- Next recommended task: Install the rebuilt debug APK, clear UBGitea app data once, complete login approval, and verify repository loading.
|
||||
- Next owner: Human product owner for device verification, then Claude for review.
|
||||
|
||||
## 2026-08-26 — TASK-020 repository-list crash fix
|
||||
|
||||
- Agent and role: Codex, incident resolver.
|
||||
- Root cause: The repository `LazyColumn` used `RepositoryCoordinates` as its item key. Compose passes lazy-item keys to Android saved state, but this domain object is not a `Bundle`-saveable type, causing an uncaught main-thread `IllegalArgumentException` as soon as authenticated rows rendered.
|
||||
- Implementation: Repository rows now use the stable string key `owner/name`; repository components cannot contain `/`, so the key remains unique across owners and repositories while being Android-saveable.
|
||||
- Regression coverage: Added tests for deterministic key encoding and for equal repository names under different owners.
|
||||
- Checks: Focused tests and `assembleDebug testDebugUnitTest lintDebug` passed. The APK installed wirelessly over the authenticated device, `MainActivity` remained resumed, and the cleared crash buffer stayed empty. Final visual inspection is pending because the handset locked.
|
||||
|
||||
38
tasks/020-repository-list-saveable-key.md
Normal file
38
tasks/020-repository-list-saveable-key.md
Normal file
@ -0,0 +1,38 @@
|
||||
# TASK-020: Prevent repository-list crash after login
|
||||
|
||||
Status: implemented; unlocked-screen confirmation pending
|
||||
Owner: Codex
|
||||
Reviewer: Claude
|
||||
|
||||
## Outcome
|
||||
|
||||
After a successful OAuth login, the repository list renders without terminating the app, and subsequent launches remain usable.
|
||||
|
||||
## Risk
|
||||
|
||||
Compose lazy-list item keys participate in saved UI state on Android. A key that cannot be stored in a `Bundle` throws on the main thread while the list is composed.
|
||||
|
||||
## Writable paths
|
||||
|
||||
- `app/src/main/java/com/ubisam/ubgitea/feature/repositories/RepositoryListScreen.kt`
|
||||
- matching unit tests
|
||||
- this task file and `docs/development-log.md`
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] Repository rows use a unique, stable, Android-saveable key.
|
||||
- [x] A regression test covers repositories with the same name under different owners.
|
||||
- [x] Debug build, unit tests, and Android lint pass.
|
||||
- [ ] The rebuilt APK launches and renders the authenticated repository list on the physical device.
|
||||
- [x] Repository secret-pattern scan reports no credential material.
|
||||
|
||||
## Incident evidence
|
||||
|
||||
Physical-device crash buffer on 2026-08-26 reported `IllegalArgumentException: Type of the key RepositoryCoordinates(...) is not supported` from `SaveableStateHolderImpl.SaveableStateProvider`, originating while the repository `LazyColumn` was composed.
|
||||
|
||||
## Verification evidence
|
||||
|
||||
- Focused regression tests passed.
|
||||
- `assembleDebug testDebugUnitTest lintDebug` passed.
|
||||
- The rebuilt APK installed over the existing authenticated installation successfully; the app process remained alive with `MainActivity` resumed and the post-launch crash buffer empty.
|
||||
- The handset locked before the rendered repository rows could be inspected, so visual confirmation remains pending.
|
||||
Loading…
x
Reference in New Issue
Block a user