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.
82 lines
2.1 KiB
Swift
82 lines
2.1 KiB
Swift
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)
|
|
}
|
|
}
|