learning_ai_clock/ios/ChronoMind/Shared/TimerEngine/Urgency.swift

138 lines
3.9 KiB
Swift

// Urgency System
// 5 levels mapping to notification style, sound, vibration, visual intensity, snooze behavior
// Ported from web/src/lib/urgency.ts
import SwiftUI
// MARK: - Urgency Level
enum UrgencyLevel: String, Codable, CaseIterable, Identifiable {
case critical
case important
case standard
case gentle
case passive
var id: String { rawValue }
}
// MARK: - Notification Style
enum NotificationStyle: String, Codable {
case persistent // Critical: won't auto-dismiss
case prominent // Important: sound + banner
case `default` // Standard: normal notification
case subtle // Gentle: silent banner
case badge // Passive: badge only
}
// MARK: - Urgency Configuration
struct UrgencyConfig {
let level: UrgencyLevel
let label: String
let color: Color
let colorHex: String
let notificationStyle: NotificationStyle
let soundEnabled: Bool
let vibrationPattern: [Int] // ms on/off pattern
let visualIntensity: Double // 0-1
let autoSnoozeMinutes: Int? // nil = no auto-snooze
let requireConfirmToDismiss: Bool
let fullScreenOverlay: Bool
}
// MARK: - Urgency Configs
let urgencyConfigs: [UrgencyLevel: UrgencyConfig] = [
.critical: UrgencyConfig(
level: .critical,
label: "Critical",
color: Color(hex: 0xFF4757),
colorHex: "#FF4757",
notificationStyle: .persistent,
soundEnabled: true,
vibrationPattern: [200, 100, 200, 100, 400],
visualIntensity: 1.0,
autoSnoozeMinutes: nil,
requireConfirmToDismiss: true,
fullScreenOverlay: true
),
.important: UrgencyConfig(
level: .important,
label: "Important",
color: Color(hex: 0xFF9F43),
colorHex: "#FF9F43",
notificationStyle: .prominent,
soundEnabled: true,
vibrationPattern: [200, 100, 200],
visualIntensity: 0.8,
autoSnoozeMinutes: 10,
requireConfirmToDismiss: false,
fullScreenOverlay: false
),
.standard: UrgencyConfig(
level: .standard,
label: "Standard",
color: Color(hex: 0xFECA57),
colorHex: "#FECA57",
notificationStyle: .default,
soundEnabled: true,
vibrationPattern: [200],
visualIntensity: 0.6,
autoSnoozeMinutes: 5,
requireConfirmToDismiss: false,
fullScreenOverlay: false
),
.gentle: UrgencyConfig(
level: .gentle,
label: "Gentle",
color: Color(hex: 0x2ED573),
colorHex: "#2ED573",
notificationStyle: .subtle,
soundEnabled: true,
vibrationPattern: [100],
visualIntensity: 0.3,
autoSnoozeMinutes: 5,
requireConfirmToDismiss: false,
fullScreenOverlay: false
),
.passive: UrgencyConfig(
level: .passive,
label: "Passive",
color: Color(hex: 0xA5B1C7),
colorHex: "#A5B1C7",
notificationStyle: .badge,
soundEnabled: false,
vibrationPattern: [],
visualIntensity: 0.1,
autoSnoozeMinutes: nil,
requireConfirmToDismiss: false,
fullScreenOverlay: false
),
]
let urgencyOrder: [UrgencyLevel] = [.critical, .important, .standard, .gentle, .passive]
func getUrgencyConfig(_ level: UrgencyLevel) -> UrgencyConfig {
urgencyConfigs[level]!
}
func getUrgencyIndex(_ level: UrgencyLevel) -> Int {
urgencyOrder.firstIndex(of: level) ?? 0
}
// MARK: - Color Extension
extension Color {
init(hex: UInt, alpha: Double = 1.0) {
self.init(
.sRGB,
red: Double((hex >> 16) & 0xFF) / 255.0,
green: Double((hex >> 8) & 0xFF) / 255.0,
blue: Double(hex & 0xFF) / 255.0,
opacity: alpha
)
}
}