1
0
mirror of https://github.com/immich-app/immich.git synced 2025-07-16 07:24:40 +02:00

show sync information

This commit is contained in:
Alex
2025-07-01 15:37:52 -05:00
parent 3cb2f896b9
commit c8d7ad3935
6 changed files with 287 additions and 22 deletions

View File

@ -1,7 +1,200 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
enum MemoryTypeEnum {
// do not change this order!
onThisDay,
}
class MemoryData {
final int year;
MemoryData({
required this.year,
});
MemoryData copyWith({
int? year,
}) {
return MemoryData(
year: year ?? this.year,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'year': year,
};
}
factory MemoryData.fromMap(Map<String, dynamic> map) {
return MemoryData(
year: map['year'] as int,
);
}
String toJson() => json.encode(toMap());
factory MemoryData.fromJson(String source) =>
MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() => 'MemoryData(year: $year)';
@override
bool operator ==(covariant MemoryData other) {
if (identical(this, other)) return true;
return other.year == year;
}
@override
int get hashCode => year.hashCode;
}
// Model for a memory stored in the server
class Memory {}
class Memory {
final String id;
final DateTime createdAt;
final DateTime updatedAt;
final DateTime? deletedAt;
final String ownerId;
// enum
final MemoryTypeEnum type;
final MemoryData data;
final bool isSaved;
final DateTime memoryAt;
final DateTime? seenAt;
final DateTime? showAt;
final DateTime? hideAt;
Memory({
required this.id,
required this.createdAt,
required this.updatedAt,
this.deletedAt,
required this.ownerId,
required this.type,
required this.data,
required this.isSaved,
required this.memoryAt,
this.seenAt,
this.showAt,
this.hideAt,
});
Memory copyWith({
String? id,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? deletedAt,
String? ownerId,
MemoryTypeEnum? type,
MemoryData? data,
bool? isSaved,
DateTime? memoryAt,
DateTime? seenAt,
DateTime? showAt,
DateTime? hideAt,
}) {
return Memory(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
ownerId: ownerId ?? this.ownerId,
type: type ?? this.type,
data: data ?? this.data,
isSaved: isSaved ?? this.isSaved,
memoryAt: memoryAt ?? this.memoryAt,
seenAt: seenAt ?? this.seenAt,
showAt: showAt ?? this.showAt,
hideAt: hideAt ?? this.hideAt,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'createdAt': createdAt.millisecondsSinceEpoch,
'updatedAt': updatedAt.millisecondsSinceEpoch,
'deletedAt': deletedAt?.millisecondsSinceEpoch,
'ownerId': ownerId,
'type': type.index,
'data': data.toMap(),
'isSaved': isSaved,
'memoryAt': memoryAt.millisecondsSinceEpoch,
'seenAt': seenAt?.millisecondsSinceEpoch,
'showAt': showAt?.millisecondsSinceEpoch,
'hideAt': hideAt?.millisecondsSinceEpoch,
};
}
factory Memory.fromMap(Map<String, dynamic> map) {
return Memory(
id: map['id'] as String,
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt'] as int),
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int),
deletedAt: map['deletedAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['deletedAt'] as int)
: null,
ownerId: map['ownerId'] as String,
type: MemoryTypeEnum.values[map['type'] as int],
data: MemoryData.fromMap(map['data'] as Map<String, dynamic>),
isSaved: map['isSaved'] as bool,
memoryAt: DateTime.fromMillisecondsSinceEpoch(map['memoryAt'] as int),
seenAt: map['seenAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['seenAt'] as int)
: null,
showAt: map['showAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['showAt'] as int)
: null,
hideAt: map['hideAt'] != null
? DateTime.fromMillisecondsSinceEpoch(map['hideAt'] as int)
: null,
);
}
String toJson() => json.encode(toMap());
factory Memory.fromJson(String source) =>
Memory.fromMap(json.decode(source) as Map<String, dynamic>);
@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)';
}
@override
bool operator ==(covariant Memory other) {
if (identical(this, other)) return true;
return other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.deletedAt == deletedAt &&
other.ownerId == ownerId &&
other.type == type &&
other.data == data &&
other.isSaved == isSaved &&
other.memoryAt == memoryAt &&
other.seenAt == seenAt &&
other.showAt == showAt &&
other.hideAt == hideAt;
}
@override
int get hashCode {
return id.hashCode ^
createdAt.hashCode ^
updatedAt.hashCode ^
deletedAt.hashCode ^
ownerId.hashCode ^
type.hashCode ^
data.hashCode ^
isSaved.hashCode ^
memoryAt.hashCode ^
seenAt.hashCode ^
showAt.hashCode ^
hideAt.hashCode;
}
}

View File

