Ubisam-MobileGit/tasks/030-gitea-green-theme-and-repo-row-enhancements.md
choiminyeong f6ac20c8ed TASK-063: task records say what is actually open
No task waits on a Codex review; the redesign tasks are confirmed on the
product owner's Z Fold7; TASK-016's leftovers are on hold; no biometric
reauthentication.

Agent: main (opus)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:25:49 +09:00

164 lines
11 KiB
Markdown

# TASK-030: Gitea-green theme, pagination footer height fix, repository row language/favorite
Status: implemented; all required checks pass; the human product owner has not yet confirmed live
Owner: Claude
Reviewer: Codex
## Outcome
Three connected requests, delivered together: the whole app is now themed around Gitea's own
brand green (previously it used Compose Material3's unthemed default — purple — since the app's
`ColorScheme` had never actually been given real values); every pagination footer's buttons
(previous page/next page/numbered page buttons) now render at one guaranteed-consistent height,
fixing a live-reported bug where they visibly varied; and each repository row now shows its
primary language and Gitea star count, with a tappable star toggle wired to the app's existing
(previously built but never connected to any screen) favorite/star action.
## Scope
- Included: `ui/theme/Color.kt` (new), `ui/theme/Theme.kt` (real `lightColorScheme`/`darkColorScheme`
values instead of Compose's defaults), new `ui/PaginationFooter.kt` (`SimplePaginationFooter`,
`PaginationButtonHeight`), `feature/history/HistoryScreen.kt`/`feature/notifications/NotificationsScreen.kt`/`feature/repositories/RepositoryListScreen.kt`
(their plain previous/next footers now call the shared composable),
`feature/workitems/WorkItemsScreen.kt` (both its plain fallback footer and its numbered footer's
buttons now set an explicit height), `domain/model/RepositoryModels.kt` (`RepositorySummary`
gains `language`/`starsCount`), `data/repositories/GiteaRepositoryBrowserApi.kt` (parses both
from the repository list response Gitea already returns), `feature/repositories/RepositoryListViewModel.kt`
(`RepositoryRowUiModel` gains the same two fields), `feature/repositories/RepositoryListScreen.kt`
(renders language + a `FavoriteStar` toggle per row, wires `onToggleFavorite`),
`MainActivity.kt` (`onToggleFavorite` wiring).
- Excluded: No change to any screen's actual functionality, navigation, or gesture behavior — this
task is deliberately colors/sizing/one-new-row-affordance only, per the human product owner's
explicit instruction ("디자인을 변경하면서 현재의 기능이 절대 변동되어서는 안돼... 조작감도
마찬가지야"). No attempt to determine a repository's *already*-starred state on initial load for
the ALL list (see Design notes) — that remains exactly the limitation TASK-018 already had, not
a new one introduced here. No per-language color coding (see Design notes).
## Design notes
- **Gitea's real brand green, not a guess**: verified against Gitea's own source
(`web_src/css/themes/theme-gitea-light.css`'s `--color-logo: #609926`) before picking a palette,
per this project's established convention. The Material3 `primary` role itself uses a slightly
deeper tone of that same green (`#3B6A1F`) rather than the exact logo value — white text on
`#609926` directly sits around a 3.4:1 contrast ratio, under WCAG's 4.5:1 threshold for
normal-size button labels; the rest of the app's now ~20 M3 color roles (secondary/tertiary,
each with a container + on-container pair, plus the full light/dark neutral scale) were hand-built
as a coherent tonal palette grown from that same hue family. `error`/`onError`/`errorContainer`/
`onErrorContainer` were deliberately left at Material3's own baseline red — nothing about this
request was about changing what an error (or a removed diff line) looks like.
- **The pagination-footer height fix is one shared component, not four separate patches**: all
four pagination UIs (repository list, history, notifications, work items' plain fallback) now
call one `SimplePaginationFooter`, and work items' numbered footer's individual buttons
(previously mixing `TextButton` and `OutlinedButton` with a custom, tighter `contentPadding` on
the numbered buttons specifically) now each set `Modifier.height(PaginationButtonHeight)`
explicitly. Pinning one explicit height on every button removes the possibility of disagreement
by construction, regardless of which specific Material3 default/padding interaction was actually
responsible for the reported drift — a more robust fix than chasing that exact mechanism down.
Each screen keeps its own string resources (so their text stays independently localizable); only
the visual composable is shared.
- **Language and star count needed no new network call**: Gitea's repository-list endpoint
(verified against `modules/structs/repo.go`'s `Repository` struct) already returns both
`language` and `stars_count` on the exact same call this app already makes to populate the list.
- **The favorite-star toggle reuses `toggleFavorite` exactly as TASK-018 already built and tested
it, unmodified** — this task only connects a UI trigger that never existed, it doesn't change the
underlying action. That action is already context-sensitive per list mode: on the ALL list it
stars (and `favoriteAction` only reflects *this session's* interaction, defaulting to
`Idle`/outlined even for a repository starred before this session — a known limitation carried
over unchanged, not newly introduced); on the FAVORITES list every row is inherently already
starred (that's why it's showing), so tapping there un-favorites and removes the row on success
rather than toggling the icon's own look. `FavoriteStar`'s rendering branches on which list mode
is current specifically to get this right: filled/primary-colored when actually confirmed
starred (or, on the FAVORITES list, whenever not mid-unstar), outlined otherwise, error-tinted on
a failed attempt (still tappable to retry), all sharing one `Row` clickable so it doesn't also
trigger the row's own "open this repository" tap.
- **No per-language color coding**: GitHub/Gitea's own "colored dot per language" convention
(visible in the reference screenshot) comes from a maintained language-color mapping (the
`linguist` project) this app has no copy of and no reliable way to source accurately; the
language name is shown as plain text instead, matching what was actually asked for ("어떤
언어인지... 보여줄래") without fabricating colors that might not match Gitea's own.
## Acceptance criteria
- [x] Every color visible across the app (tab indicators, buttons, selected states, links) now
reads as Gitea-brand green instead of Compose's unthemed default purple.
- [x] Dark mode has its own complete, coherent color scheme (not just the light one shown at a
lower opacity).
- [x] `error`/diff-removed-line coloring is visually unchanged (still red).
- [x] Every pagination footer's buttons (previous/next/numbered) render at the same height as each
other, confirmed by direct visual inspection on the live device (not just by code review).
- [x] Each repository row shows its Gitea-reported primary language (when non-blank) and star
count.
- [x] Tapping a row's star toggle stars it on the ALL list (or un-favorites and removes the row on
the FAVORITES list) via the exact same `toggleFavorite` action TASK-018 already built —
confirmed live on the device (star count/outline visibly responded to a tap).
- [x] Build, unit tests, and lint pass.
- [ ] Full live confirmation from the human product owner across all three changes together — the
device screenshots taken this session confirm the green theme, consistent footer heights,
and language/star display are all visibly correct, but the human product owner hasn't yet
given explicit sign-off in this exact session turn.
## Required checks
```text
./gradlew assembleDebug
./gradlew testDebugUnitTest
./gradlew lintDebug
```
## Evidence
- `ui/theme/Color.kt` (new): the full hand-built light/dark tonal palette, with the Gitea-source
citation for the seed green in its file-level doc comment.
- `ui/theme/Theme.kt`: `lightColorScheme(...)`/`darkColorScheme(...)` now pass every role explicitly
from `Color.kt` (previously called with no arguments at all, i.e. Compose's own baseline purple).
- `ui/PaginationFooter.kt` (new): `PaginationButtonHeight = 40.dp` (matching Material3's own
`ButtonDefaults.MinHeight`, made explicit rather than trusted implicitly) and
`SimplePaginationFooter`.
- `HistoryScreen.kt`/`NotificationsScreen.kt`/`RepositoryListScreen.kt`: each screen's `PageFooter`
(or, for repositories, its inline pagination `Row`) now delegates to `SimplePaginationFooter`,
passing its own existing string resources; now-unused `OutlinedButton` imports removed where
applicable.
- `WorkItemsScreen.kt`: plain fallback `PageFooter` also now uses `SimplePaginationFooter`;
`NumberedPageFooter`'s `TextButton`/`OutlinedButton` calls each gained
`Modifier.height(PaginationButtonHeight)`.
- `RepositoryModels.kt`: `RepositorySummary` gained `language: String? = null` and
`starsCount: Int = 0` (both defaulted so no existing call site needed to change).
- `GiteaRepositoryBrowserApi.kt`: `RepositoryDto` gained `language`/`stars_count` fields;
`mapRepository` populates both (blank language becomes `null`).
- `RepositoryListViewModel.kt`: `RepositoryRowUiModel` gained the same two fields; `toUiModel()`
updated.
- `RepositoryListScreen.kt`: new `FavoriteStar` composable (mode-aware rendering described in
Design notes); each row gained a `Row` showing language (or a blank `Spacer` when absent) and the
star toggle; `onToggleFavorite` threaded through `RepositoryListScreen`/`RepositoryContent`.
- `MainActivity.kt`: `onToggleFavorite = viewModel::toggleFavorite`.
- New test: `GiteaRepositoryBrowserApiTest.kt` (`language`/`stars_count` mapped correctly; a blank
`language` string becomes `null`).
- `./gradlew compileDebugKotlin compileDebugUnitTestKotlin`: BUILD SUCCESSFUL.
- `./gradlew testDebugUnitTest`: BUILD SUCCESSFUL, all unit tests passing (including the new one
above).
- `./gradlew assembleDebug lintDebug`: BUILD SUCCESSFUL, 0 lint errors.
- Live device: build installed over wireless `adb`. Screenshots taken directly on the device
confirm: the green theme applied consistently across the repository list, its tabs, and the
branch-detail file browser; the repository list's previous/next footer buttons render at matching
heights; each row shows its language (e.g. "C++", "C#") and star count with the outline/filled
star icon.
## Known limitations
- On the ALL repositories list, a repository already starred before the current app session still
shows an outlined (not filled) star until acted on in this session — `favoriteAction` only
tracks this session's own interaction, not the server's actual current starred state at load
time. This is carried over unchanged from TASK-018's original design, not a new gap.
- No per-language color coding (see Design notes) — language is shown as plain text only.
- Contrast for the hand-built color palette was reasoned through directly (informal luminance/
contrast-ratio estimation against WCAG's 4.5:1 threshold for the primary/onPrimary pairing
specifically) rather than verified with an automated contrast-checking tool across every one of
the ~20 color roles: the palette is a solid, deliberate design, but a full formal accessibility
audit of every role pairing hasn't been done.
- Full live human confirmation of this batch is still pending, even though device screenshots
taken directly this session already show all three pieces working correctly.
## Review findings
None yet — no Codex review pending (Codex retired, 2026-09-29).