文件
AUSleeping-IOS/AreYouSleeping/Views/DashboardView.swift
T

135 行
5.1 KiB
Swift

import SwiftUI
struct DashboardView: View {
@EnvironmentObject var store: Store
@State private var now = Date()
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
NavigationStack {
ScrollView {
VStack(spacing: 20) {
// 时钟 + 日期
VStack(spacing: 4) {
Text(timeString)
.font(.system(size: 56, weight: .thin, design: .rounded))
Text(dateString)
.font(.subheadline).foregroundColor(.secondary)
}
.padding(.top, 20)
// 问候语
Text(greeting)
.font(.title2)
// 倒计时
VStack(spacing: 8) {
Text(statusTitle)
.font(.headline)
Text(countdownText)
.font(.system(size: 28, weight: .medium))
.foregroundColor(.blue)
}
.padding()
.frame(maxWidth: .infinity)
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 16))
// 睡眠状态卡片
HStack(spacing: 16) {
statusCard(title: "就寝时间", value: TimeUtil.fmt(store.bedtimeMinutes))
statusCard(title: "起床时间", value: TimeUtil.fmt(store.waketimeMinutes))
}
// 监督状态
HStack {
Image(systemName: store.supervisionEnabled ? "shield.checkered" : "shield.slash")
.foregroundColor(store.supervisionEnabled ? .green : .red)
Text(store.supervisionEnabled ? "监督运行中" : "监督已关闭")
.font(.subheadline)
}
.padding(.horizontal)
// 入睡/起床按钮
if store.isSleeping {
Button {
store.endSleep()
} label: {
Label("我起床了", systemImage: "sunrise.fill")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.tint(.orange)
} else {
Button {
store.startSleep()
} label: {
Label("我要睡觉了", systemImage: "moon.zzz.fill")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.controlSize(.large)
.tint(.indigo)
}
}
.padding()
}
.navigationTitle("睡了吗")
.onReceive(timer) { t in now = t }
}
}
private var timeString: String {
let f = DateFormatter(); f.dateFormat = "HH:mm"; return f.string(from: now)
}
private var dateString: String {
let f = DateFormatter(); f.dateFormat = "yyyy年M月d日 EEEE"; f.locale = Locale(identifier: "zh_CN")
return f.string(from: now)
}
private var greeting: String {
let h = Calendar.current.component(.hour, from: now)
switch h {
case 0..<6: return "夜深了,好好休息"
case 6..<12: return "早上好!新的一天开始了"
case 12..<18: return "下午好,注意休息"
default: return "晚上好,准备放松吧"
}
}
private var statusTitle: String {
if store.isSleeping { return "正在睡眠中" }
let nowMin = TimeUtil.nowMinutes()
if TimeUtil.inNightWindow(nowMin, bedtime: store.bedtimeMinutes, waketime: store.waketimeMinutes) {
return "已到睡觉时间!"
}
return "距离睡觉还有"
}
private var countdownText: String {
if store.isSleeping {
let elapsed = Int((Date().timeIntervalSince1970 * 1000 - store.sleepStartMillis) / 3_600_000)
return "已睡 \(elapsed) 小时"
}
let nowMin = TimeUtil.nowMinutes()
var remain = store.bedtimeMinutes - nowMin
if remain < 0 { remain += 24 * 60 }
return "\(remain / 60) 小时 \(remain % 60) 分钟"
}
@ViewBuilder
private func statusCard(title: String, value: String) -> some View {
VStack(spacing: 4) {
Text(title).font(.caption).foregroundColor(.secondary)
Text(value).font(.title3).bold()
}
.frame(maxWidth: .infinity)
.padding()
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}