learning_ai_clock/ios/ChronoMind/Shared/TimerEngine/ContextMessages.swift
saravanakumardb1 11e50295ea feat: fix web build, add repo infra, port iOS engine modules, add routine screens
- fix(web): cast window through unknown in platform-sync.ts (TS2352)
- docs: add AGENTS.md, README.md, CLAUDE.md, .windsurfrules, .cursorrules, env.example
- feat(ios): port Recurrence.swift from web/src/lib/recurrence.ts
- feat(ios): port NLParser.swift from web/src/lib/nl-parser.ts
- feat(ios): port ContextMessages.swift from web/src/lib/context-messages.ts
- feat(ios): add CMRoutine model + Routines.swift engine with state machine + templates
- feat(ios): add RoutineListView, RoutineRunnerView, RoutineEditorView
- feat(android): add RoutineScreen.kt with list, runner, templates, step controls

Web: 373 tests passing, build succeeds with --webpack flag
2026-02-28 01:50:35 -08:00

177 lines
5.9 KiB
Swift

// Contextual Pre-Warning Messages
// Keyword helpful prep message mapping. Expandable, no LLM needed.
// Used in notification body and on timeline to give actionable context.
// Ported from web/src/lib/context-messages.ts
import Foundation
// MARK: - Context Rule
struct ContextRule {
let keywords: [String]
let messages: [String]
}
// MARK: - Rules Engine
private let contextRules: [ContextRule] = [
// Meetings & calls
ContextRule(
keywords: ["meeting", "standup", "sync", "huddle", "scrum", "1:1", "one-on-one"],
messages: ["Review your agenda", "Check meeting notes", "Prepare talking points"]
),
ContextRule(
keywords: ["call", "phone", "dial"],
messages: ["Have the number ready", "Review call notes", "Find a quiet spot"]
),
ContextRule(
keywords: ["interview", "screening"],
messages: ["Review the job description", "Prepare your questions", "Test your camera and mic"]
),
ContextRule(
keywords: ["presentation", "demo", "pitch"],
messages: ["Run through your slides", "Check your screen sharing", "Have backup ready"]
),
// Travel & transport
ContextRule(
keywords: ["flight", "plane", "airport"],
messages: ["Check in online", "Verify gate number", "Pack your carry-on"]
),
ContextRule(
keywords: ["train", "bus", "subway", "metro"],
messages: ["Check for delays", "Have your ticket ready"]
),
ContextRule(
keywords: ["drive", "commute", "carpool", "uber", "lyft", "taxi", "cab"],
messages: ["Check traffic conditions", "Grab your keys"]
),
ContextRule(
keywords: ["pickup", "pick up", "drop off", "dropoff"],
messages: ["Confirm the location", "Check for any updates"]
),
// Health & wellness
ContextRule(
keywords: ["doctor", "dentist", "therapist", "appointment", "clinic", "hospital"],
messages: ["Bring your insurance card", "Leave with travel buffer", "Note any symptoms to mention"]
),
ContextRule(
keywords: ["medicine", "medication", "pill", "vitamin"],
messages: ["Take with water", "Check dosage"]
),
ContextRule(
keywords: ["workout", "exercise", "gym", "run", "yoga", "stretch"],
messages: ["Hydrate beforehand", "Change into workout clothes", "Warm up first"]
),
// Food & cooking
ContextRule(
keywords: ["cook", "cooking", "bake", "baking", "oven", "recipe"],
messages: ["Preheat the oven", "Gather your ingredients", "Check you have everything"]
),
ContextRule(
keywords: ["pasta", "noodle", "rice", "boil"],
messages: ["Start boiling water", "Salt the water"]
),
ContextRule(
keywords: ["dinner", "lunch", "breakfast", "meal", "eat"],
messages: ["Start prepping ingredients", "Set the table"]
),
ContextRule(
keywords: ["laundry", "washer", "dryer", "clothes"],
messages: ["Move clothes to dryer", "Check pockets first"]
),
// Work & productivity
ContextRule(
keywords: ["deadline", "due", "submit", "submission"],
messages: ["Final review before submitting", "Double-check requirements"]
),
ContextRule(
keywords: ["class", "lecture", "lesson", "school", "study"],
messages: ["Pack your materials", "Review last session notes"]
),
ContextRule(
keywords: ["focus", "deep work", "concentrate"],
messages: ["Close unnecessary tabs", "Put phone on silent", "Grab water"]
),
// Personal
ContextRule(
keywords: ["birthday", "anniversary", "celebration", "party"],
messages: ["Check if the gift is ready", "Confirm the plan"]
),
ContextRule(
keywords: ["walk", "dog", "pet"],
messages: ["Grab the leash", "Bring waste bags"]
),
ContextRule(
keywords: ["sleep", "bed", "bedtime", "wind down", "rest"],
messages: ["Start winding down", "Put away screens", "Set tomorrow's alarm"]
),
ContextRule(
keywords: ["wake", "morning", "alarm"],
messages: ["Time to get up!", "Stretch and hydrate"]
),
]
// MARK: - Lookup
/// Get a contextual message for a timer label.
/// Returns the first matching message, or nil if no match.
func getContextMessage(label: String) -> String? {
let lower = label.lowercased()
for rule in contextRules {
if rule.keywords.contains(where: { lower.contains($0) }) {
return rule.messages.first
}
}
return nil
}
/// Get all matching contextual messages for a timer label.
/// Returns an array of messages from all matching rules.
func getAllContextMessages(label: String) -> [String] {
let lower = label.lowercased()
var messages: [String] = []
for rule in contextRules {
if rule.keywords.contains(where: { lower.contains($0) }) {
if let first = rule.messages.first {
messages.append(first)
}
}
}
return messages
}
/// Get a contextual message formatted for a pre-warning notification.
/// Includes the time remaining context.
func getWarningMessage(label: String, minutesBefore: Int) -> String {
let contextMsg = getContextMessage(label: label)
let timeStr: String
if minutesBefore >= 60 {
let hours = minutesBefore / 60
let mins = minutesBefore % 60
timeStr = mins > 0 ? "\(hours)h \(mins)m" : "\(hours)h"
} else {
timeStr = "\(minutesBefore)m"
}
let base = "\(label) in \(timeStr)"
if let msg = contextMsg {
return "\(base)\(msg)"
}
return base
}
/// Check if a label matches any context rule.
func hasContextMatch(label: String) -> Bool {
return getContextMessage(label: label) != nil
}
/// Get all registered context rules (for UI display / editing).
func getContextRules() -> [ContextRule] {
return contextRules
}