mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 05:19:13 +00:00
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
This commit is contained in:
@@ -79,6 +79,7 @@
|
|||||||
A9BA1D1E2E1EAD51005BDCEF /* SF-Mono-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = A9BA1D1C2E1EAD51005BDCEF /* SF-Mono-Bold.otf */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
||||||
A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.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 = "<group>"; };
|
A9BA1D1C2E1EAD51005BDCEF /* SF-Mono-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Mono-Bold.otf"; sourceTree = "<group>"; };
|
||||||
A9BA1D1D2E1EAD51005BDCEF /* SF-Mono-BoldItalic.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Mono-BoldItalic.otf"; sourceTree = "<group>"; };
|
A9BA1D1D2E1EAD51005BDCEF /* SF-Mono-BoldItalic.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Mono-BoldItalic.otf"; sourceTree = "<group>"; };
|
||||||
A9C060EA2E357FD300CA9374 /* Haptics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Haptics.swift; sourceTree = "<group>"; };
|
A9C060EA2E357FD300CA9374 /* Haptics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Haptics.swift; sourceTree = "<group>"; };
|
||||||
|
A9C060EC2E3FBCD000CA9374 /* SnippetPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnippetPicker.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>"; };
|
||||||
A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
||||||
@@ -458,6 +460,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A93F283C2E2A5DCB0092B8D5 /* SnippetManagerView.swift */,
|
A93F283C2E2A5DCB0092B8D5 /* SnippetManagerView.swift */,
|
||||||
|
A9C060EC2E3FBCD000CA9374 /* SnippetPicker.swift */,
|
||||||
A9A2F4F52E3001D300D0AE9B /* AddSnippetView.swift */,
|
A9A2F4F52E3001D300D0AE9B /* AddSnippetView.swift */,
|
||||||
);
|
);
|
||||||
path = Snippets;
|
path = Snippets;
|
||||||
@@ -788,6 +791,7 @@
|
|||||||
A9DA97732E0D40C100142DDC /* HostSymbolPreview.swift in Sources */,
|
A9DA97732E0D40C100142DDC /* HostSymbolPreview.swift in Sources */,
|
||||||
A90B38342E3EA046002B56FC /* Bundle.swift in Sources */,
|
A90B38342E3EA046002B56FC /* Bundle.swift in Sources */,
|
||||||
A9FD376B2E16DABF005319A8 /* AnsiPickerView.swift in Sources */,
|
A9FD376B2E16DABF005319A8 /* AnsiPickerView.swift in Sources */,
|
||||||
|
A9C060ED2E3FBCD000CA9374 /* SnippetPicker.swift in Sources */,
|
||||||
A96BE6A62E113DB000C0FEE9 /* ColorCodable.swift in Sources */,
|
A96BE6A62E113DB000C0FEE9 /* ColorCodable.swift in Sources */,
|
||||||
A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */,
|
A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */,
|
||||||
A96BE6A42E113D9400C0FEE9 /* ThemeCodable.swift in Sources */,
|
A96BE6A42E113D9400C0FEE9 /* ThemeCodable.swift in Sources */,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import SwiftUI
|
|||||||
|
|
||||||
//app icon
|
//app icon
|
||||||
extension Bundle {
|
extension Bundle {
|
||||||
var iconFilename: String? {
|
var appIconFilename: String? {
|
||||||
guard let icons = infoDictionary?["CFBundleIcons"] as? [String: Any],
|
guard let icons = infoDictionary?["CFBundleIcons"] as? [String: Any],
|
||||||
let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any],
|
let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any],
|
||||||
let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
|
let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
|
||||||
@@ -23,9 +23,23 @@ extension Bundle {
|
|||||||
extension UIImage {
|
extension UIImage {
|
||||||
var appIcon: Image {
|
var appIcon: Image {
|
||||||
// let fallback = Image(uiImage: UIImage())
|
// 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 }
|
// guard let uiImage = UIImage(named: filename) else { return fallback }
|
||||||
// return uiImage
|
// return uiImage
|
||||||
return Image("Icon")
|
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") + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getHostkey() -> String? {
|
func getHostkey() -> String? {
|
||||||
|
guard connected else { return nil }
|
||||||
|
|
||||||
var hostkey: ssh_key?
|
var hostkey: ssh_key?
|
||||||
ssh_get_server_publickey(session, &hostkey)
|
ssh_get_server_publickey(session, &hostkey)
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,35 @@ struct AboutView: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
||||||
.ignoresSafeArea(.all)
|
.ignoresSafeArea(.all)
|
||||||
List {
|
// List {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
UIImage().appIcon
|
||||||
|
.resizable().scaledToFit()
|
||||||
|
.frame(width: 100)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 26))
|
||||||
|
Text("ShhShell")
|
||||||
|
.font(.largeTitle.monospaced())
|
||||||
HStack {
|
HStack {
|
||||||
UIImage().appIcon
|
Text(Bundle.main.appVersion)
|
||||||
.resizable().scaledToFit()
|
.monospaced()
|
||||||
.frame(width: 100)
|
.font(.subheadline)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 26))
|
Text(Bundle.main.appBuild)
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
.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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
ShhShell/Views/Snippets/SnippetPicker.swift
Normal file
41
ShhShell/Views/Snippets/SnippetPicker.swift
Normal file
@@ -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)
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@ struct ShellTabView: View {
|
|||||||
@ObservedObject var container = TerminalViewContainer.shared
|
@ObservedObject var container = TerminalViewContainer.shared
|
||||||
@State var selectedID: UUID?
|
@State var selectedID: UUID?
|
||||||
|
|
||||||
|
@State var showSnippetPicker: Bool = false
|
||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
var foreground: Color {
|
var foreground: Color {
|
||||||
@@ -75,11 +77,22 @@ struct ShellTabView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer()
|
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(.horizontal, 10)
|
||||||
.padding(.vertical, 5)
|
.padding(.vertical, 10)
|
||||||
.background(hostsManager.tint, ignoresSafeAreaEdges: .all)
|
.background(hostsManager.tint, ignoresSafeAreaEdges: .all)
|
||||||
.frame(height: 30)
|
.frame(height: 40)
|
||||||
|
|
||||||
if container.sessionIDs.count > 1 {
|
if container.sessionIDs.count > 1 {
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
|||||||
Reference in New Issue
Block a user