feat(receive): add adaptive receive flow and document opening

This commit is contained in:
2026-07-12 04:15:21 +02:00
parent 757966379b
commit 996cc0a5ab
30 changed files with 1203 additions and 92 deletions

View File

@@ -58,16 +58,68 @@ final class VniDropHostViewController: UIViewController {
}
struct ComposeView: UIViewControllerRepresentable {
let externalInvitations: ExternalInvitationController
func makeUIViewController(context: Self.Context) -> UIViewController {
VniDropHostViewController(composeController: MainViewControllerKt.MainViewController())
VniDropHostViewController(
composeController: MainViewControllerKt.MainViewController(
externalInvitations: externalInvitations
)
)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Self.Context) {}
}
struct ContentView: View {
let externalInvitations: ExternalInvitationController
var body: some View {
ComposeView()
ComposeView(externalInvitations: externalInvitations)
.ignoresSafeArea()
.onOpenURL(perform: openInvitation)
}
private func openInvitation(_ url: URL) {
guard url.pathExtension.caseInsensitiveCompare("vnd") == .orderedSame else {
externalInvitations.reportOpenFailure(message: "This is not a VniDrop invitation")
return
}
let hasSecurityAccess = url.startAccessingSecurityScopedResource()
defer {
if hasSecurityAccess {
url.stopAccessingSecurityScopedResource()
}
}
do {
let values = try url.resourceValues(forKeys: [.fileSizeKey])
if let fileSize = values.fileSize, fileSize > 65_536 {
throw InvitationOpenError.tooLarge
}
let data = try Data(contentsOf: url, options: .mappedIfSafe)
guard data.count <= 65_536 else { throw InvitationOpenError.tooLarge }
guard let raw = String(data: data, encoding: .utf8) else {
throw InvitationOpenError.invalidEncoding
}
externalInvitations.openInvitation(raw: raw)
} catch {
externalInvitations.reportOpenFailure(
message: (error as? LocalizedError)?.errorDescription ?? "The invitation could not be opened"
)
}
}
}
private enum InvitationOpenError: LocalizedError {
case tooLarge
case invalidEncoding
var errorDescription: String? {
switch self {
case .tooLarge: "The invitation is too large"
case .invalidEncoding: "The invitation is not valid text"
}
}
}

View File

@@ -4,6 +4,45 @@
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>VniDrop Invitation</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.vnidrop.app.invitation</string>
</array>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>VniDrop Invitation</string>
<key>UTTypeIdentifier</key>
<string>com.vnidrop.app.invitation</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>vnd</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.vnidrop.transfer</string>
</dict>
</dict>
</array>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
</dict>

View File

@@ -1,10 +1,13 @@
import Shared
import SwiftUI
@main
struct iOSApp: App {
private let externalInvitations = ExternalInvitationController()
var body: some Scene {
WindowGroup {
ContentView()
ContentView(externalInvitations: externalInvitations)
}
}
}