142 lines
4.7 KiB
Swift
142 lines
4.7 KiB
Swift
//
|
|
// KeysSection.swift
|
|
// OTP
|
|
//
|
|
// Created by Shadowfacts on 8/24/21.
|
|
//
|
|
|
|
import SwiftUI
|
|
import UniformTypeIdentifiers
|
|
|
|
struct KeysSection: View {
|
|
@ObservedObject private var store: KeyStore = .shared
|
|
@ObservedObject private var entryHolder: AppView.CodeHolder
|
|
@State private var editedEntry: AppView.CodeEntry? = nil
|
|
@State private var presentedQRCode: AppView.CodeEntry? = nil
|
|
|
|
init(codeHolder: AppView.CodeHolder) {
|
|
self.entryHolder = codeHolder
|
|
}
|
|
|
|
var body: some View {
|
|
Section {
|
|
ForEach(entryHolder.sortedEntries) { (entry) in
|
|
KeyView(key: entry.key, currentCode: entry.code)
|
|
// disabled because dropping onto list rows does not work :/
|
|
// .onDrag {
|
|
// NSItemProvider(object: entry.id.uuidString as NSString)
|
|
// }
|
|
.contextMenu {
|
|
self.keyMenu(entry: entry)
|
|
}
|
|
}
|
|
.onDelete { (indices) in
|
|
withAnimation(.default) {
|
|
for index in indices {
|
|
store.removeKey(entryID: entryHolder.sortedEntries[index].id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.sheet(item: $editedEntry, content: self.editFormSheet)
|
|
.sheet(item: $presentedQRCode, content: self.qrCodeSheet)
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func keyMenu(entry: AppView.CodeEntry) -> some View {
|
|
Section {
|
|
Menu {
|
|
Button("No Folder") {
|
|
withAnimation {
|
|
store.moveEntryToFolder(entryID: entry.id, folderID: nil)
|
|
}
|
|
}
|
|
.disabled(entry.entry.folderID == nil)
|
|
|
|
Section {
|
|
ForEach(store.sortedFolders) { (folder) in
|
|
Button {
|
|
withAnimation {
|
|
store.moveEntryToFolder(entryID: entry.id, folderID: folder.id)
|
|
}
|
|
} label: {
|
|
Text(folder.name)
|
|
}
|
|
.disabled(entry.entry.folderID == folder.id)
|
|
}
|
|
}
|
|
} label: {
|
|
Label("Move to Folder", systemImage: "folder")
|
|
}
|
|
|
|
Button {
|
|
// even the .contextMenu closure is called again, SwiftUI seems not to update the actual context menu buttons
|
|
// so when this closure is called, it's copy of entry may be stale if the entry's since been edited
|
|
// so we lookup the known current one by ID and edit that
|
|
let realEntry = entryHolder.entries.first { $0.id == entry.id }
|
|
editedEntry = realEntry
|
|
} label: {
|
|
Label("Edit Key", systemImage: "pencil")
|
|
}
|
|
|
|
// todo: can't mark menu as destructive
|
|
Menu {
|
|
Button("Cancel", role: .cancel) {}
|
|
|
|
Button("Delete Key", role: .destructive) {
|
|
// todo: why doesn't this animation work?
|
|
withAnimation(.default) {
|
|
store.removeKey(entryID: entry.id)
|
|
}
|
|
}
|
|
} label: {
|
|
Label("Delete Key", systemImage: "trash")
|
|
}
|
|
}
|
|
|
|
Section {
|
|
Button {
|
|
let realEntry = entryHolder.entries.first { $0.id == entry.id }
|
|
presentedQRCode = realEntry
|
|
} label: {
|
|
Label("Export as QR", systemImage: "qrcode")
|
|
}
|
|
|
|
Button {
|
|
UIPasteboard.general.url = entry.key.url
|
|
} label: {
|
|
Label("Copy as URL", systemImage: "link")
|
|
}
|
|
}
|
|
}
|
|
|
|
private func editFormSheet(editedEntry: AppView.CodeEntry) -> some View {
|
|
NavigationView {
|
|
EditKeyForm(editingKey: editedEntry.key) { (action) in
|
|
self.editedEntry = nil
|
|
switch action {
|
|
case .cancel:
|
|
break
|
|
case .save(let key):
|
|
store.updateKey(entryID: editedEntry.id, newKey: key)
|
|
}
|
|
}
|
|
.navigationTitle("Edit Key")
|
|
}
|
|
}
|
|
|
|
private func qrCodeSheet(entry: AppView.CodeEntry) -> some View {
|
|
NavigationView {
|
|
QRCodeView(key: entry.key)
|
|
.id(entry.id)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
struct KeysSection_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
KeysSection(codeHolder: .init(store: .shared))
|
|
}
|
|
}
|