Ubisam-MobileGit/tasks/030-gitea-green-theme-and-repo-row-enhancements.md
choiminyeong f693dbdb5b TASK-030: Gitea-green theme, pagination footer height fix, repo language/star
Replaces Compose Material3's unthemed default (purple) with a real color
scheme built from Gitea's own brand green, verified against Gitea's source
(--color-logo: #609926). Fixes a live-reported bug where pagination footer
button heights visibly varied by pinning one explicit height on every
button across all four screens' footers, and by sharing one
SimplePaginationFooter for the plain previous/next case. Each repository
row now shows its Gitea-reported primary language and a tappable star
toggle wired to the existing toggleFavorite action.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 23:10:59 +09:00

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 (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

  • 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 toggleFavorite action 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 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 — pending Codex/human review.