Skip to content

Commit b876f36

Browse files
shenlong-tanwenkirill-dev-pro
authored andcommitted
feat(mobile): sqlite (immich-app#16861)
* refactor: user entity * chore: rebase fixes * refactor: remove int user Id * refactor: migrate store userId from int to string * refactor: rename uid to id * feat: drift * pr feedback * refactor: move common overrides to mixin --------- Co-authored-by: shenlong-tanwen <[email protected]>
1 parent 5d7e753 commit b876f36

23 files changed

+2123
-30
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ mobile/openapi/**/*.dart linguist-generated=true
66
mobile/lib/**/*.g.dart -diff -merge
77
mobile/lib/**/*.g.dart linguist-generated=true
88

9+
mobile/lib/**/*.drift.dart -diff -merge
10+
mobile/lib/**/*.drift.dart linguist-generated=true
11+
912
open-api/typescript-sdk/fetch-client.ts -diff -merge
1013
open-api/typescript-sdk/fetch-client.ts linguist-generated=true
1114

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
],
4040
"explorer.fileNesting.enabled": true,
4141
"explorer.fileNesting.patterns": {
42-
"*.ts": "${capture}.spec.ts,${capture}.mock.ts"
42+
"*.ts": "${capture}.spec.ts,${capture}.mock.ts",
43+
"*.dart": "${capture}.g.dart,${capture}.gr.dart,${capture}.drift.dart"
4344
}
4445
}

mobile/analysis_options.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ analyzer:
3636
exclude:
3737
- openapi/**
3838
- lib/generated_plugin_registrant.dart
39+
- lib/**/*.g.dart
40+
- lib/**/*.drift.dart
3941

4042
plugins:
4143
- custom_lint

