TASK-042 follow-up: colored status badges on NotificationsScreen

Closes the known limitation from the previous commit: NotificationsScreen
had the identical plain-text state-label gap, in a separate screen/enum
(NotificationSubjectState, which also has an UNKNOWN case). Adds its own
StatusBadge composable with the same color roles, mapping UNKNOWN to the
neutral surfaceVariant treatment VisibilityBadge already uses for private.

Live-verified on-device: notifications 전체 list shows all three real
colors side by side (닫힘/병합됨/열림).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
최민영 2026-08-29 22:44:00 +09:00
parent 471456258b
commit ca999a7bb8
3 changed files with 69 additions and 9 deletions

View File

@ -11,11 +11,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Tab import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow import androidx.compose.material3.TabRow
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -101,7 +103,7 @@ private fun NotificationRow(notification: NotificationSummary, onSelected: () ->
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
) )
Text(stringResource(notification.subjectType.labelResource), 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) 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 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 private val NotificationsError.messageResource: Int
get() = when (this) { get() = when (this) {
NotificationsError.OFFLINE -> R.string.notifications_offline NotificationsError.OFFLINE -> R.string.notifications_offline

View File

@ -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 yet reviewed this session), and consider extending today's status-badge fix to
`NotificationsScreen.kt` for consistency. `NotificationsScreen.kt` for consistency.
- Next owner: Claude, continuing per the standing direction. - 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.

View File

@ -83,14 +83,21 @@ with a compact colored badge, reusing the `VisibilityBadge` pattern TASK-039 alr
## Known limitations ## Known limitations
- `NotificationsScreen.kt` still renders its own PR/이슈 상태 column as plain text — a second, None outstanding for this task — see the follow-up below, which closed the one gap originally
separate location with the same visual gap this task fixed on the work-items screens. Not touched recorded here.
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 ## Follow-up (same session): NotificationsScreen
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 `NotificationsScreen.kt`'s own PR/이슈 상태 column had the identical gap (plain-text state label) in a
(`errorContainer`/`onErrorContainer`) is the same theme role used unconditionally elsewhere in the separate screen this task didn't originally touch. Added a second, independent `StatusBadge`
app, so this is a low-risk gap, not left silently assumed away. 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 ## Review findings