Files
kangkang/体己/Features/Quick/A1ViewfinderView.swift
link2026 c050865db5 feat(ui): UI 骨架基线 — 3 Tab + RecordSheet + Quick/Archive 流程占位
替换 Xcode 默认模板:
- 删除 ContentView/Item/__App
- 新增 App/TijiApp(SwiftData ModelContainer)、RootView(3 Tab + RecordSheet)
- DesignSystem:Tokens(色板/字体/圆角)+ Components(卡片/按钮/Chip)
- Models:Indicator / Report / DiaryEntry @Model 初版
- Features:Home / Quick(A1-A3)/ Archive(B1-B5)/ Record / Trends / Me 静态 UI

W2 AI 基座工作将在此基线上叠加。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 14:49:21 +08:00

160 lines
5.3 KiB
Swift

import SwiftUI
#if canImport(UIKit)
import UIKit
#endif
struct A1ViewfinderView: View {
var onShoot: () -> Void
var onClose: () -> Void
@State private var dotPulse = false
var body: some View {
GeometryReader { geometry in
ZStack {
Color(red: 0.04, green: 0.047, blue: 0.04).ignoresSafeArea()
mockCameraPreview(screenHeight: geometry.size.height)
VStack {
HStack {
Button(action: onClose) {
Image(systemName: "xmark")
.font(.system(size: 18, weight: .semibold))
.foregroundStyle(Color.white)
.frame(width: 36, height: 36)
}
Spacer()
}
.padding(.horizontal, 6)
.padding(.top, 50)
topHint
Spacer()
}
SmartFramer()
.allowsHitTesting(false)
.ignoresSafeArea()
identifiedPill
.padding(.top, geometry.size.height * 0.62 - 20)
VStack {
Spacer()
bottomControls
}
}
}
#if os(iOS)
.statusBarHidden(false)
#endif
.preferredColorScheme(.dark)
}
private func mockCameraPreview(screenHeight: CGFloat) -> some View {
RadialGradient(
colors: [Color.white.opacity(0.05), Color.clear],
center: .init(x: 0.5, y: 0.3),
startRadius: 20,
endRadius: 400
)
.overlay(alignment: .center) {
VStack(alignment: .leading, spacing: 6) {
Text("总胆固醇 TC 5.42 mmol/L").opacity(0.65)
Text("甘油三酯 TG 1.78 mmol/L").opacity(0.65)
Text("低密度脂蛋白 3.84 mmol/L ↑").fontWeight(.semibold).opacity(1)
Text("高密度脂蛋白 1.21 mmol/L").opacity(0.65)
Text("载脂蛋白 A1 1.42 g/L").opacity(0.45)
Text("载脂蛋白 B 1.04 g/L").opacity(0.45)
}
.font(.system(size: 11, design: .monospaced))
.foregroundStyle(Tj.Palette.text)
.padding(.vertical, 20)
.padding(.horizontal, 18)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 0.96, green: 0.93, blue: 0.87).opacity(0.92))
.clipShape(RoundedRectangle(cornerRadius: 4, style: .continuous))
.rotationEffect(.degrees(-1.2))
.shadow(color: .black.opacity(0.45), radius: 15, x: 0, y: 12)
.padding(.horizontal, 24)
.padding(.vertical, screenHeight * 0.20)
}
}
private var topHint: some View {
Text("对准异常的那一行就好 · 不用拍整张")
.font(.system(size: 12))
.tracking(0.5)
.foregroundStyle(Color.white.opacity(0.92))
.padding(.horizontal, 14)
.padding(.vertical, 7)
.background(Capsule().fill(Color(red: 0.08, green: 0.11, blue: 0.094).opacity(0.7)))
.padding(.top, 6)
}
private var identifiedPill: some View {
HStack(spacing: 6) {
Circle()
.fill(Tj.Palette.paper)
.frame(width: 6, height: 6)
.opacity(dotPulse ? 1 : 0.35)
Text("AI 已识别到 1 项指标")
.font(.system(size: 11))
.tracking(0.5)
}
.foregroundStyle(Tj.Palette.paper)
.padding(.horizontal, 10)
.padding(.vertical, 4)
.background(Capsule().fill(Color(red: 0.37, green: 0.47, blue: 0.31).opacity(0.85)))
.onAppear {
withAnimation(.easeInOut(duration: 2.2).repeatForever(autoreverses: true)) {
dotPulse.toggle()
}
}
}
private var bottomControls: some View {
HStack {
CircleIconButton(icon: "bolt.fill", size: 44) { }
Spacer()
Button(action: onShoot) {
ZStack {
Circle().fill(Tj.Palette.ink)
Circle().strokeBorder(Tj.Palette.paper, lineWidth: 4)
}
.frame(width: 72, height: 72)
.overlay(
Circle().strokeBorder(Color.white.opacity(0.2), lineWidth: 1)
.frame(width: 76, height: 76)
)
}
.buttonStyle(.plain)
Spacer()
CircleIconButton(icon: "photo.on.rectangle", size: 44) { }
}
.padding(.horizontal, 32)
.padding(.bottom, 40)
}
}
private struct CircleIconButton: View {
let icon: String
let size: CGFloat
let action: () -> Void
var body: some View {
Button(action: action) {
ZStack {
Circle().fill(Color.white.opacity(0.12))
Image(systemName: icon)
.font(.system(size: 18, weight: .medium))
.foregroundStyle(Tj.Palette.paper)
}
.frame(width: size, height: size)
}
.buttonStyle(.plain)
}
}