tasks: replace category text pill with TickTick-style icon glyphs (KC-62)
Some checks failed
CI / build-and-test (push) Has been cancelled

Every task row was tagging itself "Reminder" via a text badge for the
default category, adding no information. Swapped for icon-only glyphs
(nil for the generic .reminder case) folded into the existing alarm/
repeat indicator row; countdown/date info was already present or
redundant with the leading time-track, so no separate countdown text
was added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
kutesir
2026-07-09 14:17:18 +03:00
parent 9723775cb6
commit d8f7abff92
3 changed files with 84 additions and 12 deletions

View File

@@ -2118,3 +2118,50 @@ Not build-verified (no iOS runtime here). Self-reviewed: balanced braces/
parens confirmed per-file. `StopCountdownIntent` needs to land in the parens confirmed per-file. `StopCountdownIntent` needs to land in the
KisaniCalWidgets target (already covered by `project.yml`'s `sources: -path: KisaniCalWidgets target (already covered by `project.yml`'s `sources: -path:
KisaniCalWidgets` glob — no project.yml change needed). KisaniCalWidgets` glob — no project.yml change needed).
## KC-62 — Task row category pill replaced with TickTick-style icon glyphs
Status: Implemented (not build-verified — no iOS runtime here)
Reported by: User, from device screenshots ("reminder labeling a bit too
much, let's do it just like TickTick... show countdown info too")
Area: Today (task rows, both the top mini-timeline and the Tomorrow/Next 7
Days/Later list)
### Description
Every task row rendered a `TagChip` text badge showing `task.category
.rawValue` — for the vast majority of tasks (the default `.reminder`
category) this just says "Reminder" on nearly every row, adding no real
information. Confirmed only 2 call sites exist app-wide (`grep -rn
"TagChip(" KisaniCal/Views/*.swift`), both in `TodayView.swift` — Matrix and
Calendar don't render this pill at all, so "everywhere" (user's chosen
scope) resolves to these two.
### Change
- Added `TaskCategory.glyph: String?` (`TaskItem.swift`) — maps each
category to a small SF Symbol, `nil` for `.reminder` (the generic default
stays unmarked, matching TickTick's "no badge unless it says something"
density): `.birthday → gift.fill`, `.domain → briefcase.fill`, `.annual →
calendar`, `.custom → tag.fill`.
- **`TaskRowView`** (Tomorrow/Next 7 Days/Later rows — matches the user's
screenshot exactly): removed the `TagChip` call outright and folded the
category glyph into the row's existing ⏰/↻ icon `HStack`. This row
already carried a countdown (`countdownLabel(to:)`) next to the due date,
so "show countdown info too" was already satisfied — no countdown change
needed here.
- **`TodayTLRow`** (top mini-timeline — Overdue/Today/Next 3 Days/Upcoming):
same glyph swap, and while in there also added the ⏰/↻ indicators this
row was missing (it only had the category pill before). No standalone
countdown text added here — the leading time-track column already shows
either the time-of-day or the short date (`MMM d`) for non-today entries,
so a duplicate "in X days" string would be redundant clutter in an already
dense timeline row.
Files: `KisaniCal/Models/TaskItem.swift`, `KisaniCal/Views/TodayView.swift`.
### Note
Not build-verified (no iOS runtime here). Self-reviewed: balanced braces/
parens confirmed per-file (`TaskItem.swift` has one pre-existing stray `(`
imbalance confirmed via `git stash` to predate this change — a comment
artifact, not introduced here). `TagChip` itself is left intact in
`SharedComponents.swift` since it's a generic shared component, just no
longer called from these two sites.

View File

@@ -104,6 +104,18 @@ enum TaskCategory: String, Codable {
case domain = "Domain" case domain = "Domain"
case annual = "Annual" case annual = "Annual"
case custom = "Custom" case custom = "Custom"
/// Icon-only glyph for task rows `.reminder` is the generic default
/// and stays unmarked so the badge only appears when it adds information.
var glyph: String? {
switch self {
case .reminder: return nil
case .birthday: return "gift.fill"
case .domain: return "briefcase.fill"
case .annual: return "calendar"
case .custom: return "tag.fill"
}
}
} }
enum TaskColor: String, Codable { enum TaskColor: String, Codable {

View File

@@ -564,11 +564,25 @@ private struct TodayTLRow: View {
} }
} }
Spacer(minLength: 0) Spacer(minLength: 0)
TagChip( // TickTick-style icon only, no text badge; date/time already
text: entry.task.category.rawValue, // shown in the leading time-track column for this row.
color: entry.color, HStack(spacing: 5) {
bg: entry.task.quadrant.softColor if let glyph = entry.task.category.glyph {
) Image(systemName: glyph)
.font(.system(size: 11))
.foregroundColor(entry.color)
}
if entry.task.reminderDate != nil || entry.task.constantReminder {
Image(systemName: "alarm")
.font(.system(size: 11))
.foregroundColor(AppColors.text3(cs))
}
if entry.task.isRecurring {
Image(systemName: "repeat")
.font(.system(size: 11))
.foregroundColor(AppColors.text3(cs))
}
}
Button(action: onToggle) { Button(action: onToggle) {
ZStack { ZStack {
RoundedRectangle(cornerRadius: 5, style: .continuous) RoundedRectangle(cornerRadius: 5, style: .continuous)
@@ -1357,8 +1371,13 @@ struct TaskRowView: View {
Spacer() Spacer()
// reminder · 🔁 recurring indicators // reminder · 🔁 recurring · tag icon indicators (TickTick-style icon only, no text badge)
HStack(spacing: 5) { HStack(spacing: 5) {
if let glyph = task.category.glyph {
Image(systemName: glyph)
.font(.system(size: 11))
.foregroundColor(task.quadrant.color)
}
if task.reminderDate != nil || task.constantReminder { if task.reminderDate != nil || task.constantReminder {
Image(systemName: "alarm") Image(systemName: "alarm")
.font(.system(size: 11)) .font(.system(size: 11))
@@ -1370,12 +1389,6 @@ struct TaskRowView: View {
.foregroundColor(AppColors.text3(cs)) .foregroundColor(AppColors.text3(cs))
} }
} }
TagChip(
text: task.category.rawValue,
color: task.quadrant.color,
bg: task.quadrant.softColor
)
.padding(.trailing, 9) .padding(.trailing, 9)
} }
.frame(minHeight: 48) .frame(minHeight: 48)