mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-04-18 05:22:11 +00:00
Lots more SwiftUI cleanup.
This commit is contained in:
parent
c2fc71d299
commit
54d7fbe88d
@ -21,14 +21,14 @@ struct AppDelegate: App {
|
|||||||
|
|
||||||
@SceneBuilder var body: some Scene {
|
@SceneBuilder var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView<Updater, AgentStatusChecker>()
|
ContentView<Updater, AgentStatusChecker>(runningSetup: $showingSetup)
|
||||||
.environmentObject(storeList)
|
.environmentObject(storeList)
|
||||||
.environmentObject(updater)
|
.environmentObject(updater)
|
||||||
.environmentObject(agentStatusChecker)
|
.environmentObject(agentStatusChecker)
|
||||||
.sheet(isPresented: $showingSetup) {
|
.sheet(isPresented: $showingSetup) {
|
||||||
SetupView { completed in
|
SetupView { completed in
|
||||||
self.showingSetup = false
|
showingSetup = false
|
||||||
self.hasRunSetup = completed
|
hasRunSetup = completed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
@ -51,7 +51,7 @@ struct AppDelegate: App {
|
|||||||
}
|
}
|
||||||
CommandGroup(after: .help) {
|
CommandGroup(after: .help) {
|
||||||
Button("Setup Secret Agent") {
|
Button("Setup Secret Agent") {
|
||||||
self.showingSetup = true
|
showingSetup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,39 +7,40 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
|
|||||||
@EnvironmentObject var storeList: SecretStoreList
|
@EnvironmentObject var storeList: SecretStoreList
|
||||||
@EnvironmentObject var updater: UpdaterType
|
@EnvironmentObject var updater: UpdaterType
|
||||||
@EnvironmentObject var agentStatusChecker: AgentStatusCheckerType
|
@EnvironmentObject var agentStatusChecker: AgentStatusCheckerType
|
||||||
var runSetupBlock: (() -> Void)?
|
|
||||||
|
|
||||||
@State private var active: AnySecret.ID?
|
@State private var active: AnySecret.ID?
|
||||||
@State private var showingCreation = false
|
@State private var showingCreation = false
|
||||||
@State private var deletingSecret: AnySecret?
|
@State private var deletingSecret: AnySecret?
|
||||||
@State private var selectedUpdate: Release?
|
@State private var selectedUpdate: Release?
|
||||||
|
@Binding var runningSetup: Bool
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
if storeList.anyAvailable {
|
if storeList.anyAvailable {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
List(selection: $active) {
|
List(selection: $active) {
|
||||||
ForEach(storeList.stores) { store in
|
ForEach(storeList.stores) { store in
|
||||||
if store.isAvailable {
|
if store.isAvailable {
|
||||||
Section(header: Text(store.name)) {
|
Section(header: Text(store.name)) {
|
||||||
if store.secrets.isEmpty {
|
if store.secrets.isEmpty {
|
||||||
if store is AnySecretStoreModifiable {
|
if store is AnySecretStoreModifiable {
|
||||||
NavigationLink(destination: EmptyStoreModifiableView(), tag: Constants.emptyStoreModifiableTag, selection: self.$active) {
|
NavigationLink(destination: EmptyStoreModifiableView(), tag: Constants.emptyStoreModifiableTag, selection: $active) {
|
||||||
Text("No Secrets")
|
Text("No Secrets")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NavigationLink(destination: EmptyStoreView(), tag: Constants.emptyStoreTag, selection: $active) {
|
||||||
|
Text("No Secrets")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NavigationLink(destination: EmptyStoreView(), tag: Constants.emptyStoreTag, selection: self.$active) {
|
ForEach(store.secrets) { secret in
|
||||||
Text("No Secrets")
|
NavigationLink(destination: SecretDetailView(secret: secret), tag: secret.id, selection: $active) {
|
||||||
}
|
Text(secret.name)
|
||||||
}
|
}.contextMenu {
|
||||||
} else {
|
if store is AnySecretStoreModifiable {
|
||||||
ForEach(store.secrets) { secret in
|
Button(action: { delete(secret: secret) }) {
|
||||||
NavigationLink(destination: SecretDetailView(secret: secret), tag: secret.id, selection: self.$active) {
|
Text("Delete")
|
||||||
Text(secret.name)
|
}
|
||||||
}.contextMenu {
|
|
||||||
if store is AnySecretStoreModifiable {
|
|
||||||
Button(action: { self.delete(secret: secret) }) {
|
|
||||||
Text("Delete")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,42 +48,35 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}.onAppear {
|
||||||
|
active = nextDefaultSecret
|
||||||
}
|
}
|
||||||
}.onAppear {
|
.frame(minWidth: 100, idealWidth: 240)
|
||||||
self.active = self.nextDefaultSecret
|
.sheet(item: $deletingSecret) { secret in
|
||||||
}
|
if storeList.modifiableStore != nil {
|
||||||
.frame(minWidth: 100, idealWidth: 240)
|
DeleteSecretView(secret: secret, store: storeList.modifiableStore!) { deleted in
|
||||||
.sheet(item: $deletingSecret) { secret in
|
deletingSecret = nil
|
||||||
if self.storeList.modifiableStore != nil {
|
if deleted {
|
||||||
DeleteSecretView(secret: secret, store: self.storeList.modifiableStore!) { deleted in
|
active = nextDefaultSecret
|
||||||
self.deletingSecret = nil
|
}
|
||||||
if deleted {
|
|
||||||
self.active = self.nextDefaultSecret
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
NoStoresView()
|
NoStoresView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $showingCreation) {
|
.sheet(isPresented: $showingCreation) {
|
||||||
CreateSecretView {
|
CreateSecretView(showing: $showingCreation)
|
||||||
self.showingCreation = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.frame(minWidth: 640, minHeight: 320)
|
.frame(minWidth: 640, minHeight: 320)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
// if updater.update != nil {
|
updateNotice
|
||||||
updateNotice()
|
agentNotice
|
||||||
// }
|
|
||||||
// if !agentStatusChecker.running {
|
|
||||||
// agentNotice()z
|
|
||||||
// }
|
|
||||||
ToolbarItem {
|
ToolbarItem {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.showingCreation = true
|
showingCreation = true
|
||||||
}, label: {
|
}, label: {
|
||||||
Image(systemName: "plus")
|
Image(systemName: "plus")
|
||||||
})
|
})
|
||||||
@ -90,12 +84,9 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNotice() -> ToolbarItem<Void, AnyView> {
|
var updateNotice: ToolbarItem<Void, AnyView> {
|
||||||
// let update = updater.update ?? Release(name: "", html_url: URL(string:"https://example.com")!, body: "")
|
|
||||||
guard let update = updater.update else {
|
guard let update = updater.update else {
|
||||||
return ToolbarItem {
|
return ToolbarItem { AnyView(Spacer()) }
|
||||||
AnyView(Spacer())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let color: Color
|
let color: Color
|
||||||
let text: String
|
let text: String
|
||||||
@ -108,7 +99,7 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
|
|||||||
}
|
}
|
||||||
return ToolbarItem {
|
return ToolbarItem {
|
||||||
AnyView(Button(action: {
|
AnyView(Button(action: {
|
||||||
self.selectedUpdate = update
|
selectedUpdate = update
|
||||||
}, label: {
|
}, label: {
|
||||||
Text(text)
|
Text(text)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
@ -122,20 +113,25 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// func agentNotice() -> ToolbarItem<Void, AnyView> {
|
var agentNotice: ToolbarItem<Void, AnyView> {
|
||||||
// ToolbarItem {
|
guard agentStatusChecker.running else {
|
||||||
// Button(action: {
|
return ToolbarItem { AnyView(Spacer()) }
|
||||||
// self.runSetupBlock?()
|
}
|
||||||
// }, label: {
|
return ToolbarItem {
|
||||||
// Text("Agent is not running.")
|
AnyView(
|
||||||
// .font(.headline)
|
Button(action: {
|
||||||
// .foregroundColor(.white)
|
runningSetup = true
|
||||||
// })
|
}, label: {
|
||||||
// .background(Color.orange)
|
Text("Secret Agent Is Not Running")
|
||||||
// .cornerRadius(5)
|
.font(.headline)
|
||||||
// }
|
.foregroundColor(.white)
|
||||||
// }
|
})
|
||||||
|
.background(Color.orange)
|
||||||
|
.cornerRadius(5)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func delete<SecretType: Secret>(secret: SecretType) {
|
func delete<SecretType: Secret>(secret: SecretType) {
|
||||||
deletingSecret = AnySecret(secret)
|
deletingSecret = AnySecret(secret)
|
||||||
@ -143,12 +139,12 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
|
|||||||
|
|
||||||
var nextDefaultSecret: AnyHashable? {
|
var nextDefaultSecret: AnyHashable? {
|
||||||
let fallback: AnyHashable
|
let fallback: AnyHashable
|
||||||
if self.storeList.modifiableStore?.isAvailable ?? false {
|
if storeList.modifiableStore?.isAvailable ?? false {
|
||||||
fallback = Constants.emptyStoreModifiableTag
|
fallback = Constants.emptyStoreModifiableTag
|
||||||
} else {
|
} else {
|
||||||
fallback = Constants.emptyStoreTag
|
fallback = Constants.emptyStoreTag
|
||||||
}
|
}
|
||||||
return self.storeList.stores.compactMap(\.secrets.first).first?.id ?? fallback
|
return storeList.stores.compactMap(\.secrets.first).first?.id ?? fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,8 @@ struct CreateSecretView: View {
|
|||||||
|
|
||||||
@State var name = ""
|
@State var name = ""
|
||||||
@State var requiresAuthentication = true
|
@State var requiresAuthentication = true
|
||||||
|
@Binding var showing: Bool
|
||||||
var dismissalBlock: () -> ()
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
@ -36,8 +35,10 @@ struct CreateSecretView: View {
|
|||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("Cancel", action: dismissalBlock)
|
Button("Cancel") {
|
||||||
.keyboardShortcut(.cancelAction)
|
showing = false
|
||||||
|
}
|
||||||
|
.keyboardShortcut(.cancelAction)
|
||||||
Button("Create", action: save)
|
Button("Create", action: save)
|
||||||
.disabled(name.isEmpty)
|
.disabled(name.isEmpty)
|
||||||
.keyboardShortcut(.defaultAction)
|
.keyboardShortcut(.defaultAction)
|
||||||
@ -47,6 +48,6 @@ struct CreateSecretView: View {
|
|||||||
|
|
||||||
func save() {
|
func save() {
|
||||||
try! store.create(name: name, requiresAuthentication: requiresAuthentication)
|
try! store.create(name: name, requiresAuthentication: requiresAuthentication)
|
||||||
dismissalBlock()
|
showing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onExitCommand {
|
.onExitCommand {
|
||||||
self.dismissalBlock(false)
|
dismissalBlock(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
@ -47,7 +47,7 @@ struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
.disabled(confirm != secret.name)
|
.disabled(confirm != secret.name)
|
||||||
.keyboardShortcut(.delete)
|
.keyboardShortcut(.delete)
|
||||||
Button("Don't Delete") {
|
Button("Don't Delete") {
|
||||||
self.dismissalBlock(false)
|
dismissalBlock(false)
|
||||||
}
|
}
|
||||||
.keyboardShortcut(.cancelAction)
|
.keyboardShortcut(.cancelAction)
|
||||||
}
|
}
|
||||||
@ -58,6 +58,6 @@ struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
|
|
||||||
func delete() {
|
func delete() {
|
||||||
try! store.delete(secret: secret)
|
try! store.delete(secret: secret)
|
||||||
self.dismissalBlock(true)
|
dismissalBlock(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ struct SecretDetailView<SecretType: Secret>: View {
|
|||||||
.frame(minWidth: 150, maxWidth: .infinity)
|
.frame(minWidth: 150, maxWidth: .infinity)
|
||||||
.padding()
|
.padding()
|
||||||
}.onDrag {
|
}.onDrag {
|
||||||
return NSItemProvider(item: NSData(data: self.keyWriter.openSSHFingerprint(secret: self.secret).data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
|
return NSItemProvider(item: NSData(data: keyWriter.openSSHFingerprint(secret: secret).data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
|
||||||
}
|
}
|
||||||
Spacer().frame(height: 10)
|
Spacer().frame(height: 10)
|
||||||
GroupBox(label: Text("Public Key")) {
|
GroupBox(label: Text("Public Key")) {
|
||||||
@ -35,7 +35,7 @@ struct SecretDetailView<SecretType: Secret>: View {
|
|||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.onDrag {
|
.onDrag {
|
||||||
return NSItemProvider(item: NSData(data: self.keyString.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
|
return NSItemProvider(item: NSData(data: keyString.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,17 @@ struct SetupView: View {
|
|||||||
index: 1,
|
index: 1,
|
||||||
nestedView: nil,
|
nestedView: nil,
|
||||||
actionText: "Install") {
|
actionText: "Install") {
|
||||||
self.installLaunchAgent()
|
installLaunchAgent()
|
||||||
}
|
}
|
||||||
SetupStepView(text: "Add this line to your shell config (.bashrc or .zshrc) telling SSH to talk to SecretAgent when it wants to authenticate. Drag this into your config file.",
|
SetupStepView(text: "Add this line to your shell config (.bashrc or .zshrc) telling SSH to talk to SecretAgent when it wants to authenticate. Drag this into your config file.",
|
||||||
index: 2,
|
index: 2,
|
||||||
nestedView: SetupStepCommandView(text: Constants.socketPrompt),
|
nestedView: SetupStepCommandView(text: Constants.socketPrompt),
|
||||||
actionText: "Added") {
|
actionText: "Added") {
|
||||||
self.markAsDone()
|
markAsDone()
|
||||||
}
|
}
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button(action: { self.completion?(true) }) {
|
Button(action: { completion?(true) }) {
|
||||||
Text("Finish")
|
Text("Finish")
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
@ -69,7 +69,7 @@ struct SetupStepView<NestedViewType: View>: View {
|
|||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.completed = self.action()
|
completed = action()
|
||||||
}) {
|
}) {
|
||||||
Text(actionText)
|
Text(actionText)
|
||||||
}.disabled(completed)
|
}.disabled(completed)
|
||||||
@ -101,8 +101,7 @@ struct SetupStepCommandView: View {
|
|||||||
.background(Color(white: 0, opacity: 0.10))
|
.background(Color(white: 0, opacity: 0.10))
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
.onDrag {
|
.onDrag {
|
||||||
return NSItemProvider(item: NSData(data: self.text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
|
return NSItemProvider(item: NSData(data: text.data(using: .utf8)!), typeIdentifier: kUTTypeUTF8PlainText as String)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user