added dialogview for custom dialogs

added nice green color
updated debug host
reduced sleep greatly
removed channel checker in sshqueasync loop
set dark mode on the app
gonna start work on async in sshhandler
This commit is contained in:
neon443
2025-06-24 12:33:52 +01:00
parent 3f2c92cd91
commit 1e3a57d788
8 changed files with 112 additions and 8 deletions

View File

@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.237",
"green" : "0.725",
"red" : "0.350"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -32,6 +32,7 @@
A985545F2E056EDD009051BD /* KeychainLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985545E2E056EDD009051BD /* KeychainLayer.swift */; }; A985545F2E056EDD009051BD /* KeychainLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985545E2E056EDD009051BD /* KeychainLayer.swift */; };
A98554612E058433009051BD /* HostsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554602E058433009051BD /* HostsManager.swift */; }; A98554612E058433009051BD /* HostsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554602E058433009051BD /* HostsManager.swift */; };
A98554632E0587DF009051BD /* HostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554622E0587DF009051BD /* HostsView.swift */; }; A98554632E0587DF009051BD /* HostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554622E0587DF009051BD /* HostsView.swift */; };
A9B15A9A2E0ABA0400F66E02 /* DialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B15A992E0ABA0400F66E02 /* DialogView.swift */; };
A9C4140C2E096DB7005E3047 /* SSHError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C4140B2E096DB7005E3047 /* SSHError.swift */; }; A9C4140C2E096DB7005E3047 /* SSHError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C4140B2E096DB7005E3047 /* SSHError.swift */; };
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; }; A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@@ -98,6 +99,7 @@
A985545E2E056EDD009051BD /* KeychainLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainLayer.swift; sourceTree = "<group>"; }; A985545E2E056EDD009051BD /* KeychainLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainLayer.swift; sourceTree = "<group>"; };
A98554602E058433009051BD /* HostsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsManager.swift; sourceTree = "<group>"; }; A98554602E058433009051BD /* HostsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsManager.swift; sourceTree = "<group>"; };
A98554622E0587DF009051BD /* HostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsView.swift; sourceTree = "<group>"; }; A98554622E0587DF009051BD /* HostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsView.swift; sourceTree = "<group>"; };
A9B15A992E0ABA0400F66E02 /* DialogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogView.swift; sourceTree = "<group>"; };
A9C4140B2E096DB7005E3047 /* SSHError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHError.swift; sourceTree = "<group>"; }; A9C4140B2E096DB7005E3047 /* SSHError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHError.swift; sourceTree = "<group>"; };
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; }; A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -137,6 +139,7 @@
children = ( children = (
A92317292E07113100ECE1E6 /* TerminalController.swift */, A92317292E07113100ECE1E6 /* TerminalController.swift */,
A923172E2E08851200ECE1E6 /* ShellView.swift */, A923172E2E08851200ECE1E6 /* ShellView.swift */,
A9B15A992E0ABA0400F66E02 /* DialogView.swift */,
A923172C2E07138000ECE1E6 /* SSHTerminalView.swift */, A923172C2E07138000ECE1E6 /* SSHTerminalView.swift */,
); );
path = Terminal; path = Terminal;
@@ -421,6 +424,7 @@
A98554632E0587DF009051BD /* HostsView.swift in Sources */, A98554632E0587DF009051BD /* HostsView.swift in Sources */,
A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */, A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */,
A93143C02DF61B3200FCD5DB /* Host.swift in Sources */, A93143C02DF61B3200FCD5DB /* Host.swift in Sources */,
A9B15A9A2E0ABA0400F66E02 /* DialogView.swift in Sources */,
A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */, A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */,
A98554612E058433009051BD /* HostsManager.swift in Sources */, A98554612E058433009051BD /* HostsManager.swift in Sources */,
A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */, A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */,

View File

@@ -56,6 +56,15 @@ extension Host {
Host(address: "") Host(address: "")
} }
static var debug: Host { static var debug: Host {
Host(address: "localhost", username: "default", password: "") Host(
address: "localhost",
port: 22,
username: "neon443",
password: "password",
publicKey: nil,
privateKey: nil,
passphrase: "",
hostkey: nil
)
} }
} }

View File

