Files
daily-notification-plugin/ios/Plugin/DailyNotificationModel.swift
Server 5844b92e18 feat(ios): implement Phase 1 permission methods and fix build issues
Implement checkPermissionStatus() and requestNotificationPermissions()
methods for iOS plugin, matching Android functionality. Fix compilation
errors across plugin files and add comprehensive build/test infrastructure.

Key Changes:
- Add checkPermissionStatus() and requestNotificationPermissions() methods
- Fix 13+ categories of Swift compilation errors (type conversions, logger
  API, access control, async/await, etc.)
- Create DailyNotificationScheduler, DailyNotificationStorage,
  DailyNotificationStateActor, and DailyNotificationErrorCodes components
- Fix CoreData initialization to handle missing model gracefully for Phase 1
- Add iOS test app build script with simulator auto-detection
- Update directive with lessons learned from build and permission work

Build Status:  BUILD SUCCEEDED
Test App:  Ready for iOS Simulator testing

Files Modified:
- doc/directives/0003-iOS-Android-Parity-Directive.md (lessons learned)
- ios/Plugin/DailyNotificationPlugin.swift (Phase 1 methods)
- ios/Plugin/DailyNotificationModel.swift (CoreData fix)
- 11+ other plugin files (compilation fixes)

Files Added:
- ios/Plugin/DailyNotificationScheduler.swift
- ios/Plugin/DailyNotificationStorage.swift
- ios/Plugin/DailyNotificationStateActor.swift
- ios/Plugin/DailyNotificationErrorCodes.swift
- scripts/build-ios-test-app.sh
- scripts/setup-ios-test-app.sh
- test-apps/ios-test-app/ (full test app)
- Multiple Phase 1 documentation files
2025-11-13 05:14:24 -08:00

176 lines
4.9 KiB
Swift

//
// DailyNotificationModel.xcdatamodeld
// DailyNotificationPlugin
//
// Created by Matthew Raymer on 2025-09-22
// Copyright © 2025 TimeSafari. All rights reserved.
//
import Foundation
import CoreData
/**
* Core Data model for Daily Notification Plugin
* Mirrors Android SQLite schema for cross-platform consistency
*
* @author Matthew Raymer
* @version 1.1.0
* @created 2025-09-22 09:22:32 UTC
*/
// MARK: - ContentCache Entity
@objc(ContentCache)
public class ContentCache: NSManagedObject {
}
extension ContentCache {
@nonobjc public class func fetchRequest() -> NSFetchRequest<ContentCache> {
return NSFetchRequest<ContentCache>(entityName: "ContentCache")
}
@NSManaged public var id: String?
@NSManaged public var fetchedAt: Date?
@NSManaged public var ttlSeconds: Int32
@NSManaged public var payload: Data?
@NSManaged public var meta: String?
}
extension ContentCache: Identifiable {
}
// MARK: - Schedule Entity
@objc(Schedule)
public class Schedule: NSManagedObject {
}
extension Schedule {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Schedule> {
return NSFetchRequest<Schedule>(entityName: "Schedule")
}
@NSManaged public var id: String?
@NSManaged public var kind: String?
@NSManaged public var cron: String?
@NSManaged public var clockTime: String?
@NSManaged public var enabled: Bool
@NSManaged public var lastRunAt: Date?
@NSManaged public var nextRunAt: Date?
@NSManaged public var jitterMs: Int32
@NSManaged public var backoffPolicy: String?
@NSManaged public var stateJson: String?
}
extension Schedule: Identifiable {
}
// MARK: - Callback Entity
@objc(Callback)
public class Callback: NSManagedObject {
}
extension Callback {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Callback> {
return NSFetchRequest<Callback>(entityName: "Callback")
}
@NSManaged public var id: String?
@NSManaged public var kind: String?
@NSManaged public var target: String?
@NSManaged public var headersJson: String?
@NSManaged public var enabled: Bool
@NSManaged public var createdAt: Date?
}
extension Callback: Identifiable {
}
// MARK: - History Entity
@objc(History)
public class History: NSManagedObject {
}
extension History {
@nonobjc public class func fetchRequest() -> NSFetchRequest<History> {
return NSFetchRequest<History>(entityName: "History")
}
@NSManaged public var id: String?
@NSManaged public var refId: String?
@NSManaged public var kind: String?
@NSManaged public var occurredAt: Date?
@NSManaged public var durationMs: Int32
@NSManaged public var outcome: String?
@NSManaged public var diagJson: String?
}
extension History: Identifiable {
}
// MARK: - Persistence Controller
// Phase 2: CoreData integration for advanced features
// Phase 1: Stubbed out - CoreData model not yet created
class PersistenceController {
// Lazy initialization to prevent Phase 1 errors
private static var _shared: PersistenceController?
static var shared: PersistenceController {
if _shared == nil {
_shared = PersistenceController()
}
return _shared!
}
let container: NSPersistentContainer?
private var initializationError: Error?
init(inMemory: Bool = false) {
// Phase 1: CoreData model doesn't exist yet, so we'll handle gracefully
// Phase 2: Will create DailyNotificationModel.xcdatamodeld
var tempContainer: NSPersistentContainer? = nil
do {
tempContainer = NSPersistentContainer(name: "DailyNotificationModel")
if inMemory {
tempContainer?.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
}
var loadError: Error? = nil
tempContainer?.loadPersistentStores { _, error in
if let error = error as NSError? {
loadError = error
print("DNP-PLUGIN: CoreData model not found (Phase 1 - expected). Error: \(error.localizedDescription)")
print("DNP-PLUGIN: CoreData features will be available in Phase 2")
}
}
if let error = loadError {
self.initializationError = error
self.container = nil
} else {
tempContainer?.viewContext.automaticallyMergesChangesFromParent = true
self.container = tempContainer
}
} catch {
print("DNP-PLUGIN: Failed to initialize CoreData container: \(error.localizedDescription)")
self.initializationError = error
self.container = nil
}
}
/**
* Check if CoreData is available (Phase 2+)
*/
var isAvailable: Bool {
return container != nil && initializationError == nil
}
}