Files
keevault/MyPass/Views/GroupBrowserView.swift
T

94 lines
2.8 KiB
Swift
Raw Normal View History

//
// GroupBrowserView.swift
// MyPass
//
import SwiftUI
import MyPassCore
struct GroupBrowserView: View {
@ObservedObject var vm: VaultViewModel
let group: MyPassCore.Group
@State private var selectedEntry: Entry?
@State private var showAddEntry = false
var body: some View {
List {
if vm.isSearching {
searchResultsSection
} else {
groupTreeSection
}
}
.navigationTitle(group.name)
.searchable(text: $vm.searchQuery, prompt: "Search all entries…")
.toolbar {
#if os(iOS)
ToolbarItem(placement: .navigationBarTrailing) { EditButton() }
#endif
ToolbarItem(placement: .primaryAction) {
Button { showAddEntry = true } label: {
Image(systemName: "plus")
}
}
}
.sheet(isPresented: $showAddEntry) {
let editVM = EntryEditViewModel(session: vm.session, groupId: group.id)
EntryEditView(vm: editVM)
}
.alert("Error", isPresented: Binding(
get: { vm.errorMessage != nil },
set: { if !$0 { vm.errorMessage = nil } }
)) {
Button("OK", role: .cancel) { vm.errorMessage = nil }
} message: {
Text(vm.errorMessage ?? "")
}
}
@ViewBuilder
private var searchResultsSection: some View {
ForEach(vm.filteredEntries) { entry in
NavigationLink(destination: EntryDetailView(entry: entry, session: vm.session)) {
EntryRow(entry: entry)
}
}
}
@ViewBuilder
private var groupTreeSection: some View {
if !group.subgroups.isEmpty {
Section("Groups") {
ForEach(group.subgroups) { sub in
NavigationLink(destination: GroupBrowserView(vm: vm, group: sub)) {
Label(sub.name, systemImage: "folder")
}
}
}
}
if !group.entries.isEmpty {
Section("Entries") {
ForEach(group.entries) { entry in
NavigationLink(destination: EntryDetailView(entry: entry, session: vm.session)) {
EntryRow(entry: entry)
}
}
.onDelete { offsets in
offsets.map { group.entries[$0] }.forEach { vm.deleteEntry($0, fromGroup: group) }
}
}
}
}
}
private struct EntryRow: View {
let entry: Entry
var body: some View {
VStack(alignment: .leading, spacing: 2) {
Text(entry.title).font(.body)
Text(entry.username).font(.caption).foregroundStyle(.secondary)
}
}
}