Skip to content

Commit 7eabadd

Browse files
committed
feat: Add memory export functionality and enhance SettingsView with confirmation alert and About section
1 parent e279c8f commit 7eabadd

File tree

2 files changed

+63
-6
lines changed

2 files changed

+63
-6
lines changed

Sources/Models/MemoryStore.swift

+19
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,22 @@ class MemoryStore: ObservableObject {
262262
return Array(filtered.prefix(topK))
263263
}
264264
}
265+
266+
extension MemoryStore {
267+
/// Exports the memories array as a temporary JSON file and returns the file URL, or `nil` on failure.
268+
func exportMemoriesAsJSONFile() -> URL? {
269+
do {
270+
let data = try JSONEncoder().encode(memories)
271+
let tempDir = FileManager.default.temporaryDirectory
272+
let filename = "memories-\(UUID().uuidString).json"
273+
let fileURL = tempDir.appendingPathComponent(filename)
274+
275+
try data.write(to: fileURL, options: .atomic)
276+
print("[MemoryStore] Exported memories to file: \(fileURL)")
277+
return fileURL
278+
} catch {
279+
print("[MemoryStore] Error exporting memories: \(error)")
280+
return nil
281+
}
282+
}
283+
}

Sources/Views/SettingsView.swift

+44-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Description:
66
// A SwiftUI form for adjusting chat settings (provider, model, API key, etc.),
77
// with dynamic fetching **only** for OpenAI. Anthropic/GitHub use fallback models.
8+
// Now includes an About link and a confirmation before clearing history.
89
//
910

1011
import SwiftUI
@@ -36,7 +37,10 @@ struct SettingsView: View {
3637

3738
/// Toggles the share sheet for exporting chat history.
3839
@State private var isShowingShareSheet = false
39-
40+
41+
/// Toggles the confirmation alert before clearing history.
42+
@State private var isShowingClearConfirmation = false
43+
4044
/// Optional callback to clear messages (e.g., “Clear Conversation History”).
4145
var clearMessages: (() -> Void)? = nil
4246

@@ -53,6 +57,8 @@ struct SettingsView: View {
5357
voiceSection
5458
themeSection
5559
exportSection
60+
exportMemoriesSection
61+
aboutSection
5662
clearHistorySection
5763
}
5864
.navigationTitle("Settings")
@@ -63,6 +69,15 @@ struct SettingsView: View {
6369
applicationActivities: nil
6470
)
6571
}
72+
.alert(
73+
"Are you sure you want to clear all chat history?",
74+
isPresented: $isShowingClearConfirmation
75+
) {
76+
Button("Clear", role: .destructive) {
77+
clearMessages?()
78+
}
79+
Button("Cancel", role: .cancel) {}
80+
}
6681
.onAppear {
6782
// Load system voices if needed
6883
systemVoices = VoiceHelper.getAvailableVoices()
@@ -84,7 +99,6 @@ extension SettingsView {
8499
}
85100
}
86101
.pickerStyle(.segmented)
87-
// Updated onChange in iOS 17
88102
.onChange(of: chatViewModel.appSettings.selectedProvider) { oldProvider, newProvider in
89103
Task {
90104
// 1) Fetch or apply fallback models
@@ -101,7 +115,7 @@ extension SettingsView {
101115
chatViewModel.appSettings.selectedModelId = newProvider.defaultModel.id
102116
}
103117

104-
// 3) IMPORTANT: Re-init chat service so we actually switch providers now
118+
// 3) Re-init chat service so the switch happens now
105119
chatViewModel.initializeChatService(with: chatViewModel.appSettings)
106120

107121
// 4) Persist
@@ -159,14 +173,13 @@ extension SettingsView {
159173
SecureField("OpenAI API Key", text: $chatViewModel.appSettings.openAIKey)
160174
.textInputAutocapitalization(.never)
161175
.autocorrectionDisabled()
162-
// iOS 17 two-parameter onChange
163176
.onChange(of: chatViewModel.appSettings.openAIKey) { oldValue, newValue in
164177
Task {
165178
await chatViewModel.saveSettings()
166179
print("[SettingsView] OpenAI key changed -> saved.")
167180
}
168181
}
169-
182+
170183
case .anthropic:
171184
SecureField("Anthropic API Key", text: $chatViewModel.appSettings.anthropicKey)
172185
.textInputAutocapitalization(.never)
@@ -262,11 +275,36 @@ extension SettingsView {
262275
}
263276
}
264277

278+
private var exportMemoriesSection: some View {
279+
Section(header: Text("Export Memories"),
280+
footer: Text("Exports your Memories.json content as a separate JSON file.")) {
281+
Button("Export Memories to JSON") {
282+
if let fileURL = chatViewModel.memoryStore.exportMemoriesAsJSONFile() {
283+
shareSheetItems = [fileURL]
284+
isShowingShareSheet = true
285+
} else {
286+
print("Failed to export memories as JSON.")
287+
}
288+
}
289+
}
290+
}
291+
292+
// MARK: About
293+
private var aboutSection: some View {
294+
Section(header: Text("About")) {
295+
NavigationLink("About Ophelia") {
296+
// Ensure you have an AboutView (or rename to your custom view):
297+
AboutView()
298+
}
299+
}
300+
}
301+
265302
// MARK: Clear History
266303
private var clearHistorySection: some View {
267304
Section {
305+
// Tapping this triggers an alert confirmation
268306
Button(role: .destructive) {
269-
clearMessages?()
307+
isShowingClearConfirmation = true
270308
} label: {
271309
Text("Clear Conversation History")
272310
}

0 commit comments

Comments
 (0)