From 7ff7e6d79a94a5c39232e01924eb9fc0a4e166a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Fri, 1 May 2026 22:47:12 +0200 Subject: [PATCH] Default migrationStep to latest so fresh installs skip migrations Previously migrationStep defaulted to 0, forcing every fresh install to iterate through every migration. Set the default to the latest step (7) and update other StorageValue defaults to match the post-migration final state on a fresh install: - snoozerPosition: .menu -> .position3 - nightscoutPosition: .position3 -> .position4 - remotePosition: .position4 -> .menu - hasSeenFatProteinOrderChange: false -> true Add reminder comments at the migrationStep declaration and at the runMigrationsIfNeeded() block so future authors bump the default and update affected defaults whenever a new step is added. --- LoopFollow/Storage/Storage.swift | 17 ++++++++++------- .../ViewControllers/MainViewController.swift | 6 ++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/LoopFollow/Storage/Storage.swift b/LoopFollow/Storage/Storage.swift index 5dea5ebb1..0e32a48f0 100644 --- a/LoopFollow/Storage/Storage.swift +++ b/LoopFollow/Storage/Storage.swift @@ -33,7 +33,7 @@ class Storage { var mealWithFatProtein = StorageValue(key: "mealWithFatProtein", defaultValue: false) // TODO: This flag can be deleted in March 2027. Check the commit for other places to cleanup. - var hasSeenFatProteinOrderChange = StorageValue(key: "hasSeenFatProteinOrderChange", defaultValue: false) + var hasSeenFatProteinOrderChange = StorageValue(key: "hasSeenFatProteinOrderChange", defaultValue: true) var backgroundRefreshType = StorageValue(key: "backgroundRefreshType", defaultValue: .silentTune) @@ -194,7 +194,10 @@ class Storage { var nsWriteAuth = StorageValue(key: "nsWriteAuth", defaultValue: false) var nsAdminAuth = StorageValue(key: "nsAdminAuth", defaultValue: false) - var migrationStep = StorageValue(key: "migrationStep", defaultValue: 0) + // When adding a new migration step in `runMigrationsIfNeeded()`, bump this default + // to the new latest step number so fresh installs skip all migrations. Other defaults + // in this file must reflect the post-migration final state for a fresh install. + var migrationStep = StorageValue(key: "migrationStep", defaultValue: 7) var persistentNotification = StorageValue(key: "persistentNotification", defaultValue: false) var persistentNotificationLastBGTime = StorageValue(key: "persistentNotificationLastBGTime", defaultValue: .distantPast) @@ -206,9 +209,9 @@ class Storage { // Tab positions - which position each item is in (positions 1-4 are customizable, 5 is always Menu) var homePosition = StorageValue(key: "homePosition", defaultValue: .position1) var alarmsPosition = StorageValue(key: "alarmsPosition", defaultValue: .position2) - var snoozerPosition = StorageValue(key: "snoozerPosition", defaultValue: .menu) - var nightscoutPosition = StorageValue(key: "nightscoutPosition", defaultValue: .position3) - var remotePosition = StorageValue(key: "remotePosition", defaultValue: .position4) + var snoozerPosition = StorageValue(key: "snoozerPosition", defaultValue: .position3) + var nightscoutPosition = StorageValue(key: "nightscoutPosition", defaultValue: .position4) + var remotePosition = StorageValue(key: "remotePosition", defaultValue: .menu) var statisticsPosition = StorageValue(key: "statisticsPosition", defaultValue: .menu) var treatmentsPosition = StorageValue(key: "treatmentsPosition", defaultValue: .menu) @@ -233,8 +236,8 @@ class Storage { /// launch, where Storage was initialized while UserDefaults was encrypted and all values were /// cached as their defaults. /// - /// `migrationStep` is intentionally excluded: viewDidLoad writes it to 6 during the BFU - /// launch; if we reloaded it and the flush had somehow not landed yet, migrations would re-run. + /// `migrationStep` is intentionally excluded: viewDidLoad writes it to the latest step during + /// the BFU launch; if we reloaded it and the flush had somehow not landed yet, migrations would re-run. /// /// SecureStorageValue properties (maxBolus, maxCarbs, maxProtein, maxFat, bolusIncrement) are /// not covered here — SecureStorageValue does not implement reload() and Keychain has the same diff --git a/LoopFollow/ViewControllers/MainViewController.swift b/LoopFollow/ViewControllers/MainViewController.swift index ddfb2f3f0..3f37f3d66 100644 --- a/LoopFollow/ViewControllers/MainViewController.swift +++ b/LoopFollow/ViewControllers/MainViewController.swift @@ -1015,6 +1015,12 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele // Capture before migrations run: true for existing users, false for fresh installs. let isExistingUser = Storage.shared.migrationStep.exists + // When adding a new migration step below: + // 1. Bump the `migrationStep` defaultValue in Storage.swift to the new latest step + // number so fresh installs skip every migration. + // 2. Update any other StorageValue defaults in Storage.swift that this new step + // mutates, so a fresh install ends up in the same state as a migrated user. + // Step 1: Released in v3.0.0 (2025-07-07). Can be removed after 2026-07-07. if Storage.shared.migrationStep.value < 1 { Storage.shared.migrateStep1()