| Code | What It Does | How It Does It |
| ▶ IMPORTS | | |
| import SwiftUI
import UserNotifications
import Combine
import CoreLocation
import MapKit | Framework imports | Imports SwiftUI, UserNotifications, Combine, CoreLocation, MapKit. |
| // CLLocationCoordinate2D retroactive Equatable conformance (needed for onChange)
extension CLLocationCoordinate2D: @retroactive Equatable {
public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
}
} | Documentation comment | Describes the following declaration. |
| // Simple codable venue passed from MindTheShow via URL
struct PendingVenue: Codable {
let name: String
let lat: Double
let lon: Double
} | Documentation comment | Describes the following declaration. |
| // Shared data manager for incoming shared content
class SharedDataManager: ObservableObject {
static let shared = SharedDataManager()
@Published var pendingEntry: (name: String, content: String)?
@Published var shouldImportSharedEntry = false
@Published var pendingMapCenter: CLLocationCoordinate2D?
@Published var pendingMapSpan: MKCoordinateSpan?
@Published var pendingMapName: String?
@Published var pendingVenues: [PendingVenue] = []
} | Documentation comment | Describes the following declaration. |
| @main
struct SpotsApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject private var sharedDataManager = SharedDataManager.shared
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(sharedDataManager)
.onOpenURL { url in
handleIncomingURL(url)
}
}
}
private func handleIncomingURL(_ url: URL) {
guard url.scheme == "spots" else { return }
let host = url.host
if host == "import" {
// Triggered by share extension — signal ContentView to import the pending entry
sharedDataManager.shouldImportSharedEntry = true
} else if host == "map" {
// Launched from MindTheShow — spots://map?lat=X&lon=Y&latSpan=A&lonSpan=B&name=N
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems else { return }
var lat: Double?
var lon: Double?
var latSpan: Double?
var lonSpan: Double?
var name: String?
for item in queryItems {
if item.name == "lat", let v = item.value { lat = Double(v) }
else if item.name == "lon", let v = item.value { lon = Double(v) }
else if item.name == "latSpan", let v = item.value { latSpan = Double(v) }
else if item.name == "lonSpan", let v = item.value { lonSpan = Double(v) }
else if item.name == "name" { name = item.value?.removingPercentEncoding }
else if item.name == "venues",
let raw = item.value?.removingPercentEncoding,
let data = raw.data(using: .utf8),
let list = try? JSONDecoder().decode([PendingVenue].self, from: data) {
sharedDataManager.pendingVenues = list
}
}
if let lat, let lon {
sharedDataManager.pendingMapCenter = CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
if let latSpan, let lonSpan {
sharedDataManager.pendingMapSpan = MKCoordinateSpan(latitudeDelta: latSpan, longitudeDelta: lonSpan)
}
sharedDataManager.pendingMapName = name
} else if host == "add" {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems else { return }
var name = ""
var content = ""
for item in queryItems {
if item.name == "name" {
name = item.value?.removingPercentEncoding ?? ""
} else if item.name == "content" {
content = item.value?.removingPercentEncoding ?? ""
}
}
if !name.isEmpty {
sharedDataManager.pendingEntry = (name: name, content: content)
}
}
}
} | Code block | See source code for full implementation. |
| class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Style the navigation bar title and strip the white rounded-rectangle
// container that iOS automatically puts around leading bar button items.
let titleColor = UIColor(red: 0/255, green: 45/255, blue: 114/255, alpha: 1)
let titleFont = UIFont.systemFont(ofSize: 17, weight: .semibold)
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithDefaultBackground()
barAppearance.titleTextAttributes = [
.foregroundColor: titleColor,
.font: titleFont
]
// Empty background image = no white capsule on any bar button item
let btnAppearance = UIBarButtonItemAppearance(style: .plain)
btnAppearance.normal.backgroundImage = UIImage()
btnAppearance.highlighted.backgroundImage = UIImage()
btnAppearance.disabled.backgroundImage = UIImage()
barAppearance.buttonAppearance = btnAppearance
UINavigationBar.appearance().standardAppearance = barAppearance
UINavigationBar.appearance().compactAppearance = barAppearance
UINavigationBar.appearance().scrollEdgeAppearance = barAppearance
UNUserNotificationCenter.current().delegate = self
// Pre-warm the WKWebView web content process so the first PDF export is instant.
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
SpotsPDFExporter.prewarm()
}
// Initialize WatchConnectivity on a background thread.
// Two-step approach to prevent any main-thread blocking:
// 1. PhoneConnectivityManager.init() is now a no-op (no WCSession call),
// so the static-let lock is acquired and released on the BG thread.
// 2. activateWCSession() then makes the expensive synchronous Mach IPC
// call to the Watch daemon — also on the BG thread.
// If ContentView.onAppear accesses .shared before step 1 completes, Swift's
// static-let lock will block momentarily on the BG thread — but that lock
// is released as soon as init() returns (which is now instant), so the main
// thread can never block for more than a few microseconds.
DispatchQueue.global(qos: .userInitiated).async {
PhoneConnectivityManager.shared.activateWCSession()
}
// Initialize iCloud container on a background thread at launch so the
// iCloud daemon has time to register the container before it's needed.
DispatchQueue.global(qos: .utility).async {
let url = FileManager.default.url(forUbiquityContainerIdentifier: nil)
DispatchQueue.main.async {
print("ℹ️ iCloud container initialized at launch: \(url?.path ?? "nil — iCloud unavailable")")
}
}
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
completionHandler()
}
} | `AppDelegate` class | Defines the `AppDelegate` class. Conforms to NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate. |