mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 05:19:13 +00:00
terminalViewContainer is now an observable object
made the session list view more pretty terminalviewcontaner has a static shared property which is an instance of itself then it has sessions inside with a dict of uuid:terminalcontainer inside hostsview is in the section "hosts"
This commit is contained in:
@@ -341,8 +341,8 @@
|
||||
A96C6B042E0C523E00F377FE /* Hosts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A985545C2E055D4D009051BD /* ConnectionView.swift */,
|
||||
A98554622E0587DF009051BD /* HostsView.swift */,
|
||||
A985545C2E055D4D009051BD /* ConnectionView.swift */,
|
||||
);
|
||||
path = Hosts;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -133,7 +133,8 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
func makeLabel(forHost: Host) -> String {
|
||||
func makeLabel(forHost: Host?) -> String {
|
||||
guard let forHost else { return "" }
|
||||
if forHost.name.isEmpty && forHost.address.isEmpty {
|
||||
return forHost.id.uuidString
|
||||
} else if forHost.name.isEmpty {
|
||||
|
||||
@@ -15,6 +15,9 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
||||
private var session: ssh_session?
|
||||
private var channel: ssh_channel?
|
||||
|
||||
@MainActor var container: TerminalViewContainer {
|
||||
TerminalViewContainer.shared
|
||||
}
|
||||
var sessionID: UUID?
|
||||
|
||||
var scrollback: [String] = []
|
||||
@@ -140,7 +143,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
||||
|
||||
if let sessionID {
|
||||
Task { @MainActor in
|
||||
TerminalViewContainer.shared.removeValue(forKey: sessionID)
|
||||
container.sessions.removeValue(forKey: sessionID)
|
||||
self.sessionID = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,36 +17,38 @@ struct HostsView: View {
|
||||
Text("Add your first Host!")
|
||||
}
|
||||
|
||||
ForEach(hostsManager.hosts) { host in
|
||||
NavigationLink() {
|
||||
ConnectionView(
|
||||
handler: SSHHandler(host: host),
|
||||
hostsManager: hostsManager,
|
||||
keyManager: keyManager
|
||||
)
|
||||
} label: {
|
||||
SymbolPreview(symbol: host.symbol, label: host.label)
|
||||
.frame(width: 40, height: 40)
|
||||
Text(hostsManager.makeLabel(forHost: host))
|
||||
}
|
||||
.id(host)
|
||||
.animation(.default, value: host)
|
||||
.swipeActions(edge: .trailing) {
|
||||
Button(role: .destructive) {
|
||||
hostsManager.removeHost(host)
|
||||
Section("Hosts") {
|
||||
ForEach(hostsManager.hosts) { host in
|
||||
NavigationLink() {
|
||||
ConnectionView(
|
||||
handler: SSHHandler(host: host),
|
||||
hostsManager: hostsManager,
|
||||
keyManager: keyManager
|
||||
)
|
||||
} label: {
|
||||
Label("Delete", systemImage: "trash")
|
||||
SymbolPreview(symbol: host.symbol, label: host.label)
|
||||
.frame(width: 40, height: 40)
|
||||
Text(hostsManager.makeLabel(forHost: host))
|
||||
}
|
||||
Button() {
|
||||
hostsManager.duplicateHost(host)
|
||||
} label: {
|
||||
Label("Duplicate", systemImage: "square.filled.on.square")
|
||||
.id(host)
|
||||
.animation(.default, value: host)
|
||||
.swipeActions(edge: .trailing) {
|
||||
Button(role: .destructive) {
|
||||
hostsManager.removeHost(host)
|
||||
} label: {
|
||||
Label("Delete", systemImage: "trash")
|
||||
}
|
||||
Button() {
|
||||
hostsManager.duplicateHost(host)
|
||||
} label: {
|
||||
Label("Duplicate", systemImage: "square.filled.on.square")
|
||||
}
|
||||
}
|
||||
}
|
||||
.onMove(perform: {
|
||||
hostsManager.moveHost(from: $0, to: $1)
|
||||
})
|
||||
}
|
||||
.onMove(perform: {
|
||||
hostsManager.moveHost(from: $0, to: $1)
|
||||
})
|
||||
|
||||
Section() {
|
||||
NavigationLink {
|
||||
|
||||
@@ -9,20 +9,34 @@ import SwiftUI
|
||||
|
||||
struct SessionView: View {
|
||||
@ObservedObject var hostsManager: HostsManager
|
||||
@ObservedObject var container = TerminalViewContainer.shared
|
||||
|
||||
@State var key: UUID
|
||||
@State var shellPresented: Bool = false
|
||||
|
||||
var host: Host {
|
||||
container.sessions[key]?.handler.host ?? Host.blank
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Text(key.uuidString)
|
||||
.onTapGesture {
|
||||
shellPresented.toggle()
|
||||
}
|
||||
.fullScreenCover(isPresented: $shellPresented) {
|
||||
ShellView(
|
||||
handler: TerminalViewContainer.shared[key]!.handler,
|
||||
hostsManager: hostsManager
|
||||
)
|
||||
}
|
||||
HStack {
|
||||
Image(systemName: "apple.terminal")
|
||||
.resizable().scaledToFit()
|
||||
.frame(width: 40, height: 40)
|
||||
.foregroundStyle(.terminalGreen)
|
||||
SymbolPreview(symbol: host.symbol, label: host.label)
|
||||
.frame(width: 40, height: 40)
|
||||
Text(hostsManager.makeLabel(forHost: host))
|
||||
}
|
||||
.onTapGesture {
|
||||
shellPresented.toggle()
|
||||
}
|
||||
.fullScreenCover(isPresented: $shellPresented) {
|
||||
ShellView(
|
||||
handler: container.sessions[key]?.handler ?? SSHHandler(host: Host.blank),
|
||||
hostsManager: hostsManager
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,15 @@ struct SessionsListView: View {
|
||||
@ObservedObject var hostsManager: HostsManager
|
||||
@ObservedObject var keyManager: KeyManager
|
||||
|
||||
@ObservedObject var container = TerminalViewContainer.shared
|
||||
|
||||
var body: some View {
|
||||
Section("Sessions") {
|
||||
ForEach(TerminalViewContainer.shared.map {$0.key}, id: \.self) { key in
|
||||
SessionView(hostsManager: hostsManager, key: key)
|
||||
if !container.sessions.isEmpty {
|
||||
Section("Sessions") {
|
||||
ForEach(container.sessionIDs, id: \.self) { key in
|
||||
SessionView(hostsManager: hostsManager, key: key)
|
||||
.id(container.sessions[key]!.handler.connected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ struct ShellView: View {
|
||||
@ObservedObject var handler: SSHHandler
|
||||
@ObservedObject var hostsManager: HostsManager
|
||||
|
||||
@ObservedObject var container = TerminalViewContainer.shared
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
@@ -19,7 +21,7 @@ struct ShellView: View {
|
||||
TerminalController(handler: handler, hostsManager: hostsManager)
|
||||
.onAppear {
|
||||
if let sessionID = handler.sessionID {
|
||||
TerminalViewContainer.shared[sessionID]?.terminalView.restoreScrollback()
|
||||
container.sessions[sessionID]?.terminalView.restoreScrollback()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,11 @@ struct TerminalController: UIViewRepresentable {
|
||||
@ObservedObject var handler: SSHHandler
|
||||
@ObservedObject var hostsManager: HostsManager
|
||||
|
||||
@ObservedObject var container = TerminalViewContainer.shared
|
||||
|
||||
func makeUIView(context: Context) -> TerminalView {
|
||||
if let sessionID = handler.sessionID {
|
||||
if let existing = TerminalViewContainer.shared[sessionID] {
|
||||
if let existing = container.sessions[sessionID] {
|
||||
return existing.terminalView
|
||||
}
|
||||
}
|
||||
@@ -30,7 +32,7 @@ struct TerminalController: UIViewRepresentable {
|
||||
tv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
if let sessionID = handler.sessionID {
|
||||
TerminalViewContainer.shared[sessionID] = TerminalContainer(
|
||||
container.sessions[sessionID] = TerminalContainer(
|
||||
handler: handler,
|
||||
terminalView: tv
|
||||
)
|
||||
|
||||
@@ -7,10 +7,15 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class TerminalViewContainer {
|
||||
@MainActor static var shared: [
|
||||
UUID: TerminalContainer
|
||||
] = [:]
|
||||
@MainActor
|
||||
public final class TerminalViewContainer: ObservableObject {
|
||||
static let shared = TerminalViewContainer()
|
||||
|
||||
@Published var sessions: [UUID: TerminalContainer] = [:]
|
||||
|
||||
var sessionIDs: [UUID] {
|
||||
return sessions.map({ $0.key })
|
||||
}
|
||||
}
|
||||
|
||||
struct TerminalContainer {
|
||||
|
||||
Reference in New Issue
Block a user