Add per-user notification time preferences

Allow users to customize when they receive notification reminders:
- Add hour fields to NotificationPreference model
- Add timezone conversion utilities (localHourToUtc, utcHourToLocal)
- Add time picker UI for iOS (wheel picker in sheet)
- Add time picker UI for Android (hour chip selector dialog)
- Times stored in UTC, displayed in user's local timezone
- Add localized strings for time picker UI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-07 00:25:38 -06:00
parent 83e2cd14a6
commit 9d6e7c4f2a
10 changed files with 1086 additions and 7 deletions
+69
View File
@@ -176,4 +176,73 @@ enum DateUtils {
let today = Calendar.current.startOfDay(for: Date())
return date < today
}
// MARK: - Timezone Conversion Utilities
/// Convert a local hour (0-23) to UTC hour
/// - Parameter localHour: Hour in the device's local timezone (0-23)
/// - Returns: Hour in UTC (0-23)
static func localHourToUtc(_ localHour: Int) -> Int {
let now = Date()
let calendar = Calendar.current
// Create a date with the given local hour
var components = calendar.dateComponents(in: TimeZone.current, from: now)
components.hour = localHour
components.minute = 0
components.second = 0
guard let localDate = calendar.date(from: components) else {
return localHour
}
// Get the hour in UTC
var utcCalendar = Calendar.current
utcCalendar.timeZone = TimeZone(identifier: "UTC")!
let utcHour = utcCalendar.component(.hour, from: localDate)
return utcHour
}
/// Convert a UTC hour (0-23) to local hour
/// - Parameter utcHour: Hour in UTC (0-23)
/// - Returns: Hour in the device's local timezone (0-23)
static func utcHourToLocal(_ utcHour: Int) -> Int {
let now = Date()
// Create a calendar in UTC
var utcCalendar = Calendar.current
utcCalendar.timeZone = TimeZone(identifier: "UTC")!
// Create a date with the given UTC hour
var components = utcCalendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: now)
components.hour = utcHour
components.minute = 0
components.second = 0
guard let utcDate = utcCalendar.date(from: components) else {
return utcHour
}
// Get the hour in local timezone
let localHour = Calendar.current.component(.hour, from: utcDate)
return localHour
}
/// Format an hour (0-23) to a human-readable 12-hour format
/// - Parameter hour: Hour in 24-hour format (0-23)
/// - Returns: Formatted string like "8:00 AM" or "2:00 PM"
static func formatHour(_ hour: Int) -> String {
switch hour {
case 0:
return "12:00 AM"
case 1..<12:
return "\(hour):00 AM"
case 12:
return "12:00 PM"
default:
return "\(hour - 12):00 PM"
}
}
}