mirror of
https://github.com/somegeekintn/SimDirs.git
synced 2026-04-27 14:57:40 +00:00
Added ability to boot / shutdown devices
This commit is contained in:
parent
0e5b2fbf78
commit
e75373084a
3 changed files with 67 additions and 3 deletions
|
|
@ -43,7 +43,34 @@ struct SimCtl {
|
||||||
return try JSONDecoder().decode([String : [String : [SimDevice]]].self, from: json)["devices"] ?? [:]
|
return try JSONDecoder().decode([String : [String : [SimDevice]]].self, from: json)["devices"] ?? [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readDevice(_ device: SimDevice) throws -> SimDevice? {
|
||||||
|
let json : Data = try run(args: ["list", "-j", "devices", device.udid])
|
||||||
|
let decoded = try JSONDecoder().decode([String : [String : [SimDevice]]].self, from: json)["devices"] ?? [:]
|
||||||
|
var result : SimDevice? = nil
|
||||||
|
|
||||||
|
for devices in decoded.values {
|
||||||
|
if let match = devices.first(where: { $0.udid == device.udid }) {
|
||||||
|
result = match
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func readAllDevices() throws -> [SimDevice] {
|
func readAllDevices() throws -> [SimDevice] {
|
||||||
return try readAllRuntimeDevices().flatMap { $1 }
|
return try readAllRuntimeDevices().flatMap { $1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func bootDevice(_ device: SimDevice, boot: Bool) async throws {
|
||||||
|
try await withThrowingTaskGroup(of: Void.self) { group in
|
||||||
|
group.addTask { let _ : Data = try run(args: [boot ? "boot" : "shutdown", device.udid]) }
|
||||||
|
group.addTask { try await Task.sleep(nanoseconds: 1_000_000_000) }
|
||||||
|
try await group.next() // delay or run complate
|
||||||
|
}
|
||||||
|
|
||||||
|
if let refreshedDev = try readDevice(device) {
|
||||||
|
await MainActor.run { () -> Void in device.updateDevice(from: refreshedDev) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,24 @@ class SimDevice: ObservableObject, Decodable {
|
||||||
case booted = "Booted"
|
case booted = "Booted"
|
||||||
case shuttingDown = "Shutting Down"
|
case shuttingDown = "Shutting Down"
|
||||||
case shutdown = "Shutdown"
|
case shutdown = "Shutdown"
|
||||||
|
|
||||||
|
var showBooted : Bool {
|
||||||
|
switch self {
|
||||||
|
case .booted, .booting: return true
|
||||||
|
default: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var name : String
|
@Published var name : String
|
||||||
@Published var state : State
|
@Published var state : State
|
||||||
@Published var isAvailable : Bool
|
@Published var isAvailable : Bool
|
||||||
@Published var availabilityError : String?
|
@Published var availabilityError : String?
|
||||||
|
var isTransitioning : Bool { state == .booting || state == .shuttingDown }
|
||||||
|
var isBooted : Bool {
|
||||||
|
get { state.showBooted == true }
|
||||||
|
set { bootDevice(newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
let udid : String
|
let udid : String
|
||||||
let dataPath : String
|
let dataPath : String
|
||||||
|
|
@ -98,7 +110,7 @@ class SimDevice: ObservableObject, Decodable {
|
||||||
return !(name == other.name && state == other.state && isAvailable == other.isAvailable && availabilityError == other.availabilityError)
|
return !(name == other.name && state == other.state && isAvailable == other.isAvailable && availabilityError == other.availabilityError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateDevice(from other: SimDevice) -> Bool {
|
@discardableResult func updateDevice(from other: SimDevice) -> Bool {
|
||||||
guard hasChanged(from: other) else { return false }
|
guard hasChanged(from: other) else { return false }
|
||||||
|
|
||||||
name = other.name
|
name = other.name
|
||||||
|
|
@ -108,6 +120,21 @@ class SimDevice: ObservableObject, Decodable {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func bootDevice(_ boot: Bool) {
|
||||||
|
if boot && state == .shutdown || !boot && state == .booted {
|
||||||
|
let simctl = SimCtl()
|
||||||
|
|
||||||
|
state = boot ? .booting : .shuttingDown
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
try await simctl.bootDevice(self, boot: boot)
|
||||||
|
} catch {
|
||||||
|
print("Failed to \(boot ? "boot" : "shutdown") device: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SimDevice: SourceItemData {
|
extension SimDevice: SourceItemData {
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,21 @@ extension SimDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceHeader: View {
|
struct DeviceHeader: View {
|
||||||
@ObservedObject var device : SimDevice
|
@ObservedObject var device : SimDevice
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 3.0) {
|
VStack(alignment: .leading, spacing: 3.0) {
|
||||||
Text("State: \(device.state.rawValue)")
|
HStack(spacing: 8.0) {
|
||||||
|
Toggle("Booted", isOn: $device.isBooted)
|
||||||
|
.toggleStyle(.switch)
|
||||||
|
.disabled(device.isTransitioning)
|
||||||
|
|
||||||
|
if device.isTransitioning {
|
||||||
|
ProgressView()
|
||||||
|
.controlSize(.small)
|
||||||
|
Text(device.state.rawValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
Text("UDID: \(device.udid)")
|
Text("UDID: \(device.udid)")
|
||||||
}
|
}
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue