From 97eb58d1dcafea2bd8a4822f6655dbc097141c8c Mon Sep 17 00:00:00 2001 From: superdooper86 Date: Wed, 15 Jul 2026 23:28:39 +0200 Subject: [PATCH] feat: use a default template for automatic notes --- .../Managers/LocalStorageManager.swift | 13 ++++++++++++ meetingnotes/Services/LocalAPIServer.swift | 6 ++---- .../ViewModels/MeetingListViewModel.swift | 4 ++-- .../ViewModels/MeetingViewModel.swift | 10 +++++---- .../ViewModels/SettingsViewModel.swift | 19 +---------------- .../ViewModels/TemplatesViewModel.swift | 9 +++++++- meetingnotes/Views/SettingsView.swift | 6 ++++++ meetingnotes/Views/TemplateListView.swift | 21 +++++++++++++++++-- 8 files changed, 57 insertions(+), 31 deletions(-) diff --git a/meetingnotes/Managers/LocalStorageManager.swift b/meetingnotes/Managers/LocalStorageManager.swift index 9fb0cde..c190ab4 100644 --- a/meetingnotes/Managers/LocalStorageManager.swift +++ b/meetingnotes/Managers/LocalStorageManager.swift @@ -269,6 +269,19 @@ class LocalStorageManager { return templates.sorted { $0.title < $1.title } } + + func preferredTemplateID(in templates: [NoteTemplate]? = nil) -> UUID? { + let availableTemplates = templates ?? loadTemplates() + if let selectedTemplateID = UserDefaultsManager.shared.selectedTemplateId, + availableTemplates.contains(where: { $0.id == selectedTemplateID }) { + return selectedTemplateID + } + + let fallbackTemplateID = availableTemplates.first(where: { $0.title == "Standard Meeting" })?.id + ?? availableTemplates.first?.id + UserDefaultsManager.shared.selectedTemplateId = fallbackTemplateID + return fallbackTemplateID + } /// Deletes a template from local storage /// - Parameter template: The template to delete diff --git a/meetingnotes/Services/LocalAPIServer.swift b/meetingnotes/Services/LocalAPIServer.swift index 6ee40ca..222c4ab 100644 --- a/meetingnotes/Services/LocalAPIServer.swift +++ b/meetingnotes/Services/LocalAPIServer.swift @@ -244,7 +244,7 @@ private final class LocalRecordingController { return statusPayload() } - let meeting = Meeting() + let meeting = Meeting(templateId: LocalStorageManager.shared.preferredTemplateID()) guard LocalStorageManager.shared.saveMeeting(meeting) else { throw LocalRecordingError.saveFailed } @@ -288,9 +288,7 @@ private final class LocalRecordingController { meeting.transcriptChunks = chunks let templates = LocalStorageManager.shared.loadTemplates() if meeting.templateId == nil { - meeting.templateId = UserDefaultsManager.shared.selectedTemplateId - ?? templates.first(where: { $0.title == "Standard Meeting" })?.id - ?? templates.first?.id + meeting.templateId = LocalStorageManager.shared.preferredTemplateID(in: templates) } _ = LocalStorageManager.shared.saveMeeting(meeting) NotificationCenter.default.post(name: .meetingSaved, object: meeting) diff --git a/meetingnotes/ViewModels/MeetingListViewModel.swift b/meetingnotes/ViewModels/MeetingListViewModel.swift index 26d6e80..3821d82 100644 --- a/meetingnotes/ViewModels/MeetingListViewModel.swift +++ b/meetingnotes/ViewModels/MeetingListViewModel.swift @@ -68,11 +68,11 @@ class MeetingListViewModel: ObservableObject { } func createNewMeeting() -> Meeting { - let newMeeting = Meeting() + let newMeeting = Meeting(templateId: LocalStorageManager.shared.preferredTemplateID()) meetings.insert(newMeeting, at: 0) _ = LocalStorageManager.shared.saveMeeting(newMeeting) // Track meeting creation event PostHogSDK.shared.capture("meeting_created") return newMeeting } -} \ No newline at end of file +} diff --git a/meetingnotes/ViewModels/MeetingViewModel.swift b/meetingnotes/ViewModels/MeetingViewModel.swift index 461b8ca..ae23fb8 100644 --- a/meetingnotes/ViewModels/MeetingViewModel.swift +++ b/meetingnotes/ViewModels/MeetingViewModel.swift @@ -228,11 +228,13 @@ class MeetingViewModel: ObservableObject { func loadTemplates() { templates = LocalStorageManager.shared.loadTemplates() - // Load per-meeting template or default to Standard Meeting - if let meetingTemplateId = meeting.templateId { + // Keep an existing meeting's template, otherwise use the configured default. + if let meetingTemplateId = meeting.templateId, + templates.contains(where: { $0.id == meetingTemplateId }) { selectedTemplateId = meetingTemplateId - } else if let defaultTemplate = templates.first(where: { $0.title == "Standard Meeting" }) { - selectedTemplateId = defaultTemplate.id + } else { + selectedTemplateId = LocalStorageManager.shared.preferredTemplateID(in: templates) + meeting.templateId = selectedTemplateId } } diff --git a/meetingnotes/ViewModels/SettingsViewModel.swift b/meetingnotes/ViewModels/SettingsViewModel.swift index 4506ca7..eb04b78 100644 --- a/meetingnotes/ViewModels/SettingsViewModel.swift +++ b/meetingnotes/ViewModels/SettingsViewModel.swift @@ -52,24 +52,7 @@ class SettingsViewModel: ObservableObject { func loadTemplates() { templates = LocalStorageManager.shared.loadTemplates() - - // Validate that the selected template still exists - if let selectedId = settings.selectedTemplateId { - if !templates.contains(where: { $0.id == selectedId }) { - // Selected template was deleted, clear the selection - settings.selectedTemplateId = nil - } - } - - // If no template is selected, select the first default template - if settings.selectedTemplateId == nil { - if let defaultTemplate = templates.first(where: { $0.title == "Standard Meeting" }) { - settings.selectedTemplateId = defaultTemplate.id - } else if let firstTemplate = templates.first { - // Fallback to first available template - settings.selectedTemplateId = firstTemplate.id - } - } + settings.selectedTemplateId = LocalStorageManager.shared.preferredTemplateID(in: templates) } func saveSettings(showMessage: Bool = true) { diff --git a/meetingnotes/ViewModels/TemplatesViewModel.swift b/meetingnotes/ViewModels/TemplatesViewModel.swift index 9091ec4..2c2bd6d 100644 --- a/meetingnotes/ViewModels/TemplatesViewModel.swift +++ b/meetingnotes/ViewModels/TemplatesViewModel.swift @@ -4,6 +4,7 @@ import SwiftUI @MainActor class TemplatesViewModel: ObservableObject { @Published var templates: [NoteTemplate] = [] + @Published private(set) var defaultTemplateID: UUID? = nil @Published var isLoading = false @Published var errorMessage: String? @@ -14,8 +15,14 @@ class TemplatesViewModel: ObservableObject { func loadTemplates() { isLoading = true templates = LocalStorageManager.shared.loadTemplates() + defaultTemplateID = LocalStorageManager.shared.preferredTemplateID(in: templates) isLoading = false } + + func setDefaultTemplate(_ template: NoteTemplate) { + UserDefaultsManager.shared.selectedTemplateId = template.id + defaultTemplateID = template.id + } func saveTemplate(_ template: NoteTemplate) { if LocalStorageManager.shared.saveTemplate(template) { @@ -42,4 +49,4 @@ class TemplatesViewModel: ObservableObject { ] ) } -} \ No newline at end of file +} diff --git a/meetingnotes/Views/SettingsView.swift b/meetingnotes/Views/SettingsView.swift index 97a44b5..10068f4 100644 --- a/meetingnotes/Views/SettingsView.swift +++ b/meetingnotes/Views/SettingsView.swift @@ -144,6 +144,12 @@ struct SettingsView: View { Text("Create and manage note templates") .font(.caption) .foregroundColor(.secondary) + + Picker("Default template", selection: $viewModel.settings.selectedTemplateId) { + ForEach(viewModel.templates) { template in + Text(template.title).tag(Optional(template.id)) + } + } Button { navigationPath.append("templates") diff --git a/meetingnotes/Views/TemplateListView.swift b/meetingnotes/Views/TemplateListView.swift index 60a2204..92684bc 100644 --- a/meetingnotes/Views/TemplateListView.swift +++ b/meetingnotes/Views/TemplateListView.swift @@ -16,7 +16,7 @@ struct TemplateListView: View { Text(template.title) .font(.headline) if template.isDefault { - Text("Default") + Text("Built-in") .font(.caption) .padding(.horizontal, 6) .padding(.vertical, 2) @@ -38,6 +38,15 @@ struct TemplateListView: View { } Spacer() + + Button { + viewModel.setDefaultTemplate(template) + } label: { + Image(systemName: viewModel.defaultTemplateID == template.id ? "star.fill" : "star") + .foregroundColor(viewModel.defaultTemplateID == template.id ? .accentColor : .secondary) + } + .buttonStyle(.plain) + .help(viewModel.defaultTemplateID == template.id ? "Default template" : "Use as default template") if !template.isDefault { Button(role: .destructive) { @@ -50,6 +59,14 @@ struct TemplateListView: View { } } .contextMenu { + if viewModel.defaultTemplateID != template.id { + Button { + viewModel.setDefaultTemplate(template) + } label: { + Label("Use as Default", systemImage: "star") + } + } + if !template.isDefault { Button(role: .destructive) { viewModel.deleteTemplate(template) @@ -94,4 +111,4 @@ struct TemplateListView: View { #Preview { TemplateListView() -} \ No newline at end of file +}