import SwiftUI /// 手表主页:一键录音、今日数、最近录音;录完传 iPhone,整理在手机端完成。 struct ContentView: View { @EnvironmentObject private var sessionManager: WatchSessionManager @StateObject private var recorder = WatchRecorder() @State private var phase = Phase.idle @State private var notes = WatchStore.load() @State private var lastURL: URL? enum Phase { case idle, recording, sending, sent, error(String) } var body: some View { ScrollView { VStack(spacing: 12) { switch phase { case .idle: recordButton Text("今日速记 \(sessionManager.todayCount) 条") .font(.caption2) .foregroundStyle(.secondary) case .recording: recordingView case .sending: ProgressView("正在传到 iPhone…") case .sent: Label("已传到 iPhone", systemImage: "checkmark.circle.fill") .font(.caption) .foregroundStyle(.green) Button("再录一条") { phase = .idle } .font(.caption) case .error(let message): Text(message) .font(.caption) .foregroundStyle(.red) .multilineTextAlignment(.center) if let url = lastURL { Button("重试传输") { send(url: url) } .font(.caption) } Button("返回") { phase = .idle } .font(.caption) } if !notes.isEmpty { Divider() ForEach(notes.prefix(5)) { note in HStack { Text(note.createdAt, format: .dateTime.hour().minute()) .font(.caption2) Spacer() Text(formatTime(note.duration)) .font(.caption2) .foregroundStyle(.secondary) Image(systemName: note.sent ? "checkmark.icloud.fill" : "paperplane") .font(.caption2) .foregroundStyle(note.sent ? .green : .secondary) } } } } .padding() } } private var recordButton: some View { Button { Task { guard await recorder.requestPermission() else { phase = .error("没有麦克风权限,请在手表设置里开启。") return } do { try recorder.start() phase = .recording } catch { phase = .error("录音启动失败:\(error.localizedDescription)") } } } label: { ZStack { Circle().fill(Color.red) Image(systemName: "mic.fill") .font(.title2) .foregroundStyle(.white) } .frame(width: 72, height: 72) } .buttonStyle(.plain) } private var recordingView: some View { VStack(spacing: 10) { HStack(spacing: 4) { Circle().fill(Color.red).frame(width: 8, height: 8) Text("录音中 \(formatTime(recorder.elapsed))") .font(.caption) } Button("停止并发送") { guard let url = recorder.stop() else { phase = .error("录音文件没生成,请再试一次。") return } lastURL = url send(url: url) } .font(.caption) .tint(.red) } } private func send(url: URL) { phase = .sending sessionManager.transfer(url: url) { result in switch result { case .success: notes.insert(WatchNote(createdAt: Date(), duration: recorder.elapsed, sent: true), at: 0) WatchStore.append(notes[0]) phase = .sent case .failure(let error): phase = .error(error.localizedDescription) } } } private func formatTime(_ time: TimeInterval) -> String { let total = Int(time) return String(format: "%d:%02d", total / 60, total % 60) } }