From 9154264ea7a657b9b2d4ac7039af7d1e6a9c4376 Mon Sep 17 00:00:00 2001 From: tigerenwork Date: Mon, 29 Jun 2026 21:52:37 +0800 Subject: [PATCH] fix: replace daily time text field with native DatePickers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Daily schedule mode now shows macOS-native hour:minute DatePickers instead of a comma-separated text field - Each time entry has its own picker with a remove button - '+ Add time' button to add more entries - Minimum 1 entry enforced (remove disabled when only 1 left) - No hardcoded defaults — starts empty, user picks their times Co-Authored-By: Claude --- Sources/Views/Settings/SettingsView.swift | 76 +++++++++++++++++------ 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/Sources/Views/Settings/SettingsView.swift b/Sources/Views/Settings/SettingsView.swift index e403bc0..684d3fb 100644 --- a/Sources/Views/Settings/SettingsView.swift +++ b/Sources/Views/Settings/SettingsView.swift @@ -59,16 +59,31 @@ struct SettingsView: View { } if config.pollIntervalSeconds == -1 { - VStack(alignment: .leading, spacing: 4) { - Text("Refresh at these times (comma-separated, 24h):") + VStack(alignment: .leading, spacing: 6) { + Text("Refresh at these times:") .font(.caption) .foregroundStyle(.secondary) - TextField("08:00, 14:00", text: dailyTimesBinding) - .font(.caption) - .textFieldStyle(.roundedBorder) - Text("Example: 08:00, 14:00, 20:00") - .font(.caption2) - .foregroundStyle(.secondary) + + ForEach(dailyTimeBindings.indices, id: \.self) { index in + HStack { + DatePicker("", selection: dailyTimeBindings[index], + displayedComponents: .hourAndMinute) + .labelsHidden() + + Button(action: { removeDailyTime(at: index) }) { + Image(systemName: "minus.circle.fill") + .foregroundStyle(.red) + } + .buttonStyle(.plain) + .disabled(config.dailyRefreshTimes.count <= 1) + } + } + + Button(action: addDailyTime) { + Label("Add time", systemImage: "plus.circle") + .font(.caption) + } + .buttonStyle(.plain) } } } @@ -165,18 +180,41 @@ struct SettingsView: View { .padding(.vertical, 2) } - // MARK: - Daily times binding + // MARK: - Daily times - private var dailyTimesBinding: Binding { - Binding( - get: { config.dailyRefreshTimes.joined(separator: ", ") }, - set: { newValue in - config.dailyRefreshTimes = newValue - .components(separatedBy: ",") - .map { $0.trimmingCharacters(in: .whitespaces) } - .filter { !$0.isEmpty } - } - ) + /// Reference date for time-only DatePickers + private var timeRef: Date { + Calendar.current.date(from: DateComponents(year: 2000, month: 1, day: 1))! + } + + private var dailyTimeBindings: [Binding] { + config.dailyRefreshTimes.indices.map { index in + Binding( + get: { + let parts = config.dailyRefreshTimes[index].components(separatedBy: ":") + let hour = Int(parts.first ?? "") ?? 0 + let minute = Int(parts.last ?? "") ?? 0 + return Calendar.current.date( + bySettingHour: hour, minute: minute, second: 0, of: timeRef + ) ?? timeRef + }, + set: { newDate in + let comps = Calendar.current.dateComponents([.hour, .minute], from: newDate) + let h = String(format: "%02d", comps.hour ?? 0) + let m = String(format: "%02d", comps.minute ?? 0) + config.dailyRefreshTimes[index] = "\(h):\(m)" + } + ) + } + } + + private func addDailyTime() { + config.dailyRefreshTimes.append("09:00") + } + + private func removeDailyTime(at index: Int) { + guard config.dailyRefreshTimes.count > 1 else { return } + config.dailyRefreshTimes.remove(at: index) } // MARK: - Actions