缺少代码差异信息,无法生成具体的commit message。请提供code differences内容以便分析并生成符合Angular规范的提交信息。

当您提供代码差异后,我将按照以下格式生成:

```
<type>(<scope>): <subject>

<body>
```

其中type会根据更改类型选择(feat、fix、docs、style、refactor等),scope表示影响范围,subject简要描述变更内容,body详细说明修改内容。
This commit is contained in:
link2026
2026-06-07 14:17:18 +08:00
parent 074d99715d
commit 77a4ee1c37
66 changed files with 2676 additions and 548 deletions

View File

@@ -35,9 +35,40 @@ struct ProfileEditView: View {
private struct ProfileEditForm: View {
@Environment(\.modelContext) private var ctx
@Bindable var profile: UserProfile
@State private var healthImportDraft: HealthProfileImportDraft?
@State private var healthImportError: String?
@State private var isImportingHealthProfile = false
var body: some View {
Form {
Section {
Button {
importHealthProfile()
} label: {
HStack(spacing: 10) {
if isImportingHealthProfile {
ProgressView()
} else {
Image(systemName: "heart.text.square")
.foregroundStyle(Tj.Palette.ink)
}
VStack(alignment: .leading, spacing: 2) {
Text("从 Apple 健康导入")
.foregroundStyle(Tj.Palette.text)
Text("只读取生日、性别、身高、血型")
.font(.tjScaled( 12))
.foregroundStyle(Tj.Palette.text3)
}
}
}
.disabled(isImportingHealthProfile)
.accessibilityElement(children: .combine)
.accessibilityLabel("从 Apple 健康导入")
.accessibilityHint("读取生日、性别、身高和血型,确认后填入个人资料")
} footer: {
Text("导入前会先显示预览,确认后才覆盖个人资料。")
}
Section {
BirthYearRow(profile: profile)
SexRow(profile: profile)
@@ -67,6 +98,90 @@ private struct ProfileEditForm: View {
profile.updatedAt = .now
try? ctx.save()
}
.sheet(item: $healthImportDraft) { draft in
HealthProfileImportPreviewSheet(
draft: draft,
profile: profile
) {
draft.apply(to: profile)
try? ctx.save()
healthImportDraft = nil
}
}
.alert("无法导入 Apple 健康资料", isPresented: Binding(
get: { healthImportError != nil },
set: { if !$0 { healthImportError = nil } }
)) {
Button("", role: .cancel) { healthImportError = nil }
} message: {
Text(healthImportError ?? "")
}
}
private func importHealthProfile() {
guard !isImportingHealthProfile else { return }
isImportingHealthProfile = true
healthImportError = nil
Task {
do {
healthImportDraft = try await HealthProfileImportService.shared.fetchDraft()
} catch {
healthImportError = error.localizedDescription
}
isImportingHealthProfile = false
}
}
}
private struct HealthProfileImportPreviewSheet: View {
@Environment(\.dismiss) private var dismiss
let draft: HealthProfileImportDraft
let profile: UserProfile
let onApply: () -> Void
private var preview: HealthProfileImportPreview {
HealthProfileImportPreview(draft: draft, current: profile)
}
var body: some View {
NavigationStack {
List {
Section {
ForEach(preview.fields, id: \.title) { field in
HStack(alignment: .firstTextBaseline) {
Text(field.title)
.foregroundStyle(Tj.Palette.text)
Spacer(minLength: 12)
VStack(alignment: .trailing, spacing: 4) {
Text(field.imported ?? "未读取到")
.foregroundStyle(field.imported == nil ? Tj.Palette.text3 : Tj.Palette.text)
Text("当前: \(field.current)")
.font(.tjScaled( 11))
.foregroundStyle(Tj.Palette.text3)
}
}
}
} footer: {
Text("未读取到的字段不会修改。")
}
}
.navigationTitle("确认导入")
.navigationBarTitleDisplayMode(.inline)
.scrollContentBackground(.hidden)
.background(Tj.Palette.sand.ignoresSafeArea())
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("取消") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button("导入") {
onApply()
dismiss()
}
.fontWeight(.semibold)
}
}
}
}
}
@@ -112,7 +227,7 @@ private struct BirthYearRow: View {
Text(selectedLabel)
.foregroundStyle(profile.birthYear == nil ? Tj.Palette.text3 : Tj.Palette.text2)
Image(systemName: "chevron.right")
.font(.system(size: 12, weight: .semibold))
.font(.tjScaled( 12, weight: .semibold))
.foregroundStyle(Tj.Palette.text3)
.rotationEffect(.degrees(expanded ? 90 : 0))
}
@@ -212,7 +327,7 @@ private struct BMIFooter: View {
var body: some View {
if let bmi = profile.bmi {
Text("BMI: \(String(format: "%.1f", bmi)) \(label(bmi))")
.font(.system(size: 11))
.font(.tjScaled( 11))
}
}
@@ -282,7 +397,7 @@ private struct ChronicSection: View {
private func chip(label: String, selected: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
Text(label)
.font(.system(size: 13, weight: selected ? .semibold : .regular))
.font(.tjScaled( 13, weight: selected ? .semibold : .regular))
.foregroundStyle(selected ? Tj.Palette.paper : Tj.Palette.text)
.padding(.horizontal, 12)
.padding(.vertical, 6)