diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index 39f6475..9149f90 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -73,6 +73,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 */; }; + A98CAB442E4229F7005E4C42 /* HostIconPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98CAB432E4229F7005E4C42 /* HostIconPicker.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 */; }; @@ -204,6 +205,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 = ""; }; + A98CAB432E4229F7005E4C42 /* HostIconPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostIconPicker.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 = ""; }; @@ -518,6 +520,7 @@ children = ( A98554622E0587DF009051BD /* HostsView.swift */, A985545C2E055D4D009051BD /* ConnectionView.swift */, + A98CAB432E4229F7005E4C42 /* HostIconPicker.swift */, ); path = Hosts; sourceTree = ""; @@ -804,6 +807,7 @@ A96C6B002E0C45FE00F377FE /* KeyDetailView.swift in Sources */, A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */, A96C90A12E12B87A00724253 /* TextBox.swift in Sources */, + A98CAB442E4229F7005E4C42 /* HostIconPicker.swift in Sources */, A9FD37652E169937005319A8 /* AuthType.swift in Sources */, A96BE6A82E116E2B00C0FEE9 /* SessionsListView.swift in Sources */, A96C90A32E12D53B00724253 /* KeyType.swift in Sources */, diff --git a/ShhShell/Views/Hosts/ConnectionView.swift b/ShhShell/Views/Hosts/ConnectionView.swift index 1dad412..610e662 100644 --- a/ShhShell/Views/Hosts/ConnectionView.swift +++ b/ShhShell/Views/Hosts/ConnectionView.swift @@ -16,40 +16,13 @@ struct ConnectionView: View { @State var privkeyStr: String = "" @State var showTerminal: Bool = false + @State var showIconPicker: Bool = false var body: some View { ZStack { hostsManager.selectedTheme.background.suiColor.opacity(0.7) .ignoresSafeArea(.all) List { - Section { - ScrollView(.horizontal) { - HStack { - ForEach(HostSymbol.allCases, id: \.self) { symbol in - ZStack { - if handler.host.symbol == symbol { - RoundedRectangle(cornerRadius: 10) - .fill(.gray.opacity(0.5)) - } - HostSymbolPreview(symbol: symbol, label: handler.host.label) - .padding(5) - } - .frame(width: 60, height: 60) - .onTapGesture { - withAnimation { handler.host.symbol = symbol } - } - } - } - } - - HStack { - HostSymbolPreview(symbol: handler.host.symbol, label: handler.host.label) - .id(handler.host) - .frame(width: 60, height: 60) - - TextBox(label: "Icon Text", text: $handler.host.label, prompt: "a few letters in the icon") - } - } Section { Text("\(handler.state)") .foregroundStyle(handler.state.color) @@ -138,7 +111,21 @@ Hostkey fingerprint is \(handler.getHostkey() ?? "nil") """) } } + .popover(isPresented: $showIconPicker, attachmentAnchor: .point(.center), arrowEdge: .bottom) { + HostIconPicker(host: $handler.host) + .frame(minWidth: 300, minHeight: 200) + .modifier(presentationCompactPopover()) + } .toolbar { + ToolbarItem { + Button() { + showIconPicker.toggle() + } label: { + HostSymbolPreview(symbol: handler.host.symbol, label: handler.host.label, small: true) + .id(handler.host) + } + } + ToolbarItem() { Button() { handler.go() diff --git a/ShhShell/Views/Hosts/HostIconPicker.swift b/ShhShell/Views/Hosts/HostIconPicker.swift new file mode 100644 index 0000000..597d119 --- /dev/null +++ b/ShhShell/Views/Hosts/HostIconPicker.swift @@ -0,0 +1,40 @@ +// +// HostIconPicker.swift +// ShhShell +// +// Created by neon443 on 05/08/2025. +// + +import SwiftUI + +struct HostIconPicker: View { + @Binding var host: Host + + var body: some View { + List { + ScrollView(.horizontal) { + HStack { + ForEach(HostSymbol.allCases, id: \.self) { symbol in + ZStack { + if host.symbol == symbol { + RoundedRectangle(cornerRadius: 10) + .fill(.gray.opacity(0.5)) + } + HostSymbolPreview(symbol: symbol, label: host.label) + .padding(5) + } + .frame(width: 50, height: 50) + .onTapGesture { + withAnimation { host.symbol = symbol } + } + } + } + } + TextBox(label: "Icon Text", text: $host.label, prompt: "") + } + } +} + +#Preview { + HostIconPicker(host: .constant(Host.debug)) +} diff --git a/ShhShell/Views/Misc/HostSymbolPreview.swift b/ShhShell/Views/Misc/HostSymbolPreview.swift index 2d5b563..8209c03 100644 --- a/ShhShell/Views/Misc/HostSymbolPreview.swift +++ b/ShhShell/Views/Misc/HostSymbolPreview.swift @@ -10,21 +10,38 @@ import SwiftUI struct HostSymbolPreview: View { @State var symbol: HostSymbol @State var label: String + @State var small: Bool = false - var body: some View { - ZStack(alignment: .center) { - symbol.image - .resizable().scaledToFit() - .symbolRenderingMode(.monochrome) - .blur(radius: 1) - symbol.image - .resizable().scaledToFit() - .symbolRenderingMode(.monochrome) - Text(label) - .font(.headline) - .offset(symbol.offset) + var body: some View { + if small { + HStack(alignment: .center, spacing: 5) { + Text(label) + .font(.headline) + ZStack(alignment: .center) { + symbol.image + .resizable().scaledToFit() + .symbolRenderingMode(.monochrome) + .blur(radius: 1) + symbol.image + .resizable().scaledToFit() + .symbolRenderingMode(.monochrome) + } + } + } else { + ZStack(alignment: .center) { + symbol.image + .resizable().scaledToFit() + .symbolRenderingMode(.monochrome) + .blur(radius: 1) + symbol.image + .resizable().scaledToFit() + .symbolRenderingMode(.monochrome) + Text(label) + .font(.headline) + .offset(symbol.offset) + } } - } + } } #Preview {