CalendarBindingsStore.swift 55 lignes · 2272 octets
import Foundation

/// Binding between a local device calendar and a Projectiaon entity (RDV or bookable resource).
/// JSON keys match the Android store (`kind`/`serverResourceId`/`displayName`/`androidCalendarId`);
/// `androidCalendarId` keeps its name for wire compatibility — on iOS it holds the
/// `EventKitIdMap` numeric id of the bound calendar.
struct CalendarBinding: Codable, Equatable {
    var kind: String // "rdv" | "salle" | "materiel" | "vehicule"
    var serverResourceId: String? = nil
    var displayName: String
    var androidCalendarId: Int64? = nil
}

/// Persists the user-bound `CalendarBinding`s as JSON (Android: SharedPreferences
/// `card2vcf_calendar_bindings`; iOS: UserDefaults, same key names).
final class CalendarBindingsStore {
    static let PREFS_NAME = "card2vcf_calendar_bindings"
    static let KEY_BINDINGS = "bindings"

    private let defaults: UserDefaults
    private var storageKey: String { "\(Self.PREFS_NAME).\(Self.KEY_BINDINGS)" }

    init(defaults: UserDefaults = .standard) {
        self.defaults = defaults
    }

    func list() -> [CalendarBinding] {
        guard let raw = defaults.string(forKey: storageKey) else { return [] }
        return (try? JSONDecoder().decode([CalendarBinding].self, from: Data(raw.utf8))) ?? []
    }

    /// Replaces the existing binding with the same `kind`/`serverResourceId`, otherwise appends it.
    func upsert(_ binding: CalendarBinding) {
        let updated = list().filter { !matches($0, kind: binding.kind, serverResourceId: binding.serverResourceId) } + [binding]
        save(updated)
    }

    func remove(kind: String, serverResourceId: String?) {
        save(list().filter { !matches($0, kind: kind, serverResourceId: serverResourceId) })
    }

    func clear() {
        defaults.removeObject(forKey: storageKey)
    }

    private func save(_ bindings: [CalendarBinding]) {
        guard let data = try? JSONEncoder().encode(bindings),
              let json = String(data: data, encoding: .utf8) else { return }
        defaults.set(json, forKey: storageKey)
    }

    private func matches(_ binding: CalendarBinding, kind: String, serverResourceId: String?) -> Bool {
        binding.kind == kind && binding.serverResourceId == serverResourceId
    }
}