feat: 添加拍药盒功能和语音直达入口

- 实现拍药盒扫描流程,支持本地OCR识别药品信息
- 在日记页面添加拍药盒和记症状的三选一入口
- 优化按钮点击区域,确保符合苹果HIG最小命中区标准
- 添加用药记录到时间线的独立分类显示
- 实现长按+号语音直达功能,支持语音意图分类跳转
- 更新项目配置文件,启用代码分析和死代码剥离选项
- 增加多项本地化字符串支持新功能
```
This commit is contained in:
link2026
2026-06-13 09:16:25 +08:00
parent f58d6064ba
commit 6c6a950140
30 changed files with 1856 additions and 64 deletions

View File

@@ -38,6 +38,7 @@ private struct ProfileEditForm: View {
@State private var healthImportDraft: HealthProfileImportDraft?
@State private var healthImportError: String?
@State private var isImportingHealthProfile = false
@State private var showMedicationScan = false
var body: some View {
Form {
@@ -88,7 +89,8 @@ private struct ProfileEditForm: View {
StringListSection(title: String(appLoc: "家族史"), placeholder: String(appLoc: "如:母亲 高血压"),
items: $profile.familyHistory)
StringListSection(title: String(appLoc: "当前用药"), placeholder: String(appLoc: "如:缬沙坦 80mg qd"),
items: $profile.currentMedications)
items: $profile.currentMedications,
onScan: { showMedicationScan = true })
}
.navigationTitle("个人资料")
.navigationBarTitleDisplayMode(.inline)
@@ -98,6 +100,16 @@ private struct ProfileEditForm: View {
profile.updatedAt = .now
try? ctx.save()
}
.fullScreenCover(isPresented: $showMedicationScan) {
// OCR + LLM :
// (线)+ ()
MedicationScanFlow(
onSave: { entries in
MedicationArchiver.archive(entries: entries, in: ctx)
},
onClose: { showMedicationScan = false }
)
}
.sheet(item: $healthImportDraft) { draft in
HealthProfileImportPreviewSheet(
draft: draft,
@@ -456,10 +468,27 @@ private struct StringListSection: View {
let title: String
let placeholder: String
@Binding var items: [String]
/// nil ()
var onScan: (() -> Void)? = nil
@State private var newInput = ""
var body: some View {
Section(title) {
if let onScan {
Button(action: onScan) {
HStack(spacing: 10) {
Image(systemName: "camera.viewfinder")
.foregroundStyle(Tj.Palette.ink)
VStack(alignment: .leading, spacing: 2) {
Text("拍药盒自动识别")
.foregroundStyle(Tj.Palette.text)
Text("拍药盒或说明书,本地识别药名与规格")
.font(.tjScaled( 12))
.foregroundStyle(Tj.Palette.text3)
}
}
}
}
ForEach(items, id: \.self) { item in
HStack {
Text(item)