summaryrefslogtreecommitdiff
path: root/Sora/Views/Settings/Section/SettingsImportExportView.swift
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-03-03 03:15:53 -0800
committerFuwn <[email protected]>2025-03-03 03:15:53 -0800
commit682147c550ae1d6512b2fc5984993f395ff44e06 (patch)
tree90b4b0fd868fb8f6cb472deee28c8c21f19e747a /Sora/Views/Settings/Section/SettingsImportExportView.swift
parentfeat: Development commit (diff)
downloadsora-testing-682147c550ae1d6512b2fc5984993f395ff44e06.tar.xz
sora-testing-682147c550ae1d6512b2fc5984993f395ff44e06.zip
feat: Development commit
Diffstat (limited to 'Sora/Views/Settings/Section/SettingsImportExportView.swift')
-rw-r--r--Sora/Views/Settings/Section/SettingsImportExportView.swift125
1 files changed, 125 insertions, 0 deletions
diff --git a/Sora/Views/Settings/Section/SettingsImportExportView.swift b/Sora/Views/Settings/Section/SettingsImportExportView.swift
new file mode 100644
index 0000000..983b175
--- /dev/null
+++ b/Sora/Views/Settings/Section/SettingsImportExportView.swift
@@ -0,0 +1,125 @@
+import SwiftUI
+import UniformTypeIdentifiers
+
+struct SettingsImportExportView: View {
+ @EnvironmentObject private var settings: SettingsManager
+ @State private var isFileExporterPresented = false
+ @State private var isFileImporterPresented = false
+ @State private var exportError: Error?
+ @State private var importError: Error?
+
+ var body: some View {
+ Group {
+ Button("Import Bookmarks") {
+ isFileImporterPresented = true
+ }
+
+ Button("Export Bookmarks") {
+ exportBookmarksToFile()
+ }
+ }
+ #if os(macOS)
+ .frame(maxWidth: .infinity, alignment: .trailing)
+ .fileExporter(
+ isPresented: $isFileExporterPresented,
+ document: try? JSONFileDocument(settings.exportBookmarks()),
+ contentType: .json,
+ defaultFilename: "sora_bookmarks.json"
+ ) { result in
+ switch result {
+ case .success:
+ break
+
+ case .failure(let error):
+ exportError = error
+ }
+ }
+ #endif
+ .fileImporter(
+ isPresented: $isFileImporterPresented,
+ allowedContentTypes: [.json],
+ allowsMultipleSelection: false
+ ) { result in
+ handleImportResult(result)
+ }
+ .alert(
+ "Export Failed",
+ isPresented: Binding(
+ get: { exportError != nil },
+ set: { if !$0 { exportError = nil } }
+ )
+ ) {
+ Button("OK", role: .cancel) { () }
+ } message: {
+ Text(exportError?.localizedDescription ?? "An unknown error occurred while exporting.")
+ }
+ .alert(
+ "Import Failed",
+ isPresented: Binding(
+ get: { importError != nil },
+ set: { if !$0 { importError = nil } }
+ )
+ ) {
+ Button("OK", role: .cancel) { () }
+ } message: {
+ Text(importError?.localizedDescription ?? "An unknown error occurred while importing.")
+ }
+ }
+
+ private func exportBookmarksToFile() {
+ do {
+ #if os(macOS)
+ _ = try settings.exportBookmarks()
+ isFileExporterPresented = true
+
+ #elseif os(iOS)
+ let data = try settings.exportBookmarks()
+ let temporaryURL = FileManager.default.temporaryDirectory
+ .appendingPathComponent("sora_bookmarks.json")
+
+ try data.write(to: temporaryURL)
+
+ let activityController = UIActivityViewController(
+ activityItems: [temporaryURL],
+ applicationActivities: nil
+ )
+
+ if let windowScene = UIApplication.shared.connectedScenes
+ .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
+ let rootViewController = windowScene.windows.first?.rootViewController
+ {
+ activityController.popoverPresentationController?.sourceView = rootViewController.view
+
+ rootViewController.present(activityController, animated: true)
+ }
+
+ activityController.completionWithItemsHandler = { _, _, _, _ in
+ try? FileManager.default.removeItem(at: temporaryURL)
+ }
+ #endif
+ } catch {
+ exportError = error
+ }
+ }
+
+ private func handleImportResult(_ result: Result<[URL], Error>) {
+ do {
+ guard let selectedFile = try result.get().first else { return }
+ guard selectedFile.startAccessingSecurityScopedResource() else {
+ throw ImportError.accessDenied
+ }
+
+ defer { selectedFile.stopAccessingSecurityScopedResource() }
+
+ let data = try Data(contentsOf: selectedFile)
+
+ try settings.importBookmarks(from: data)
+ } catch {
+ importError = error
+ }
+ }
+
+ private enum ImportError: Error {
+ case accessDenied
+ }
+}