1
0
mirror of https://github.com/immich-app/immich.git synced 2025-10-31 00:18:28 +02:00

feat(mobile): drift people sync

This commit is contained in:
wuzihao051119
2025-07-11 18:14:15 +08:00
parent d087f7c870
commit b346318d05
25 changed files with 1245 additions and 59 deletions

File diff suppressed because one or more lines are too long

View File

@@ -124,7 +124,21 @@ class DriftMemory {
@override
String toString() {
return 'Memory(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, ownerId: $ownerId, type: $type, data: $data, isSaved: $isSaved, memoryAt: $memoryAt, seenAt: $seenAt, showAt: $showAt, hideAt: $hideAt, assets: $assets)';
return '''Memory {
id: $id,
createdAt: $createdAt,
updatedAt: $updatedAt,
deletedAt: ${deletedAt ?? "<NA>"},
ownerId: $ownerId,
type: $type,
data: $data,
isSaved: $isSaved,
memoryAt: $memoryAt,
seenAt: ${seenAt ?? "<NA>"},
showAt: ${showAt ?? "<NA>"},
hideAt: ${hideAt ?? "<NA>"},
assets: $assets
}''';
}
@override

View File

@@ -1,7 +1,8 @@
import 'dart:convert';
class Person {
const Person({
// TODO: Remove PersonDto once Isar is removed
class PersonDto {
const PersonDto({
required this.id,
this.birthDate,
required this.isHidden,
@@ -22,7 +23,7 @@ class Person {
return 'Person(id: $id, birthDate: $birthDate, isHidden: $isHidden, name: $name, thumbnailPath: $thumbnailPath, updatedAt: $updatedAt)';
}
Person copyWith({
PersonDto copyWith({
String? id,
DateTime? birthDate,
bool? isHidden,
@@ -30,7 +31,7 @@ class Person {
String? thumbnailPath,
DateTime? updatedAt,
}) {
return Person(
return PersonDto(
id: id ?? this.id,
birthDate: birthDate ?? this.birthDate,
isHidden: isHidden ?? this.isHidden,
@@ -51,8 +52,8 @@ class Person {
};
}
factory Person.fromMap(Map<String, dynamic> map) {
return Person(
factory PersonDto.fromMap(Map<String, dynamic> map) {
return PersonDto(
id: map['id'] as String,
birthDate: map['birthDate'] != null
? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int)
@@ -68,11 +69,11 @@ class Person {
String toJson() => json.encode(toMap());
factory Person.fromJson(String source) =>
Person.fromMap(json.decode(source) as Map<String, dynamic>);
factory PersonDto.fromJson(String source) =>
PersonDto.fromMap(json.decode(source) as Map<String, dynamic>);
@override
bool operator ==(covariant Person other) {
bool operator ==(covariant PersonDto other) {
if (identical(this, other)) return true;
return other.id == id &&
@@ -93,3 +94,109 @@ class Person {
updatedAt.hashCode;
}
}
// Model for a person stored in the server
class Person {
final String id;
final DateTime createdAt;
final DateTime updatedAt;
final String ownerId;
final String name;
final String? faceAssetId;
final String thumbnailPath;
final bool isFavorite;
final bool isHidden;
final String? color;
final DateTime? birthDate;
const Person({
required this.id,
required this.createdAt,
required this.updatedAt,
required this.ownerId,
required this.name,
this.faceAssetId,
required this.thumbnailPath,
required this.isFavorite,
required this.isHidden,
required this.color,
this.birthDate,
});
Person copyWith({
String? id,
DateTime? createdAt,
DateTime? updatedAt,
String? ownerId,
String? name,
String? faceAssetId,
String? thumbnailPath,
bool? isFavorite,
bool? isHidden,
String? color,
DateTime? birthDate,
}) {
return Person(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
ownerId: ownerId ?? this.ownerId,
name: name ?? this.name,
faceAssetId: faceAssetId ?? this.faceAssetId,
thumbnailPath: thumbnailPath ?? this.thumbnailPath,
isFavorite: isFavorite ?? this.isFavorite,
isHidden: isHidden ?? this.isHidden,
color: color ?? this.color,
birthDate: birthDate ?? this.birthDate,
);
}
@override
String toString() {
return '''Person {
id: $id,
createdAt: $createdAt,
updatedAt: $updatedAt,
ownerId: $ownerId,
name: $name,
faceAssetId: ${faceAssetId ?? "<NA>"},
thumbnailPath: $thumbnailPath,
isFavorite: $isFavorite,
isHidden: $isHidden,
color: ${color ?? "<NA>"},
birthDate: ${birthDate ?? "<NA>"}
}''';
}
@override
bool operator ==(covariant Person other) {
if (identical(this, other)) return true;
return other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.ownerId == ownerId &&
other.name == name &&
other.faceAssetId == faceAssetId &&
other.thumbnailPath == thumbnailPath &&
other.isFavorite == isFavorite &&
other.isHidden == isHidden &&
other.color == color &&
other.birthDate == birthDate;
}
@override
int get hashCode {
return id.hashCode ^
createdAt.hashCode ^
updatedAt.hashCode ^
ownerId.hashCode ^
name.hashCode ^
faceAssetId.hashCode ^
thumbnailPath.hashCode ^
isFavorite.hashCode ^
isHidden.hashCode ^
color.hashCode ^
birthDate.hashCode;
}
}

View File

@@ -1,5 +1,3 @@
import 'dart:convert';
// Model for a stack stored in the server
class Stack {
final String id;
@@ -32,34 +30,15 @@ class Stack {
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'createdAt': createdAt.millisecondsSinceEpoch,
'updatedAt': updatedAt.millisecondsSinceEpoch,
'ownerId': ownerId,
'primaryAssetId': primaryAssetId,
};
}
factory Stack.fromMap(Map<String, dynamic> map) {
return Stack(
id: map['id'] as String,
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt'] as int),
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int),
ownerId: map['ownerId'] as String,
primaryAssetId: map['primaryAssetId'] as String,
);
}
String toJson() => json.encode(toMap());
factory Stack.fromJson(String source) =>
Stack.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() {
return 'Stack(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, ownerId: $ownerId, primaryAssetId: $primaryAssetId)';
return '''Stack {
id: $id,
createdAt: $createdAt,
updatedAt: $updatedAt,
ownerId: $ownerId,
primaryAssetId: $primaryAssetId
}''';
}
@override

View File

@@ -179,6 +179,10 @@ class SyncStreamService {
data.cast(),
debugLabel: 'partner',
);
case SyncEntityType.personV1:
return _syncStreamRepository.updatePeopleV1(data.cast());
case SyncEntityType.personDeleteV1:
return _syncStreamRepository.deletePeopleV1(data.cast());
default:
_logger.warning("Unknown sync data type: $type");
}

View File

@@ -0,0 +1,34 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
class PersonEntity extends Table with DriftDefaultsMixin {
const PersonEntity();
TextColumn get id => text()();
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
TextColumn get ownerId =>
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
TextColumn get name => text()();
// TODO: foreign key refering to asset faces
TextColumn get faceAssetId => text().nullable()();
TextColumn get thumbnailPath => text()();
BoolColumn get isFavorite => boolean()();
BoolColumn get isHidden => boolean()();
TextColumn get color => text().nullable()();
DateTimeColumn get birthDate => dateTime().nullable()();
@override
Set<Column> get primaryKey => {id};
}

View File

@@ -0,0 +1,933 @@
// dart format width=80
// ignore_for_file: type=lint
import 'package:drift/drift.dart' as i0;
import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart'
as i1;
import 'package:immich_mobile/infrastructure/entities/person.entity.dart' as i2;
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i3;
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
as i4;
import 'package:drift/internal/modular.dart' as i5;
typedef $$PersonEntityTableCreateCompanionBuilder = i1.PersonEntityCompanion
Function({
required String id,
i0.Value<DateTime> createdAt,
i0.Value<DateTime> updatedAt,
required String ownerId,
required String name,
i0.Value<String?> faceAssetId,
required String thumbnailPath,
required bool isFavorite,
required bool isHidden,
i0.Value<String?> color,
i0.Value<DateTime?> birthDate,
});
typedef $$PersonEntityTableUpdateCompanionBuilder = i1.PersonEntityCompanion
Function({
i0.Value<String> id,
i0.Value<DateTime> createdAt,
i0.Value<DateTime> updatedAt,
i0.Value<String> ownerId,
i0.Value<String> name,
i0.Value<String?> faceAssetId,
i0.Value<String> thumbnailPath,
i0.Value<bool> isFavorite,
i0.Value<bool> isHidden,
i0.Value<String?> color,
i0.Value<DateTime?> birthDate,
});
final class $$PersonEntityTableReferences extends i0.BaseReferences<
i0.GeneratedDatabase, i1.$PersonEntityTable, i1.PersonEntityData> {
$$PersonEntityTableReferences(super.$_db, super.$_table, super.$_typedResult);
static i4.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
i5.ReadDatabaseContainer(db)
.resultSet<i4.$UserEntityTable>('user_entity')
.createAlias(i0.$_aliasNameGenerator(
i5.ReadDatabaseContainer(db)
.resultSet<i1.$PersonEntityTable>('person_entity')
.ownerId,
i5.ReadDatabaseContainer(db)
.resultSet<i4.$UserEntityTable>('user_entity')
.id));
i4.$$UserEntityTableProcessedTableManager get ownerId {
final $_column = $_itemColumn<String>('owner_id')!;
final manager = i4
.$$UserEntityTableTableManager(
$_db,
i5.ReadDatabaseContainer($_db)
.resultSet<i4.$UserEntityTable>('user_entity'))
.filter((f) => f.id.sqlEquals($_column));
final item = $_typedResult.readTableOrNull(_ownerIdTable($_db));
if (item == null) return manager;
return i0.ProcessedTableManager(
manager.$state.copyWith(prefetchedData: [item]));
}
}
class $$PersonEntityTableFilterComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$PersonEntityTable> {
$$PersonEntityTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.ColumnFilters<String> get id => $composableBuilder(
column: $table.id, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get name => $composableBuilder(
column: $table.name, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get faceAssetId => $composableBuilder(
column: $table.faceAssetId,
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get thumbnailPath => $composableBuilder(
column: $table.thumbnailPath,
builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<bool> get isFavorite => $composableBuilder(
column: $table.isFavorite, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<bool> get isHidden => $composableBuilder(
column: $table.isHidden, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<String> get color => $composableBuilder(
column: $table.color, builder: (column) => i0.ColumnFilters(column));
i0.ColumnFilters<DateTime> get birthDate => $composableBuilder(
column: $table.birthDate, builder: (column) => i0.ColumnFilters(column));
i4.$$UserEntityTableFilterComposer get ownerId {
final i4.$$UserEntityTableFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.ownerId,
referencedTable: i5.ReadDatabaseContainer($db)
.resultSet<i4.$UserEntityTable>('user_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i4.$$UserEntityTableFilterComposer(
$db: $db,
$table: i5.ReadDatabaseContainer($db)
.resultSet<i4.$UserEntityTable>('user_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$PersonEntityTableOrderingComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$PersonEntityTable> {
$$PersonEntityTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.ColumnOrderings<String> get id => $composableBuilder(
column: $table.id, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get updatedAt => $composableBuilder(
column: $table.updatedAt,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get name => $composableBuilder(
column: $table.name, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get faceAssetId => $composableBuilder(
column: $table.faceAssetId,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get thumbnailPath => $composableBuilder(
column: $table.thumbnailPath,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<bool> get isFavorite => $composableBuilder(
column: $table.isFavorite,
builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<bool> get isHidden => $composableBuilder(
column: $table.isHidden, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<String> get color => $composableBuilder(
column: $table.color, builder: (column) => i0.ColumnOrderings(column));
i0.ColumnOrderings<DateTime> get birthDate => $composableBuilder(
column: $table.birthDate,
builder: (column) => i0.ColumnOrderings(column));
i4.$$UserEntityTableOrderingComposer get ownerId {
final i4.$$UserEntityTableOrderingComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.ownerId,
referencedTable: i5.ReadDatabaseContainer($db)
.resultSet<i4.$UserEntityTable>('user_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i4.$$UserEntityTableOrderingComposer(
$db: $db,
$table: i5.ReadDatabaseContainer($db)
.resultSet<i4.$UserEntityTable>('user_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$PersonEntityTableAnnotationComposer
extends i0.Composer<i0.GeneratedDatabase, i1.$PersonEntityTable> {
$$PersonEntityTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
i0.GeneratedColumn<String> get id =>
$composableBuilder(column: $table.id, builder: (column) => column);
i0.GeneratedColumn<DateTime> get createdAt =>
$composableBuilder(column: $table.createdAt, builder: (column) => column);
i0.GeneratedColumn<DateTime> get updatedAt =>
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
i0.GeneratedColumn<String> get name =>
$composableBuilder(column: $table.name, builder: (column) => column);
i0.GeneratedColumn<String> get faceAssetId => $composableBuilder(
column: $table.faceAssetId, builder: (column) => column);
i0.GeneratedColumn<String> get thumbnailPath => $composableBuilder(
column: $table.thumbnailPath, builder: (column) => column);
i0.GeneratedColumn<bool> get isFavorite => $composableBuilder(
column: $table.isFavorite, builder: (column) => column);
i0.GeneratedColumn<bool> get isHidden =>
$composableBuilder(column: $table.isHidden, builder: (column) => column);
i0.GeneratedColumn<String> get color =>
$composableBuilder(column: $table.color, builder: (column) => column);
i0.GeneratedColumn<DateTime> get birthDate =>
$composableBuilder(column: $table.birthDate, builder: (column) => column);
i4.$$UserEntityTableAnnotationComposer get ownerId {
final i4.$$UserEntityTableAnnotationComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.ownerId,
referencedTable: i5.ReadDatabaseContainer($db)
.resultSet<i4.$UserEntityTable>('user_entity'),
getReferencedColumn: (t) => t.id,
builder: (joinBuilder,
{$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer}) =>
i4.$$UserEntityTableAnnotationComposer(
$db: $db,
$table: i5.ReadDatabaseContainer($db)
.resultSet<i4.$UserEntityTable>('user_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
$removeJoinBuilderFromRootComposer,
));
return composer;
}
}
class $$PersonEntityTableTableManager extends i0.RootTableManager<
i0.GeneratedDatabase,
i1.$PersonEntityTable,
i1.PersonEntityData,
i1.$$PersonEntityTableFilterComposer,
i1.$$PersonEntityTableOrderingComposer,
i1.$$PersonEntityTableAnnotationComposer,
$$PersonEntityTableCreateCompanionBuilder,
$$PersonEntityTableUpdateCompanionBuilder,
(i1.PersonEntityData, i1.$$PersonEntityTableReferences),
i1.PersonEntityData,
i0.PrefetchHooks Function({bool ownerId})> {
$$PersonEntityTableTableManager(
i0.GeneratedDatabase db, i1.$PersonEntityTable table)
: super(i0.TableManagerState(
db: db,
table: table,
createFilteringComposer: () =>
i1.$$PersonEntityTableFilterComposer($db: db, $table: table),
createOrderingComposer: () =>
i1.$$PersonEntityTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () =>
i1.$$PersonEntityTableAnnotationComposer($db: db, $table: table),
updateCompanionCallback: ({
i0.Value<String> id = const i0.Value.absent(),
i0.Value<DateTime> createdAt = const i0.Value.absent(),
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
i0.Value<String> ownerId = const i0.Value.absent(),
i0.Value<String> name = const i0.Value.absent(),
i0.Value<String?> faceAssetId = const i0.Value.absent(),
i0.Value<String> thumbnailPath = const i0.Value.absent(),
i0.Value<bool> isFavorite = const i0.Value.absent(),
i0.Value<bool> isHidden = const i0.Value.absent(),
i0.Value<String?> color = const i0.Value.absent(),
i0.Value<DateTime?> birthDate = const i0.Value.absent(),
}) =>
i1.PersonEntityCompanion(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
ownerId: ownerId,
name: name,
faceAssetId: faceAssetId,
thumbnailPath: thumbnailPath,
isFavorite: isFavorite,
isHidden: isHidden,
color: color,
birthDate: birthDate,
),
createCompanionCallback: ({
required String id,
i0.Value<DateTime> createdAt = const i0.Value.absent(),
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
required String ownerId,
required String name,
i0.Value<String?> faceAssetId = const i0.Value.absent(),
required String thumbnailPath,
required bool isFavorite,
required bool isHidden,
i0.Value<String?> color = const i0.Value.absent(),
i0.Value<DateTime?> birthDate = const i0.Value.absent(),
}) =>
i1.PersonEntityCompanion.insert(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
ownerId: ownerId,
name: name,
faceAssetId: faceAssetId,
thumbnailPath: thumbnailPath,
isFavorite: isFavorite,
isHidden: isHidden,
color: color,
birthDate: birthDate,
),
withReferenceMapper: (p0) => p0
.map((e) => (
e.readTable(table),
i1.$$PersonEntityTableReferences(db, table, e)
))
.toList(),
prefetchHooksCallback: ({ownerId = false}) {
return i0.PrefetchHooks(
db: db,
explicitlyWatchedTables: [],
addJoins: <
T extends i0.TableManagerState<
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic,
dynamic>>(state) {
if (ownerId) {
state = state.withJoin(
currentTable: table,
currentColumn: table.ownerId,
referencedTable:
i1.$$PersonEntityTableReferences._ownerIdTable(db),
referencedColumn:
i1.$$PersonEntityTableReferences._ownerIdTable(db).id,
) as T;
}
return state;
},
getPrefetchedDataCallback: (items) async {
return [];
},
);
},
));
}
typedef $$PersonEntityTableProcessedTableManager = i0.ProcessedTableManager<
i0.GeneratedDatabase,
i1.$PersonEntityTable,
i1.PersonEntityData,
i1.$$PersonEntityTableFilterComposer,
i1.$$PersonEntityTableOrderingComposer,
i1.$$PersonEntityTableAnnotationComposer,
$$PersonEntityTableCreateCompanionBuilder,
$$PersonEntityTableUpdateCompanionBuilder,
(i1.PersonEntityData, i1.$$PersonEntityTableReferences),
i1.PersonEntityData,
i0.PrefetchHooks Function({bool ownerId})>;
class $PersonEntityTable extends i2.PersonEntity
with i0.TableInfo<$PersonEntityTable, i1.PersonEntityData> {
@override
final i0.GeneratedDatabase attachedDatabase;
final String? _alias;
$PersonEntityTable(this.attachedDatabase, [this._alias]);
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
@override
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
'id', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _createdAtMeta =
const i0.VerificationMeta('createdAt');
@override
late final i0.GeneratedColumn<DateTime> createdAt =
i0.GeneratedColumn<DateTime>('created_at', aliasedName, false,
type: i0.DriftSqlType.dateTime,
requiredDuringInsert: false,
defaultValue: i3.currentDateAndTime);
static const i0.VerificationMeta _updatedAtMeta =
const i0.VerificationMeta('updatedAt');
@override
late final i0.GeneratedColumn<DateTime> updatedAt =
i0.GeneratedColumn<DateTime>('updated_at', aliasedName, false,
type: i0.DriftSqlType.dateTime,
requiredDuringInsert: false,
defaultValue: i3.currentDateAndTime);
static const i0.VerificationMeta _ownerIdMeta =
const i0.VerificationMeta('ownerId');
@override
late final i0.GeneratedColumn<String> ownerId = i0.GeneratedColumn<String>(
'owner_id', aliasedName, false,
type: i0.DriftSqlType.string,
requiredDuringInsert: true,
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'REFERENCES user_entity (id) ON DELETE CASCADE'));
static const i0.VerificationMeta _nameMeta =
const i0.VerificationMeta('name');
@override
late final i0.GeneratedColumn<String> name = i0.GeneratedColumn<String>(
'name', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _faceAssetIdMeta =
const i0.VerificationMeta('faceAssetId');
@override
late final i0.GeneratedColumn<String> faceAssetId =
i0.GeneratedColumn<String>('face_asset_id', aliasedName, true,
type: i0.DriftSqlType.string, requiredDuringInsert: false);
static const i0.VerificationMeta _thumbnailPathMeta =
const i0.VerificationMeta('thumbnailPath');
@override
late final i0.GeneratedColumn<String> thumbnailPath =
i0.GeneratedColumn<String>('thumbnail_path', aliasedName, false,
type: i0.DriftSqlType.string, requiredDuringInsert: true);
static const i0.VerificationMeta _isFavoriteMeta =
const i0.VerificationMeta('isFavorite');
@override
late final i0.GeneratedColumn<bool> isFavorite = i0.GeneratedColumn<bool>(
'is_favorite', aliasedName, false,
type: i0.DriftSqlType.bool,
requiredDuringInsert: true,
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'CHECK ("is_favorite" IN (0, 1))'));
static const i0.VerificationMeta _isHiddenMeta =
const i0.VerificationMeta('isHidden');
@override
late final i0.GeneratedColumn<bool> isHidden = i0.GeneratedColumn<bool>(
'is_hidden', aliasedName, false,
type: i0.DriftSqlType.bool,
requiredDuringInsert: true,
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'CHECK ("is_hidden" IN (0, 1))'));
static const i0.VerificationMeta _colorMeta =
const i0.VerificationMeta('color');
@override
late final i0.GeneratedColumn<String> color = i0.GeneratedColumn<String>(
'color', aliasedName, true,
type: i0.DriftSqlType.string, requiredDuringInsert: false);
static const i0.VerificationMeta _birthDateMeta =
const i0.VerificationMeta('birthDate');
@override
late final i0.GeneratedColumn<DateTime> birthDate =
i0.GeneratedColumn<DateTime>('birth_date', aliasedName, true,
type: i0.DriftSqlType.dateTime, requiredDuringInsert: false);
@override
List<i0.GeneratedColumn> get $columns => [
id,
createdAt,
updatedAt,
ownerId,
name,
faceAssetId,
thumbnailPath,
isFavorite,
isHidden,
color,
birthDate
];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'person_entity';
@override
i0.VerificationContext validateIntegrity(
i0.Insertable<i1.PersonEntityData> instance,
{bool isInserting = false}) {
final context = i0.VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
} else if (isInserting) {
context.missing(_idMeta);
}
if (data.containsKey('created_at')) {
context.handle(_createdAtMeta,
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
}
if (data.containsKey('updated_at')) {
context.handle(_updatedAtMeta,
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
}
if (data.containsKey('owner_id')) {
context.handle(_ownerIdMeta,
ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta));
} else if (isInserting) {
context.missing(_ownerIdMeta);
}
if (data.containsKey('name')) {
context.handle(
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
} else if (isInserting) {
context.missing(_nameMeta);
}
if (data.containsKey('face_asset_id')) {
context.handle(
_faceAssetIdMeta,
faceAssetId.isAcceptableOrUnknown(
data['face_asset_id']!, _faceAssetIdMeta));
}
if (data.containsKey('thumbnail_path')) {
context.handle(
_thumbnailPathMeta,
thumbnailPath.isAcceptableOrUnknown(
data['thumbnail_path']!, _thumbnailPathMeta));
} else if (isInserting) {
context.missing(_thumbnailPathMeta);
}
if (data.containsKey('is_favorite')) {
context.handle(
_isFavoriteMeta,
isFavorite.isAcceptableOrUnknown(
data['is_favorite']!, _isFavoriteMeta));
} else if (isInserting) {
context.missing(_isFavoriteMeta);
}
if (data.containsKey('is_hidden')) {
context.handle(_isHiddenMeta,
isHidden.isAcceptableOrUnknown(data['is_hidden']!, _isHiddenMeta));
} else if (isInserting) {
context.missing(_isHiddenMeta);
}
if (data.containsKey('color')) {
context.handle(
_colorMeta, color.isAcceptableOrUnknown(data['color']!, _colorMeta));
}
if (data.containsKey('birth_date')) {
context.handle(_birthDateMeta,
birthDate.isAcceptableOrUnknown(data['birth_date']!, _birthDateMeta));
}
return context;
}
@override
Set<i0.GeneratedColumn> get $primaryKey => {id};
@override
i1.PersonEntityData map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return i1.PersonEntityData(
id: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
createdAt: attachedDatabase.typeMapping.read(
i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
updatedAt: attachedDatabase.typeMapping.read(
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
ownerId: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!,
name: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!,
faceAssetId: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string, data['${effectivePrefix}face_asset_id']),
thumbnailPath: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string, data['${effectivePrefix}thumbnail_path'])!,
isFavorite: attachedDatabase.typeMapping
.read(i0.DriftSqlType.bool, data['${effectivePrefix}is_favorite'])!,
isHidden: attachedDatabase.typeMapping
.read(i0.DriftSqlType.bool, data['${effectivePrefix}is_hidden'])!,
color: attachedDatabase.typeMapping
.read(i0.DriftSqlType.string, data['${effectivePrefix}color']),
birthDate: attachedDatabase.typeMapping
.read(i0.DriftSqlType.dateTime, data['${effectivePrefix}birth_date']),
);
}
@override
$PersonEntityTable createAlias(String alias) {
return $PersonEntityTable(attachedDatabase, alias);
}
@override
bool get withoutRowId => true;
@override
bool get isStrict => true;
}
class PersonEntityData extends i0.DataClass
implements i0.Insertable<i1.PersonEntityData> {
final String id;
final DateTime createdAt;
final DateTime updatedAt;
final String ownerId;
final String name;
final String? faceAssetId;
final String thumbnailPath;
final bool isFavorite;
final bool isHidden;
final String? color;
final DateTime? birthDate;
const PersonEntityData(
{required this.id,
required this.createdAt,
required this.updatedAt,
required this.ownerId,
required this.name,
this.faceAssetId,
required this.thumbnailPath,
required this.isFavorite,
required this.isHidden,
this.color,
this.birthDate});
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
map['id'] = i0.Variable<String>(id);
map['created_at'] = i0.Variable<DateTime>(createdAt);
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
map['owner_id'] = i0.Variable<String>(ownerId);
map['name'] = i0.Variable<String>(name);
if (!nullToAbsent || faceAssetId != null) {
map['face_asset_id'] = i0.Variable<String>(faceAssetId);
}
map['thumbnail_path'] = i0.Variable<String>(thumbnailPath);
map['is_favorite'] = i0.Variable<bool>(isFavorite);
map['is_hidden'] = i0.Variable<bool>(isHidden);
if (!nullToAbsent || color != null) {
map['color'] = i0.Variable<String>(color);
}
if (!nullToAbsent || birthDate != null) {
map['birth_date'] = i0.Variable<DateTime>(birthDate);
}
return map;
}
factory PersonEntityData.fromJson(Map<String, dynamic> json,
{i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return PersonEntityData(
id: serializer.fromJson<String>(json['id']),
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
ownerId: serializer.fromJson<String>(json['ownerId']),
name: serializer.fromJson<String>(json['name']),
faceAssetId: serializer.fromJson<String?>(json['faceAssetId']),
thumbnailPath: serializer.fromJson<String>(json['thumbnailPath']),
isFavorite: serializer.fromJson<bool>(json['isFavorite']),
isHidden: serializer.fromJson<bool>(json['isHidden']),
color: serializer.fromJson<String?>(json['color']),
birthDate: serializer.fromJson<DateTime?>(json['birthDate']),
);
}
@override
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<String>(id),
'createdAt': serializer.toJson<DateTime>(createdAt),
'updatedAt': serializer.toJson<DateTime>(updatedAt),
'ownerId': serializer.toJson<String>(ownerId),
'name': serializer.toJson<String>(name),
'faceAssetId': serializer.toJson<String?>(faceAssetId),
'thumbnailPath': serializer.toJson<String>(thumbnailPath),
'isFavorite': serializer.toJson<bool>(isFavorite),
'isHidden': serializer.toJson<bool>(isHidden),
'color': serializer.toJson<String?>(color),
'birthDate': serializer.toJson<DateTime?>(birthDate),
};
}
i1.PersonEntityData copyWith(
{String? id,
DateTime? createdAt,
DateTime? updatedAt,
String? ownerId,
String? name,
i0.Value<String?> faceAssetId = const i0.Value.absent(),
String? thumbnailPath,
bool? isFavorite,
bool? isHidden,
i0.Value<String?> color = const i0.Value.absent(),
i0.Value<DateTime?> birthDate = const i0.Value.absent()}) =>
i1.PersonEntityData(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
ownerId: ownerId ?? this.ownerId,
name: name ?? this.name,
faceAssetId: faceAssetId.present ? faceAssetId.value : this.faceAssetId,
thumbnailPath: thumbnailPath ?? this.thumbnailPath,
isFavorite: isFavorite ?? this.isFavorite,
isHidden: isHidden ?? this.isHidden,
color: color.present ? color.value : this.color,
birthDate: birthDate.present ? birthDate.value : this.birthDate,
);
PersonEntityData copyWithCompanion(i1.PersonEntityCompanion data) {
return PersonEntityData(
id: data.id.present ? data.id.value : this.id,
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId,
name: data.name.present ? data.name.value : this.name,
faceAssetId:
data.faceAssetId.present ? data.faceAssetId.value : this.faceAssetId,
thumbnailPath: data.thumbnailPath.present
? data.thumbnailPath.value
: this.thumbnailPath,
isFavorite:
data.isFavorite.present ? data.isFavorite.value : this.isFavorite,
isHidden: data.isHidden.present ? data.isHidden.value : this.isHidden,
color: data.color.present ? data.color.value : this.color,
birthDate: data.birthDate.present ? data.birthDate.value : this.birthDate,
);
}
@override
String toString() {
return (StringBuffer('PersonEntityData(')
..write('id: $id, ')
..write('createdAt: $createdAt, ')
..write('updatedAt: $updatedAt, ')
..write('ownerId: $ownerId, ')
..write('name: $name, ')
..write('faceAssetId: $faceAssetId, ')
..write('thumbnailPath: $thumbnailPath, ')
..write('isFavorite: $isFavorite, ')
..write('isHidden: $isHidden, ')
..write('color: $color, ')
..write('birthDate: $birthDate')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(id, createdAt, updatedAt, ownerId, name,
faceAssetId, thumbnailPath, isFavorite, isHidden, color, birthDate);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is i1.PersonEntityData &&
other.id == this.id &&
other.createdAt == this.createdAt &&
other.updatedAt == this.updatedAt &&
other.ownerId == this.ownerId &&
other.name == this.name &&
other.faceAssetId == this.faceAssetId &&
other.thumbnailPath == this.thumbnailPath &&
other.isFavorite == this.isFavorite &&
other.isHidden == this.isHidden &&
other.color == this.color &&
other.birthDate == this.birthDate);
}
class PersonEntityCompanion extends i0.UpdateCompanion<i1.PersonEntityData> {
final i0.Value<String> id;
final i0.Value<DateTime> createdAt;
final i0.Value<DateTime> updatedAt;
final i0.Value<String> ownerId;
final i0.Value<String> name;
final i0.Value<String?> faceAssetId;
final i0.Value<String> thumbnailPath;
final i0.Value<bool> isFavorite;
final i0.Value<bool> isHidden;
final i0.Value<String?> color;
final i0.Value<DateTime?> birthDate;
const PersonEntityCompanion({
this.id = const i0.Value.absent(),
this.createdAt = const i0.Value.absent(),
this.updatedAt = const i0.Value.absent(),
this.ownerId = const i0.Value.absent(),
this.name = const i0.Value.absent(),
this.faceAssetId = const i0.Value.absent(),
this.thumbnailPath = const i0.Value.absent(),
this.isFavorite = const i0.Value.absent(),
this.isHidden = const i0.Value.absent(),
this.color = const i0.Value.absent(),
this.birthDate = const i0.Value.absent(),
});
PersonEntityCompanion.insert({
required String id,
this.createdAt = const i0.Value.absent(),
this.updatedAt = const i0.Value.absent(),
required String ownerId,
required String name,
this.faceAssetId = const i0.Value.absent(),
required String thumbnailPath,
required bool isFavorite,
required bool isHidden,
this.color = const i0.Value.absent(),
this.birthDate = const i0.Value.absent(),
}) : id = i0.Value(id),
ownerId = i0.Value(ownerId),
name = i0.Value(name),
thumbnailPath = i0.Value(thumbnailPath),
isFavorite = i0.Value(isFavorite),
isHidden = i0.Value(isHidden);
static i0.Insertable<i1.PersonEntityData> custom({
i0.Expression<String>? id,
i0.Expression<DateTime>? createdAt,
i0.Expression<DateTime>? updatedAt,
i0.Expression<String>? ownerId,
i0.Expression<String>? name,
i0.Expression<String>? faceAssetId,
i0.Expression<String>? thumbnailPath,
i0.Expression<bool>? isFavorite,
i0.Expression<bool>? isHidden,
i0.Expression<String>? color,
i0.Expression<DateTime>? birthDate,
}) {
return i0.RawValuesInsertable({
if (id != null) 'id': id,
if (createdAt != null) 'created_at': createdAt,
if (updatedAt != null) 'updated_at': updatedAt,
if (ownerId != null) 'owner_id': ownerId,
if (name != null) 'name': name,
if (faceAssetId != null) 'face_asset_id': faceAssetId,
if (thumbnailPath != null) 'thumbnail_path': thumbnailPath,
if (isFavorite != null) 'is_favorite': isFavorite,
if (isHidden != null) 'is_hidden': isHidden,
if (color != null) 'color': color,
if (birthDate != null) 'birth_date': birthDate,
});
}
i1.PersonEntityCompanion copyWith(
{i0.Value<String>? id,
i0.Value<DateTime>? createdAt,
i0.Value<DateTime>? updatedAt,
i0.Value<String>? ownerId,
i0.Value<String>? name,
i0.Value<String?>? faceAssetId,
i0.Value<String>? thumbnailPath,
i0.Value<bool>? isFavorite,
i0.Value<bool>? isHidden,
i0.Value<String?>? color,
i0.Value<DateTime?>? birthDate}) {
return i1.PersonEntityCompanion(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
ownerId: ownerId ?? this.ownerId,
name: name ?? this.name,
faceAssetId: faceAssetId ?? this.faceAssetId,
thumbnailPath: thumbnailPath ?? this.thumbnailPath,
isFavorite: isFavorite ?? this.isFavorite,
isHidden: isHidden ?? this.isHidden,
color: color ?? this.color,
birthDate: birthDate ?? this.birthDate,
);
}
@override
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
final map = <String, i0.Expression>{};
if (id.present) {
map['id'] = i0.Variable<String>(id.value);
}
if (createdAt.present) {
map['created_at'] = i0.Variable<DateTime>(createdAt.value);
}
if (updatedAt.present) {
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
}
if (ownerId.present) {
map['owner_id'] = i0.Variable<String>(ownerId.value);
}
if (name.present) {
map['name'] = i0.Variable<String>(name.value);
}
if (faceAssetId.present) {
map['face_asset_id'] = i0.Variable<String>(faceAssetId.value);
}
if (thumbnailPath.present) {
map['thumbnail_path'] = i0.Variable<String>(thumbnailPath.value);
}
if (isFavorite.present) {
map['is_favorite'] = i0.Variable<bool>(isFavorite.value);
}
if (isHidden.present) {
map['is_hidden'] = i0.Variable<bool>(isHidden.value);
}
if (color.present) {
map['color'] = i0.Variable<String>(color.value);
}
if (birthDate.present) {
map['birth_date'] = i0.Variable<DateTime>(birthDate.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('PersonEntityCompanion(')
..write('id: $id, ')
..write('createdAt: $createdAt, ')
..write('updatedAt: $updatedAt, ')
..write('ownerId: $ownerId, ')
..write('name: $name, ')
..write('faceAssetId: $faceAssetId, ')
..write('thumbnailPath: $thumbnailPath, ')
..write('isFavorite: $isFavorite, ')
..write('isHidden: $isHidden, ')
..write('color: $color, ')
..write('birthDate: $birthDate')
..write(')'))
.toString();
}
}

View File

@@ -10,6 +10,7 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/memory.entity.dart';
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
import 'package:immich_mobile/infrastructure/entities/person.entity.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.dart';
@@ -52,6 +53,7 @@ class IsarDatabaseRepository implements IDatabaseRepository {
MemoryEntity,
MemoryAssetEntity,
StackEntity,
PersonEntity,
],
include: {
'package:immich_mobile/infrastructure/entities/merged_asset.drift',

View File

@@ -29,9 +29,11 @@ import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.
as i13;
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart'
as i14;
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart'
as i15;
import 'package:drift/internal/modular.dart' as i16;
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
as i16;
import 'package:drift/internal/modular.dart' as i17;
abstract class $Drift extends i0.GeneratedDatabase {
$Drift(i0.QueryExecutor e) : super(e);
@@ -61,8 +63,9 @@ abstract class $Drift extends i0.GeneratedDatabase {
late final i13.$MemoryAssetEntityTable memoryAssetEntity =
i13.$MemoryAssetEntityTable(this);
late final i14.$StackEntityTable stackEntity = i14.$StackEntityTable(this);
i15.MergedAssetDrift get mergedAssetDrift => i16.ReadDatabaseContainer(this)
.accessor<i15.MergedAssetDrift>(i15.MergedAssetDrift.new);
late final i15.$PersonEntityTable personEntity = i15.$PersonEntityTable(this);
i16.MergedAssetDrift get mergedAssetDrift => i17.ReadDatabaseContainer(this)
.accessor<i16.MergedAssetDrift>(i16.MergedAssetDrift.new);
@override
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
@@ -84,7 +87,8 @@ abstract class $Drift extends i0.GeneratedDatabase {
remoteAlbumUserEntity,
memoryEntity,
memoryAssetEntity,
stackEntity
stackEntity,
personEntity
];
@override
i0.StreamQueryUpdateRules get streamUpdateRules =>
@@ -216,6 +220,13 @@ abstract class $Drift extends i0.GeneratedDatabase {
i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete),
],
),
i0.WritePropagation(
on: i0.TableUpdateQuery.onTableName('user_entity',
limitUpdateKind: i0.UpdateKind.delete),
result: [
i0.TableUpdate('person_entity', kind: i0.UpdateKind.delete),
],
),
],
);
@override
@@ -255,4 +266,6 @@ class $DriftManager {
i13.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity);
i14.$$StackEntityTableTableManager get stackEntity =>
i14.$$StackEntityTableTableManager(_db, _db.stackEntity);
i15.$$PersonEntityTableTableManager get personEntity =>
i15.$$PersonEntityTableTableManager(_db, _db.personEntity);
}

View File

@@ -0,0 +1,36 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/person.model.dart';
import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
class DriftPersonRepository extends DriftDatabaseRepository {
final Drift _db;
const DriftPersonRepository(this._db) : super(_db);
Future<List<Person>> getAll(String userId) {
final query = _db.personEntity.select()
..where((e) => e.ownerId.equals(userId));
return query.map((person) {
return person.toDto();
}).get();
}
}
extension on PersonEntityData {
Person toDto() {
return Person(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
ownerId: ownerId,
name: name,
faceAssetId: faceAssetId,
thumbnailPath: thumbnailPath,
isFavorite: isFavorite,
isHidden: isHidden,
color: color,
birthDate: birthDate,
);
}
}

View File

@@ -56,6 +56,7 @@ class SyncApiRepository {
SyncRequestType.memoryToAssetsV1,
SyncRequestType.stacksV1,
SyncRequestType.partnerStacksV1,
SyncRequestType.peopleV1,
],
).toJson(),
);
@@ -170,6 +171,8 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
SyncEntityType.partnerStackV1: SyncStackV1.fromJson,
SyncEntityType.partnerStackBackfillV1: SyncStackV1.fromJson,
SyncEntityType.partnerStackDeleteV1: SyncStackDeleteV1.fromJson,
SyncEntityType.personV1: SyncPersonV1.fromJson,
SyncEntityType.personDeleteV1: SyncPersonDeleteV1.fromJson,
};
class _SyncAckV1 {

View File

@@ -7,6 +7,7 @@ import 'package:immich_mobile/domain/models/memory.model.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/person.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart';
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart';
@@ -460,6 +461,48 @@ class SyncStreamRepository extends DriftDatabaseRepository {
rethrow;
}
}
Future<void> updatePeopleV1(Iterable<SyncPersonV1> data) async {
try {
await _db.batch((batch) {
for (final person in data) {
final companion = PersonEntityCompanion(
createdAt: Value(person.createdAt),
updatedAt: Value(person.updatedAt),
ownerId: Value(person.ownerId),
name: Value(person.name),
faceAssetId: Value(person.faceAssetId),
thumbnailPath: Value(person.thumbnailPath),
isFavorite: Value(person.isFavorite),
isHidden: Value(person.isHidden),
color: Value(person.color),
birthDate: Value(person.birthDate),
);
batch.insert(
_db.personEntity,
companion.copyWith(id: Value(person.id)),
onConflict: DoUpdate((_) => companion),
);
}
});
} catch (error, stack) {
_logger.severe('Error: updatePeopleV1', error, stack);
rethrow;
}
}
Future<void> deletePeopleV1(
Iterable<SyncPersonDeleteV1> data,
) async {
try {
await _db.personEntity.deleteWhere(
(row) => row.id.isIn(data.map((e) => e.personId)),
);
} catch (error, stack) {
_logger.severe('Error: deletePeopleV1', error, stack);
}
}
}
extension on AssetTypeEnum {

View File

@@ -237,7 +237,7 @@ class SearchFilter {
String? filename;
String? description;
String? language;
Set<Person> people;
Set<PersonDto> people;
SearchLocationFilter location;
SearchCameraFilter camera;
SearchDateFilter date;
@@ -282,7 +282,7 @@ class SearchFilter {
String? filename,
String? description,
String? language,
Set<Person>? people,
Set<PersonDto>? people,
SearchLocationFilter? location,
SearchCameraFilter? camera,
SearchDateFilter? date,

View File

@@ -147,7 +147,7 @@ class SearchPage extends HookConsumerWidget {
);
showPeoplePicker() {
handleOnSelect(Set<Person> value) {
handleOnSelect(Set<PersonDto> value) {
filter.value = filter.value.copyWith(
people: value,
);

View File

@@ -122,6 +122,7 @@ final _features = [
await db.memoryEntity.deleteAll();
await db.memoryAssetEntity.deleteAll();
await db.stackEntity.deleteAll();
await db.personEntity.deleteAll();
},
),
_Feature(

View File

@@ -166,6 +166,10 @@ final _remoteStats = [
name: 'Stacks',
load: (db) => db.managers.stackEntity.count(),
),
_Stat(
name: 'People',
load: (db) => db.managers.personEntity.count(),
),
];
@RoutePage()

View File

@@ -0,0 +1,7 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/infrastructure/repositories/person.repository.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
final driftPersonProvider = Provider<DriftPersonRepository>(
(ref) => DriftPersonRepository(ref.watch(driftProvider)),
);

View File

@@ -9,7 +9,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'people.provider.g.dart';
@riverpod
Future<List<Person>> getAllPeople(
Future<List<PersonDto>> getAllPeople(
Ref ref,
) async {
final PersonService personService = ref.read(personServiceProvider);

View File

@@ -6,11 +6,12 @@ part of 'people.provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$getAllPeopleHash() => r'226947af3b09ce62224916543958dd1d5e2ba651';
String _$getAllPeopleHash() => r'2c5e6a207683f15ab209650615fdf9cb7f76c736';
/// See also [getAllPeople].
@ProviderFor(getAllPeople)
final getAllPeopleProvider = AutoDisposeFutureProvider<List<Person>>.internal(
final getAllPeopleProvider =
AutoDisposeFutureProvider<List<PersonDto>>.internal(
getAllPeople,
name: r'getAllPeopleProvider',
debugGetCreateSourceHash:
@@ -21,7 +22,7 @@ final getAllPeopleProvider = AutoDisposeFutureProvider<List<Person>>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef GetAllPeopleRef = AutoDisposeFutureProviderRef<List<Person>>;
typedef GetAllPeopleRef = AutoDisposeFutureProviderRef<List<PersonDto>>;
String _$personAssetsHash() => r'c1d35ee0e024bd6915e21bc724be4b458a14bc24';
/// Copied from Dart SDK

View File

@@ -43,6 +43,7 @@ class AuthRepository extends DatabaseRepository {
_drift.memoryEntity.deleteAll(),
_drift.memoryAssetEntity.deleteAll(),
_drift.stackEntity.deleteAll(),
_drift.personEntity.deleteAll(),
]);
});
}

View File

@@ -13,19 +13,19 @@ class PersonApiRepository extends ApiRepository {
PersonApiRepository(this._api);
Future<List<Person>> getAll() async {
Future<List<PersonDto>> getAll() async {
final dto = await checkNull(_api.getAllPeople());
return dto.people.map(_toPerson).toList();
}
Future<Person> update(String id, {String? name}) async {
Future<PersonDto> update(String id, {String? name}) async {
final dto = await checkNull(
_api.updatePerson(id, PersonUpdateDto(name: name)),
);
return _toPerson(dto);
}
static Person _toPerson(PersonResponseDto dto) => Person(
static PersonDto _toPerson(PersonResponseDto dto) => PersonDto(
birthDate: dto.birthDate,
id: dto.id,
isHidden: dto.isHidden,

View File

@@ -28,7 +28,7 @@ class PersonService {
this._assetRepository,
);
Future<List<Person>> getAllPeople() async {
Future<List<PersonDto>> getAllPeople() async {
try {
return await _personApiRepository.getAll();
} catch (error, stack) {
@@ -48,7 +48,7 @@ class PersonService {
return [];
}
Future<Person?> updateName(String id, String name) async {
Future<PersonDto?> updateName(String id, String name) async {
try {
return await _personApiRepository.update(id, name: name);
} catch (error, stack) {

View File

@@ -14,8 +14,8 @@ import 'package:immich_mobile/widgets/common/search_field.dart';
class PeoplePicker extends HookConsumerWidget {
const PeoplePicker({super.key, required this.onSelect, this.filter});
final Function(Set<Person>) onSelect;
final Set<Person>? filter;
final Function(Set<PersonDto>) onSelect;
final Set<PersonDto>? filter;
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -24,7 +24,7 @@ class PeoplePicker extends HookConsumerWidget {
final searchQuery = useState('');
final people = ref.watch(getAllPeopleProvider);
final headers = ApiService.getRequestHeaders();
final selectedPeople = useState<Set<Person>>(filter ?? {});
final selectedPeople = useState<Set<PersonDto>>(filter ?? {});
return Column(
children: [

View File

@@ -101,6 +101,10 @@ void main() {
debugLabel: any(named: 'debugLabel'),
),
).thenAnswer(successHandler);
when(() => mockSyncStreamRepo.updatePeopleV1(any()))
.thenAnswer(successHandler);
when(() => mockSyncStreamRepo.deletePeopleV1(any()))
.thenAnswer(successHandler);
sut = SyncStreamService(
syncApiRepository: mockSyncApiRepo,