Skip to content

Commit 35f36bd

Browse files
committed
bug: fix user defaults migration issues.
1 parent 276f2d3 commit 35f36bd

File tree

4 files changed

+35
-46
lines changed

4 files changed

+35
-46
lines changed

Dayflow/Dayflow/App/AppDelegate.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
2424
private var pendingDeepLinkURLs: [URL] = []
2525
private var pendingRecordingAnalyticsReason: String?
2626

27+
override init() {
28+
UserDefaultsMigrator.migrateIfNeeded()
29+
super.init()
30+
}
31+
2732
func applicationDidFinishLaunching(_ note: Notification) {
2833
// Block termination by default; only specific flows enable it.
2934
AppDelegate.allowTermination = false

Dayflow/Dayflow/Models/TimelineCategory.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,8 @@ final class CategoryStore: ObservableObject {
172172

173173
private func load() {
174174
let decoded = CategoryPersistence.loadPersistedCategories()
175-
if decoded.isEmpty {
176-
categories = CategoryPersistence.defaultCategories
177-
} else {
178-
categories = CategoryPersistence.ensureIdleCategoryPresent(in: decoded)
179-
}
175+
let effective = decoded.isEmpty ? CategoryPersistence.defaultCategories : decoded
176+
categories = CategoryPersistence.ensureIdleCategoryPresent(in: effective)
180177
}
181178

182179
private func save() {

Dayflow/Dayflow/Utilities/UserDefaultsMigrator.swift

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import Foundation
22

33
enum UserDefaultsMigrator {
44
private static let sentinelKey = "didMigrateFromSandboxDefaults"
5+
private static let skippedKeyPrefixes = ["NS", "Apple", "AV", "SU"]
56

6-
static func migrateIfNeeded() {
7-
let defaults = UserDefaults.standard
7+
static func migrateIfNeeded(
8+
defaults: UserDefaults = .standard,
9+
fileManager: FileManager = .default
10+
) {
811
if defaults.bool(forKey: sentinelKey) {
912
return
1013
}
@@ -14,53 +17,37 @@ enum UserDefaultsMigrator {
1417
return
1518
}
1619

17-
let fileManager = FileManager.default
18-
let containerPlist = fileManager.homeDirectoryForCurrentUser
20+
let containerPlistURL = fileManager.homeDirectoryForCurrentUser
1921
.appendingPathComponent("Library/Containers/\(bundleId)/Data/Library/Preferences/\(bundleId).plist")
20-
let targetPlist = fileManager.homeDirectoryForCurrentUser
21-
.appendingPathComponent("Library/Preferences/\(bundleId).plist")
2222

23-
guard fileManager.fileExists(atPath: containerPlist.path) else {
23+
guard fileManager.fileExists(atPath: containerPlistURL.path) else {
2424
defaults.set(true, forKey: sentinelKey)
2525
return
2626
}
2727

28-
do {
29-
if fileManager.fileExists(atPath: targetPlist.path) {
30-
let backup = targetPlist.appendingPathExtension("preMigration")
31-
do {
32-
try? fileManager.removeItem(at: backup)
33-
try fileManager.moveItem(at: targetPlist, to: backup)
34-
} catch {
35-
print("⚠️ UserDefaultsMigrator: failed to back up existing defaults: \(error)")
36-
}
37-
}
38-
39-
if fileManager.fileExists(atPath: targetPlist.path) {
40-
try fileManager.removeItem(at: targetPlist)
41-
}
42-
43-
try fileManager.copyItem(at: containerPlist, to: targetPlist)
44-
if let migratedDefaults = NSDictionary(contentsOf: targetPlist) as? [String: Any] {
45-
var mergedDefaults = defaults.persistentDomain(forName: bundleId) ?? [:]
46-
var didMerge = false
28+
guard let legacyDomain = NSDictionary(contentsOf: containerPlistURL) as? [String: Any], legacyDomain.isEmpty == false else {
29+
defaults.set(true, forKey: sentinelKey)
30+
return
31+
}
4732

48-
for (key, value) in migratedDefaults where mergedDefaults[key] == nil {
49-
mergedDefaults[key] = value
50-
didMerge = true
51-
}
33+
let filteredLegacy = legacyDomain.filter { key, _ in
34+
guard key != sentinelKey else { return false }
35+
return skippedKeyPrefixes.contains { prefix in key.hasPrefix(prefix) } == false
36+
}
5237

53-
if didMerge {
54-
// Hydrate missing keys so callers see the migrated values without clobbering newer writes.
55-
defaults.setPersistentDomain(mergedDefaults, forName: bundleId)
56-
}
57-
} else {
58-
print("⚠️ UserDefaultsMigrator: failed to hydrate migrated defaults from \(targetPlist.path)")
59-
}
38+
if filteredLegacy.isEmpty {
6039
defaults.set(true, forKey: sentinelKey)
61-
print("UserDefaultsMigrator: copied sandbox defaults to \(targetPlist.path)")
62-
} catch {
63-
print("⚠️ UserDefaultsMigrator: failed to migrate defaults: \(error)")
40+
return
41+
}
42+
43+
var mergedDomain = defaults.persistentDomain(forName: bundleId) ?? [:]
44+
for (key, value) in filteredLegacy {
45+
mergedDomain[key] = value
6446
}
47+
48+
defaults.setPersistentDomain(mergedDomain, forName: bundleId)
49+
defaults.set(true, forKey: sentinelKey)
50+
51+
print("UserDefaultsMigrator: migrated \(filteredLegacy.count) keys from sandbox defaults")
6552
}
6653
}

Dayflow/Dayflow/Views/Onboarding/LLMProviderSetupView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ struct LLMProviderSetupView: View {
508508
)
509509

510510
VStack(alignment: .leading, spacing: 12) {
511-
Text("Choose your Gemini model")
511+
Text("Choose your Gemini model. If you're on the free tier, pick 2.5 Pro, it's the most powerful model and is completely free to use. If you're on a paid plan, which is not recommended, I recommend 2.5 Flash-Lite to minimize costs.")
512512
.font(.custom("Nunito", size: 16))
513513
.fontWeight(.semibold)
514514
.foregroundColor(.black.opacity(0.85))

0 commit comments

Comments
 (0)