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 */; };
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 = "<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>"; };
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>"; };
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; };
/* 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 */,

View File

@@ -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
)
}
}

View File

@@ -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

View File

@@ -20,6 +20,7 @@ struct ShhShellApp: App {
keyManager: keyManager,
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
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()
}

View File

@@ -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 {