@@ -12,7 +12,8 @@ import SwiftUI
class SSHHandler: @unchecked Sendable, ObservableObject { class SSHHandler: @unchecked Sendable, ObservableObject {
private var session: ssh_session? private var session: ssh_session?
var channel: ssh_channel? private var channel: ssh_channel?
private let sshQueue = DispatchQueue(label: "SSH Queue")
@Published var connected: Bool = false @Published var connected: Bool = false
@Published var authorized: Bool = false @Published var authorized: Bool = false
@@ -332,22 +333,22 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
} }
func readFromChannel() -> String? { func readFromChannel() -> String? {
if !connected {
return nil
}
guard connected else { return nil } guard connected else { return nil }
guard ssh_channel_is_open(channel) != 0 || ssh_channel_is_eof(channel) == 0 else { guard ssh_channel_is_open(channel) != 0 || ssh_channel_is_eof(channel) == 0 else {
disconnect() disconnect()
return nil return nil
} }
var buffer: [CChar] = Array(repeating: 0, count: 512) var buffer: [CChar] = Array(repeating: 0, count: 4096)
let nbytes = ssh_channel_read_nonblocking(channel, &buffer, UInt32(buffer.count), 0) let nbytes = ssh_channel_read_nonblocking(channel, &buffer, UInt32(buffer.count), 0)
guard nbytes > 0 else { return nil } guard nbytes > 0 else { return nil }
let data = Data(bytes: buffer, count: Int(nbytes)) let data = Data(bytes: buffer, count: Int(nbytes))
if let string = String(data: data, encoding: .utf8) { if let string = String(data: data, encoding: .utf8) {
#if DEBUG
print(String(data: Data(bytes: buffer, count: Int(nbytes)), encoding: .utf8)!)
#endif
return string return string
} }
return nil return nil

View File

@@ -20,6 +20,7 @@ struct ShhShellApp: App {
keyManager: keyManager, keyManager: keyManager,
hostsManager: hostsManager hostsManager: hostsManager
) )
.colorScheme(.dark)
} }
} }
} }

View File

@@ -0,0 +1,67 @@
//
// DialogView.swift
// ShhShell
//
// Created by neon443 on 24/06/2025.
//
import SwiftUI
struct DialogView: View {
@ObservedObject var handler: SSHHandler
@State var showDialog: Bool = true
@State var icon: String = "network.slash"
@State var headline: String = "Disconnected"
@State var text: String = "Connection to the SSH server has been lost, try reconnecting"
var body: some View {
GeometryReader { geo in
let width = geo.size.width*0.75
let height = geo.size.height*0.15
if showDialog {
ZStack(alignment: .center) {
Color.black
.clipShape(RoundedRectangle(cornerRadius: 15))
.frame(maxWidth: width, maxHeight: height)
.shadow(color: .white, radius: 2)
HStack(alignment: .top) {
Image(systemName: icon)
.resizable().scaledToFit()
.frame(width: width*0.2)
.foregroundStyle(.terminalGreen)
.symbolRenderingMode(.hierarchical)
VStack(alignment: .leading) {
Text(headline)
.foregroundStyle(.terminalGreen)
.font(.title2)
.bold()
Text(text)
.foregroundStyle(.terminalGreen)
.font(.footnote)
}
.frame(width: width*0.7)
}
.frame(maxWidth: width, maxHeight: height)
}
.transition(
.asymmetric(
insertion: .move(edge: .bottom),
removal: .move(edge: .bottom)
)
.combined(with: .opacity)
)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
Button("show button") {
withAnimation { showDialog.toggle() }
}
}
}
#Preview {
ZStack {
Color.black
DialogView(handler: SSHHandler(host: Host.debug))
}
}

View File

@@ -26,7 +26,6 @@ final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalVie
terminalDelegate = self terminalDelegate = self
sshQueue.async { sshQueue.async {
guard let handler = self.handler else { return } guard let handler = self.handler else { return }
guard handler.channel != nil else { return }
while handler.connected { while handler.connected {
if let read = handler.readFromChannel() { if let read = handler.readFromChannel() {
@@ -35,7 +34,7 @@ final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalVie
await self.feed(text: read) await self.feed(text: read)
} }
} else { } else {
usleep(100_000) usleep(1_000)
} }
// self?.setNeedsDisplay() // self?.setNeedsDisplay()
} }

View File

@@ -13,6 +13,9 @@ struct ShellView: View {
var body: some View { var body: some View {
NavigationStack { NavigationStack {
ZStack { ZStack {
if !handler.connected {
DialogView(handler: handler, showDialog: !handler.connected)
}
TerminalController(handler: handler) TerminalController(handler: handler)
} }
.toolbar { .toolbar {