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>
11 KiB
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(reallightColorScheme/darkColorSchemevalues instead of Compose's defaults), newui/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(RepositorySummarygainslanguage/starsCount),data/repositories/GiteaRepositoryBrowserApi.kt(parses both from the repository list response Gitea already returns),feature/repositories/RepositoryListViewModel.kt(RepositoryRowUiModelgains the same two fields),feature/repositories/RepositoryListScreen.kt(renders language + aFavoriteStartoggle per row, wiresonToggleFavorite),MainActivity.kt(onToggleFavoritewiring). - 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 Material3primaryrole itself uses a slightly deeper tone of that same green (#3B6A1F) rather than the exact logo value — white text on#609926directly 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/onErrorContainerwere 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 mixingTextButtonandOutlinedButtonwith a custom, tightercontentPaddingon the numbered buttons specifically) now each setModifier.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'sRepositorystruct) already returns bothlanguageandstars_counton the exact same call this app already makes to populate the list. - The favorite-star toggle reuses
toggleFavoriteexactly 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 (andfavoriteActiononly reflects this session's interaction, defaulting toIdle/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 oneRowclickable 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
linguistproject) 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
- 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.
- Dark mode has its own complete, coherent color scheme (not just the light one shown at a lower opacity).
error/diff-removed-line coloring is visually unchanged (still red).- 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).
- Each repository row shows its Gitea-reported primary language (when non-blank) and star count.
- 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
toggleFavoriteaction TASK-018 already built — confirmed live on the device (star count/outline visibly responded to a tap). - 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
./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 fromColor.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 ownButtonDefaults.MinHeight, made explicit rather than trusted implicitly) andSimplePaginationFooter.HistoryScreen.kt/NotificationsScreen.kt/RepositoryListScreen.kt: each screen'sPageFooter(or, for repositories, its inline paginationRow) now delegates toSimplePaginationFooter, passing its own existing string resources; now-unusedOutlinedButtonimports removed where applicable.WorkItemsScreen.kt: plain fallbackPageFooteralso now usesSimplePaginationFooter;NumberedPageFooter'sTextButton/OutlinedButtoncalls each gainedModifier.height(PaginationButtonHeight).RepositoryModels.kt:RepositorySummarygainedlanguage: String? = nullandstarsCount: Int = 0(both defaulted so no existing call site needed to change).GiteaRepositoryBrowserApi.kt:RepositoryDtogainedlanguage/stars_countfields;mapRepositorypopulates both (blank language becomesnull).RepositoryListViewModel.kt:RepositoryRowUiModelgained the same two fields;toUiModel()updated.RepositoryListScreen.kt: newFavoriteStarcomposable (mode-aware rendering described in Design notes); each row gained aRowshowing language (or a blankSpacerwhen absent) and the star toggle;onToggleFavoritethreaded throughRepositoryListScreen/RepositoryContent.MainActivity.kt:onToggleFavorite = viewModel::toggleFavorite.- New test:
GiteaRepositoryBrowserApiTest.kt(language/stars_countmapped correctly; a blanklanguagestring becomesnull). ./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 —
favoriteActiononly 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).