summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-03-15 22:19:01 -0700
committerFuwn <[email protected]>2025-03-15 22:19:01 -0700
commit808f34a5ac6e63f6a1abeeb98c03e625caa23cae (patch)
treea737d81d7ee343f26e41c2d47372606110976d2e
parentfeat: Development commit (diff)
downloadsora-testing-808f34a5ac6e63f6a1abeeb98c03e625caa23cae.tar.xz
sora-testing-808f34a5ac6e63f6a1abeeb98c03e625caa23cae.zip
feat: Development commit
-rw-r--r--Localizable.xcstrings6
-rw-r--r--Sora/Data/Settings/SettingsManager.swift128
-rw-r--r--Sora/Sora.entitlements2
-rw-r--r--Sora/Views/Settings/Section/SettingsSettingsView.swift10
4 files changed, 136 insertions, 10 deletions
diff --git a/Localizable.xcstrings b/Localizable.xcstrings
index 8d52372..2a303c0 100644
--- a/Localizable.xcstrings
+++ b/Localizable.xcstrings
@@ -152,6 +152,9 @@
"Invalid Domain" : {
},
+ "Keep bookmarks, search history, and providers up to date on all your devices." : {
+
+ },
"Loading %@…" : {
},
@@ -326,6 +329,9 @@
"Suggestion Mode" : {
},
+ "Sync with iCloud" : {
+
+ },
"Tags" : {
"localizations" : {
"ja" : {
diff --git a/Sora/Data/Settings/SettingsManager.swift b/Sora/Data/Settings/SettingsManager.swift
index 909016d..b2749e1 100644
--- a/Sora/Data/Settings/SettingsManager.swift
+++ b/Sora/Data/Settings/SettingsManager.swift
@@ -23,6 +23,11 @@ class SettingsManager: ObservableObject {
@AppStorage("preloadedCarouselImages")
var preloadedCarouselImages = 3
+ @AppStorage("enableICloudSync")
+ var enableICloudSync: Bool = false
+
+ private var iCloudSyncObservation: NSObjectProtocol?
+
#if os(macOS)
@AppStorage("saveTagsToFile")
var saveTagsToFile = false
@@ -50,11 +55,32 @@ class SettingsManager: ObservableObject {
// MARK: - Computed Properties
var bookmarks: [SettingsBookmark] {
get {
- (Self.decode([SettingsBookmark].self, from: bookmarksData) ?? [])
+ if enableICloudSync {
+ if let data = NSUbiquitousKeyValueStore.default.data(forKey: "bookmarks") {
+ return (Self.decode([SettingsBookmark].self, from: data) ?? [])
+ .sorted { $0.date > $1.date }
+ }
+
+ return (Self.decode([SettingsBookmark].self, from: bookmarksData) ?? [])
+ .sorted { $0.date > $1.date }
+ }
+
+ return (Self.decode([SettingsBookmark].self, from: bookmarksData) ?? [])
.sorted { $0.date > $1.date }
}
- set { bookmarksData = Self.encode(newValue) ?? bookmarksData }
+ set {
+ let sortedBookmarks = newValue.sorted { $0.date > $1.date }
+
+ bookmarksData = Self.encode(sortedBookmarks) ?? Data()
+
+ if enableICloudSync {
+ NSUbiquitousKeyValueStore.default.set(
+ Self.encode(sortedBookmarks),
+ forKey: "bookmarks"
+ )
+ }
+ }
}
var displayRatings: [BooruRating] {
@@ -73,11 +99,31 @@ class SettingsManager: ObservableObject {
var searchHistory: [BooruSearchQuery] {
get {
- (Self.decode([BooruSearchQuery].self, from: searchHistoryData) ?? [])
+ if enableICloudSync {
+ if let data = NSUbiquitousKeyValueStore.default.data(forKey: "searchHistory") {
+ return (Self.decode([BooruSearchQuery].self, from: data) ?? [])
+ .sorted { $0.date > $1.date }
+ }
+
+ return (Self.decode([BooruSearchQuery].self, from: searchHistoryData) ?? [])
+ .sorted { $0.date > $1.date }
+ }
+
+ return (Self.decode([BooruSearchQuery].self, from: searchHistoryData) ?? [])
.sorted { $0.date > $1.date }
}
- set { searchHistoryData = Self.encode(newValue) ?? searchHistoryData }
+ set {
+ let sortedHistory = newValue.sorted { $0.date > $1.date }
+
+ searchHistoryData = Self.encode(sortedHistory) ?? Data()
+
+ if enableICloudSync {
+ NSUbiquitousKeyValueStore.default.set(
+ Self.encode(sortedHistory), forKey: "searchHistory"
+ )
+ }
+ }
}
var preferredBooru: BooruProvider {
@@ -90,14 +136,51 @@ class SettingsManager: ObservableObject {
var customProviders: [BooruProviderCustom] {
get {
- Self.decode(
- [BooruProviderCustom].self,
- from: customProvidersData
- ) ?? []
+ if enableICloudSync {
+ if let data = NSUbiquitousKeyValueStore.default.data(forKey: "customProviders") {
+ return Self.decode([BooruProviderCustom].self, from: data) ?? []
+ }
+
+ return Self.decode([BooruProviderCustom].self, from: customProvidersData) ?? []
+ }
+
+ return Self.decode([BooruProviderCustom].self, from: customProvidersData) ?? []
}
set {
- customProvidersData = Self.encode(newValue) ?? customProvidersData
+ customProvidersData = Self.encode(newValue) ?? Data()
+
+ if enableICloudSync {
+ NSUbiquitousKeyValueStore.default.set(
+ Self.encode(newValue),
+ forKey: "customProviders"
+ )
+ }
+ }
+ }
+
+ // MARK: - Initialisation
+ init() {
+ iCloudSyncObservation = NotificationCenter.default.addObserver(
+ forName: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
+ object: NSUbiquitousKeyValueStore.default,
+ queue: .main
+ ) { [weak self] _ in
+ guard let localSelf = self, localSelf.enableICloudSync else { return } // swiftlint:disable:this self_binding
+
+ if let data = NSUbiquitousKeyValueStore.default.data(forKey: "bookmarks") {
+ localSelf.bookmarksData = data
+ }
+
+ if let data = NSUbiquitousKeyValueStore.default.data(forKey: "searchHistory") {
+ localSelf.searchHistoryData = data
+ }
+
+ if let data = NSUbiquitousKeyValueStore.default.data(forKey: "customProviders") {
+ localSelf.customProvidersData = data
+ }
+
+ localSelf.objectWillChange.send()
}
}
@@ -132,9 +215,27 @@ class SettingsManager: ObservableObject {
#endif
}
+ func syncToICloud() {
+ if enableICloudSync {
+ NSUbiquitousKeyValueStore.default.set(bookmarksData, forKey: "bookmarks")
+ NSUbiquitousKeyValueStore.default.set(searchHistoryData, forKey: "searchHistory")
+ NSUbiquitousKeyValueStore.default.set(customProvidersData, forKey: "customProviders")
+ }
+ }
+
// MARK: - Bookmark Management
func addBookmark(provider: BooruProvider, tags: [String]) {
- bookmarks.append(SettingsBookmark(provider: provider, tags: tags.map { $0.lowercased() }))
+ var updatedBookmarks = bookmarks
+
+ updatedBookmarks.append(
+ SettingsBookmark(provider: provider, tags: tags.map { $0.lowercased() })
+ )
+
+ if let data = Self.encode(updatedBookmarks), data.count < 1_000_000 { // 1 MB
+ bookmarks = updatedBookmarks
+ } else {
+ debugPrint("SettingsManager.addBookmark: iCloud data limit exceeded")
+ }
}
func removeBookmark(at offsets: IndexSet) {
@@ -200,4 +301,11 @@ class SettingsManager: ObservableObject {
}
}
#endif
+
+ // MARK: - Deinitialisation
+ deinit {
+ if let observation = iCloudSyncObservation {
+ NotificationCenter.default.removeObserver(observation)
+ }
+ }
}
diff --git a/Sora/Sora.entitlements b/Sora/Sora.entitlements
index 264aa0a..e06fcf4 100644
--- a/Sora/Sora.entitlements
+++ b/Sora/Sora.entitlements
@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>com.apple.developer.ubiquity-kvstore-identifier</key>
+ <string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.pictures.read-write</key>
diff --git a/Sora/Views/Settings/Section/SettingsSettingsView.swift b/Sora/Views/Settings/Section/SettingsSettingsView.swift
index 404d252..8062a90 100644
--- a/Sora/Views/Settings/Section/SettingsSettingsView.swift
+++ b/Sora/Views/Settings/Section/SettingsSettingsView.swift
@@ -4,6 +4,16 @@ struct SettingsSettingsView: View {
@EnvironmentObject var settings: SettingsManager
var body: some View {
+ Toggle(isOn: $settings.enableICloudSync) {
+ Text("Sync with iCloud")
+
+ Text("Keep bookmarks, search history, and providers up to date on all your devices.")
+ .font(.caption)
+ }
+ .onChange(of: settings.enableICloudSync) { _, _ in
+ settings.syncToICloud()
+ }
+
Button("Reset to Defaults") {
settings.resetToDefaults()
}