mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
added a prompt to TextBox
fix right alignment in textbox added quick connect fix blank keys being returned from getKeys() safely unwrap keys in keydetailview swap buttons on shellview's titlbar
This commit is contained in:
@@ -185,6 +185,7 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
||||
func getKeys() -> [Keypair] {
|
||||
var result: [Keypair] = []
|
||||
for host in hosts {
|
||||
guard host.privateKey != nil && host.publicKey != nil else { continue }
|
||||
let keypair = Keypair(publicKey: host.publicKey, privateKey: host.privateKey)
|
||||
if !result.contains(keypair) {
|
||||
result.append(keypair)
|
||||
|
||||
@@ -51,34 +51,35 @@ struct ConnectionView: View {
|
||||
.id(handler.host)
|
||||
.frame(width: 60, height: 60)
|
||||
|
||||
TextBox(label: "Icon Text", text: $handler.host.label)
|
||||
TextBox(label: "Icon Text", text: $handler.host.label, prompt: "a few letters in the icon")
|
||||
}
|
||||
}
|
||||
Section {
|
||||
Text("\(handler.state)")
|
||||
.foregroundStyle(handler.state.color)
|
||||
|
||||
TextBox(label: "Name", text: $handler.host.name)
|
||||
TextBox(label: "Name", text: $handler.host.name, prompt: "defaults to host address")
|
||||
|
||||
TextBox(label: "Address", text: $handler.host.address)
|
||||
TextBox(label: "Address", text: $handler.host.address, prompt: "required")
|
||||
|
||||
TextBox(label: "Port", text: Binding(
|
||||
get: { String(handler.host.port) },
|
||||
set: {
|
||||
if let input = Int($0) {
|
||||
handler.host.port = input
|
||||
}
|
||||
}),
|
||||
get: { String(handler.host.port) },
|
||||
set: {
|
||||
if let input = Int($0) {
|
||||
handler.host.port = input
|
||||
}
|
||||
}),
|
||||
prompt: "most likely 22",
|
||||
keyboardType: .numberPad
|
||||
)
|
||||
}
|
||||
|
||||
Section {
|
||||
TextBox(label: "Username", text: $handler.host.username)
|
||||
TextBox(label: "Username", text: $handler.host.username, prompt: "required")
|
||||
|
||||
TextBox(label: "Password", text: $handler.host.password, secure: true)
|
||||
TextBox(label: "Password", text: $handler.host.password, prompt: "not required if using publickeys", secure: true)
|
||||
|
||||
TextBox(label: "Publickey", text: $pubkeyStr)
|
||||
TextBox(label: "Publickey", text: $pubkeyStr, prompt: "in openssh format")
|
||||
.onChange(of: pubkeyStr) { _ in
|
||||
let newStr = pubkeyStr.replacingOccurrences(of: "\r\n", with: "")
|
||||
handler.host.publicKey = Data(newStr.utf8)
|
||||
@@ -88,7 +89,7 @@ struct ConnectionView: View {
|
||||
handler.host.publicKey = Data(newStr.utf8)
|
||||
}
|
||||
|
||||
TextBox(label: "Privatekey", text: $privkeyStr, secure: true)
|
||||
TextBox(label: "Privatekey", text: $privkeyStr, prompt: "required if using publickeys", secure: true)
|
||||
.onSubmit {
|
||||
let newStr = privkeyStr.replacingOccurrences(of: "\r\n", with: "")
|
||||
handler.host.privateKey = Data(newStr.utf8)
|
||||
@@ -98,7 +99,7 @@ struct ConnectionView: View {
|
||||
handler.host.privateKey = Data(newStr.utf8)
|
||||
}
|
||||
|
||||
TextBox(label: "Passphrase", text: $handler.host.passphrase)
|
||||
TextBox(label: "Passphrase", text: $handler.host.passphrase, prompt: "optional")
|
||||
}
|
||||
|
||||
Button() {
|
||||
|
||||
@@ -32,6 +32,24 @@ struct HostsView: View {
|
||||
}
|
||||
.id(host)
|
||||
.animation(.default, value: host)
|
||||
.fullScreenCover(
|
||||
isPresented: Binding(
|
||||
get: { checkShell(handler.state) },
|
||||
set: { newValue in
|
||||
handler.go()
|
||||
}
|
||||
)
|
||||
) {
|
||||
ShellView(handler: handler, hostsManager: hostsManager)
|
||||
}
|
||||
.swipeActions(edge: .leading) {
|
||||
Button() {
|
||||
handler.go()
|
||||
} label: {
|
||||
Label("Quick Connect", systemImage: "power")
|
||||
}
|
||||
.foregroundStyle(.green)
|
||||
}
|
||||
.swipeActions(edge: .trailing) {
|
||||
Button(role: .destructive) {
|
||||
hostsManager.removeHost(host)
|
||||
@@ -43,6 +61,7 @@ struct HostsView: View {
|
||||
} label: {
|
||||
Label("Duplicate", systemImage: "square.filled.on.square")
|
||||
}
|
||||
.foregroundStyle(.blue)
|
||||
}
|
||||
}
|
||||
.onMove(perform: {
|
||||
|
||||
@@ -12,6 +12,13 @@ struct KeyDetailView: View {
|
||||
@State var keypair: Keypair
|
||||
@State private var reveal: Bool = false
|
||||
|
||||
var publicKey: Data {
|
||||
return keypair.publicKey ?? "".data(using: .utf8)!
|
||||
}
|
||||
var privateKey: Data {
|
||||
return keypair.privateKey ?? "".data(using: .utf8)!
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
||||
@@ -31,14 +38,14 @@ struct KeyDetailView: View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Public key")
|
||||
.bold()
|
||||
Text(String(data: keypair.publicKey!, encoding: .utf8) ?? "nil")
|
||||
Text(String(data: publicKey, encoding: .utf8) ?? "nil")
|
||||
}
|
||||
VStack(alignment: .leading) {
|
||||
Text("Private key")
|
||||
.bold()
|
||||
.frame(maxWidth: .infinity)
|
||||
ZStack(alignment: .center) {
|
||||
Text(String(data: keypair.privateKey!, encoding: .utf8) ?? "nil")
|
||||
Text(String(data: privateKey, encoding: .utf8) ?? "nil")
|
||||
.blur(radius: reveal ? 0 : 5)
|
||||
VStack {
|
||||
Image(systemName: "eye.slash.fill")
|
||||
@@ -62,9 +69,7 @@ struct KeyDetailView: View {
|
||||
Button {
|
||||
Task {
|
||||
guard await hostsManager.authWithBiometrics() else { return }
|
||||
if let privateKey = keypair.privateKey {
|
||||
UIPasteboard.general.string = String(data: privateKey, encoding: .utf8)
|
||||
}
|
||||
UIPasteboard.general.string = String(data: privateKey, encoding: .utf8)
|
||||
}
|
||||
} label: {
|
||||
CenteredLabel(title: "Copy private key", systemName: "document.on.document")
|
||||
|
||||
@@ -10,22 +10,24 @@ import SwiftUI
|
||||
struct TextBox: View {
|
||||
@State var label: String
|
||||
@Binding var text: String
|
||||
@State var prompt: String
|
||||
@State var secure: Bool = false
|
||||
@State var keyboardType: UIKeyboardType = .default
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(label)
|
||||
Spacer()
|
||||
if secure {
|
||||
SecureField("", text: $text)
|
||||
SecureField("", text: $text, prompt: Text(prompt))
|
||||
.multilineTextAlignment(.trailing)
|
||||
} else {
|
||||
TextField("", text: $text)
|
||||
TextField("", text: $text, prompt: Text(prompt))
|
||||
.multilineTextAlignment(.trailing)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TextBox(label: "Label", text: .constant("asdflkajsdl"))
|
||||
TextBox(label: "Label", text: .constant("asdflkajsdl"), prompt: "")
|
||||
}
|
||||
|
||||
@@ -47,13 +47,6 @@ struct ShellView: View {
|
||||
.navigationTitle(handler.title)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button() {
|
||||
dismiss()
|
||||
} label: {
|
||||
Label("Close", systemImage: "arrow.down.right.and.arrow.up.left")
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button() {
|
||||
handler.disconnect()
|
||||
@@ -62,6 +55,13 @@ struct ShellView: View {
|
||||
Label("Disconnect", systemImage: "xmark.app.fill")
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button() {
|
||||
dismiss()
|
||||
} label: {
|
||||
Label("Close", systemImage: "arrow.down.right.and.arrow.up.left")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user