Fix iOS time display and add timer unit labels
Times were always showing 0 because ISO8601DateFormatter with default options does not parse fractional seconds, but Prisma/Node.js serialises dates as "2026-02-20T09:00:00.000Z" (with .000). Every date(from:) call silently returned nil, so elapsedTime and duration always fell back to 0. - Date+Extensions: fromISO8601 now tries .withFractionalSeconds first, then falls back to whole seconds — single place to maintain - OngoingTimer.elapsedTime: use Date.fromISO8601() instead of bare formatter - TimeEntry.duration: use Date.fromISO8601() instead of bare formatters - TimerView: add TimerUnitLabels view showing h/min/sec column headers under the monospaced clock digits
This commit is contained in:
@@ -44,6 +44,8 @@ struct TimerView: View {
|
||||
.font(.system(size: 64, weight: .light, design: .monospaced))
|
||||
.foregroundStyle(viewModel.activeTimer != nil ? .primary : .secondary)
|
||||
|
||||
TimerUnitLabels(elapsed: viewModel.elapsedTime)
|
||||
|
||||
if let project = viewModel.selectedProject {
|
||||
ProjectColorBadge(
|
||||
color: project.color,
|
||||
@@ -123,7 +125,31 @@ struct TimerView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct ProjectPickerSheet: View {
|
||||
/// Displays "h min sec" (or "min sec") column labels aligned under the
|
||||
/// monospaced timer digits.
|
||||
private struct TimerUnitLabels: View {
|
||||
let elapsed: TimeInterval
|
||||
|
||||
private var showHours: Bool { Int(elapsed) >= 3600 }
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
if showHours {
|
||||
Text("h")
|
||||
.frame(width: 64)
|
||||
Text("min")
|
||||
.frame(width: 64)
|
||||
} else {
|
||||
Text("min")
|
||||
.frame(width: 64)
|
||||
}
|
||||
Text("sec")
|
||||
.frame(width: 64)
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
let projects: [Project]
|
||||
let selectedProject: Project?
|
||||
let onSelect: (Project?) -> Void
|
||||
|
||||
@@ -9,9 +9,7 @@ struct OngoingTimer: Codable, Identifiable, Equatable {
|
||||
let updatedAt: String
|
||||
|
||||
var elapsedTime: TimeInterval {
|
||||
guard let start = ISO8601DateFormatter().date(from: startTime) else {
|
||||
return 0
|
||||
}
|
||||
guard let start = Date.fromISO8601(startTime) else { return 0 }
|
||||
return Date().timeIntervalSince(start)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ struct TimeEntry: Codable, Identifiable, Equatable {
|
||||
let updatedAt: String
|
||||
|
||||
var duration: TimeInterval {
|
||||
guard let start = ISO8601DateFormatter().date(from: startTime),
|
||||
let end = ISO8601DateFormatter().date(from: endTime) else {
|
||||
return 0
|
||||
}
|
||||
guard let start = Date.fromISO8601(startTime),
|
||||
let end = Date.fromISO8601(endTime) else { return 0 }
|
||||
return end.timeIntervalSince(start)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,14 @@ extension Date {
|
||||
}
|
||||
|
||||
static func fromISO8601(_ string: String) -> Date? {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
formatter.formatOptions = [.withInternetDateTime]
|
||||
return formatter.date(from: string)
|
||||
// Try with fractional seconds first (e.g. "2026-02-20T09:00:00.000Z" from
|
||||
// Prisma/Node.js JSON serialisation), then fall back to whole seconds.
|
||||
let withFractional = ISO8601DateFormatter()
|
||||
withFractional.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
if let date = withFractional.date(from: string) { return date }
|
||||
|
||||
let wholeSec = ISO8601DateFormatter()
|
||||
wholeSec.formatOptions = [.withInternetDateTime]
|
||||
return wholeSec.date(from: string)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user