diff options
| author | Christian Cleberg <[email protected]> | 2026-04-23 23:12:34 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-23 23:12:34 -0500 |
| commit | b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6 (patch) | |
| tree | 099cea2cc4324331a719ed2cad8c0815033b5471 /DomainDig/CloudSharingSheet.swift | |
| parent | f045a5d339a796f40a9e958436ebc6f5314bdab8 (diff) | |
| download | domain-dig-b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6.tar.gz domain-dig-b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6.tar.bz2 domain-dig-b35f1b432fc24fbab1fa05593c9a0bca7e4d95a6.zip | |
feat(v3.6.0): add iCloud sharing for workflows and tracked domains
- implement CloudKit sharing (CKShare) for TrackedDomain and DomainWorkflow
- support read-only and editable permissions
- add Share actions and shared state indicators in UI
- handle shared record ownership and participant roles
- implement deterministic conflict resolution to prevent duplication
- ensure compatibility with existing iCloud sync layer
- maintain local-first behavior with graceful offline handling
- remove debug logging for domain availability/rdap messages
notes:
- no custom backend or accounts introduced
- sharing is Apple ecosystem only (iCloud-based)
- large history data remains local-only
Diffstat (limited to 'DomainDig/CloudSharingSheet.swift')
| -rw-r--r-- | DomainDig/CloudSharingSheet.swift | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/DomainDig/CloudSharingSheet.swift b/DomainDig/CloudSharingSheet.swift new file mode 100644 index 0000000..3d524ef --- /dev/null +++ b/DomainDig/CloudSharingSheet.swift @@ -0,0 +1,84 @@ +import CloudKit +import Foundation +import SwiftUI +import UIKit + +struct CloudSharingSheet: UIViewControllerRepresentable { + @Environment(\.dismiss) private var dismiss + + let entity: ShareableEntity + let title: String + + func makeCoordinator() -> Coordinator { + Coordinator(dismiss: dismiss, title: title) + } + + func makeUIViewController(context: Context) -> UIViewController { + UIViewController() + } + + func updateUIViewController(_ uiViewController: UIViewController, context: Context) { + context.coordinator.presentIfNeeded(from: uiViewController, entity: entity) + } + + final class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate { + private let dismissAction: DismissAction + private let title: String + private let observer = CKSystemSharingUIObserver(container: .default()) + private var hasPresented = false + + init(dismiss: DismissAction, title: String) { + self.dismissAction = dismiss + self.title = title + super.init() + + observer.systemSharingUIDidSaveShareBlock = { _, _ in + Task { @MainActor in + await CloudSyncService.shared.syncNow(trigger: .manual) + } + } + + observer.systemSharingUIDidStopSharingBlock = { _, _ in + Task { @MainActor in + await CloudSyncService.shared.syncNow(trigger: .manual) + } + } + } + + func presentIfNeeded(from presenter: UIViewController, entity: ShareableEntity) { + guard !hasPresented else { return } + hasPresented = true + + let itemProvider = NSItemProvider() + let container = CKContainer.default() + + Task { @MainActor in + do { + if let existingShare = try await CloudSyncService.shared.existingShare(for: entity) { + itemProvider.registerCKShare(existingShare, container: container) + } else { + itemProvider.registerCKShare(container: container) { + try await CloudSyncService.shared.createShare(for: entity) + } + } + } catch { + dismissAction() + return + } + + let configuration = UIActivityItemsConfiguration(itemProviders: [itemProvider]) + let activityController = UIActivityViewController(activityItemsConfiguration: configuration) + activityController.completionWithItemsHandler = { [dismissAction] _, _, _, _ in + dismissAction() + } + activityController.popoverPresentationController?.sourceView = presenter.view + activityController.presentationController?.delegate = self + presenter.present(activityController, animated: true) + } + } + + func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + dismissAction() + } + } +} |
