From 1e3a57d788176a36a3cae33ad45f6305098f0ddc Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Tue, 24 Jun 2025 12:33:52 +0100 Subject: [PATCH] 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 --- .../terminalGreen.colorset/Contents.json | 20 ++++++ ShhShell.xcodeproj/project.pbxproj | 4 ++ ShhShell/Host/Host.swift | 11 ++- ShhShell/SSH/SSHHandler.swift | 11 +-- ShhShell/ShhShellApp.swift | 1 + ShhShell/Views/Terminal/DialogView.swift | 67 +++++++++++++++++++ ShhShell/Views/Terminal/SSHTerminalView.swift | 3 +- ShhShell/Views/Terminal/ShellView.swift | 3 + 8 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 Resources/Assets.xcassets/terminalGreen.colorset/Contents.json create mode 100644 ShhShell/Views/Terminal/DialogView.swift diff --git a/Resources/Assets.xcassets/terminalGreen.colorset/Contents.json b/Resources/Assets.xcassets/terminalGreen.colorset/Contents.json new file mode 100644 index 0000000..c74662a --- /dev/null +++ b/Resources/Assets.xcassets/terminalGreen.colorset/Contents.json @@ -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 + } +} diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index 6612f2f..7bccab1 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ A985545F2E056EDD009051BD /* KeychainLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985545E2E056EDD009051BD /* KeychainLayer.swift */; }; A98554612E058433009051BD /* HostsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554602E058433009051BD /* HostsManager.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 */; }; A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; }; /* End PBXBuildFile section */ @@ -98,6 +99,7 @@ A985545E2E056EDD009051BD /* KeychainLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainLayer.swift; sourceTree = ""; }; A98554602E058433009051BD /* HostsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsManager.swift; sourceTree = ""; }; A98554622E0587DF009051BD /* HostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsView.swift; sourceTree = ""; }; + A9B15A992E0ABA0400F66E02 /* DialogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogView.swift; sourceTree = ""; }; A9C4140B2E096DB7005E3047 /* SSHError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHError.swift; sourceTree = ""; }; A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -137,6 +139,7 @@ children = ( A92317292E07113100ECE1E6 /* TerminalController.swift */, A923172E2E08851200ECE1E6 /* ShellView.swift */, + A9B15A992E0ABA0400F66E02 /* DialogView.swift */, A923172C2E07138000ECE1E6 /* SSHTerminalView.swift */, ); path = Terminal; @@ -421,6 +424,7 @@ A98554632E0587DF009051BD /* HostsView.swift in Sources */, A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */, A93143C02DF61B3200FCD5DB /* Host.swift in Sources */, + A9B15A9A2E0ABA0400F66E02 /* DialogView.swift in Sources */, A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */, A98554612E058433009051BD /* HostsManager.swift in Sources */, A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */, diff --git a/ShhShell/Host/Host.swift b/ShhShell/Host/Host.swift index d73bc38..7f9a415 100644 --- a/ShhShell/Host/Host.swift +++ b/ShhShell/Host/Host.swift @@ -56,6 +56,15 @@ extension Host { Host(address: "") } 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 + ) } } diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index db39b80..125cbe6 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -12,7 +12,8 @@ import SwiftUI class SSHHandler: @unchecked Sendable, ObservableObject { 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 authorized: Bool = false @@ -332,22 +333,22 @@ class SSHHandler: @unchecked Sendable, ObservableObject { } func readFromChannel() -> String? { - if !connected { - return nil - } guard connected else { return nil } guard ssh_channel_is_open(channel) != 0 || ssh_channel_is_eof(channel) == 0 else { disconnect() 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) guard nbytes > 0 else { return nil } let data = Data(bytes: buffer, count: Int(nbytes)) 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 nil diff --git a/ShhShell/ShhShellApp.swift b/ShhShell/ShhShellApp.swift index beb553e..60b0635 100644 --- a/ShhShell/ShhShellApp.swift +++ b/ShhShell/ShhShellApp.swift @@ -20,6 +20,7 @@ struct ShhShellApp: App { keyManager: keyManager, hostsManager: hostsManager ) + .colorScheme(.dark) } } } diff --git a/ShhShell/Views/Terminal/DialogView.swift b/ShhShell/Views/Terminal/DialogView.swift new file mode 100644 index 0000000..752d51a --- /dev/null +++ b/ShhShell/Views/Terminal/DialogView.swift @@ -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)) + } +} diff --git a/ShhShell/Views/Terminal/SSHTerminalView.swift b/ShhShell/Views/Terminal/SSHTerminalView.swift index ab3f9a5..b5d2c96 100644 --- a/ShhShell/Views/Terminal/SSHTerminalView.swift +++ b/ShhShell/Views/Terminal/SSHTerminalView.swift @@ -26,7 +26,6 @@ final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalVie terminalDelegate = self sshQueue.async { guard let handler = self.handler else { return } - guard handler.channel != nil else { return } while handler.connected { if let read = handler.readFromChannel() { @@ -35,7 +34,7 @@ final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalVie await self.feed(text: read) } } else { - usleep(100_000) + usleep(1_000) } // self?.setNeedsDisplay() } diff --git a/ShhShell/Views/Terminal/ShellView.swift b/ShhShell/Views/Terminal/ShellView.swift index 7cd36e3..b1a8707 100644 --- a/ShhShell/Views/Terminal/ShellView.swift +++ b/ShhShell/Views/Terminal/ShellView.swift @@ -13,6 +13,9 @@ struct ShellView: View { var body: some View { NavigationStack { ZStack { + if !handler.connected { + DialogView(handler: handler, showDialog: !handler.connected) + } TerminalController(handler: handler) } .toolbar {