ProjetsViewModel.swift 64 lignes · 2461 octets
import Combine
import Foundation

// Port of ui/projets/ProjetsViewModel.kt.

@MainActor
final class ProjetsViewModel: ObservableObject {
    @Published private(set) var projets: [ProjetEntity] = []
    @Published private(set) var workflows: [WorkflowEntity] = []

    private let projetDao: ProjetDao
    private let workflowDao: WorkflowDao
    private let syncOpDao: SyncOpDao
    private var cancellables: Set<AnyCancellable> = []

    init(
        projetDao: ProjetDao = Card2vcfDatabase.shared.projetDao,
        workflowDao: WorkflowDao = Card2vcfDatabase.shared.workflowDao,
        syncOpDao: SyncOpDao = Card2vcfDatabase.shared.syncOpDao
    ) {
        self.projetDao = projetDao
        self.workflowDao = workflowDao
        self.syncOpDao = syncOpDao
        NotificationCenter.default.publisher(for: .card2vcfDatabaseDidChange)
            .receive(on: RunLoop.main)
            .sink { [weak self] _ in Task { await self?.refresh() } }
            .store(in: &cancellables)
    }

    func refresh() async {
        projets = (try? await projetDao.fetchAll()) ?? []
        workflows = ((try? await workflowDao.listAll()) ?? []).sorted { $0.nom < $1.nom }
    }

    /// Creates the project locally and queues the sync op; the push fills `serverId`.
    func createProjet(nom: String, description: String, workflowServerId: String) {
        Task {
            await createProjetAsync(nom: nom, description: description, workflowServerId: workflowServerId)
        }
    }

    func createProjetAsync(nom: String, description: String, workflowServerId: String) async {
        let now = ContactRepository.currentMillis()
        var projet = ProjetEntity()
        projet.nom = nom.trimmingCharacters(in: .whitespacesAndNewlines)
        projet.description = description.trimmingCharacters(in: .whitespacesAndNewlines)
        projet.workflowServerId = workflowServerId
        projet.createdAt = now
        projet.updatedAt = now
        guard let localId = try? await projetDao.upsert(projet) else { return }
        var op = SyncOpEntity(entityType: "projet", op: "create")
        op.payloadJson = SyncJson.encodeToString(
            CreateProjetRequest(
                nom: projet.nom,
                description: projet.description,
                workflowId: workflowServerId
            )
        )
        op.localId = localId
        op.createdAt = now
        _ = try? await syncOpDao.insert(op)
        await refresh()
    }
}