diff --git a/app/src/main/java/com/ubisam/ubgitea/feature/notifications/NotificationsScreen.kt b/app/src/main/java/com/ubisam/ubgitea/feature/notifications/NotificationsScreen.kt index 06e8b66..4695206 100644 --- a/app/src/main/java/com/ubisam/ubgitea/feature/notifications/NotificationsScreen.kt +++ b/app/src/main/java/com/ubisam/ubgitea/feature/notifications/NotificationsScreen.kt @@ -11,11 +11,13 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface import androidx.compose.material3.Tab import androidx.compose.material3.TabRow import androidx.compose.material3.Text @@ -101,7 +103,7 @@ private fun NotificationRow(notification: NotificationSummary, onSelected: () -> style = MaterialTheme.typography.bodySmall, ) Text(stringResource(notification.subjectType.labelResource), style = MaterialTheme.typography.bodySmall) - Text(stringResource(notification.subjectState.labelResource), style = MaterialTheme.typography.bodySmall) + StatusBadge(notification.subjectState) } Text(notification.title, style = MaterialTheme.typography.titleMedium, maxLines = 2) } @@ -160,6 +162,30 @@ private val NotificationSubjectState.labelResource: Int NotificationSubjectState.UNKNOWN -> R.string.notifications_state_unknown } +// Same compact colored-Surface badge WorkItemsScreen's issue/PR rows use (see that file's own +// StatusBadge doc comment for the full rationale) -- kept as its own copy rather than a shared +// component since these are two different feature packages and the two state enums +// (NotificationSubjectState vs. IssueState/PullRequestState) don't share a type to unify over. +// UNKNOWN -- a real Gitea subject state this client doesn't recognize, not a state to visually +// emphasize -- gets the same neutral surfaceVariant treatment VisibilityBadge uses for "private" +// rather than either affirmative-state color. +@Composable +private fun StatusBadge(state: NotificationSubjectState) { + val (container, content) = when (state) { + NotificationSubjectState.OPEN -> MaterialTheme.colorScheme.primaryContainer to MaterialTheme.colorScheme.onPrimaryContainer + NotificationSubjectState.CLOSED -> MaterialTheme.colorScheme.errorContainer to MaterialTheme.colorScheme.onErrorContainer + NotificationSubjectState.MERGED -> MaterialTheme.colorScheme.tertiaryContainer to MaterialTheme.colorScheme.onTertiaryContainer + NotificationSubjectState.UNKNOWN -> MaterialTheme.colorScheme.surfaceVariant to MaterialTheme.colorScheme.onSurfaceVariant + } + Surface(color = container, contentColor = content, shape = RoundedCornerShape(4.dp)) { + Text( + stringResource(state.labelResource), + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp), + ) + } +} + private val NotificationsError.messageResource: Int get() = when (this) { NotificationsError.OFFLINE -> R.string.notifications_offline diff --git a/docs/development-log.md b/docs/development-log.md index bd0ce33..79f534f 100644 --- a/docs/development-log.md +++ b/docs/development-log.md @@ -887,3 +887,30 @@ This is the append-only implementation and handoff record shared by Codex and Cl yet reviewed this session), and consider extending today's status-badge fix to `NotificationsScreen.kt` for consistency. - Next owner: Claude, continuing per the standing direction. + +## 2026-08-29 (continued) — TASK-042 follow-up: NotificationsScreen status badges + +- Agent and role: Claude, direct continuation of the same live session, closing the known limitation + recorded in TASK-042's own task file immediately after landing it. +- Commit/diff: on `claude/task-015-notifications`; `feature/notifications/NotificationsScreen.kt` + gained its own `StatusBadge` composable for `NotificationSubjectState`; + `tasks/042-workitem-status-badges.md` updated to record the closure. +- How it was implemented: `NotificationSubjectState` is a different enum from `IssueState`/ + `PullRequestState` (it also has an `UNKNOWN` case, for a subject state this client doesn't + recognize) and this is a different feature package from `WorkItemsScreen.kt`, so this is a second, + independent copy of the same badge treatment rather than a shared component — UNKNOWN maps to the + neutral `surfaceVariant` `VisibilityBadge` already uses for "private", since an unrecognized state + isn't one to visually emphasize either direction. +- Files changed: `feature/notifications/NotificationsScreen.kt`, + `tasks/042-workitem-status-badges.md`. +- Checks and results: `./gradlew compileDebugKotlin compileDebugUnitTestKotlin testDebugUnitTest assembleDebug lintDebug` + BUILD SUCCESSFUL, all existing tests passing unmodified, 0 lint errors. +- Live verification: installed over wireless `adb`. Notifications → 전체 tab: confirmed all three real + colors render side by side across the actual notification list — red "닫힘", teal "병합됨", green + "열림" (screenshot) — which also closes the earlier task's "never visually confirmed CLOSED red + live" gap, since it's the same `errorContainer` role used by both screens' badges. +- Review findings and resolutions: None from a separate review pass. +- Known limitations: None outstanding for TASK-042 or this follow-up. +- Next recommended task: continue the design-review pass — the text/image/CSV/PDF file viewers have + not yet been reviewed this session. +- Next owner: Claude, continuing per the standing direction. diff --git a/tasks/042-workitem-status-badges.md b/tasks/042-workitem-status-badges.md index 4ea0bc6..677d7e2 100644 --- a/tasks/042-workitem-status-badges.md +++ b/tasks/042-workitem-status-badges.md @@ -83,14 +83,21 @@ with a compact colored badge, reusing the `VisibilityBadge` pattern TASK-039 alr ## Known limitations -- `NotificationsScreen.kt` still renders its own PR/이슈 상태 column as plain text — a second, - separate location with the same visual gap this task fixed on the work-items screens. Not touched - here to keep this change scoped to what was actually being reviewed; worth a follow-up pass. -- Did not find a real CLOSED (닫힘) issue/PR with this fix installed to visually confirm the red badge - live — the CLOSED branch was exercised only via the existing 닫힘 rows seen in `NotificationsScreen` - (a different, unfixed screen) prior to this change. The color mapping itself - (`errorContainer`/`onErrorContainer`) is the same theme role used unconditionally elsewhere in the - app, so this is a low-risk gap, not left silently assumed away. +None outstanding for this task — see the follow-up below, which closed the one gap originally +recorded here. + +## Follow-up (same session): NotificationsScreen + +`NotificationsScreen.kt`'s own PR/이슈 상태 column had the identical gap (plain-text state label) in a +separate screen this task didn't originally touch. Added a second, independent `StatusBadge` +composable there (for `NotificationSubjectState`, a different enum with its own `UNKNOWN` case — +mapped to the neutral `surfaceVariant`/`onSurfaceVariant` `VisibilityBadge` already uses for +"private", since an unrecognized state isn't one to visually emphasize either direction) rather than +sharing code across the two feature packages. Build/test/lint re-run clean; live-verified on-device: +the notifications 전체 list now shows all three real colors side by side — red "닫힘", teal "병합됨", +green "열림" — which also closes the "never visually confirmed the red CLOSED badge live" gap +originally recorded here, since these are the same `errorContainer`/`onErrorContainer` roles used by +the work-items screens' badge. ## Review findings