DFWatchFigmaDetailViews.swift 10.7 KB
import SwiftUI

struct DFTodayStatusOverviewFigmaView: View {
    var hasData: Bool = true

    private var rows: [DFStatusOverviewRow] {
        [
            .init(title: "平均HRV", value: hasData ? "29" : "-", unit: "ms", icon: "waveform.path.ecg", tint: DFWatchFigmaColor.blue),
            .init(title: "最新心率", value: hasData ? "79" : "-", unit: "次/分", icon: "heart.fill", tint: DFWatchFigmaColor.red),
            .init(title: "步数", value: hasData ? "11198" : "-", unit: "步", icon: "figure.walk", tint: DFWatchFigmaColor.green),
            .init(title: "活动记录", value: hasData ? "400" : "-", unit: "大卡", icon: "flame.fill", tint: DFWatchFigmaColor.orange)
        ]
    }

    var body: some View {
        ZStack{
            HStack{
                Spacer()
            }
            VStack(alignment: .trailing){
                Text(.now, style: .time)
                    .font(.system(size: 14, weight: .medium))
                    .foregroundColor(.white)
                Text("我的今日状态")
                    .lineLimit(1)
                    .font(.system(size: 16, weight: .medium))
                    .minimumScaleFactor(0.7)
                    .foregroundColor(.white)
                ScrollView {
                    ForEach(rows) { row in
                        DFStatusOverviewCard(row: row)
                            .padding(.bottom, 4)
                    }
                    Spacer()
                        .frame(height: 24)
                }
            }.padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 10))
        }
    }
}

private struct DFStatusOverviewRow: Identifiable {
    let id = UUID()
    let title: String
    let value: String
    let unit: String
    let icon: String
    let tint: Color
}

private struct DFStatusOverviewCard: View {
    let row: DFStatusOverviewRow

    var body: some View {
        HStack(spacing: 0) {
            Image(systemName: row.icon)
                .frame(width: 18, height: 18)
                .foregroundColor(row.tint)
            Spacer()
                .frame(width: 6)
            Text(row.title)
                .font(.system(size: 12, weight: .medium))
                .lineLimit(1)
                .minimumScaleFactor(0.7)
                .foregroundColor(.white)
            Spacer(minLength: 0)
            Text(row.value)
                .font(.system(size: 12, weight: .medium))
                .lineLimit(1)
                .minimumScaleFactor(0.7)
                .foregroundColor(.white)
            Spacer()
                .frame(width: 2)
            Text(row.unit)
                .font(.system(size: 12, weight: .regular))
                .lineLimit(1)
                .minimumScaleFactor(0.7)
                .foregroundColor(.white.opacity(0.5))
        }
        .padding(.horizontal, 8)
        .padding(.vertical, 10)
        .background(Color.white.opacity(0.10))
        .clipShape(RoundedRectangle(cornerRadius: 10))
    }
}

struct DFWatchSettingsFigmaView: View {

    var body: some View {
        ZStack(alignment: .topTrailing){
            HStack{
                Spacer()
            }
            VStack(alignment: .leading){
                Spacer()
                    .frame(height: 14)
                DFWatchCloseView {
                    
                }
                Spacer()
                    .frame(height: 6)
                HStack{
                    Text("刷新模式")
                        .font(.system(size: 16, weight: .medium))
                        .foregroundColor(.white)
                    DFWatchFigmaProBadge()
                    Spacer()
                }.padding(.leading, 16)
                ScrollView {
                    VStack(alignment: .leading, spacing: 8) {
                        DFSettingOption(title: "HRV", accessory: .check)
                        DFSettingOption(title: "实时压力", accessory: .lock)
                        Text("刷新模式说明")
                            .font(.system(size: 9, weight: .regular))
                            .underline()
                            .foregroundColor(DFWatchFigmaColor.purpleText)
                            .padding(.leading, 8)
                    }.padding(.horizontal, 10)
                        .padding(.bottom, 24)
                }
            }
            Text(.now, style: .time)
                .font(.system(size: 14, weight: .medium))
                .foregroundColor(.white)
                .padding(.trailing, 14)
                .padding(.top, 10)
        }
    }
}

private enum DFSettingAccessory {
    case check
    case lock
}

private struct DFSettingOption: View {
    let title: String
    let accessory: DFSettingAccessory

    var body: some View {
        HStack {
            Text(title)
                .font(.system(size: 12, weight: .medium))
                .foregroundColor(.white)
            Spacer()
            switch accessory {
            case .check:
                Image(systemName: "checkmark")
                    .font(.system(size: 15, weight: .bold))
                    .foregroundColor(.white)
            case .lock:
                Image(systemName: "lock.fill")
                    .font(.system(size: 15, weight: .medium))
                    .foregroundColor(.white.opacity(0.84))
            }
        }
        .frame(height: 38)
        .padding(.horizontal, 8)
        .background(Color.white.opacity(0.10))
        .clipShape(RoundedRectangle(cornerRadius: 10))
    }
}

