From a99e0803240f77f1f051d0446ff889e69de6872f Mon Sep 17 00:00:00 2001 From: Owen Gretzinger Date: Thu, 10 Jul 2025 19:46:54 -0400 Subject: [PATCH] feat: add meeting deletion --- .../ViewModels/MeetingListViewModel.swift | 7 +++ notetaker/ViewModels/MeetingViewModel.swift | 11 +++++ notetaker/Views/MeetingDetailView.swift | 44 ++++++++++++++++--- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/notetaker/ViewModels/MeetingListViewModel.swift b/notetaker/ViewModels/MeetingListViewModel.swift index bee0796..72a7ffc 100644 --- a/notetaker/ViewModels/MeetingListViewModel.swift +++ b/notetaker/ViewModels/MeetingListViewModel.swift @@ -20,6 +20,13 @@ class MeetingListViewModel: ObservableObject { self?.loadMeetings() } .store(in: &cancellables) + + NotificationCenter.default.publisher(for: .meetingDeleted) + .sink { [weak self] _ in + print("🔔 Meeting deleted notification received. Reloading meetings list...") + self?.loadMeetings() + } + .store(in: &cancellables) } func loadMeetings() { diff --git a/notetaker/ViewModels/MeetingViewModel.swift b/notetaker/ViewModels/MeetingViewModel.swift index 617056e..f13253f 100644 --- a/notetaker/ViewModels/MeetingViewModel.swift +++ b/notetaker/ViewModels/MeetingViewModel.swift @@ -5,6 +5,7 @@ import Combine // Add notification name for meeting saved events extension Notification.Name { static let meetingSaved = Notification.Name("MeetingSaved") + static let meetingDeleted = Notification.Name("MeetingDeleted") } enum MeetingViewTab: String, CaseIterable { @@ -27,6 +28,7 @@ class MeetingViewModel: ObservableObject { @Published var isRecording = false @Published var selectedTab: MeetingViewTab = .myNotes @Published var recordingState: RecordingState = .idle + @Published var isDeleted = false private let audioManager = AudioManager() private var cancellables = Set() @@ -129,6 +131,7 @@ class MeetingViewModel: ObservableObject { } func saveMeeting() { + if isDeleted { return } print("💾 Saving meeting: \(meeting.id)") let success = LocalStorageManager.shared.saveMeeting(meeting) print("💾 Save result: \(success ? "SUCCESS" : "FAILED")") @@ -162,4 +165,12 @@ class MeetingViewModel: ObservableObject { NSPasteboard.general.setString(content, forType: .string) } + + func deleteMeeting() { + let success = LocalStorageManager.shared.deleteMeeting(meeting) + if success { + isDeleted = true + NotificationCenter.default.post(name: .meetingDeleted, object: meeting) + } + } } \ No newline at end of file diff --git a/notetaker/Views/MeetingDetailView.swift b/notetaker/Views/MeetingDetailView.swift index e145930..9a2c8d6 100644 --- a/notetaker/Views/MeetingDetailView.swift +++ b/notetaker/Views/MeetingDetailView.swift @@ -30,6 +30,8 @@ struct CollapsedTranscriptChunkView: View { struct MeetingDetailView: View { @StateObject private var viewModel: MeetingViewModel + @Environment(\.dismiss) private var dismiss + @State private var showDeleteAlert = false init(meeting: Meeting) { self._viewModel = StateObject(wrappedValue: MeetingViewModel(meeting: meeting)) @@ -37,12 +39,33 @@ struct MeetingDetailView: View { var body: some View { VStack(alignment: .leading, spacing: 20) { - // Meeting Title - TextField("Meeting Title", text: $viewModel.meeting.title) - .font(.title2) - .fontWeight(.semibold) - .textFieldStyle(.plain) - .padding(.bottom, 10) + // Meeting Title with Menu + HStack { + TextField("Meeting Title", text: $viewModel.meeting.title) + .font(.title2) + .fontWeight(.semibold) + .textFieldStyle(.plain) + + Spacer() + + // Ellipsis menu + Menu { + Button("Delete Meeting", role: .destructive) { + showDeleteAlert = true + } + } label: { + Image(systemName: "ellipsis") + .resizable() + .scaledToFit() + .frame(width: 12, height: 12) + .foregroundColor(.secondary) + } + .labelStyle(.iconOnly) + .menuIndicator(.hidden) + .menuStyle(BorderlessButtonMenuStyle()) + .frame(width: 20, height: 20) + } + .padding(.bottom, 10) // Controls Section HStack { @@ -121,6 +144,15 @@ struct MeetingDetailView: View { } message: { Text(viewModel.errorMessage ?? "") } + .alert("Delete Meeting", isPresented: $showDeleteAlert) { + Button("Delete", role: .destructive) { + viewModel.deleteMeeting() + dismiss() + } + Button("Cancel", role: .cancel) { } + } message: { + Text("Are you sure you want to delete this meeting? This action cannot be undone.") + } .onDisappear { viewModel.saveMeeting() }