Translate all 253 user-facing strings to French (formal register), including the transfer_file_count plural. Generates values-fr/strings.xml for KMP and fr localizations in the Apple catalog (marked needs_review).
VniDrop — native Apple app (iOS / iPadOS / macOS)
A native SwiftUI app for Apple platforms, sharing the existing Rust transfer core
(crates/vnidrop) through UniFFI-generated Swift bindings. The Rust crate is not
modified; the Kotlin/Compose app layer is ported to Swift and mirrors the Compose
UI screen-for-screen. Android and desktop JVM continue to use shared/ + Compose.
Layout
apple/
scripts/build-core.sh # builds the Rust core + generates Swift bindings + xcframework
VnidropCore/ # local SwiftPM package: xcframework + generated Vnidrop.swift
VniDrop/ # SwiftUI app sources
App/ # entry point, object graph, root view, environment
Core/ # repository, models, preferences, notifications, progress
Features/Send|Receive|Approvals|Settings/
UI/Theme|Components|Navigation|Feedback|Shell/
Platform/ # pickers, QR, NFC, share/export, per-OS file services
Resources/ # Localizable.xcstrings, Info.plist, entitlements, assets
Tests/ # XCTest (ported progress-derivation assertions)
Package.swift # builds VniDrop/ as a library for CLI build/test
project.yml # XcodeGen spec for the iOS/macOS app target
Build & run
Prerequisites: Xcode, Rust with the Apple targets
(aarch64-apple-ios, aarch64-apple-ios-sim, x86_64-apple-ios,
aarch64-apple-darwin), and xcodegen (brew install xcodegen).
# 1. Build the Rust core and generate the Swift bindings + xcframework.
apple/scripts/build-core.sh debug # or: release (see note below)
# 2. Generate the Xcode project.
cd apple && xcodegen generate
# 3. Open and run, or build from the CLI:
open VniDrop.xcodeproj
# macOS:
xcodebuild -project VniDrop.xcodeproj -scheme VniDrop -destination 'platform=macOS' build
# iOS simulator:
xcodebuild -project VniDrop.xcodeproj -scheme VniDrop \
-destination 'platform=iOS Simulator,name=iPhone 15' build
Command-line typecheck & tests
Package.swift builds the same sources as a library (minus the @main entry),
so the shared logic can be checked and unit-tested without Xcode:
cd apple
swift build # macOS
swift test # runs Tests/ (ported progress-derivation assertions)
# iOS typecheck:
swift build --triple arm64-apple-ios16.0-simulator --sdk "$(xcrun --sdk iphonesimulator --show-sdk-path)"
Generated / ignored artifacts
build-core.sh produces build outputs that are gitignored (see apple/.gitignore):
VnidropCore/vnidrop.xcframework/, VnidropCore/Sources/VnidropCore/Vnidrop.swift,
and .build-core/. A clean checkout must run build-core.sh before generating or
opening the Xcode project. VniDrop.xcodeproj itself is generated by XcodeGen from
project.yml and does not need to be committed.
Build profile note
The default is debug. The workspace [profile.release] uses thin LTO, which the
current macOS toolchain miscompiles into corrupt host proc-macro dylibs
("mis-aligned LINKEDIT string pool"). build-core.sh sets
CARGO_PROFILE_DEV_STRIP=none (matching the existing Gobley Xcode run-script) so
debug builds succeed. For a release core, disable LTO for proc-macros/build
scripts (e.g. add a [profile.release.build-override] lto = false locally) — the
Rust crate itself is never changed.
System frameworks
The Rust core (iroh network stack) links SystemConfiguration, Security, and
libresolv. These are declared in both Package.swift (for CLI build/test) and
project.yml (for the app target).
Parity & scope
Screens mirror the Compose UI in shared/. Two deliberate simplifications:
- Empty-state Lottie animations are rendered as SF Symbols (no
lottie-iosdependency); swap inlottie-iosif exact-parity animation is required. - The full diagnostics/telemetry stack (
diagnostics/*) is stubbed behindBugReportService/DiagnosticsBuildConfigand lands in a later phase; the UI hides the diagnostics toggle when not compiled in.