Merge develop -> main: full session (KC-51 through KC-71) #28

Merged
kutesir merged 64 commits from develop into main 2026-07-12 22:57:14 +00:00
3 changed files with 49 additions and 17 deletions
Showing only changes of commit a3a1a46afd - Show all commits

View File

@@ -1965,3 +1965,25 @@ how every other color in the app is centralized, and is accessible from any
file.
Files: `DesignTokens.swift`, `SettingsView.swift`, `OnboardingView.swift`.
---
## KC-58 — Custom coffee reminder row was unlabeled/confusing
**Status:** Implemented (not build-verified)
**Reported by:** User (screenshot: last row in "Coffee reminders" just said
"Coffee" — indistinguishable from the card's own title, no hint it's an
editable custom slot)
### Fix
- The custom-reminder row now has a small "✎ YOUR OWN REMINDER" label above
it, so it reads as a distinct, nameable 5th slot rather than a redundant
duplicate of the "Coffee reminders" card title.
- Default label changed from the confusing pre-filled "Coffee" to empty, so
the field's placeholder ("Name it, e.g. \"Second coffee\"") actually guides
the user instead of looking like a static, already-filled-in option.
- `NotificationManager` falls back to "Coffee" for the notification title only
if the user never actually typed a name (empty string), so an un-customized
custom reminder still reads sensibly if enabled.
Files: `SettingsView.swift`, `NotificationManager.swift`.

View File

@@ -265,7 +265,10 @@ final class NotificationManager: NSObject, ObservableObject, @unchecked Sendable
habitType: "coffee"
)
}
let customLabel = ud.string(forKey: "coffeeCustomLabel") ?? "Coffee"
// Empty until the user names it (the field's placeholder guides that)
// fall back to a sensible default rather than an empty notification title.
let rawCustomLabel = ud.string(forKey: "coffeeCustomLabel") ?? ""
let customLabel = rawCustomLabel.isEmpty ? "Coffee" : rawCustomLabel
addDaily(
id: "\(Self.habitPrefix).coffee.custom",
enabled: coffeeOn && (ud.object(forKey: "coffeeCustomEnabled") as? Bool ?? false),

View File

@@ -916,7 +916,7 @@ private struct HabitRemindersSheet: View {
@AppStorage("coffeeReminderEnabled", store: UserDefaults.kisani) private var coffeeReminderEnabled = false
@AppStorage("coffeeCustomEnabled", store: UserDefaults.kisani) private var coffeeCustomEnabled = false
@AppStorage("coffeeCustomLabel", store: UserDefaults.kisani) private var coffeeCustomLabel = "Coffee"
@AppStorage("coffeeCustomLabel", store: UserDefaults.kisani) private var coffeeCustomLabel = ""
@AppStorage("coffeeCustomHour", store: UserDefaults.kisani) private var coffeeCustomHour = 16
@AppStorage("coffeeCustomMinute", store: UserDefaults.kisani) private var coffeeCustomMinute = 30
@@ -1020,22 +1020,29 @@ private struct HabitRemindersSheet: View {
defaultMinute: 0, defaultEnabled: slot == "Morning")
}
Divider().background(AppColors.border(cs)).padding(.leading, 14)
HStack(spacing: 11) {
TextField("Custom label", text: $coffeeCustomLabel)
.font(AppFonts.sans(12.5)).foregroundColor(AppColors.text(cs))
Spacer()
if coffeeCustomEnabled {
DatePicker("", selection: Binding(
get: { Calendar.current.date(bySettingHour: coffeeCustomHour, minute: coffeeCustomMinute, second: 0, of: Date()) ?? Date() },
set: { v in
let c = Calendar.current.dateComponents([.hour, .minute], from: v)
coffeeCustomHour = c.hour ?? coffeeCustomHour
coffeeCustomMinute = c.minute ?? coffeeCustomMinute
}
), displayedComponents: .hourAndMinute)
.labelsHidden().tint(AppColors.accent)
VStack(alignment: .leading, spacing: 5) {
HStack(spacing: 4) {
Image(systemName: "pencil").font(.system(size: 9))
Text("YOUR OWN REMINDER").font(AppFonts.mono(8, weight: .bold))
}
.foregroundColor(AppColors.text3(cs))
HStack(spacing: 11) {
TextField("Name it, e.g. \"Second coffee\"", text: $coffeeCustomLabel)
.font(AppFonts.sans(12.5)).foregroundColor(AppColors.text(cs))
Spacer()
if coffeeCustomEnabled {
DatePicker("", selection: Binding(
get: { Calendar.current.date(bySettingHour: coffeeCustomHour, minute: coffeeCustomMinute, second: 0, of: Date()) ?? Date() },
set: { v in
let c = Calendar.current.dateComponents([.hour, .minute], from: v)
coffeeCustomHour = c.hour ?? coffeeCustomHour
coffeeCustomMinute = c.minute ?? coffeeCustomMinute
}
), displayedComponents: .hourAndMinute)
.labelsHidden().tint(AppColors.accent)
}
Toggle("", isOn: $coffeeCustomEnabled).labelsHidden().tint(AppColors.accent).scaleEffect(0.85)
}
Toggle("", isOn: $coffeeCustomEnabled).labelsHidden().tint(AppColors.accent).scaleEffect(0.85)
}
.padding(.horizontal, 14).padding(.vertical, 9)
}