138 lines
3.9 KiB
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
|
|
)
|
|
}
|
|
}
|