diff --git a/Alarm/Views/TimerView.swift b/Alarm/Views/TimerView.swift index f79a9d6..2037535 100644 --- a/Alarm/Views/TimerView.swift +++ b/Alarm/Views/TimerView.swift @@ -2,9 +2,12 @@ import SwiftUI import Combine struct TimerView: View { + private let presets = [60, 5 * 60, 10 * 60, 25 * 60] + @State private var durationSeconds: Int = 300 @State private var remainingSeconds: Int = 300 @State private var isRunning = false + @State private var didComplete = false private let ticker = Timer.publish(every: 1, on: .main, in: .common).autoconnect() var body: some View { @@ -18,6 +21,12 @@ struct TimerView: View { .font(.system(size: 68, weight: .light, design: .rounded)) .monospacedDigit() + Text(statusText) + .font(.system(size: 15, weight: .regular)) + .foregroundStyle(Color(white: 0.42)) + + presetRow + Stepper("时长:\(durationSeconds / 60) 分钟", value: $durationSeconds, in: 60 ... 24 * 3600, step: 60) .font(.system(size: 16, weight: .regular)) .disabled(isRunning) @@ -44,13 +53,19 @@ struct TimerView: View { .padding() } .navigationTitle("计时器") + .alert("计时结束", isPresented: $didComplete) { + Button("确定", role: .cancel) {} + } message: { + Text("本轮 \(durationSummary(durationSeconds)) 已完成。") + } .onReceive(ticker) { _ in guard isRunning else { return } - if remainingSeconds > 0 { + if remainingSeconds > 1 { remainingSeconds -= 1 - } else { - stop() + return } + + complete() } } .preferredColorScheme(.light) @@ -58,6 +73,7 @@ struct TimerView: View { private func start() { guard remainingSeconds > 0 else { return } + didComplete = false isRunning = true } @@ -65,12 +81,74 @@ struct TimerView: View { isRunning = false } + private func complete() { + stop() + remainingSeconds = 0 + didComplete = true + } + private func format(_ seconds: Int) -> String { let h = seconds / 3600 let m = (seconds % 3600) / 60 let s = seconds % 60 return String(format: "%02d:%02d:%02d", h, m, s) } + + private var presetRow: some View { + HStack(spacing: 10) { + ForEach(presets, id: \.self) { preset in + Button { + applyPreset(preset) + } label: { + Text(durationSummary(preset)) + .font(.system(size: 14, weight: .medium)) + .foregroundStyle(durationSeconds == preset ? .white : Color(white: 0.2)) + .padding(.horizontal, 14) + .padding(.vertical, 10) + .background( + Capsule() + .fill(durationSeconds == preset ? Color.orange : Color.white) + ) + } + .buttonStyle(.plain) + .disabled(isRunning) + .opacity(isRunning ? 0.45 : 1) + } + } + } + + private var statusText: String { + if didComplete { + return "本轮倒计时已完成" + } + if isRunning { + return "进行中 · 剩余 \(durationSummary(remainingSeconds))" + } + if remainingSeconds == durationSeconds { + return "选择常用时长后即可开始" + } + return "已暂停,可继续或重置" + } + + private func applyPreset(_ preset: Int) { + guard !isRunning else { return } + durationSeconds = preset + remainingSeconds = preset + didComplete = false + } + + private func durationSummary(_ seconds: Int) -> String { + if seconds < 3600 { + return "\(seconds / 60) 分钟" + } + + let hours = seconds / 3600 + let minutes = (seconds % 3600) / 60 + if minutes == 0 { + return "\(hours) 小时" + } + return "\(hours) 小时 \(minutes) 分钟" + } } #Preview {