Add a native iOS client for relay-based file sharing
The SwiftUI app bundles the Go swarm engine through gomobile, so an iPhone is a real peer using the existing PAKE handshake, chunk verification, and relay fallback. XcodeGen builds the project and devicectl installs it on the paired phone.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import Foundation
|
||||
|
||||
/// Which side of the room the setup screen is preparing. Once a room is
|
||||
/// running the distinction only changes labels: every peer can send and
|
||||
/// receive, just like the CLI.
|
||||
enum RoomMode: String, CaseIterable, Identifiable {
|
||||
case send
|
||||
case receive
|
||||
|
||||
var id: String { rawValue }
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .send: return "Send"
|
||||
case .receive: return "Receive"
|
||||
}
|
||||
}
|
||||
|
||||
var icon: String {
|
||||
switch self {
|
||||
case .send: return "arrow.up.circle.fill"
|
||||
case .receive: return "arrow.down.circle.fill"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One file's progress as reported by the Go engine. The JSON field names
|
||||
/// match `swarm.FileStatus`; no conversion layer is needed.
|
||||
struct FileProgress: Codable, Identifiable, Hashable {
|
||||
let name: String
|
||||
let size: Int64
|
||||
let haveChunks: Int64
|
||||
let totalChunks: Int64
|
||||
let complete: Bool
|
||||
|
||||
var id: String { name }
|
||||
|
||||
var fraction: Double {
|
||||
guard totalChunks > 0 else { return 0 }
|
||||
return min(1, max(0, Double(haveChunks) / Double(totalChunks)))
|
||||
}
|
||||
|
||||
var formattedSize: String {
|
||||
ByteCountFormatter.string(fromByteCount: size, countStyle: .file)
|
||||
}
|
||||
}
|
||||
|
||||
/// The whole room snapshot decoded from `ShareSession.statusJSON()`. The
|
||||
/// Go bridge keeps the same shape across launches so the UI never has to
|
||||
/// know about gomobile objects beyond the session itself.
|
||||
struct RoomStatus: Codable {
|
||||
var code: String
|
||||
var relay: String
|
||||
var outDir: String
|
||||
var running: Bool
|
||||
var peers: Int
|
||||
var files: [FileProgress]
|
||||
var error: String?
|
||||
|
||||
var allComplete: Bool {
|
||||
!files.isEmpty && files.allSatisfy(\.complete)
|
||||
}
|
||||
|
||||
var receivedFiles: [FileProgress] {
|
||||
files.filter(\.complete)
|
||||
}
|
||||
}
|
||||
|
||||
/// A file that has already been copied into the app's seed directory.
|
||||
/// Holding the copied URL (rather than the security-scoped picker URL)
|
||||
/// means the Go engine can keep reading it after the picker goes away.
|
||||
struct PickedFile: Identifiable, Hashable {
|
||||
let id = UUID()
|
||||
let url: URL
|
||||
let name: String
|
||||
let size: Int64
|
||||
|
||||
var formattedSize: String {
|
||||
ByteCountFormatter.string(fromByteCount: size, countStyle: .file)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user