rename: Jarvis -> Jervis target, scheme, and folder throughout
The bundle-ID and display-name renames weren't enough — the actual Xcode target/product name was still "Jarvis", which drives CFBundleName, Xcode's Organizer archive list, the .xcodeproj filename, and the scheme name. Renamed all the way through: - project.yml: top-level name, target key, PRODUCT_NAME, source/info paths - Jarvis/ -> Jervis/ (source folder, git-tracked as renames, no content diffs on the moved files) - .gitignore, CI workflows, README, CONTRIBUTING: Jarvis.xcodeproj / scheme Jarvis -> Jervis.xcodeproj / scheme Jervis Verified: xcodebuild -scheme Jervis succeeds, produces Jervis.app, CFBundleName/CFBundleExecutable/CFBundleDisplayName all read "Jervis". CFBundleIdentifier intentionally stays com.kisani.jarvis (per prior decision — bundle ID isn't user-facing anywhere including Organizer). Swift type names (JarvisApp, JarvisWordmark, etc.) and the Gitea repo name/URL are unchanged — pure internal source identifiers, not user or developer-facing product identity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
75
Jervis/Notifications/NotificationSettings.swift
Normal file
75
Jervis/Notifications/NotificationSettings.swift
Normal file
@@ -0,0 +1,75 @@
|
||||
// NotificationSettings.swift
|
||||
// Jarvis — persisted notification preferences: breaking alerts + morning/evening
|
||||
// briefings with weather.
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
final class NotificationSettings: ObservableObject {
|
||||
static let shared = NotificationSettings()
|
||||
private let key = "jarvis_notifications_v1"
|
||||
|
||||
// Master intent (actual OS permission tracked by NotificationManager).
|
||||
@Published var enabled: Bool { didSet { persist() } }
|
||||
|
||||
// Breaking / new-story alerts
|
||||
@Published var breakingEnabled: Bool { didSet { persist() } }
|
||||
@Published var breakingMinSignal: Int { didSet { persist() } }
|
||||
|
||||
// Morning briefing
|
||||
@Published var morningEnabled: Bool { didSet { persist() } }
|
||||
@Published var morningHour: Int { didSet { persist() } }
|
||||
@Published var morningMinute: Int { didSet { persist() } }
|
||||
|
||||
// Evening briefing
|
||||
@Published var eveningEnabled: Bool { didSet { persist() } }
|
||||
@Published var eveningHour: Int { didSet { persist() } }
|
||||
@Published var eveningMinute: Int { didSet { persist() } }
|
||||
|
||||
// Weather
|
||||
@Published var weatherEnabled: Bool { didSet { persist() } }
|
||||
@Published var locationName: String { didSet { persist() } }
|
||||
@Published var latitude: Double? { didSet { persist() } }
|
||||
@Published var longitude: Double? { didSet { persist() } }
|
||||
@Published var resolvedPlace: String? { didSet { persist() } }
|
||||
|
||||
private struct Stored: Codable {
|
||||
var enabled, breakingEnabled, morningEnabled, eveningEnabled, weatherEnabled: Bool
|
||||
var breakingMinSignal, morningHour, morningMinute, eveningHour, eveningMinute: Int
|
||||
var locationName: String
|
||||
var latitude, longitude: Double?
|
||||
var resolvedPlace: String?
|
||||
}
|
||||
|
||||
private init() {
|
||||
if let data = UserDefaults.standard.data(forKey: key),
|
||||
let s = try? JSONDecoder().decode(Stored.self, from: data) {
|
||||
enabled = s.enabled
|
||||
breakingEnabled = s.breakingEnabled; breakingMinSignal = s.breakingMinSignal
|
||||
morningEnabled = s.morningEnabled; morningHour = s.morningHour; morningMinute = s.morningMinute
|
||||
eveningEnabled = s.eveningEnabled; eveningHour = s.eveningHour; eveningMinute = s.eveningMinute
|
||||
weatherEnabled = s.weatherEnabled; locationName = s.locationName
|
||||
latitude = s.latitude; longitude = s.longitude; resolvedPlace = s.resolvedPlace
|
||||
} else {
|
||||
enabled = true
|
||||
breakingEnabled = true; breakingMinSignal = 65
|
||||
morningEnabled = true; morningHour = 7; morningMinute = 0
|
||||
eveningEnabled = true; eveningHour = 18; eveningMinute = 0
|
||||
weatherEnabled = true; locationName = ""
|
||||
latitude = nil; longitude = nil; resolvedPlace = nil
|
||||
}
|
||||
}
|
||||
|
||||
private func persist() {
|
||||
let s = Stored(enabled: enabled, breakingEnabled: breakingEnabled,
|
||||
morningEnabled: morningEnabled, eveningEnabled: eveningEnabled,
|
||||
weatherEnabled: weatherEnabled, breakingMinSignal: breakingMinSignal,
|
||||
morningHour: morningHour, morningMinute: morningMinute,
|
||||
eveningHour: eveningHour, eveningMinute: eveningMinute,
|
||||
locationName: locationName, latitude: latitude, longitude: longitude,
|
||||
resolvedPlace: resolvedPlace)
|
||||
if let data = try? JSONEncoder().encode(s) { UserDefaults.standard.set(data, forKey: key) }
|
||||
}
|
||||
|
||||
var hasResolvedLocation: Bool { latitude != nil && longitude != nil }
|
||||
}
|
||||
Reference in New Issue
Block a user