Files
kangkang/康康/Services/ReminderService.swift
link2026 1b01923c8e feat(capture): 统一报告捕获流程并集成视觉语言模型识别
- 替换 QuickCaptureFlow 和 ArchiveFlow 为 UnifiedCaptureFlow 统一流程
- 新增 VLSession 封装 Qwen2.5-VL 模型进行图像文本推理
- 实现 AIRuntime 中 VL 模型的准备和分析功能
- 添加 VLPrompts 定义体检化验单识别的 JSON 输出模板
- 创建 CaptureReviewForm 提供 VL 解析结果的可编辑表单界面
- 集成 VisionKit 文档扫描器支持真机多页文档扫描
- 为模拟器实现 PhotosPicker 回退方案选择已有照片
- 在 RootView 中统一使用 UnifiedCaptureFlow 处理快速和归档流程
- 添加 CustomMetricEditor 支持自定义监测指标的创建编辑删除
- 扩展 KangkangApp 模型配置以支持新数据类型
- 实现档案列表中症状结束功能通过时间线行点击触发
2026-05-26 11:18:00 +08:00

95 lines
3.7 KiB
Swift

import Foundation
import UserNotifications
///
/// `metricId` iOS N weekly-repeats ,id
/// `kangkang.reminder.<metricId>.w<weekday>`,便 weekday cancel
///
/// SwiftData `MetricReminder`;,
/// SwiftData
enum ReminderService {
static let idPrefix = "kangkang.reminder."
enum AuthState: String {
case granted, denied, notDetermined, provisional
}
// MARK: - authorization
static func currentAuthState() async -> AuthState {
let settings = await UNUserNotificationCenter.current().notificationSettings()
switch settings.authorizationStatus {
case .authorized: return .granted
case .denied: return .denied
case .provisional: return .provisional
case .ephemeral: return .granted
case .notDetermined: return .notDetermined
@unknown default: return .notDetermined
}
}
/// granted/denied
@discardableResult
static func requestAuthorization() async -> AuthState {
let center = UNUserNotificationCenter.current()
let settings = await center.notificationSettings()
if settings.authorizationStatus != .notDetermined {
return await currentAuthState()
}
do {
let granted = try await center.requestAuthorization(options: [.alert, .sound, .badge])
return granted ? .granted : .denied
} catch {
return .denied
}
}
// MARK: - upsert / cancel
/// metric pending , enabled//weekdays
/// `MetricReminder` save
static func sync(_ reminder: MetricReminder) async {
cancel(metricId: reminder.metricId)
guard reminder.enabled, !reminder.weekdays.isEmpty else { return }
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "该测\(reminder.displayName)"
content.body = "在「+ 新建 → 指标记录 → \(reminder.displayName)」记录一次"
content.sound = .default
content.threadIdentifier = "kangkang.reminder.\(reminder.metricId)"
for weekday in reminder.weekdays {
var comps = DateComponents()
comps.hour = reminder.hour
comps.minute = reminder.minute
comps.weekday = weekday
let trigger = UNCalendarNotificationTrigger(dateMatching: comps, repeats: true)
let id = identifier(metricId: reminder.metricId, weekday: weekday)
let request = UNNotificationRequest(identifier: id,
content: content,
trigger: trigger)
try? await center.add(request)
}
}
/// metric pending (7 weekday ,)
static func cancel(metricId: String) {
let center = UNUserNotificationCenter.current()
let ids = (1...7).map { identifier(metricId: metricId, weekday: $0) }
center.removePendingNotificationRequests(withIdentifiers: ids)
}
/// Me Tab
static func cancelAll() {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
}
// MARK: - helpers
private static func identifier(metricId: String, weekday: Int) -> String {
"\(idPrefix)\(metricId).w\(weekday)"
}
}