// // 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) } } }