Files
share/apps/ios/Share/Models.swift
T
TZGyn 9a37e93cfc 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.
2026-10-26 22:24:47 +08:00

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)
}
}