From 7db11172c0eaf7352943307a02bff590f17ad396 Mon Sep 17 00:00:00 2001 From: Angelo Stavrow Date: Fri, 5 Nov 2021 14:18:36 -0400 Subject: [PATCH] Move user defaults to App Group --- Shared/Account/AccountModel.swift | 4 +- .../Extensions/UserDefaults+Extensions.swift | 64 +++++++++++++++++++ Shared/Models/WriteFreelyModel.swift | 2 +- Shared/PostEditor/PostEditorModel.swift | 6 +- Shared/Preferences/PreferencesModel.swift | 2 +- Shared/WriteFreely_MultiPlatformApp.swift | 6 +- .../project.pbxproj | 6 ++ .../xcschemes/xcschememanagement.plist | 4 +- macOS/AppDelegate.swift | 4 +- macOS/PostEditor/PostEditorView.swift | 4 +- macOS/Settings/MacUpdatesView.swift | 6 +- 11 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 Shared/Extensions/UserDefaults+Extensions.swift diff --git a/Shared/Account/AccountModel.swift b/Shared/Account/AccountModel.swift index 1d91b95..0e6a6e8 100644 --- a/Shared/Account/AccountModel.swift +++ b/Shared/Account/AccountModel.swift @@ -54,8 +54,8 @@ extension AccountError: LocalizedError { } struct AccountModel { - @AppStorage("isLoggedIn") var isLoggedIn: Bool = false - private let defaults = UserDefaults.standard + @AppStorage(WFDefaults.isLoggedIn, store: UserDefaults.shared) var isLoggedIn: Bool = false + private let defaults = UserDefaults.shared let usernameStringKey = "usernameStringKey" let serverStringKey = "serverStringKey" diff --git a/Shared/Extensions/UserDefaults+Extensions.swift b/Shared/Extensions/UserDefaults+Extensions.swift new file mode 100644 index 0000000..47e554c --- /dev/null +++ b/Shared/Extensions/UserDefaults+Extensions.swift @@ -0,0 +1,64 @@ +import Foundation + +enum WFDefaults { + static let isLoggedIn = "isLoggedIn" + static let showAllPostsFlag = "showAllPostsFlag" + static let selectedCollectionURL = "selectedCollectionURL" + static let lastDraftURL = "lastDraftURL" + #if os(macOS) + static let automaticallyChecksForUpdates = "automaticallyChecksForUpdates" + static let subscribeToBetaUpdates = "subscribeToBetaUpdates" + #endif +} + +extension UserDefaults { + + private enum DefaultsError: Error { + case couldNotMigrateStandardDefaults + + var description: String { + switch self { + case .couldNotMigrateStandardDefaults: + return "Could not migrate user defaults to group container." + } + } + } + + private static let appGroupName: String = "group.com.abunchtell.writefreely" + private static let didMigrateDefaultsToAppGroup: String = "didMigrateDefaultsToAppGroup" + private static let didRemoveStandardDefaults: String = "didRemoveStandardDefaults" + + static var shared: UserDefaults { + if let groupDefaults = UserDefaults(suiteName: UserDefaults.appGroupName), + groupDefaults.bool(forKey: UserDefaults.didMigrateDefaultsToAppGroup) { + return groupDefaults + } else { + do { + let groupDefaults = try UserDefaults.standard.migrateDefaultsToAppGroup() + return groupDefaults + } catch { + return UserDefaults.standard + } + } + } + + private func migrateDefaultsToAppGroup() throws -> UserDefaults { + let userDefaults = UserDefaults.standard + let groupDefaults = UserDefaults(suiteName: UserDefaults.appGroupName) + + if let groupDefaults = groupDefaults { + if groupDefaults.bool(forKey: UserDefaults.didMigrateDefaultsToAppGroup) { + return groupDefaults + } + + for (key, value) in userDefaults.dictionaryRepresentation() { + groupDefaults.set(value, forKey: key) + } + groupDefaults.set(true, forKey: UserDefaults.didMigrateDefaultsToAppGroup) + return groupDefaults + } else { + throw DefaultsError.couldNotMigrateStandardDefaults + } + } + +} diff --git a/Shared/Models/WriteFreelyModel.swift b/Shared/Models/WriteFreelyModel.swift index e6c9a23..49247ea 100644 --- a/Shared/Models/WriteFreelyModel.swift +++ b/Shared/Models/WriteFreelyModel.swift @@ -36,7 +36,7 @@ final class WriteFreelyModel: ObservableObject { // swiftlint:enable line_length internal var client: WFClient? - private let defaults = UserDefaults.standard + private let defaults = UserDefaults.shared private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "NetworkMonitor") internal var postToUpdate: WFAPost? diff --git a/Shared/PostEditor/PostEditorModel.swift b/Shared/PostEditor/PostEditorModel.swift index 6970949..29a3bc8 100644 --- a/Shared/PostEditor/PostEditorModel.swift +++ b/Shared/PostEditor/PostEditorModel.swift @@ -8,9 +8,9 @@ enum PostAppearance: String { } struct PostEditorModel { - @AppStorage("showAllPostsFlag") var showAllPostsFlag: Bool = false - @AppStorage("selectedCollectionURL") var selectedCollectionURL: URL? - @AppStorage("lastDraftURL") var lastDraftURL: URL? + @AppStorage(WFDefaults.showAllPostsFlag, store: UserDefaults.shared) var showAllPostsFlag: Bool = false + @AppStorage(WFDefaults.selectedCollectionURL, store: UserDefaults.shared) var selectedCollectionURL: URL? + @AppStorage(WFDefaults.lastDraftURL, store: UserDefaults.shared) var lastDraftURL: URL? func saveLastDraft(_ post: WFAPost) { self.lastDraftURL = post.status != PostStatus.published.rawValue ? post.objectID.uriRepresentation() : nil diff --git a/Shared/Preferences/PreferencesModel.swift b/Shared/Preferences/PreferencesModel.swift index a7acf85..d151d52 100644 --- a/Shared/Preferences/PreferencesModel.swift +++ b/Shared/Preferences/PreferencesModel.swift @@ -1,7 +1,7 @@ import SwiftUI class PreferencesModel: ObservableObject { - private let defaults = UserDefaults.standard + private let defaults = UserDefaults.shared let colorSchemeIntegerKey = "colorSchemeIntegerKey" let defaultFontIntegerKey = "defaultFontIntegerKey" diff --git a/Shared/WriteFreely_MultiPlatformApp.swift b/Shared/WriteFreely_MultiPlatformApp.swift index 3ba051d..0ea2760 100644 --- a/Shared/WriteFreely_MultiPlatformApp.swift +++ b/Shared/WriteFreely_MultiPlatformApp.swift @@ -10,9 +10,9 @@ struct CheckForDebugModifier { #if os(macOS) if NSEvent.modifierFlags.contains(.shift) { // Clear the launch-to-last-draft values to load a new draft. - UserDefaults.standard.setValue(false, forKey: "showAllPostsFlag") - UserDefaults.standard.setValue(nil, forKey: "selectedCollectionURL") - UserDefaults.standard.setValue(nil, forKey: "lastDraftURL") + UserDefaults.shared.setValue(false, forKey: WFDefaults.showAllPostsFlag) + UserDefaults.shared.setValue(nil, forKey: WFDefaults.selectedCollectionURL) + UserDefaults.shared.setValue(nil, forKey: WFDefaults.lastDraftURL) } else { // No-op } diff --git a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj index 6e32322..49d55a3 100644 --- a/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj +++ b/WriteFreely-MultiPlatform.xcodeproj/project.pbxproj @@ -24,6 +24,8 @@ 1714DD6B260BAC2C000C0DFF /* WriteFreely in Frameworks */ = {isa = PBXBuildFile; productRef = 1714DD6A260BAC2C000C0DFF /* WriteFreely */; }; 171BFDFA24D4AF8300888236 /* CollectionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BFDF924D4AF8300888236 /* CollectionListView.swift */; }; 171BFDFB24D4AF8300888236 /* CollectionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BFDF924D4AF8300888236 /* CollectionListView.swift */; }; + 171DC677272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */; }; + 171DC678272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */; }; 172C492E2593981900E20ADF /* MacUpdatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172C492D2593981900E20ADF /* MacUpdatesView.swift */; }; 173E19D1254318F600440F0F /* RemoteChangePromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173E19D0254318F600440F0F /* RemoteChangePromptView.swift */; }; 173E19E3254329CC00440F0F /* PostTextEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173E19E2254329CC00440F0F /* PostTextEditingView.swift */; }; @@ -135,6 +137,7 @@ 17120DAB24E1B99F002B9F6C /* AccountLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLoginView.swift; sourceTree = ""; }; 17120DB124E1E19C002B9F6C /* SettingsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHeaderView.swift; sourceTree = ""; }; 171BFDF924D4AF8300888236 /* CollectionListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionListView.swift; sourceTree = ""; }; + 171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Extensions.swift"; sourceTree = ""; }; 172C492D2593981900E20ADF /* MacUpdatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacUpdatesView.swift; sourceTree = ""; }; 173E19D0254318F600440F0F /* RemoteChangePromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteChangePromptView.swift; sourceTree = ""; }; 173E19E2254329CC00440F0F /* PostTextEditingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTextEditingView.swift; sourceTree = ""; }; @@ -277,6 +280,7 @@ 17B37C5525C8679800FE75E9 /* WriteFreelyModel+API.swift */, 17B37C5C25C8698900FE75E9 /* WriteFreelyModel+APIHandlers.swift */, 17B37C4A25C8661300FE75E9 /* WriteFreelyModel+Keychain.swift */, + 171DC676272C7D0B002B9B8A /* UserDefaults+Extensions.swift */, ); path = Extensions; sourceTree = ""; @@ -757,6 +761,7 @@ 171BFDFA24D4AF8300888236 /* CollectionListView.swift in Sources */, 1756DBB324FECDBB00207AB8 /* PostEditorStatusToolbarView.swift in Sources */, 17120DB224E1E19C002B9F6C /* SettingsHeaderView.swift in Sources */, + 171DC677272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */, 1756DBB724FED3A400207AB8 /* LocalStorageModel.xcdatamodeld in Sources */, 17B996DA2502D23E0017B536 /* WFAPost+CoreDataProperties.swift in Sources */, 1756AE7724CB2EDD00FD7257 /* PostEditorView.swift in Sources */, @@ -785,6 +790,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 171DC678272C7D0B002B9B8A /* UserDefaults+Extensions.swift in Sources */, 17DF32AD24C87D3500BCE2E3 /* ContentView.swift in Sources */, 1756DBBB24FED45500207AB8 /* LocalStorageManager.swift in Sources */, 17A4FEED25927E730037E96B /* AppDelegate.swift in Sources */, diff --git a/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist b/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist index 2723ebe..6cd8075 100644 --- a/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/WriteFreely-MultiPlatform.xcodeproj/xcuserdata/angelo.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ WriteFreely-MultiPlatform (iOS).xcscheme_^#shared#^_ orderHint - 0 + 1 WriteFreely-MultiPlatform (macOS).xcscheme_^#shared#^_ orderHint - 1 + 0 diff --git a/macOS/AppDelegate.swift b/macOS/AppDelegate.swift index 76c2308..e002e64 100644 --- a/macOS/AppDelegate.swift +++ b/macOS/AppDelegate.swift @@ -6,8 +6,8 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationWillFinishLaunching(_ notification: Notification) { // Check UserDefaults for values; if the key doesn't exist (e.g., if MacUpdatesView hasn't ever been shown), // bool(forKey:) returns false, so set SUUpdater.shared() appropriately. - let automaticallyChecksForUpdates = UserDefaults.standard.bool(forKey: "automaticallyChecksForUpdates") - let subscribeToBetaUpdates = UserDefaults.standard.bool(forKey: "subscribeToBetaUpdates") + let automaticallyChecksForUpdates = UserDefaults.shared.bool(forKey: WFDefaults.automaticallyChecksForUpdates) + let subscribeToBetaUpdates = UserDefaults.shared.bool(forKey: WFDefaults.subscribeToBetaUpdates) // Set Sparkle properties. SUUpdater.shared()?.automaticallyChecksForUpdates = automaticallyChecksForUpdates diff --git a/macOS/PostEditor/PostEditorView.swift b/macOS/PostEditor/PostEditorView.swift index a20bd41..56bedc9 100644 --- a/macOS/PostEditor/PostEditorView.swift +++ b/macOS/PostEditor/PostEditorView.swift @@ -61,7 +61,7 @@ struct PostEditorView: View { struct PostEditorView_EmptyPostPreviews: PreviewProvider { static var previews: some View { - let context = LocalStorageManager.standard.persistentContainer.viewContext + let context = LocalStorageManager.standard.container.viewContext let testPost = WFAPost(context: context) testPost.createdDate = Date() testPost.appearance = "norm" @@ -76,7 +76,7 @@ struct PostEditorView_EmptyPostPreviews: PreviewProvider { struct PostEditorView_ExistingPostPreviews: PreviewProvider { static var previews: some View { - let context = LocalStorageManager.standard.persistentContainer.viewContext + let context = LocalStorageManager.standard.container.viewContext let testPost = WFAPost(context: context) testPost.title = "Test Post Title" testPost.body = "Here's some cool sample body text." diff --git a/macOS/Settings/MacUpdatesView.swift b/macOS/Settings/MacUpdatesView.swift index 45f682a..53b4f0e 100644 --- a/macOS/Settings/MacUpdatesView.swift +++ b/macOS/Settings/MacUpdatesView.swift @@ -7,8 +7,10 @@ enum AppcastFeedUrl: String { } struct MacUpdatesView: View { - @AppStorage("automaticallyChecksForUpdates") var automaticallyChecksForUpdates: Bool = false - @AppStorage("subscribeToBetaUpdates") var subscribeToBetaUpdates: Bool = false + @AppStorage(WFDefaults.automaticallyChecksForUpdates, store: UserDefaults.shared) + var automaticallyChecksForUpdates: Bool = false + @AppStorage(WFDefaults.subscribeToBetaUpdates, store: UserDefaults.shared) + var subscribeToBetaUpdates: Bool = false @State private var lastUpdateCheck: Date? private let betaWarningString = """