I am newbie in SwiftUI. I have intermediate level knowledge on Python and Shell Script. Trying to make an App that basically run backup job to copy data from my MacOS to Network drive. I was able to achieve that using AppleScript integrating Python script earlier but now I am trying to implement same function with an interesting view.
With below code I am trying to create a function that can call a shell script on click (Prefer to store the script inside the App) from any location (Unfortunately not seeing any native solution for Python in SwiftUI) and return realtime output on view window. The code I am writing is for MacOS and not for iPhone basically.
Can anyone please help me guide through right direction please.
import SwiftUI
import Foundation
enum ViewState {
case DefaultView
case BackupTaskView
}
struct BackupView : View {
@State var showing : ViewState = .DefaultView
var body: some View {
HeaderView()
VStack {
if showing == .DefaultView {
DefaultView(showing:$showing)
}
if showing == .BackupTaskView {
BackupTaskView(showing:$showing)
}
}
.frame(width: 700, height: .infinity, alignment: .topLeading)
.padding(8)
Spacer()
FooterView()
}
}
private struct DefaultView: View {
@Binding var showing : ViewState
@State var navigated = false
@State var result : String = ""
var body: some View {
VStack {
Text(
"Hello, World!"
)
}
.frame(width: 700, height: .infinity, alignment: .topLeading)
.padding(8)
Spacer()
VStack {
Button(
action: { self.showing = .BackupTaskView }
)
{
Image("backup")
.resizable()
.frame(maxWidth: 180, maxHeight: 180)
}
.buttonStyle(PlainButtonStyle())
}
Spacer()
}
}
private struct BackupTaskView : View {
@Binding var showing : ViewState
@State var result : String = ""
@State var script = "/Users/samiron/Documents/Backup.sh"
@State var isRunning = false
var body: some View {
VStack {
Form {
Section {
Text("\(result)")
}
.onAppear{self.executeCommand()}
}
}
}
func executeCommand() -> (String?) {
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = [ script ]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let result = String(data: data, encoding: .utf8)
task.waitUntilExit()
return result
}
}
struct BackupView_Previews: PreviewProvider {
static var previews: some View {
BackupView()
}
}
CodePudding user response:
I assume you wanted something, like
Section {
Text("\(result)")
}
.onAppear{
self.result = "Executing..."
DispatchQueue.global(qos: .background).async {
let output = self.executeCommand() // << run in background
DispatchQueue.main.async {
self.result = output ?? "Failed" // << update UI on main
}
}
}