@@ -35,7 +35,8 @@ class GlobalSettings extends Table {
3535 .nullable ()();
3636
3737 // If adding a new column to this table, consider whether [BoolGlobalSettings]
38- // can do the job instead (by adding a value to the [BoolGlobalSetting] enum).
38+ // or [IntGlobalSettings] can do the job instead (by adding a value to the
39+ // [BoolGlobalSetting] or [IntGlobalSetting] enum).
3940 // That way is more convenient, when it works, because
4041 // it avoids a migration and therefore several added copies of our schema
4142 // in the Drift generated files.
@@ -50,6 +51,9 @@ class GlobalSettings extends Table {
5051/// referring to a possible setting from [BoolGlobalSetting] .
5152/// For settings in [BoolGlobalSetting] without a row in this table,
5253/// the setting's value is that of [BoolGlobalSetting.default_] .
54+ ///
55+ /// See also:
56+ /// - [IntGlobalSettings] , the int-valued counterpart of this table.
5357@DataClassName ('BoolGlobalSettingRow' )
5458class BoolGlobalSettings extends Table {
5559 /// The setting's name, a possible name from [BoolGlobalSetting] .
@@ -73,6 +77,37 @@ class BoolGlobalSettings extends Table {
7377 Set <Column <Object >>? get primaryKey => {name};
7478}
7579
80+ /// The table of the user's int-valued, account-independent settings.
81+ ///
82+ /// These apply across all the user's accounts on this client
83+ /// (i.e. on this install of the app on this device).
84+ ///
85+ /// Each row is a [IntGlobalSettingRow] ,
86+ /// referring to a possible setting from [IntGlobalSetting] .
87+ /// For settings in [IntGlobalSetting] without a row in this table,
88+ /// the setting's value is `null` .
89+ ///
90+ /// See also:
91+ /// - [BoolGlobalSettings] , the bool-valued counterpart of this table.
92+ @DataClassName ('IntGlobalSettingRow' )
93+ class IntGlobalSettings extends Table {
94+ /// The setting's name, a possible name from [IntGlobalSetting] .
95+ ///
96+ /// The table may have rows where [name] is not the name of any
97+ /// enum value in [IntGlobalSetting] .
98+ /// This happens if the app has previously run at a future or modified
99+ /// version which had additional values in that enum,
100+ /// and the user set one of those additional settings.
101+ /// The app ignores any such unknown rows.
102+ TextColumn get name => text ()();
103+
104+ /// The user's chosen value for the setting.
105+ IntColumn get value => integer ()();
106+
107+ @override
108+ Set <Column <Object >>? get primaryKey => {name};
109+ }
110+
76111/// The table of [Account] records in the app's database.
77112class Accounts extends Table {
78113 /// The ID of this account in the app's local database.
@@ -116,7 +151,7 @@ class UriConverter extends TypeConverter<Uri, String> {
116151 @override Uri fromSql (String fromDb) => Uri .parse (fromDb);
117152}
118153
119- @DriftDatabase (tables: [GlobalSettings , BoolGlobalSettings , Accounts ])
154+ @DriftDatabase (tables: [GlobalSettings , BoolGlobalSettings , IntGlobalSettings , Accounts ])
120155class AppDatabase extends _$AppDatabase {
121156 AppDatabase (super .e);
122157
@@ -129,7 +164,7 @@ class AppDatabase extends _$AppDatabase {
129164 // information on using the build_runner.
130165 // * Write a migration in `_migrationSteps` below.
131166 // * Write tests.
132- static const int latestSchemaVersion = 9 ; // See note.
167+ static const int latestSchemaVersion = 11 ; // See note.
133168
134169 @override
135170 int get schemaVersion => latestSchemaVersion;
@@ -200,7 +235,30 @@ class AppDatabase extends _$AppDatabase {
200235 // assume there wasn't also the legacy app before that.
201236 await m.database.update (schema.globalSettings).write (
202237 RawValuesInsertable ({'legacy_upgrade_state' : Constant ('noLegacy' )}));
203- }
238+ },
239+ from9To10: (m, schema) async {
240+ await m.createTable (schema.intGlobalSettings);
241+ },
242+ from10To11: (Migrator m, Schema11 schema) async {
243+ // To provide a smooth experience for users when they first install a new
244+ // version of the app with support for the "last visited account" feature,
245+ // we set the first available account as the last visited one. This way,
246+ // the user is still taken straight to the first account, just as they
247+ // were used to before, instead of being shown the "choose account" page.
248+ final firstAccountId = await (m.database.selectOnly (schema.accounts)
249+ ..addColumns ([schema.accounts.id])
250+ ..limit (1 )
251+ ).map ((row) => row.read (schema.accounts.id)).getSingleOrNull ();
252+ if (firstAccountId == null ) return ;
253+
254+ // Like `globalStore.setLastVisitedAccount(firstAccountId)`,
255+ // as of the schema at the time of this migration.
256+ await m.database.into (schema.intGlobalSettings).insert (
257+ RawValuesInsertable ({
258+ 'name' : Variable ('lastVisitedAccountId' ),
259+ 'value' : Variable (firstAccountId),
260+ }));
261+ },
204262 );
205263
206264 Future <void > _createLatestSchema (Migrator m) async {
@@ -256,6 +314,14 @@ class AppDatabase extends _$AppDatabase {
256314 return result;
257315 }
258316
317+ Future <Map <IntGlobalSetting , int >> getIntGlobalSettings () async {
318+ return {
319+ for (final row in await select (intGlobalSettings).get ())
320+ if (IntGlobalSetting .byName (row.name) case final setting? )
321+ setting: row.value
322+ };
323+ }
324+
259325 Future <int > createAccount (AccountsCompanion values) async {
260326 try {
261327 return await into (accounts).insert (values);
0 commit comments