struct DFProRequiredInfoFigmaView: View {
    var body: some View {
        ZStack(alignment: .topTrailing){
            HStack{
                Spacer()
            }
            VStack(alignment: .center){
                Spacer()
                    .frame(height: 14)
                HStack{
                    DFWatchCloseView {
                        
                    }
                    Spacer()
                }
                Spacer()
                    .frame(height: 6)
                DFWatchFigmaProBadge()
                Spacer()
                    .frame(height: 10)
                ScrollView {
                    VStack(alignment: .leading, spacing: 11) {
                        Text("该功能需要DoubleFeel Pro会员才可使用。你可以前往手机App开通会员。")
                        Text("如果已经开通会员,但手表端还没有显示,可以先退出当前页面,再重新进入,会员状态通常会自动更新。")
                    }
                    .font(.system(size: 11, weight: .regular))
                    .foregroundColor(.white)
                    .lineSpacing(2)
                    .padding(.horizontal, 12)
                    .padding(.bottom, 24)
                }
            }
            Text(.now, style: .time)
                .font(.system(size: 14, weight: .medium))
                .foregroundColor(.white)
                .padding(.trailing, 14)
                .padding(.top, 10)
        }
    }
}

struct DFRefreshModeInfoFigmaView: View {
    var body: some View {
        ZStack(alignment: .topTrailing){
            HStack{
                Spacer()
            }
            VStack(alignment: .leading){
                Spacer()
                    .frame(height: 14)
                DFWatchCloseView {
                    
                }
                Spacer()
                    .frame(height: 8)
                ScrollView {
                    VStack(alignment: .leading){
                        Text("HRV")
                            .font(.system(size: 14, weight: .medium))
                            .foregroundColor(.white)
                        Spacer()
                            .frame(height: 4)
                        Text("""
    一般情况下,Apple Watch 会每隔一段时间自动采集一次 HRV 数据。
    在佩戴稳定、身体静止或放松状态下,系统更容易获取有效 HRV 数据。
    剧烈运动、频繁活动、手表佩戴不稳定或刚解锁 Apple Watch 后,数据同步可能会延迟。
    Apple Watch 与 iPhone 的健康数据同步由 Apple Health 系统完成,因此并不会始终实时更新。
    """)
                            .font(.system(size: 9, weight: .regular))
                            .foregroundColor(.white.opacity(0.8))
                        Spacer()
                            .frame(height: 14)
                        Text("实时压力")
                            .font(.system(size: 14, weight: .medium))
                            .foregroundColor(.white)
                        Spacer()
                            .frame(height: 4)
                        Text("""
实时压力会结合当前 HRV、心率状态与个人历史数据动态变化。
通常情况下:
 · 手机 App 会自动刷新当天综合压力状态
 · Apple Watch 会显示最近一次的实时压力变化
由于 Apple Health 数据同步存在延迟,实时压力可能不会立即更新。
""")
                            .font(.system(size: 9, weight: .regular))
                            .foregroundColor(.white.opacity(0.8))
                        Spacer()
                            .frame(height: 14)
                        Divider()
                            .overlay(Color.white.opacity(0.25))
                        Spacer()
                            .frame(height: 14)
                        Text("""
以下情况可能导致数据延迟或暂时不可用:
 · Apple Watch 处于低电量模式
 · Apple Health 权限未开启
 · 长时间未佩戴 Apple Watch
 · 正在运动或身体频繁活动
 · 手表刚解锁或刚重新佩戴
 · 系统尚未完成数据同步
""")
                            .font(.system(size: 8, weight: .regular))
                            .foregroundColor(.white.opacity(0.8))
                    }.padding(.horizontal, 10)
                        .padding(.bottom, 24)
                }
            }
            VStack(alignment: .trailing){
                Text(.now, style: .time)
                    .font(.system(size: 14, weight: .medium))
                    .foregroundColor(.white)
                Text("HRV")
                    .font(.system(size: 12, weight: .medium))
                    .foregroundColor(.white)
                    .opacity(0.6)
            }
            .padding(.trailing, 14)
            .padding(.top, 10)
        }
    }
}

struct DFWatchFigmaDetailPreviewGallery: View {
    var body: some View {
        TabView {
            DFTodayStatusOverviewFigmaView(hasData: true)
            DFTodayStatusOverviewFigmaView(hasData: false)
            DFWatchSettingsFigmaView()
            DFProRequiredInfoFigmaView()
            DFRefreshModeInfoFigmaView()
        }
#if os(watchOS)
        .tabViewStyle(.verticalPage)
#else
        .tabViewStyle(.page)
#endif
    }
}

#Preview("Figma watch detail states") {
    DFWatchFigmaDetailPreviewGallery()
}