SPB Git

spb/focale Public

Swift 100%
2.5 KB · 94 lines swift
Raw Blame History
1//2//  RecipeStore.swift3//  Focale4//5//  Author: Simon-Pierre Boucher6//  Contact: contact@spboucher.ai7//89import Foundation10import Observation1112@MainActor13@Observable14final class RecipeStore {15    private(set) var recipes: [Recipe] = []16    var activeRecipeID: Recipe.ID? {17        didSet { save() }18    }1920    private let fileURL: URL2122    var activeRecipe: Recipe? {23        guard let activeRecipeID else { return nil }24        return recipes.first { $0.id == activeRecipeID }25    }2627    init(directory: URL = .applicationSupportDirectory) {28        fileURL = directory.appending(path: "recipes.json")29        load()30        if recipes.isEmpty {31            recipes = Recipe.builtIns32            save()33        }34    }3536    func add(_ recipe: Recipe) {37        recipes.append(recipe)38        save()39    }4041    func update(_ recipe: Recipe) {42        guard let index = recipes.firstIndex(where: { $0.id == recipe.id }) else { return }43        recipes[index] = recipe44        save()45    }4647    func remove(_ id: Recipe.ID) {48        recipes.removeAll { $0.id == id }49        if activeRecipeID == id { activeRecipeID = nil }50        save()51    }5253    @discardableResult54    func importRecipe(from data: Data) throws -> Recipe {55        var recipe = try Recipe(importing: data)56        // Re-identify on import so two devices can hold the same shared file.57        recipe = Recipe(58            name: recipe.name,59            settings: recipe.settings,60            autoProjectName: recipe.autoProjectName,61            sceneTrigger: recipe.sceneTrigger,62            showsTimestamp: recipe.showsTimestamp,63            prioritizeOCR: recipe.prioritizeOCR64        )65        add(recipe)66        return recipe67    }6869    // MARK: - Persistence7071    private struct Snapshot: Codable {72        var recipes: [Recipe]73        var activeRecipeID: Recipe.ID?74    }7576    private func load() {77        guard let data = try? Data(contentsOf: fileURL),78              let snapshot = try? JSONDecoder().decode(Snapshot.self, from: data)79        else { return }80        recipes = snapshot.recipes81        activeRecipeID = snapshot.activeRecipeID82    }8384    private func save() {85        let snapshot = Snapshot(recipes: recipes, activeRecipeID: activeRecipeID)86        guard let data = try? JSONEncoder().encode(snapshot) else { return }87        try? FileManager.default.createDirectory(88            at: fileURL.deletingLastPathComponent(),89            withIntermediateDirectories: true90        )91        try? data.write(to: fileURL, options: .atomic)92    }93}94