|
| 1 | +import 'dart:ui'; |
| 2 | + |
1 | 3 | import 'package:drift/drift.dart';
|
2 | 4 | import 'package:drift/internal/versioned_schema.dart';
|
3 | 5 | import 'package:drift/remote.dart';
|
@@ -27,6 +29,9 @@ class GlobalSettings extends Table {
|
27 | 29 | Column<String> get visitFirstUnread => textEnum<VisitFirstUnreadSetting>()
|
28 | 30 | .nullable()();
|
29 | 31 |
|
| 32 | + Column<String> get language => text().map(const LocaleConverter()) |
| 33 | + .nullable()(); |
| 34 | + |
30 | 35 | // If adding a new column to this table, consider whether [BoolGlobalSettings]
|
31 | 36 | // can do the job instead (by adding a value to the [BoolGlobalSetting] enum).
|
32 | 37 | // That way is more convenient, when it works, because
|
@@ -122,7 +127,7 @@ class AppDatabase extends _$AppDatabase {
|
122 | 127 | // information on using the build_runner.
|
123 | 128 | // * Write a migration in `_migrationSteps` below.
|
124 | 129 | // * Write tests.
|
125 |
| - static const int latestSchemaVersion = 7; // See note. |
| 130 | + static const int latestSchemaVersion = 8; // See note. |
126 | 131 |
|
127 | 132 | @override
|
128 | 133 | int get schemaVersion => latestSchemaVersion;
|
@@ -181,6 +186,9 @@ class AppDatabase extends _$AppDatabase {
|
181 | 186 | await m.addColumn(schema.globalSettings,
|
182 | 187 | schema.globalSettings.visitFirstUnread);
|
183 | 188 | },
|
| 189 | + from7To8: (m, schema) async { |
| 190 | + await m.addColumn(schema.globalSettings, schema.globalSettings.language); |
| 191 | + } |
184 | 192 | );
|
185 | 193 |
|
186 | 194 | Future<void> _createLatestSchema(Migrator m) async {
|
@@ -250,3 +258,55 @@ class AppDatabase extends _$AppDatabase {
|
250 | 258 | }
|
251 | 259 |
|
252 | 260 | class AccountAlreadyExistsException implements Exception {}
|
| 261 | + |
| 262 | +class LocaleConverter extends TypeConverter<Locale, String> { |
| 263 | + const LocaleConverter(); |
| 264 | + |
| 265 | + /// Parse a Unicode BCP 47 Language Identifier into [Locale]. |
| 266 | + /// |
| 267 | + /// Throw when it fails to convert [languageTag] into a [Locale]. |
| 268 | + /// |
| 269 | + /// This supports parsing a Unicode Language Identifier returned from |
| 270 | + /// [Locale.toLanguageTag]. |
| 271 | + /// |
| 272 | + /// This implementation refers to a part of |
| 273 | + /// [this EBNF grammar](https://www.unicode.org/reports/tr35/#Unicode_language_identifier), |
| 274 | + /// assuming the identifier is valid without |
| 275 | + /// [unicode_variant_subtag](https://www.unicode.org/reports/tr35/#unicode_variant_subtag). |
| 276 | + /// |
| 277 | + /// This doesn't check if the [languageTag] is a valid identifier, (i.e., when |
| 278 | + /// this returns without errors, the identifier is not necessarily |
| 279 | + /// syntactically well-formed or valid). |
| 280 | + // TODO(upstream): send this as a factory Locale.fromLanguageTag |
| 281 | + // https://github.com/flutter/flutter/issues/143491 |
| 282 | + Locale _fromLanguageTag(String languageTag) { |
| 283 | + final subtags = languageTag.replaceAll('_', '-').split('-'); |
| 284 | + |
| 285 | + return switch (subtags) { |
| 286 | + [final language, final script, final region] => |
| 287 | + Locale.fromSubtags( |
| 288 | + languageCode: language, scriptCode: script, countryCode: region), |
| 289 | + |
| 290 | + [final language, final script] when script.length == 4 => |
| 291 | + Locale.fromSubtags(languageCode: language, scriptCode: script), |
| 292 | + |
| 293 | + [final language, final region] => |
| 294 | + Locale(language, region), |
| 295 | + |
| 296 | + [final language] => |
| 297 | + Locale(language), |
| 298 | + |
| 299 | + _ => throw ArgumentError.value(languageTag, 'languageTag'), |
| 300 | + }; |
| 301 | + } |
| 302 | + |
| 303 | + @override |
| 304 | + Locale fromSql(String fromDb) { |
| 305 | + return _fromLanguageTag(fromDb); |
| 306 | + } |
| 307 | + |
| 308 | + @override |
| 309 | + String toSql(Locale value) { |
| 310 | + return value.toLanguageTag(); |
| 311 | + } |
| 312 | +} |
0 commit comments