mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 05:19:13 +00:00
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:
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 */,
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ struct ShhShellApp: App {
|
|||||||
keyManager: keyManager,
|
keyManager: keyManager,
|
||||||
hostsManager: hostsManager
|
hostsManager: hostsManager
|
||||||
)
|
)
|
||||||
|
.colorScheme(.dark)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
ShhShell/Views/Terminal/DialogView.swift
Normal file
67
ShhShell/Views/Terminal/DialogView.swift
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user