From e47b598c742d1b66268aacb8e8328e1477b20d14 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Wed, 23 Jul 2025 19:56:45 +0100 Subject: [PATCH] add snippets?? and deleete and duplicate etc --- ShhShell.xcodeproj/project.pbxproj | 4 ++ ShhShell/Host/HostsManager.swift | 18 +++++- ShhShell/Views/Snippets/AddSnippetView.swift | 64 +++++++++++++++++++ .../Views/Snippets/SnippetManagerView.swift | 50 ++++++++++++--- 4 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 ShhShell/Views/Snippets/AddSnippetView.swift diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index 0ebb43c..8aad188 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -71,6 +71,7 @@ A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A985545C2E055D4D009051BD /* ConnectionView.swift */; }; A98554612E058433009051BD /* HostsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554602E058433009051BD /* HostsManager.swift */; }; A98554632E0587DF009051BD /* HostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554622E0587DF009051BD /* HostsView.swift */; }; + A9A2F4F62E3001D300D0AE9B /* AddSnippetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A2F4F52E3001D300D0AE9B /* AddSnippetView.swift */; }; A9A587202E0BF220006B31E6 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = A9A5871F2E0BF220006B31E6 /* SwiftTerm */; }; A9BA1D192E1D9AE1005BDCEF /* SwiftTerm.Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BA1D182E1D9AE1005BDCEF /* SwiftTerm.Color.swift */; }; A9BA1D1E2E1EAD51005BDCEF /* SF-Mono-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = A9BA1D1C2E1EAD51005BDCEF /* SF-Mono-Bold.otf */; }; @@ -197,6 +198,7 @@ A985545C2E055D4D009051BD /* ConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionView.swift; sourceTree = ""; }; A98554602E058433009051BD /* HostsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsManager.swift; sourceTree = ""; }; A98554622E0587DF009051BD /* HostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsView.swift; sourceTree = ""; }; + A9A2F4F52E3001D300D0AE9B /* AddSnippetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSnippetView.swift; sourceTree = ""; }; A9BA1D182E1D9AE1005BDCEF /* SwiftTerm.Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTerm.Color.swift; sourceTree = ""; }; 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 = ""; }; @@ -440,6 +442,7 @@ isa = PBXGroup; children = ( A93F283C2E2A5DCB0092B8D5 /* SnippetManagerView.swift */, + A9A2F4F52E3001D300D0AE9B /* AddSnippetView.swift */, ); path = Snippets; sourceTree = ""; @@ -783,6 +786,7 @@ A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */, A9D819312E102D8700442D38 /* HostkeysView.swift in Sources */, A98554552E05535F009051BD /* KeyManagerView.swift in Sources */, + A9A2F4F62E3001D300D0AE9B /* AddSnippetView.swift in Sources */, A923172D2E07138000ECE1E6 /* SSHTerminalDelegate.swift in Sources */, A90936882E1AC51100856059 /* Fonts.swift in Sources */, A9FD37552E143D23005319A8 /* SecKeyConvertible.swift in Sources */, diff --git a/ShhShell/Host/HostsManager.swift b/ShhShell/Host/HostsManager.swift index 6ae3b43..59c21b3 100644 --- a/ShhShell/Host/HostsManager.swift +++ b/ShhShell/Host/HostsManager.swift @@ -35,11 +35,27 @@ class HostsManager: ObservableObject, @unchecked Sendable { loadSnippets() } + func addSnippet(_ toAdd: Snippet) { + snippets.append(toAdd) + saveSnippets() + } + + func duplicateSnippet(_ snip: Snippet) { + guard let index = snippets.firstIndex(where: { $0.id == snip.id }) else { return } + withAnimation { snippets.insert(snip, at: index+1) } + } + + func deleteSnippet(_ toDel: Snippet) { + guard let index = snippets.firstIndex(where: { $0.id == toDel.id }) else { return } + snippets.remove(at: index) + saveSnippets() + } + func loadSnippets() { userDefaults.synchronize() guard let data = userDefaults.data(forKey: "snippets") else { return } guard let decoded = try? JSONDecoder().decode([Snippet].self, from: data) else { return } - self.snippets = decoded + withAnimation { self.snippets = decoded } } func saveSnippets() { diff --git a/ShhShell/Views/Snippets/AddSnippetView.swift b/ShhShell/Views/Snippets/AddSnippetView.swift new file mode 100644 index 0000000..b1a2235 --- /dev/null +++ b/ShhShell/Views/Snippets/AddSnippetView.swift @@ -0,0 +1,64 @@ +// +// AddSnippetView.swift +// ShhShell +// +// Created by neon443 on 22/07/2025. +// + +import SwiftUI + +struct AddSnippetView: View { + @ObservedObject var hostsManager: HostsManager + @State var name: String = "" + @State var content: String = "" + + var snippet: Snippet { + Snippet(name: name, content: content) + } + + @Environment(\.dismiss) var dismiss + @Environment(\.colorScheme) var colorScheme + + var body: some View { + NavigationStack { + List { + TextBox(label: "Name", text: $name, prompt: "") + + VStack { + Text("Content") + .padding(.top) + .foregroundStyle(.gray) + .listRowSeparator(.hidden) + .multilineTextAlignment(.leading) + TextEditor(text: $content) + .autocorrectionDisabled() + .textInputAutocapitalization(.never) + .background(.black) + .clipShape(RoundedRectangle(cornerRadius: 5)) + .padding(.bottom) + .frame(minHeight: 50) + } + .toolbar { + ToolbarItem(placement: .topBarLeading) { + Button { + dismiss() + } label: { + Label("Cancel", systemImage: "xmark") + } + } + ToolbarItem(placement: .topBarTrailing) { + Button { + hostsManager.addSnippet(snippet) + } label: { + Label("Add", systemImage: "plus") + } + } + } + } + } + } +} + +#Preview { + AddSnippetView(hostsManager: HostsManager()) +} diff --git a/ShhShell/Views/Snippets/SnippetManagerView.swift b/ShhShell/Views/Snippets/SnippetManagerView.swift index f085008..3aad89a 100644 --- a/ShhShell/Views/Snippets/SnippetManagerView.swift +++ b/ShhShell/Views/Snippets/SnippetManagerView.swift @@ -9,16 +9,50 @@ import SwiftUI struct SnippetManagerView: View { @ObservedObject var hostsManager: HostsManager + @State var showSnippetAdder: Bool = false var body: some View { - ForEach(hostsManager.snippets) { snip in - Text(snip.name) - .bold() - .font(.subheadline) - Text(snip.content) - } - .toolbar { - + ZStack { + hostsManager.selectedTheme.background.suiColor.opacity(0.7) + .ignoresSafeArea(.all) + NavigationStack { + List { + ForEach(hostsManager.snippets) { snip in + Group { + Text(snip.name) + .bold() + .font(.subheadline) + Text(snip.content) + } + .swipeActions(edge: .trailing) { + Button(role: .destructive) { + hostsManager.deleteSnippet(snip) + } label: { + Label("Delete", systemImage: "trash") + } + .tint(.red) + Button { + hostsManager.duplicateSnippet(snip) + } label: { + Label("Duplicate", systemImage: "square.filled.on.square") + } + .tint(.blue) + } + } + } + .scrollContentBackground(.hidden) + .sheet(isPresented: $showSnippetAdder) { + AddSnippetView(hostsManager: hostsManager) + .presentationDetents([.medium]) + } + .toolbar { + Button() { + showSnippetAdder.toggle() + } label: { + Label("Add", systemImage: "plus") + } + } + } } } }