diff --git a/StikDebug/JSSupport/RunJSView.swift b/StikDebug/JSSupport/RunJSView.swift index 2aecded..0d5ef1e 100644 --- a/StikDebug/JSSupport/RunJSView.swift +++ b/StikDebug/JSSupport/RunJSView.swift @@ -12,7 +12,8 @@ import idevice typealias RemoteServerHandle = OpaquePointer typealias ScreenshotClientHandle = OpaquePointer -final class RunJSViewModel: ObservableObject, @unchecked Sendable { +final class RunJSViewModel: ObservableObject, Identifiable, @unchecked Sendable { + let id = UUID() var context: JSContext? @Published var logs: [String] = [] @Published var scriptName: String = "Script" @@ -34,8 +35,14 @@ final class RunJSViewModel: ObservableObject, @unchecked Sendable { } func runScript(data: Data, name: String? = nil) throws { - let scriptContent = String(data: data, encoding: .utf8) - scriptName = name ?? "Script" + let displayName = name ?? "Script" + DispatchQueue.main.async { + self.scriptName = displayName + } + + guard let scriptContent = String(data: data, encoding: .utf8) else { + throw CocoaError(.fileReadCorruptFile) + } let getPidFunction: @convention(block) () -> Int = { return self.pid @@ -210,9 +217,18 @@ struct RunJSView: View { var body: some View { ScrollViewReader { proxy in List { - ForEach(Array(model.logs.enumerated()), id: \.offset) { index, logStr in - Text(logStr) - .id(index) + if model.logs.isEmpty { + HStack(spacing: 12) { + ProgressView() + .controlSize(.small) + Text("Starting script...") + .foregroundStyle(.secondary) + } + } else { + ForEach(Array(model.logs.enumerated()), id: \.offset) { index, logStr in + Text(logStr) + .id(index) + } } } .navigationTitle("Running \(model.scriptName)") diff --git a/StikDebug/Views/HomeView.swift b/StikDebug/Views/HomeView.swift index ffe5c54..caf8ba0 100644 --- a/StikDebug/Views/HomeView.swift +++ b/StikDebug/Views/HomeView.swift @@ -19,7 +19,6 @@ struct HomeView: View { @State private var isShowingPairingFilePicker = false @State private var debugFeedback: DebugFeedback? @State private var pendingExternalURLAction: HomeExternalAction? - @State private var isShowingScriptRunner = false @State private var scriptRunModel: RunJSViewModel? private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() @@ -80,18 +79,15 @@ struct HomeView: View { allowedContentTypes: PairingFileStore.supportedContentTypes, onCompletion: importPairingFile ) - .sheet(isPresented: $isShowingScriptRunner) { + .sheet(item: $scriptRunModel) { model in NavigationStack { - if let scriptRunModel { - RunJSView(model: scriptRunModel) - .toolbar { - ToolbarItem(placement: .topBarTrailing) { - Button("Done") { isShowingScriptRunner = false } - } + RunJSView(model: model) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button("Done") { scriptRunModel = nil } } - .navigationTitle(selectedScript) - .navigationBarTitleDisplayMode(.inline) - } + } + .navigationBarTitleDisplayMode(.inline) } } } @@ -118,11 +114,10 @@ struct HomeView: View { return } - scriptRunModel = model if let name = notification.userInfo?["scriptName"] as? String { selectedScript = name } - isShowingScriptRunner = true + scriptRunModel = model } private func refreshMountStatusIfNeeded() { @@ -271,7 +266,6 @@ struct HomeView: View { DispatchQueue.main.async { scriptRunModel = model - isShowingScriptRunner = true } do {