mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-03-06 09:47:22 +01:00
Move delete to use a confirmation dialog + various other fixes. (#645)
This commit is contained in:
24
Sources/Secretive/Views/ActionButtonStyle.swift
Normal file
24
Sources/Secretive/Views/ActionButtonStyle.swift
Normal file
@@ -0,0 +1,24 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PrimaryButtonModifier: ViewModifier {
|
||||
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
// Tinted glass prominent is really hard to read on 26.0.
|
||||
if #available(macOS 26.0, *), colorScheme == .dark {
|
||||
content.buttonStyle(.glassProminent)
|
||||
} else {
|
||||
content.buttonStyle(.borderedProminent)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension View {
|
||||
|
||||
func primary() -> some View {
|
||||
modifier(PrimaryButtonModifier())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -103,6 +103,7 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
|
||||
showing = false
|
||||
}
|
||||
Button(.createSecretCreateButton, action: save)
|
||||
.primary()
|
||||
.disabled(name.isEmpty)
|
||||
}
|
||||
.padding()
|
||||
|
||||
@@ -1,63 +1,56 @@
|
||||
import SwiftUI
|
||||
import SecretKit
|
||||
|
||||
struct DeleteSecretView<StoreType: SecretStoreModifiable>: View {
|
||||
extension View {
|
||||
|
||||
@State var store: StoreType
|
||||
let secret: StoreType.SecretType
|
||||
var dismissalBlock: (Bool) -> ()
|
||||
|
||||
@State private var confirm = ""
|
||||
@State var errorText: String?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
Image(nsImage: NSApplication.shared.applicationIconImage)
|
||||
.resizable()
|
||||
.frame(width: 64, height: 64)
|
||||
.padding()
|
||||
VStack {
|
||||
HStack {
|
||||
Text(.deleteConfirmationTitle(secretName: secret.name)).bold()
|
||||
Spacer()
|
||||
}
|
||||
HStack {
|
||||
Text(.deleteConfirmationDescription(secretName: secret.name, confirmSecretName: secret.name))
|
||||
Spacer()
|
||||
}
|
||||
HStack {
|
||||
Text(.deleteConfirmationConfirmNameLabel)
|
||||
TextField(secret.name, text: $confirm)
|
||||
}
|
||||
}
|
||||
}
|
||||
if let errorText {
|
||||
Text(verbatim: errorText)
|
||||
.foregroundStyle(.red)
|
||||
.font(.callout)
|
||||
}
|
||||
HStack {
|
||||
Spacer()
|
||||
Button(.deleteConfirmationDeleteButton, action: delete)
|
||||
.disabled(confirm != secret.name)
|
||||
Button(.deleteConfirmationCancelButton) {
|
||||
dismissalBlock(false)
|
||||
}
|
||||
.keyboardShortcut(.cancelAction)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.frame(minWidth: 400)
|
||||
.onExitCommand {
|
||||
dismissalBlock(false)
|
||||
}
|
||||
func showingDeleteConfirmation(isPresented: Binding<Bool>, _ secret: AnySecret, _ store: AnySecretStoreModifiable?, dismissalBlock: @escaping (Bool) -> ()) -> some View {
|
||||
modifier(DeleteSecretConfirmationModifier(isPresented: isPresented, secret: secret, store: store, dismissalBlock: dismissalBlock))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
struct DeleteSecretConfirmationModifier: ViewModifier {
|
||||
|
||||
var isPresented: Binding<Bool>
|
||||
var secret: AnySecret
|
||||
var store: AnySecretStoreModifiable?
|
||||
var dismissalBlock: (Bool) -> ()
|
||||
@State var confirmedSecretName = ""
|
||||
@State private var errorText: String?
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.confirmationDialog(
|
||||
.deleteConfirmationTitle(secretName: secret.name),
|
||||
isPresented: isPresented,
|
||||
titleVisibility: .visible,
|
||||
actions: {
|
||||
TextField(secret.name, text: $confirmedSecretName)
|
||||
if let errorText {
|
||||
Text(verbatim: errorText)
|
||||
.foregroundStyle(.red)
|
||||
.font(.callout)
|
||||
}
|
||||
Button(.deleteConfirmationDeleteButton, action: delete)
|
||||
.disabled(confirmedSecretName != secret.name)
|
||||
Button(.deleteConfirmationCancelButton, role: .cancel) {
|
||||
dismissalBlock(false)
|
||||
}
|
||||
},
|
||||
message: {
|
||||
Text(.deleteConfirmationDescription(secretName: secret.name, confirmSecretName: secret.name))
|
||||
}
|
||||
)
|
||||
.dialogIcon(Image(systemName: "lock.trianglebadge.exclamationmark.fill"))
|
||||
.onExitCommand {
|
||||
dismissalBlock(false)
|
||||
}
|
||||
}
|
||||
|
||||
func delete() {
|
||||
Task {
|
||||
do {
|
||||
try await store.delete(secret: secret)
|
||||
try await store!.delete(secret: secret)
|
||||
dismissalBlock(true)
|
||||
} catch {
|
||||
errorText = error.localizedDescription
|
||||
|
||||
@@ -12,18 +12,6 @@ struct SecretListItemView: View {
|
||||
var deletedSecret: (AnySecret) -> Void
|
||||
var renamedSecret: (AnySecret) -> Void
|
||||
|
||||
private var showingPopup: Binding<Bool> {
|
||||
Binding(
|
||||
get: { isDeleting || isRenaming },
|
||||
set: {
|
||||
if $0 == false {
|
||||
isDeleting = false
|
||||
isRenaming = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationLink(value: secret) {
|
||||
if secret.authenticationRequirement.required {
|
||||
@@ -48,21 +36,17 @@ struct SecretListItemView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: showingPopup) {
|
||||
.showingDeleteConfirmation(isPresented: $isDeleting, secret, store as? AnySecretStoreModifiable) { deleted in
|
||||
if deleted {
|
||||
deletedSecret(secret)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $isRenaming) {
|
||||
if let modifiable = store as? AnySecretStoreModifiable {
|
||||
if isDeleting {
|
||||
DeleteSecretView(store: modifiable, secret: secret) { deleted in
|
||||
isDeleting = false
|
||||
if deleted {
|
||||
deletedSecret(secret)
|
||||
}
|
||||
}
|
||||
} else if isRenaming {
|
||||
EditSecretView(store: modifiable, secret: secret) { renamed in
|
||||
isRenaming = false
|
||||
if renamed {
|
||||
renamedSecret(secret)
|
||||
}
|
||||
EditSecretView(store: modifiable, secret: secret) { renamed in
|
||||
isRenaming = false
|
||||
if renamed {
|
||||
renamedSecret(secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ struct StoreListView: View {
|
||||
}
|
||||
|
||||
private func secretRenamed(secret: AnySecret) {
|
||||
// Toggle so name updates in list.
|
||||
activeSecret = nil
|
||||
activeSecret = secret
|
||||
}
|
||||
|
||||
@@ -56,7 +58,7 @@ struct StoreListView: View {
|
||||
extension StoreListView {
|
||||
|
||||
private var nextDefaultSecret: AnySecret? {
|
||||
return storeList.stores.first(where: { !$0.secrets.isEmpty })?.secrets.first
|
||||
return storeList.allSecrets.first
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user