mobile/build.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
targets:
2+
$default:
3+
builders:
4+
#drift @DriftDatabase()
5+
drift_dev:
6+
# Disable default builder to use modular builder instead
7+
enabled: false
8+
drift_dev:analyzer:
9+
enabled: true
10+
options: &drift_options
11+
store_date_time_values_as_text: true
12+
named_parameters: true
13+
write_from_json_string_constructor: false
14+
data_class_to_companions: false
15+
# Required for make-migrations
16+
databases:
17+
main: lib/infrastructure/repositories/db.repository.dart
18+
generate_for: &drift_generate_for
19+
- lib/infrastructure/entities/*.dart
20+
- lib/infrastructure/repositories/db.repository.dart
21+
drift_dev:modular:
22+
enabled: true
23+
options: *drift_options
24+
generate_for: *drift_generate_for
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"preferences","getter_name":"preferences","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userPreferenceConverter","dart_type_name":"UserPreferences"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id"]}},{"id":2,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"blob","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}}]}

mobile/lib/domain/models/user.model.dart

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,4 @@
1-
import 'dart:ui';
2-
3-
enum AvatarColor {
4-
// do not change this order or reuse indices for other purposes, adding is OK
5-
primary,
6-
pink,
7-
red,
8-
yellow,
9-
blue,
10-
green,
11-
purple,
12-
orange,
13-
gray,
14-
amber;
15-
16-
Color toColor({bool isDarkTheme = false}) => switch (this) {
17-
AvatarColor.primary =>
18-
isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF),
19-
AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182),
20-
AvatarColor.red => const Color.fromARGB(255, 239, 68, 68),
21-
AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8),
22-
AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246),
23-
AvatarColor.green => const Color.fromARGB(255, 22, 163, 74),
24-
AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234),
25-
AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12),
26-
AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99),
27-
AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6),
28-
};
29-
}
1+
import 'package:immich_mobile/domain/models/user_metadata.model.dart';
302

313
// TODO: Rename to User once Isar is removed
324
class UserDto {
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import 'dart:ui';
2+
3+
enum AvatarColor {
4+
// do not change this order or reuse indices for other purposes, adding is OK
5+
primary("primary"),
6+
pink("pink"),
7+
red("red"),
8+
yellow("yellow"),
9+
blue("blue"),
10+
green("green"),
11+
purple("purple"),
12+
orange("orange"),
13+
gray("gray"),
14+
amber("amber");
15+
16+
final String value;
17+
const AvatarColor(this.value);
18+
19+
Color toColor({bool isDarkTheme = false}) => switch (this) {
20+
AvatarColor.primary =>
21+
isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF),
22+
AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182),
23+
AvatarColor.red => const Color.fromARGB(255, 239, 68, 68),
24+
AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8),
25+
AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246),
26+
AvatarColor.green => const Color.fromARGB(255, 22, 163, 74),
27+
AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234),
28+
AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12),
29+
AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99),
30+
AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6),
31+
};
32+
}
33+
34+
class UserPreferences {
35+
final bool foldersEnabled;
36+
final bool memoriesEnabled;
37+
final bool peopleEnabled;
38+
final bool ratingsEnabled;
39+
final bool sharedLinksEnabled;
40+
final bool tagsEnabled;
41+
final AvatarColor userAvatarColor;
42+
final bool showSupportBadge;
43+
44+
const UserPreferences({
45+
this.foldersEnabled = false,
46+
this.memoriesEnabled = true,
47+
this.peopleEnabled = true,
48+
this.ratingsEnabled = false,
49+
this.sharedLinksEnabled = true,
50+
this.tagsEnabled = false,
51+
this.userAvatarColor = AvatarColor.primary,
52+
this.showSupportBadge = true,
53+
});
54+
55+
UserPreferences copyWith({
56+
bool? foldersEnabled,
57+
bool? memoriesEnabled,
58+
bool? peopleEnabled,
59+
bool? ratingsEnabled,
60+
bool? sharedLinksEnabled,
61+
bool? tagsEnabled,
62+
AvatarColor? userAvatarColor,
63+
bool? showSupportBadge,
64+
}) {
65+
return UserPreferences(
66+
foldersEnabled: foldersEnabled ?? this.foldersEnabled,
67+
memoriesEnabled: memoriesEnabled ?? this.memoriesEnabled,
68+
peopleEnabled: peopleEnabled ?? this.peopleEnabled,
69+
ratingsEnabled: ratingsEnabled ?? this.ratingsEnabled,
70+
sharedLinksEnabled: sharedLinksEnabled ?? this.sharedLinksEnabled,
71+
tagsEnabled: tagsEnabled ?? this.tagsEnabled,
72+
userAvatarColor: userAvatarColor ?? this.userAvatarColor,
73+
showSupportBadge: showSupportBadge ?? this.showSupportBadge,
74+
);
75+
}
76+
77+
Map<String, Object?> toMap() {
78+
final preferences = <String, Object?>{};
79+
preferences["folders-Enabled"] = foldersEnabled;
80+
preferences["memories-Enabled"] = memoriesEnabled;
81+
preferences["people-Enabled"] = peopleEnabled;
82+
preferences["ratings-Enabled"] = ratingsEnabled;
83+
preferences["sharedLinks-Enabled"] = sharedLinksEnabled;
84+
preferences["tags-Enabled"] = tagsEnabled;
85+
preferences["avatar-Color"] = userAvatarColor.value;
86+
preferences["purchase-ShowSupportBadge"] = showSupportBadge;
87+
return preferences;
88+
}
89+
90+
factory UserPreferences.fromMap(Map<String, Object?> map) {
91+
return UserPreferences(
92+
foldersEnabled: map["folders-Enabled"] as bool? ?? false,
93+
memoriesEnabled: map["memories-Enabled"] as bool? ?? true,
94+
peopleEnabled: map["people-Enabled"] as bool? ?? true,
95+
ratingsEnabled: map["ratings-Enabled"] as bool? ?? false,
96+
sharedLinksEnabled: map["sharedLinks-Enabled"] as bool? ?? true,
97+
tagsEnabled: map["tags-Enabled"] as bool? ?? false,
98+
userAvatarColor: AvatarColor.values.firstWhere(
99+
(e) => e.value == map["avatar-Color"] as String?,
100+
orElse: () => AvatarColor.primary,
101+
),
102+
showSupportBadge: map["purchase-ShowSupportBadge"] as bool? ?? true,
103+
);
104+
}
105+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'package:drift/drift.dart';
2+
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
3+
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
4+
5+
class PartnerEntity extends Table with DriftDefaultsMixin {
6+
const PartnerEntity();
7+
8+
BlobColumn get sharedById =>
9+
blob().references(UserEntity, #id, onDelete: KeyAction.cascade)();
10+
11+
BlobColumn get sharedWithId =>
12+
blob().references(UserEntity, #id, onDelete: KeyAction.cascade)();
13+
14+
BoolColumn get inTimeline => boolean().withDefault(const Constant(false))();
15+
16+
@override
17+
Set<Column> get primaryKey => {sharedById, sharedWithId};
18+
}

0 commit comments

Comments
 (0)