From ee6fc96f0124ec9965adf0672d7260994671afca Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Sun, 3 Aug 2025 17:52:20 +0100 Subject: [PATCH] added a snippet picker and it executes a callback when one is selected added a snippet button to shelltabview fix crash if hostkey changed message shows up and not connected anymore (such as failed auth) cleaned up about view and added a libssh link update bundle.swift to add version and build number getting --- ShhShell.xcodeproj/project.pbxproj | 4 ++ ShhShell/Misc/Bundle.swift | 18 ++++++++- ShhShell/SSH/SSHHandler.swift | 2 + ShhShell/Views/About/AboutView.swift | 33 +++++++++++++---- ShhShell/Views/Snippets/SnippetPicker.swift | 41 +++++++++++++++++++++ ShhShell/Views/Terminal/ShellTabView.swift | 17 ++++++++- 6 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 ShhShell/Views/Snippets/SnippetPicker.swift diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index ee11109..74a39c4 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -79,6 +79,7 @@ A9BA1D1E2E1EAD51005BDCEF /* SF-Mono-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = A9BA1D1C2E1EAD51005BDCEF /* SF-Mono-Bold.otf */; }; A9BA1D1F2E1EAD51005BDCEF /* SF-Mono-BoldItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = A9BA1D1D2E1EAD51005BDCEF /* SF-Mono-BoldItalic.otf */; }; A9C060EB2E357FD300CA9374 /* Haptics.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C060EA2E357FD300CA9374 /* Haptics.swift */; }; + A9C060ED2E3FBCD000CA9374 /* SnippetPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C060EC2E3FBCD000CA9374 /* SnippetPicker.swift */; }; A9C4140C2E096DB7005E3047 /* SSHError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C4140B2E096DB7005E3047 /* SSHError.swift */; }; A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; }; A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.swift */; }; @@ -208,6 +209,7 @@ A9BA1D1C2E1EAD51005BDCEF /* SF-Mono-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Mono-Bold.otf"; sourceTree = ""; }; A9BA1D1D2E1EAD51005BDCEF /* SF-Mono-BoldItalic.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Mono-BoldItalic.otf"; sourceTree = ""; }; A9C060EA2E357FD300CA9374 /* Haptics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Haptics.swift; sourceTree = ""; }; + A9C060EC2E3FBCD000CA9374 /* SnippetPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnippetPicker.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 = ""; }; A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; @@ -458,6 +460,7 @@ isa = PBXGroup; children = ( A93F283C2E2A5DCB0092B8D5 /* SnippetManagerView.swift */, + A9C060EC2E3FBCD000CA9374 /* SnippetPicker.swift */, A9A2F4F52E3001D300D0AE9B /* AddSnippetView.swift */, ); path = Snippets; @@ -788,6 +791,7 @@ A9DA97732E0D40C100142DDC /* HostSymbolPreview.swift in Sources */, A90B38342E3EA046002B56FC /* Bundle.swift in Sources */, A9FD376B2E16DABF005319A8 /* AnsiPickerView.swift in Sources */, + A9C060ED2E3FBCD000CA9374 /* SnippetPicker.swift in Sources */, A96BE6A62E113DB000C0FEE9 /* ColorCodable.swift in Sources */, A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */, A96BE6A42E113D9400C0FEE9 /* ThemeCodable.swift in Sources */, diff --git a/ShhShell/Misc/Bundle.swift b/ShhShell/Misc/Bundle.swift index 497b60c..f3fae7c 100644 --- a/ShhShell/Misc/Bundle.swift +++ b/ShhShell/Misc/Bundle.swift @@ -10,7 +10,7 @@ import SwiftUI //app icon extension Bundle { - var iconFilename: String? { + var appIconFilename: String? { guard let icons = infoDictionary?["CFBundleIcons"] as? [String: Any], let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any], let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String], @@ -23,9 +23,23 @@ extension Bundle { extension UIImage { var appIcon: Image { // let fallback = Image(uiImage: UIImage()) -// guard let filename = Bundle.main.iconFilename else { return fallback } +// guard let filename = Bundle.main.appIconFilename else { return fallback } // guard let uiImage = UIImage(named: filename) else { return fallback } // return uiImage return Image("Icon") } } + +extension Bundle { + var appVersion: String { + let version = infoDictionary?["CFBundleShortVersionString"] as? String + return version ?? "0.0" + } +} + +extension Bundle { + var appBuild: String { + let build = infoDictionary?["CFBundleVersion"] as? String + return "(" + (build ?? "0") + ")" + } +} diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index 8ac2616..635ab37 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -47,6 +47,8 @@ class SSHHandler: @unchecked Sendable, ObservableObject { } func getHostkey() -> String? { + guard connected else { return nil } + var hostkey: ssh_key? ssh_get_server_publickey(session, &hostkey) diff --git a/ShhShell/Views/About/AboutView.swift b/ShhShell/Views/About/AboutView.swift index 792894b..d37ddf9 100644 --- a/ShhShell/Views/About/AboutView.swift +++ b/ShhShell/Views/About/AboutView.swift @@ -14,16 +14,35 @@ struct AboutView: View { ZStack { hostsManager.selectedTheme.background.suiColor.opacity(0.7) .ignoresSafeArea(.all) - List { +// List { + VStack(alignment: .leading) { + UIImage().appIcon + .resizable().scaledToFit() + .frame(width: 100) + .clipShape(RoundedRectangle(cornerRadius: 26)) + Text("ShhShell") + .font(.largeTitle.monospaced()) HStack { - UIImage().appIcon - .resizable().scaledToFit() - .frame(width: 100) - .clipShape(RoundedRectangle(cornerRadius: 26)) - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + Text(Bundle.main.appVersion) + .monospaced() + .font(.subheadline) + Text(Bundle.main.appBuild) + .monospaced() + .font(.callout) + } + .padding(.bottom) + + Section("Thanks to") { + Link(destination: URL(string: "https://libssh.org")!) { + Text("LibSSH") + .background(.red) + } } } - .scrollContentBackground(.hidden) + .frame(maxWidth: .infinity) + .padding() +// } +// .scrollContentBackground(.hidden) } } } diff --git a/ShhShell/Views/Snippets/SnippetPicker.swift b/ShhShell/Views/Snippets/SnippetPicker.swift new file mode 100644 index 0000000..babd68e --- /dev/null +++ b/ShhShell/Views/Snippets/SnippetPicker.swift @@ -0,0 +1,41 @@ +// +// SnippetPicker.swift +// ShhShell +// +// Created by neon443 on 03/08/2025. +// + +import SwiftUI + +struct SnippetPicker: View { + @ObservedObject var hostsManager: HostsManager + var callback: ((Snippet) -> Void)? + + @Environment(\.dismiss) var dismiss + + var body: some View { + NavigationStack { + List { + ForEach(hostsManager.snippets) { snip in + Text(snip.name) + .onTapGesture { + dismiss() + callback?(snip) + } + } + .toolbar { + Button() { + dismiss() + } label: { + Image(systemName: "xmark") + } + } + } + .listStyle(.grouped) + } + } +} + +#Preview { + SnippetPicker(hostsManager: HostsManager(), callback: nil) +} diff --git a/ShhShell/Views/Terminal/ShellTabView.swift b/ShhShell/Views/Terminal/ShellTabView.swift index 6e132d3..c951f06 100644 --- a/ShhShell/Views/Terminal/ShellTabView.swift +++ b/ShhShell/Views/Terminal/ShellTabView.swift @@ -14,6 +14,8 @@ struct ShellTabView: View { @ObservedObject var container = TerminalViewContainer.shared @State var selectedID: UUID? + @State var showSnippetPicker: Bool = false + @Environment(\.dismiss) var dismiss var foreground: Color { @@ -75,11 +77,22 @@ struct ShellTabView: View { } } Spacer() + Button() { + showSnippetPicker.toggle() + } label: { + Image(systemName: "paperclip") + } + .foregroundStyle(foreground) + .sheet(isPresented: $showSnippetPicker) { + SnippetPicker(hostsManager: hostsManager) { + container.sessions[selectedID ?? UUID()]?.handler.writeToChannel($0.content) + } + } } .padding(.horizontal, 10) - .padding(.vertical, 5) + .padding(.vertical, 10) .background(hostsManager.tint, ignoresSafeAreaEdges: .all) - .frame(height: 30) + .frame(height: 40) if container.sessionIDs.count > 1 { ScrollView(.horizontal, showsIndicators: false) {