mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 05:19:13 +00:00
fix the key, hostskeys, snippet views being black sometimes
This commit is contained in:
@@ -14,58 +14,56 @@ struct HostkeysView: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
||||||
.ignoresSafeArea(.all)
|
.ignoresSafeArea(.all)
|
||||||
NavigationStack {
|
List {
|
||||||
List {
|
if hostsManager.hosts.isEmpty {
|
||||||
if hostsManager.hosts.isEmpty {
|
VStack(alignment: .leading) {
|
||||||
|
Text("Looking empty 'round here...")
|
||||||
|
.font(.title3)
|
||||||
|
.bold()
|
||||||
|
.padding(.bottom)
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text("Looking empty 'round here...")
|
Text("Connect to some hosts to collect more hostkeys!")
|
||||||
.font(.title3)
|
|
||||||
.bold()
|
|
||||||
.padding(.bottom)
|
.padding(.bottom)
|
||||||
VStack(alignment: .leading) {
|
Text("ShhShell remembers hostkey fingerprints for you, and will alert you if they change.")
|
||||||
Text("Connect to some hosts to collect more hostkeys!")
|
.font(.subheadline)
|
||||||
.padding(.bottom)
|
Text("This could be due a man in the middle attack, where a bad actor tries to impersonate your server.")
|
||||||
Text("ShhShell remembers hostkey fingerprints for you, and will alert you if they change.")
|
.font(.subheadline)
|
||||||
.font(.subheadline)
|
}
|
||||||
Text("This could be due a man in the middle attack, where a bad actor tries to impersonate your server.")
|
}
|
||||||
.font(.subheadline)
|
}
|
||||||
}
|
|
||||||
}
|
ForEach($hostsManager.hosts) { $host in
|
||||||
}
|
VStack(alignment: .leading) {
|
||||||
|
if !host.name.isEmpty {
|
||||||
ForEach($hostsManager.hosts) { $host in
|
Text("name")
|
||||||
VStack(alignment: .leading) {
|
.foregroundStyle(.gray)
|
||||||
if !host.name.isEmpty {
|
.font(.caption)
|
||||||
Text("name")
|
Text(host.name)
|
||||||
.foregroundStyle(.gray)
|
.bold()
|
||||||
.font(.caption)
|
}
|
||||||
Text(host.name)
|
Text("address")
|
||||||
.bold()
|
.foregroundStyle(.gray)
|
||||||
}
|
.font(.caption)
|
||||||
Text("address")
|
Text(host.address)
|
||||||
.foregroundStyle(.gray)
|
.bold()
|
||||||
.font(.caption)
|
Text(host.key ?? "nil")
|
||||||
Text(host.address)
|
}
|
||||||
.bold()
|
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||||
Text(host.key ?? "nil")
|
Button(/*role: .destructive*/) {
|
||||||
}
|
host.key = nil
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
hostsManager.updateHost(host)
|
||||||
Button(/*role: .destructive*/) {
|
} label: {
|
||||||
host.key = nil
|
Label("Forget", systemImage: "trash")
|
||||||
hostsManager.updateHost(host)
|
|
||||||
} label: {
|
|
||||||
Label("Forget", systemImage: "trash")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
.navigationTitle("Hostkeys")
|
|
||||||
}
|
}
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
.navigationTitle("Hostkeys")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
HostkeysView(hostsManager: HostsManager())
|
HostkeysView(hostsManager: HostsManager())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,59 +17,57 @@ struct KeyManagerView: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
||||||
.ignoresSafeArea(.all)
|
.ignoresSafeArea(.all)
|
||||||
NavigationStack {
|
List {
|
||||||
List {
|
Section() {
|
||||||
Section() {
|
ForEach(keyManager.keypairs) { kp in
|
||||||
ForEach(keyManager.keypairs) { kp in
|
NavigationLink {
|
||||||
NavigationLink {
|
KeyDetailView(
|
||||||
KeyDetailView(
|
hostsManager: hostsManager,
|
||||||
hostsManager: hostsManager,
|
keyManager: keyManager,
|
||||||
keyManager: keyManager,
|
keypair: kp
|
||||||
keypair: kp
|
)
|
||||||
)
|
} label: {
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "key")
|
||||||
|
if kp.label.isEmpty {
|
||||||
|
Text(kp.id.uuidString)
|
||||||
|
} else {
|
||||||
|
Text(kp.label)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
Text(kp.type.description)
|
||||||
|
.foregroundStyle(.gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.swipeActions(edge: .trailing) {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
keyManager.deleteKey(kp)
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
Label("Delete", systemImage: "trash")
|
||||||
Image(systemName: "key")
|
|
||||||
if kp.label.isEmpty {
|
|
||||||
Text(kp.id.uuidString)
|
|
||||||
} else {
|
|
||||||
Text(kp.label)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
Text(kp.type.description)
|
|
||||||
.foregroundStyle(.gray)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.swipeActions(edge: .trailing) {
|
|
||||||
Button(role: .destructive) {
|
|
||||||
keyManager.deleteKey(kp)
|
|
||||||
} label: {
|
|
||||||
Label("Delete", systemImage: "trash")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.id(keyManager.keypairs)
|
|
||||||
}
|
}
|
||||||
|
.id(keyManager.keypairs)
|
||||||
CenteredLabel(title: "Generate a key", systemName: "plus")
|
|
||||||
.onTapGesture {
|
|
||||||
let comment = UIDevice().model + " at " + Date().formatted(date: .numeric, time: .omitted)
|
|
||||||
keyManager.generateKey(type: .ed25519, comment: comment)
|
|
||||||
}
|
|
||||||
.listRowSeparator(.hidden)
|
|
||||||
|
|
||||||
CenteredLabel(title: "Import a key", systemName: "square.and.arrow.down")
|
|
||||||
.onTapGesture {
|
|
||||||
showImporter.toggle()
|
|
||||||
}
|
|
||||||
.sheet(isPresented: $showImporter) {
|
|
||||||
KeyImporterView(keyManager: keyManager)
|
|
||||||
.colorScheme(hostsManager.selectedTheme.background.luminance > 0.5 ? .light : .dark)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
.navigationTitle("Keys")
|
CenteredLabel(title: "Generate a key", systemName: "plus")
|
||||||
|
.onTapGesture {
|
||||||
|
let comment = UIDevice().model + " at " + Date().formatted(date: .numeric, time: .omitted)
|
||||||
|
keyManager.generateKey(type: .ed25519, comment: comment)
|
||||||
|
}
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
|
|
||||||
|
CenteredLabel(title: "Import a key", systemName: "square.and.arrow.down")
|
||||||
|
.onTapGesture {
|
||||||
|
showImporter.toggle()
|
||||||
|
}
|
||||||
|
.sheet(isPresented: $showImporter) {
|
||||||
|
KeyImporterView(keyManager: keyManager)
|
||||||
|
.colorScheme(hostsManager.selectedTheme.background.luminance > 0.5 ? .light : .dark)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
.navigationTitle("Keys")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,79 +11,77 @@ struct SnippetManagerView: View {
|
|||||||
@ObservedObject var hostsManager: HostsManager
|
@ObservedObject var hostsManager: HostsManager
|
||||||
@State var showSnippetAdder: Bool = false
|
@State var showSnippetAdder: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
||||||
.ignoresSafeArea(.all)
|
.ignoresSafeArea(.all)
|
||||||
NavigationStack {
|
List {
|
||||||
List {
|
if hostsManager.snippets.isEmpty {
|
||||||
if hostsManager.snippets.isEmpty {
|
VStack(alignment: .leading) {
|
||||||
VStack(alignment: .leading) {
|
Image(systemName: "questionmark.square.dashed")
|
||||||
Image(systemName: "questionmark.square.dashed")
|
.resizable().scaledToFit()
|
||||||
.resizable().scaledToFit()
|
.frame(width: 75)
|
||||||
.frame(width: 75)
|
.foregroundStyle(hostsManager.tint)
|
||||||
.foregroundStyle(hostsManager.tint)
|
.shadow(color: hostsManager.tint, radius: 2)
|
||||||
.shadow(color: hostsManager.tint, radius: 2)
|
.padding(.bottom, 10)
|
||||||
.padding(.bottom, 10)
|
Text("No Snippets")
|
||||||
Text("No Snippets")
|
.font(.title)
|
||||||
.font(.title)
|
.monospaced()
|
||||||
.monospaced()
|
Text("Snippets are strings of commands that can be run at once in a terminal.")
|
||||||
Text("Snippets are strings of commands that can be run at once in a terminal.")
|
.padding(.bottom)
|
||||||
.padding(.bottom)
|
.foregroundStyle(.gray)
|
||||||
.foregroundStyle(.gray)
|
.foregroundStyle(.foreground.opacity(0.7))
|
||||||
.foregroundStyle(.foreground.opacity(0.7))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ForEach(hostsManager.snippets) { snip in
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text(snip.name)
|
|
||||||
.bold()
|
|
||||||
.foregroundStyle(.gray)
|
|
||||||
.font(.subheadline)
|
|
||||||
Text(snip.content)
|
|
||||||
.lineLimit(3)
|
|
||||||
}
|
|
||||||
.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)
|
|
||||||
Button {
|
|
||||||
UIPasteboard().string = snip.content
|
|
||||||
} label: {
|
|
||||||
Label("Copy", systemImage: "doc.on.clipboard")
|
|
||||||
}
|
|
||||||
.tint(.blue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
ForEach(hostsManager.snippets) { snip in
|
||||||
.sheet(isPresented: $showSnippetAdder) {
|
VStack(alignment: .leading) {
|
||||||
AddSnippetView(hostsManager: hostsManager)
|
Text(snip.name)
|
||||||
.presentationDetents([.medium])
|
.bold()
|
||||||
}
|
.foregroundStyle(.gray)
|
||||||
.toolbar {
|
.font(.subheadline)
|
||||||
Button() {
|
Text(snip.content)
|
||||||
showSnippetAdder.toggle()
|
.lineLimit(3)
|
||||||
} label: {
|
|
||||||
Label("Add", systemImage: "plus")
|
|
||||||
}
|
}
|
||||||
|
.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)
|
||||||
|
Button {
|
||||||
|
UIPasteboard().string = snip.content
|
||||||
|
} label: {
|
||||||
|
Label("Copy", systemImage: "doc.on.clipboard")
|
||||||
|
}
|
||||||
|
.tint(.blue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
.sheet(isPresented: $showSnippetAdder) {
|
||||||
|
AddSnippetView(hostsManager: hostsManager)
|
||||||
|
.presentationDetents([.medium])
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
Button() {
|
||||||
|
showSnippetAdder.toggle()
|
||||||
|
} label: {
|
||||||
|
Label("Add", systemImage: "plus")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("Snippets")
|
.navigationTitle("Snippets")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
SnippetManagerView(hostsManager: HostsManager())
|
SnippetManagerView(hostsManager: HostsManager())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user