summaryrefslogtreecommitdiff
path: root/DomainDig/CloudSharingSheet.swift
blob: 8318e2a7b3f593f9cd954baeaeb30436f4b2c7d2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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(_: UIPresentationController) {
            dismissAction()
        }
    }
}