mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
feat(apple): native SwiftUI app for iOS and macOS
Add a native SwiftUI VniDrop app (Send/Receive/Settings) talking to the Rust core via generated UniFFI Swift bindings, plus the uniffi-bindgen helper crate. iOS uses a TabView, macOS a NavigationSplitView sidebar.
This commit is contained in:
61
apple/VniDrop/Features/Send/TransferShareActions.swift
Normal file
61
apple/VniDrop/Features/Send/TransferShareActions.swift
Normal file
@@ -0,0 +1,61 @@
|
||||
import SwiftUI
|
||||
|
||||
enum NfcShareAvailability { case available, unavailable, hidden }
|
||||
|
||||
/// Invitation delivery actions, ported from `TransferShareActions` (iosMain).
|
||||
/// Platform implementations perform export, native share, and NFC write.
|
||||
@MainActor
|
||||
protocol TransferShareActions: AnyObject {
|
||||
var canUseNativeShare: Bool { get }
|
||||
var nfcAvailability: NfcShareAvailability { get }
|
||||
|
||||
func exportInvitation(ticket: String, transferName: String, onResult: @escaping (Result<Void, Error>) -> Void)
|
||||
func shareInvitation(ticket: String, transferName: String, onResult: @escaping (Result<Void, Error>) -> Void)
|
||||
func writeInvitationToNfc(ticket: String, onResult: @escaping (Result<Void, Error>) -> Void)
|
||||
func cancelNfcWrite()
|
||||
}
|
||||
|
||||
/// The QR + delivery buttons for a transfer's share panel, ported from the button
|
||||
/// stack in `TransferSharePanel` (`TransferDetails.kt`).
|
||||
struct ShareActionsView: View {
|
||||
@Environment(\.vniColors) private var colors
|
||||
@ObservedObject var model: SendModel
|
||||
let transfer: Transfer
|
||||
let ticket: String
|
||||
|
||||
@State private var actions: TransferShareActions = makePlatformShareActions()
|
||||
@State private var writingNfc = false
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 12) {
|
||||
if actions.nfcAvailability != .hidden {
|
||||
SecondaryButton(
|
||||
title: writingNfc ? String(localized: "transfer_nfc_waiting") : String(localized: "button_write_nfc"),
|
||||
action: {
|
||||
writingNfc = true
|
||||
actions.writeInvitationToNfc(ticket: ticket) { result in
|
||||
writingNfc = false
|
||||
model.onInvitationResult(.nfc, result)
|
||||
}
|
||||
},
|
||||
enabled: actions.nfcAvailability == .available && !writingNfc
|
||||
)
|
||||
if actions.nfcAvailability == .unavailable {
|
||||
Text(LocalizedStringKey("transfer_nfc_unavailable"))
|
||||
.font(VniType.bodySmall).foregroundStyle(colors.foregroundLighter)
|
||||
}
|
||||
}
|
||||
SecondaryButton(title: String(localized: "button_download_invitation"), action: {
|
||||
actions.exportInvitation(ticket: ticket, transferName: transfer.transferName ?? "") {
|
||||
model.onInvitationResult(.export, $0)
|
||||
}
|
||||
})
|
||||
PrimaryButton(title: String(localized: "button_native_share"), action: {
|
||||
actions.shareInvitation(ticket: ticket, transferName: transfer.transferName ?? "") {
|
||||
model.onInvitationResult(.share, $0)
|
||||
}
|
||||
}, enabled: actions.canUseNativeShare)
|
||||
}
|
||||
.onDisappear { actions.cancelNfcWrite() }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user