Merge develop -> main: full session (KC-51 through KC-71) #28
@@ -1965,3 +1965,25 @@ how every other color in the app is centralized, and is accessible from any
|
|||||||
file.
|
file.
|
||||||
|
|
||||||
Files: `DesignTokens.swift`, `SettingsView.swift`, `OnboardingView.swift`.
|
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`.
|
||||||
|
|||||||
@@ -265,7 +265,10 @@ final class NotificationManager: NSObject, ObservableObject, @unchecked Sendable
|
|||||||
habitType: "coffee"
|
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(
|
addDaily(
|
||||||
id: "\(Self.habitPrefix).coffee.custom",
|
id: "\(Self.habitPrefix).coffee.custom",
|
||||||
enabled: coffeeOn && (ud.object(forKey: "coffeeCustomEnabled") as? Bool ?? false),
|
enabled: coffeeOn && (ud.object(forKey: "coffeeCustomEnabled") as? Bool ?? false),
|
||||||
|
|||||||
@@ -916,7 +916,7 @@ private struct HabitRemindersSheet: View {
|
|||||||
@AppStorage("coffeeReminderEnabled", store: UserDefaults.kisani) private var coffeeReminderEnabled = false
|
@AppStorage("coffeeReminderEnabled", store: UserDefaults.kisani) private var coffeeReminderEnabled = false
|
||||||
|
|
||||||
@AppStorage("coffeeCustomEnabled", store: UserDefaults.kisani) private var coffeeCustomEnabled = 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("coffeeCustomHour", store: UserDefaults.kisani) private var coffeeCustomHour = 16
|
||||||
@AppStorage("coffeeCustomMinute", store: UserDefaults.kisani) private var coffeeCustomMinute = 30
|
@AppStorage("coffeeCustomMinute", store: UserDefaults.kisani) private var coffeeCustomMinute = 30
|
||||||
|
|
||||||
@@ -1020,22 +1020,29 @@ private struct HabitRemindersSheet: View {
|
|||||||
defaultMinute: 0, defaultEnabled: slot == "Morning")
|
defaultMinute: 0, defaultEnabled: slot == "Morning")
|
||||||
}
|
}
|
||||||
Divider().background(AppColors.border(cs)).padding(.leading, 14)
|
Divider().background(AppColors.border(cs)).padding(.leading, 14)
|
||||||
HStack(spacing: 11) {
|
VStack(alignment: .leading, spacing: 5) {
|
||||||
TextField("Custom label", text: $coffeeCustomLabel)
|
HStack(spacing: 4) {
|
||||||
.font(AppFonts.sans(12.5)).foregroundColor(AppColors.text(cs))
|
Image(systemName: "pencil").font(.system(size: 9))
|
||||||
Spacer()
|
Text("YOUR OWN REMINDER").font(AppFonts.mono(8, weight: .bold))
|
||||||
if coffeeCustomEnabled {
|
}
|
||||||
DatePicker("", selection: Binding(
|
.foregroundColor(AppColors.text3(cs))
|
||||||
get: { Calendar.current.date(bySettingHour: coffeeCustomHour, minute: coffeeCustomMinute, second: 0, of: Date()) ?? Date() },
|
HStack(spacing: 11) {
|
||||||
set: { v in
|
TextField("Name it, e.g. \"Second coffee\"", text: $coffeeCustomLabel)
|
||||||
let c = Calendar.current.dateComponents([.hour, .minute], from: v)
|
.font(AppFonts.sans(12.5)).foregroundColor(AppColors.text(cs))
|
||||||
coffeeCustomHour = c.hour ?? coffeeCustomHour
|
Spacer()
|
||||||
coffeeCustomMinute = c.minute ?? coffeeCustomMinute
|
if coffeeCustomEnabled {
|
||||||
}
|
DatePicker("", selection: Binding(
|
||||||
), displayedComponents: .hourAndMinute)
|
get: { Calendar.current.date(bySettingHour: coffeeCustomHour, minute: coffeeCustomMinute, second: 0, of: Date()) ?? Date() },
|
||||||
.labelsHidden().tint(AppColors.accent)
|
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)
|
.padding(.horizontal, 14).padding(.vertical, 9)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user