@ -17,7 +17,7 @@ typedef $$MemoryEntityTableCreateCompanionBuilder = i1.MemoryEntityCompanion
i0.Value<DateTime> updatedAt,
i0.Value<DateTime?> deletedAt,
required String ownerId,
required i2.MemoryType type,
required i2.MemoryTypeEnum type,
required String data,
i0.Value<bool> isSaved,
required DateTime memoryAt,
@ -32,7 +32,7 @@ typedef $$MemoryEntityTableUpdateCompanionBuilder = i1.MemoryEntityCompanion
i0.Value<DateTime> updatedAt,
i0.Value<DateTime?> deletedAt,
i0.Value<String> ownerId,
i0.Value<i2.MemoryType> type,
i0.Value<i2.MemoryTypeEnum> type,
i0.Value<String> data,
i0.Value<bool> isSaved,
i0.Value<DateTime> memoryAt,
@ -93,7 +93,7 @@ class $$MemoryEntityTableFilterComposer
i0.ColumnFilters<DateTime> get deletedAt => $composableBuilder(
column: $table.deletedAt, builder: (column) => i0.ColumnFilters(column));
i0.ColumnWithTypeConverterFilters<i2.MemoryType, i2.MemoryType, int>
i0.ColumnWithTypeConverterFilters<i2.MemoryTypeEnum, i2.MemoryTypeEnum, int>
get type => $composableBuilder(
column: $table.type,
builder: (column) => i0.ColumnWithTypeConverterFilters(column));
@ -228,7 +228,7 @@ class $$MemoryEntityTableAnnotationComposer
i0.GeneratedColumn<DateTime> get deletedAt =>
$composableBuilder(column: $table.deletedAt, builder: (column) => column);
i0.GeneratedColumnWithTypeConverter<i2.MemoryType, int> get type =>
i0.GeneratedColumnWithTypeConverter<i2.MemoryTypeEnum, int> get type =>
$composableBuilder(column: $table.type, builder: (column) => column);
i0.GeneratedColumn<String> get data =>
@ -301,7 +301,7 @@ class $$MemoryEntityTableTableManager extends i0.RootTableManager<
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
i0.Value<String> ownerId = const i0.Value.absent(),
i0.Value<i2.MemoryType> type = const i0.Value.absent(),
i0.Value<i2.MemoryTypeEnum> type = const i0.Value.absent(),
i0.Value<String> data = const i0.Value.absent(),
i0.Value<bool> isSaved = const i0.Value.absent(),
i0.Value<DateTime> memoryAt = const i0.Value.absent(),
@ -329,7 +329,7 @@ class $$MemoryEntityTableTableManager extends i0.RootTableManager<
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
required String ownerId,
required i2.MemoryType type,
required i2.MemoryTypeEnum type,
required String data,
i0.Value<bool> isSaved = const i0.Value.absent(),
required DateTime memoryAt,
@ -451,10 +451,11 @@ class $MemoryEntityTable extends i3.MemoryEntity
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
'REFERENCES user_entity (id) ON DELETE CASCADE'));
@override
late final i0.GeneratedColumnWithTypeConverter<i2.MemoryType, int> type =
late final i0.GeneratedColumnWithTypeConverter<i2.MemoryTypeEnum, int> type =
i0.GeneratedColumn<int>('type', aliasedName, false,
type: i0.DriftSqlType.int, requiredDuringInsert: true)
.withConverter<i2.MemoryType>(i1.$MemoryEntityTable.$convertertype);
.withConverter<i2.MemoryTypeEnum>(
i1.$MemoryEntityTable.$convertertype);
static const i0.VerificationMeta _dataMeta =
const i0.VerificationMeta('data');
@override
@ -614,8 +615,8 @@ class $MemoryEntityTable extends i3.MemoryEntity
return $MemoryEntityTable(attachedDatabase, alias);
}
static i0.JsonTypeConverter2<i2.MemoryType, int, int> $convertertype =
const i0.EnumIndexConverter<i2.MemoryType>(i2.MemoryType.values);
static i0.JsonTypeConverter2<i2.MemoryTypeEnum, int, int> $convertertype =
const i0.EnumIndexConverter<i2.MemoryTypeEnum>(i2.MemoryTypeEnum.values);
@override
bool get withoutRowId => true;
@override
@ -629,7 +630,7 @@ class MemoryEntityData extends i0.DataClass
final DateTime updatedAt;
final DateTime? deletedAt;
final String ownerId;
final i2.MemoryType type;
final i2.MemoryTypeEnum type;
final String data;
final bool isSaved;
final DateTime memoryAt;
@ -723,7 +724,7 @@ class MemoryEntityData extends i0.DataClass
DateTime? updatedAt,
i0.Value<DateTime?> deletedAt = const i0.Value.absent(),
String? ownerId,
i2.MemoryType? type,
i2.MemoryTypeEnum? type,
String? data,
bool? isSaved,
DateTime? memoryAt,
@ -807,7 +808,7 @@ class MemoryEntityCompanion extends i0.UpdateCompanion<i1.MemoryEntityData> {
final i0.Value<DateTime> updatedAt;
final i0.Value<DateTime?> deletedAt;
final i0.Value<String> ownerId;
final i0.Value<i2.MemoryType> type;
final i0.Value<i2.MemoryTypeEnum> type;
final i0.Value<String> data;
final i0.Value<bool> isSaved;
final i0.Value<DateTime> memoryAt;
@ -834,7 +835,7 @@ class MemoryEntityCompanion extends i0.UpdateCompanion<i1.MemoryEntityData> {
this.updatedAt = const i0.Value.absent(),
this.deletedAt = const i0.Value.absent(),
required String ownerId,
required i2.MemoryType type,
required i2.MemoryTypeEnum type,
required String data,
this.isSaved = const i0.Value.absent(),
required DateTime memoryAt,
@ -882,7 +883,7 @@ class MemoryEntityCompanion extends i0.UpdateCompanion<i1.MemoryEntityData> {
i0.Value<DateTime>? updatedAt,
i0.Value<DateTime?>? deletedAt,
i0.Value<String>? ownerId,
i0.Value<i2.MemoryType>? type,
i0.Value<i2.MemoryTypeEnum>? type,
i0.Value<String>? data,
i0.Value<bool>? isSaved,
i0.Value<DateTime>? memoryAt,

View File

@ -0,0 +1,45 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/memory.model.dart';
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
class DriftMemoryRepository extends DriftDatabaseRepository {
final Drift _db;
const DriftMemoryRepository(this._db) : super(_db);
Future<List<Memory>> getAll(String userId) {
final query = _db.memoryEntity.select()
..where((e) => e.ownerId.equals(userId));
return query.map((memory) {
return memory.toDto();
}).get();
}
}
extension on MemoryEntityData {
Memory toDto() {
return Memory(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
ownerId: ownerId,
type: type,
data: MemoryData.fromJson(convertToValidJson(data)),
isSaved: isSaved,
memoryAt: memoryAt,
seenAt: seenAt,
showAt: showAt,
hideAt: hideAt,
);
}
}
String convertToValidJson(String dartString) {
// Simple regex to add quotes around keys
return dartString.replaceAllMapped(
RegExp(r'(\w+):'),
(match) => '"${match.group(1)}":',
);
}

View File

@ -102,7 +102,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
}) async {
try {
await _db.remoteAssetEntity.deleteWhere(
(row) => row.id.isIn(data.map((error) => error.assetId)));
(row) => row.id.isIn(data.map((error) => error.assetId)),
);
} catch (error, stackTrace) {
_logger.severe('Error: deleteAssetsV1 - $debugLabel', error, stackTrace);
rethrow;
@ -184,7 +185,10 @@ class SyncStreamRepository extends DriftDatabaseRepository {
});
} catch (error, stackTrace) {
_logger.severe(
'Error: updateAssetsExifV1 - $debugLabel', error, stackTrace);
'Error: updateAssetsExifV1 - $debugLabel',
error,
stackTrace,
);
rethrow;
}
}
@ -192,7 +196,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
Future<void> deleteAlbumsV1(Iterable<SyncAlbumDeleteV1> data) async {
try {
await _db.remoteAlbumEntity.deleteWhere(
(row) => row.id.isIn(data.map((error) => error.albumId)));
(row) => row.id.isIn(data.map((error) => error.albumId)),
);
} catch (error, stackTrace) {
_logger.severe('Error: deleteAlbumsV1', error, stackTrace);
rethrow;
@ -269,7 +274,10 @@ class SyncStreamRepository extends DriftDatabaseRepository {
});
} catch (error, stackTrace) {
_logger.severe(
'Error: updateAlbumUsersV1 - $debugLabel', error, stackTrace);
'Error: updateAlbumUsersV1 - $debugLabel',
error,
stackTrace,
);
rethrow;
}
}
@ -316,7 +324,10 @@ class SyncStreamRepository extends DriftDatabaseRepository {
});
} catch (error, stackTrace) {
_logger.severe(
'Error: updateAlbumToAssetsV1 - $debugLabel', error, stackTrace);
'Error: updateAlbumToAssetsV1 - $debugLabel',
error,
stackTrace,
);
rethrow;
}
}
@ -354,7 +365,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
Future<void> deleteMemoriesV1(Iterable<SyncMemoryDeleteV1> data) async {
try {
await _db.memoryEntity.deleteWhere(
(row) => row.id.isIn(data.map((error) => error.memoryId)));
(row) => row.id.isIn(data.map((error) => error.memoryId)),
);
} catch (error, stackTrace) {
_logger.severe('Error: deleteMemoriesV1', error, stackTrace);
rethrow;

View File

@ -154,6 +154,14 @@ final _remoteStats = [
name: 'Remote Albums',
load: (db) => db.managers.remoteAlbumEntity.count(),
),
_Stat(
name: 'Memories',
load: (db) => db.managers.memoryEntity.count(),
),
_Stat(
name: 'Memories Assets',
load: (db) => db.managers.memoryAssetEntity.count(),
),
];
@RoutePage()

View File

@ -1,5 +1,7 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/infrastructure/repositories/memory.repository.dart';
import 'package:immich_mobile/models/memories/memory.model.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/services/memory.service.dart';
final memoryFutureProvider =
@ -8,3 +10,7 @@ final memoryFutureProvider =
return await service.getMemoryLane();
});
final driftMemoryProvider = Provider<DriftMemoryRepository>(
(ref) => DriftMemoryRepository(ref.watch(driftProvider)),
);