mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
refactor repositories
This commit is contained in:
parent
d6495f014d
commit
e810512285
@ -9,7 +9,7 @@ class Asset extends Table {
|
|||||||
IntColumn get id => integer().autoIncrement()();
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
|
||||||
TextColumn get name => text()();
|
TextColumn get name => text()();
|
||||||
TextColumn get checksum => text().unique()();
|
TextColumn get hash => text().unique()();
|
||||||
IntColumn get height => integer().nullable()();
|
IntColumn get height => integer().nullable()();
|
||||||
IntColumn get width => integer().nullable()();
|
IntColumn get width => integer().nullable()();
|
||||||
IntColumn get type => intEnum<AssetType>()();
|
IntColumn get type => intEnum<AssetType>()();
|
||||||
|
@ -1,27 +1,23 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:immich_mobile/domain/models/asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/render_list.model.dart';
|
|
||||||
|
|
||||||
abstract class IAssetRepository {
|
abstract interface class IAssetRepository {
|
||||||
/// Batch insert asset
|
/// Batch upsert asset
|
||||||
FutureOr<bool> addAll(Iterable<Asset> assets);
|
FutureOr<bool> upsertAll(Iterable<Asset> assets);
|
||||||
|
|
||||||
/// Removes assets with the [localIds]
|
/// Removes assets with the [localIds]
|
||||||
FutureOr<List<Asset>> fetchLocalAssetsForIds(List<String> localIds);
|
FutureOr<List<Asset>> getForLocalIds(List<String> localIds);
|
||||||
|
|
||||||
/// Removes assets with the [remoteIds]
|
/// Removes assets with the [remoteIds]
|
||||||
FutureOr<List<Asset>> fetchRemoteAssetsForIds(List<String> remoteIds);
|
FutureOr<List<Asset>> getForRemoteIds(List<String> remoteIds);
|
||||||
|
|
||||||
/// Removes assets with the given [ids]
|
|
||||||
FutureOr<void> deleteAssetsForIds(List<int> ids);
|
|
||||||
|
|
||||||
/// Removes all assets
|
|
||||||
FutureOr<bool> clearAll();
|
|
||||||
|
|
||||||
/// Fetch assets from the [offset] with the [limit]
|
/// Fetch assets from the [offset] with the [limit]
|
||||||
FutureOr<List<Asset>> fetchAssets({int? offset, int? limit});
|
FutureOr<List<Asset>> getAll({int? offset, int? limit});
|
||||||
|
|
||||||
/// Streams assets as groups grouped by the group type passed
|
/// Removes assets with the given [ids]
|
||||||
Stream<RenderList> watchRenderList();
|
FutureOr<void> deleteIds(List<int> ids);
|
||||||
|
|
||||||
|
/// Removes all assets
|
||||||
|
FutureOr<bool> deleteAll();
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,19 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
|
|
||||||
abstract class ILogRepository {
|
abstract interface class ILogRepository {
|
||||||
/// Fetches all logs
|
|
||||||
FutureOr<List<LogMessage>> fetchAll();
|
|
||||||
|
|
||||||
/// Inserts a new log into the DB
|
/// Inserts a new log into the DB
|
||||||
FutureOr<bool> add(LogMessage log);
|
FutureOr<bool> create(LogMessage log);
|
||||||
|
|
||||||
/// Bulk insert logs into DB
|
/// Bulk insert logs into DB
|
||||||
FutureOr<bool> addAll(List<LogMessage> log);
|
FutureOr<bool> createAll(List<LogMessage> log);
|
||||||
|
|
||||||
|
/// Fetches all logs
|
||||||
|
FutureOr<List<LogMessage>> getAll();
|
||||||
|
|
||||||
/// Clears all logs
|
/// Clears all logs
|
||||||
FutureOr<bool> clear();
|
FutureOr<bool> deleteAll();
|
||||||
|
|
||||||
/// Truncates the logs to the most recent [limit]. Defaults to recent 250 logs
|
/// Truncates the logs to the most recent [limit]. Defaults to recent 250 logs
|
||||||
FutureOr<void> truncateLogs({int limit = 250});
|
FutureOr<void> truncate({int limit = 250});
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/render_list.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IRenderListRepository {
|
||||||
|
/// Streams the [RenderList] for the main timeline
|
||||||
|
Stream<RenderList> watchAll();
|
||||||
|
}
|
@ -12,16 +12,16 @@ abstract class IStoreConverter<T, U> {
|
|||||||
FutureOr<T?> fromPrimitive(U value);
|
FutureOr<T?> fromPrimitive(U value);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class IStoreRepository {
|
abstract interface class IStoreRepository {
|
||||||
FutureOr<T?> tryGet<T, U>(StoreKey<T, U> key);
|
FutureOr<bool> upsert<T, U>(StoreKey<T, U> key, T value);
|
||||||
|
|
||||||
FutureOr<T> get<T, U>(StoreKey<T, U> key);
|
FutureOr<T> get<T, U>(StoreKey<T, U> key);
|
||||||
|
|
||||||
FutureOr<bool> set<T, U>(StoreKey<T, U> key, T value);
|
FutureOr<T?> tryGet<T, U>(StoreKey<T, U> key);
|
||||||
|
|
||||||
FutureOr<void> delete(StoreKey key);
|
|
||||||
|
|
||||||
Stream<T?> watch<T, U>(StoreKey<T, U> key);
|
Stream<T?> watch<T, U>(StoreKey<T, U> key);
|
||||||
|
|
||||||
FutureOr<void> clearStore();
|
FutureOr<void> delete(StoreKey key);
|
||||||
|
|
||||||
|
FutureOr<void> deleteAll();
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
|
||||||
abstract class IUserRepository {
|
abstract interface class IUserRepository {
|
||||||
/// Fetches user
|
|
||||||
FutureOr<User?> fetch(String userId);
|
|
||||||
|
|
||||||
/// Insert user
|
/// Insert user
|
||||||
FutureOr<bool> add(User user);
|
FutureOr<bool> upsert(User user);
|
||||||
|
|
||||||
|
/// Fetches user
|
||||||
|
FutureOr<User?> getForId(String userId);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ enum AssetType {
|
|||||||
class Asset {
|
class Asset {
|
||||||
final int id;
|
final int id;
|
||||||
final String name;
|
final String name;
|
||||||
final String checksum;
|
final String hash;
|
||||||
final int? height;
|
final int? height;
|
||||||
final int? width;
|
final int? width;
|
||||||
final AssetType type;
|
final AssetType type;
|
||||||
@ -36,7 +36,7 @@ class Asset {
|
|||||||
const Asset({
|
const Asset({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.checksum,
|
required this.hash,
|
||||||
this.height,
|
this.height,
|
||||||
this.width,
|
this.width,
|
||||||
required this.type,
|
required this.type,
|
||||||
@ -55,7 +55,7 @@ class Asset {
|
|||||||
duration: dto.duration.tryParseInt() ?? 0,
|
duration: dto.duration.tryParseInt() ?? 0,
|
||||||
height: dto.exifInfo?.exifImageHeight?.toInt(),
|
height: dto.exifInfo?.exifImageHeight?.toInt(),
|
||||||
width: dto.exifInfo?.exifImageWidth?.toInt(),
|
width: dto.exifInfo?.exifImageWidth?.toInt(),
|
||||||
checksum: dto.checksum,
|
hash: dto.checksum,
|
||||||
name: dto.originalFileName,
|
name: dto.originalFileName,
|
||||||
livePhotoVideoId: dto.livePhotoVideoId,
|
livePhotoVideoId: dto.livePhotoVideoId,
|
||||||
modifiedTime: dto.fileModifiedAt,
|
modifiedTime: dto.fileModifiedAt,
|
||||||
@ -65,7 +65,7 @@ class Asset {
|
|||||||
Asset copyWith({
|
Asset copyWith({
|
||||||
int? id,
|
int? id,
|
||||||
String? name,
|
String? name,
|
||||||
String? checksum,
|
String? hash,
|
||||||
int? height,
|
int? height,
|
||||||
int? width,
|
int? width,
|
||||||
AssetType? type,
|
AssetType? type,
|
||||||
@ -79,7 +79,7 @@ class Asset {
|
|||||||
return Asset(
|
return Asset(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
checksum: checksum ?? this.checksum,
|
hash: hash ?? this.hash,
|
||||||
height: height ?? this.height,
|
height: height ?? this.height,
|
||||||
width: width ?? this.width,
|
width: width ?? this.width,
|
||||||
type: type ?? this.type,
|
type: type ?? this.type,
|
||||||
@ -119,7 +119,7 @@ class Asset {
|
|||||||
"remoteId": "${remoteId ?? "-"}",
|
"remoteId": "${remoteId ?? "-"}",
|
||||||
"localId": "${localId ?? "-"}",
|
"localId": "${localId ?? "-"}",
|
||||||
"name": "$name",
|
"name": "$name",
|
||||||
"checksum": "$checksum",
|
"hash": "$hash",
|
||||||
"height": ${height ?? "-"},
|
"height": ${height ?? "-"},
|
||||||
"width": ${width ?? "-"},
|
"width": ${width ?? "-"},
|
||||||
"type": "$type",
|
"type": "$type",
|
||||||
@ -135,7 +135,7 @@ class Asset {
|
|||||||
|
|
||||||
return other.id == id &&
|
return other.id == id &&
|
||||||
other.name == name &&
|
other.name == name &&
|
||||||
other.checksum == checksum &&
|
other.hash == hash &&
|
||||||
other.height == height &&
|
other.height == height &&
|
||||||
other.width == width &&
|
other.width == width &&
|
||||||
other.type == type &&
|
other.type == type &&
|
||||||
@ -151,7 +151,7 @@ class Asset {
|
|||||||
int get hashCode {
|
int get hashCode {
|
||||||
return id.hashCode ^
|
return id.hashCode ^
|
||||||
name.hashCode ^
|
name.hashCode ^
|
||||||
checksum.hashCode ^
|
hash.hashCode ^
|
||||||
height.hashCode ^
|
height.hashCode ^
|
||||||
width.hashCode ^
|
width.hashCode ^
|
||||||
type.hashCode ^
|
type.hashCode ^
|
||||||
|
@ -4,19 +4,16 @@ import 'package:drift/drift.dart';
|
|||||||
import 'package:immich_mobile/domain/entities/asset.entity.drift.dart';
|
import 'package:immich_mobile/domain/entities/asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/asset.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/asset.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/render_list.model.dart';
|
|
||||||
import 'package:immich_mobile/domain/models/render_list_element.model.dart';
|
|
||||||
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||||
import 'package:immich_mobile/utils/extensions/drift.extension.dart';
|
|
||||||
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||||
|
|
||||||
class RemoteAssetDriftRepository with LogMixin implements IAssetRepository {
|
class AssetDriftRepository with LogMixin implements IAssetRepository {
|
||||||
final DriftDatabaseRepository _db;
|
final DriftDatabaseRepository _db;
|
||||||
|
|
||||||
const RemoteAssetDriftRepository(this._db);
|
const AssetDriftRepository(this._db);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> addAll(Iterable<Asset> assets) async {
|
Future<bool> upsertAll(Iterable<Asset> assets) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) => batch.insertAllOnConflictUpdate(
|
await _db.batch((batch) => batch.insertAllOnConflictUpdate(
|
||||||
_db.asset,
|
_db.asset,
|
||||||
@ -31,7 +28,7 @@ class RemoteAssetDriftRepository with LogMixin implements IAssetRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> clearAll() async {
|
Future<bool> deleteAll() async {
|
||||||
try {
|
try {
|
||||||
await _db.asset.deleteAll();
|
await _db.asset.deleteAll();
|
||||||
return true;
|
return true;
|
||||||
@ -42,7 +39,7 @@ class RemoteAssetDriftRepository with LogMixin implements IAssetRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Asset>> fetchAssets({int? offset, int? limit}) async {
|
Future<List<Asset>> getAll({int? offset, int? limit}) async {
|
||||||
final query = _db.asset.select()
|
final query = _db.asset.select()
|
||||||
..orderBy([(asset) => OrderingTerm.desc(asset.createdTime)]);
|
..orderBy([(asset) => OrderingTerm.desc(asset.createdTime)]);
|
||||||
|
|
||||||
@ -54,40 +51,7 @@ class RemoteAssetDriftRepository with LogMixin implements IAssetRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<RenderList> watchRenderList() {
|
Future<List<Asset>> getForLocalIds(List<String> localIds) async {
|
||||||
final assetCountExp = _db.asset.id.count();
|
|
||||||
final createdTimeExp = _db.asset.createdTime;
|
|
||||||
final monthYearExp = _db.asset.createdTime.strftime('%m-%Y');
|
|
||||||
|
|
||||||
final query = _db.asset.selectOnly()
|
|
||||||
..addColumns([assetCountExp, createdTimeExp])
|
|
||||||
..groupBy([monthYearExp])
|
|
||||||
..orderBy([OrderingTerm.desc(createdTimeExp)]);
|
|
||||||
|
|
||||||
int lastAssetOffset = 0;
|
|
||||||
|
|
||||||
return query
|
|
||||||
.expand((row) {
|
|
||||||
final createdTime = row.read<DateTime>(createdTimeExp)!;
|
|
||||||
final assetCount = row.read(assetCountExp)!;
|
|
||||||
final assetOffset = lastAssetOffset;
|
|
||||||
lastAssetOffset += assetCount;
|
|
||||||
|
|
||||||
return [
|
|
||||||
RenderListMonthHeaderElement(date: createdTime),
|
|
||||||
RenderListAssetElement(
|
|
||||||
date: createdTime,
|
|
||||||
assetCount: assetCount,
|
|
||||||
assetOffset: assetOffset,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
})
|
|
||||||
.watch()
|
|
||||||
.map((elements) => RenderList(elements: elements));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<Asset>> fetchLocalAssetsForIds(List<String> localIds) async {
|
|
||||||
final query = _db.asset.select()
|
final query = _db.asset.select()
|
||||||
..where((row) => row.localId.isIn(localIds))
|
..where((row) => row.localId.isIn(localIds))
|
||||||
..orderBy([(asset) => OrderingTerm.asc(asset.localId)]);
|
..orderBy([(asset) => OrderingTerm.asc(asset.localId)]);
|
||||||
@ -96,7 +60,7 @@ class RemoteAssetDriftRepository with LogMixin implements IAssetRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Asset>> fetchRemoteAssetsForIds(List<String> remoteIds) async {
|
Future<List<Asset>> getForRemoteIds(List<String> remoteIds) async {
|
||||||
final query = _db.asset.select()
|
final query = _db.asset.select()
|
||||||
..where((row) => row.remoteId.isIn(remoteIds))
|
..where((row) => row.remoteId.isIn(remoteIds))
|
||||||
..orderBy([(asset) => OrderingTerm.asc(asset.remoteId)]);
|
..orderBy([(asset) => OrderingTerm.asc(asset.remoteId)]);
|
||||||
@ -105,7 +69,7 @@ class RemoteAssetDriftRepository with LogMixin implements IAssetRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<void> deleteAssetsForIds(List<int> ids) async {
|
FutureOr<void> deleteIds(List<int> ids) async {
|
||||||
await _db.asset.deleteWhere((row) => row.id.isIn(ids));
|
await _db.asset.deleteWhere((row) => row.id.isIn(ids));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +79,7 @@ AssetCompanion _toEntity(Asset asset) {
|
|||||||
localId: Value(asset.localId),
|
localId: Value(asset.localId),
|
||||||
remoteId: Value(asset.remoteId),
|
remoteId: Value(asset.remoteId),
|
||||||
name: asset.name,
|
name: asset.name,
|
||||||
checksum: asset.checksum,
|
hash: asset.hash,
|
||||||
height: Value(asset.height),
|
height: Value(asset.height),
|
||||||
width: Value(asset.width),
|
width: Value(asset.width),
|
||||||
type: asset.type,
|
type: asset.type,
|
||||||
@ -133,7 +97,7 @@ Asset _toModel(AssetData asset) {
|
|||||||
remoteId: asset.remoteId,
|
remoteId: asset.remoteId,
|
||||||
name: asset.name,
|
name: asset.name,
|
||||||
type: asset.type,
|
type: asset.type,
|
||||||
checksum: asset.checksum,
|
hash: asset.hash,
|
||||||
createdTime: asset.createdTime,
|
createdTime: asset.createdTime,
|
||||||
modifiedTime: asset.modifiedTime,
|
modifiedTime: asset.modifiedTime,
|
||||||
height: asset.height,
|
height: asset.height,
|
||||||
|
@ -13,12 +13,12 @@ class LogDriftRepository implements ILogRepository {
|
|||||||
const LogDriftRepository(this._db);
|
const LogDriftRepository(this._db);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<LogMessage>> fetchAll() async {
|
Future<List<LogMessage>> getAll() async {
|
||||||
return await _db.managers.logs.map(_toModel).get();
|
return await _db.managers.logs.map(_toModel).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> truncateLogs({int limit = 250}) async {
|
Future<void> truncate({int limit = 250}) async {
|
||||||
final totalCount = await _db.managers.logs.count();
|
final totalCount = await _db.managers.logs.count();
|
||||||
if (totalCount > limit) {
|
if (totalCount > limit) {
|
||||||
final rowsToDelete = totalCount - limit;
|
final rowsToDelete = totalCount - limit;
|
||||||
@ -30,7 +30,7 @@ class LogDriftRepository implements ILogRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<bool> add(LogMessage log) async {
|
FutureOr<bool> create(LogMessage log) async {
|
||||||
try {
|
try {
|
||||||
await _db.into(_db.logs).insert(LogsCompanion.insert(
|
await _db.into(_db.logs).insert(LogsCompanion.insert(
|
||||||
content: log.content,
|
content: log.content,
|
||||||
@ -48,7 +48,7 @@ class LogDriftRepository implements ILogRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<bool> addAll(List<LogMessage> logs) async {
|
FutureOr<bool> createAll(List<LogMessage> logs) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((b) {
|
await _db.batch((b) {
|
||||||
b.insertAll(
|
b.insertAll(
|
||||||
@ -71,7 +71,7 @@ class LogDriftRepository implements ILogRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<bool> clear() async {
|
FutureOr<bool> deleteAll() async {
|
||||||
try {
|
try {
|
||||||
await _db.managers.logs.delete();
|
await _db.managers.logs.delete();
|
||||||
return true;
|
return true;
|
||||||
|
46
mobile-v2/lib/domain/repositories/renderlist.repository.dart
Normal file
46
mobile-v2/lib/domain/repositories/renderlist.repository.dart
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/renderlist.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/render_list.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/render_list_element.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/repositories/database.repository.dart';
|
||||||
|
import 'package:immich_mobile/utils/extensions/drift.extension.dart';
|
||||||
|
import 'package:immich_mobile/utils/mixins/log.mixin.dart';
|
||||||
|
|
||||||
|
class RenderListDriftRepository with LogMixin implements IRenderListRepository {
|
||||||
|
final DriftDatabaseRepository _db;
|
||||||
|
|
||||||
|
const RenderListDriftRepository(this._db);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<RenderList> watchAll() {
|
||||||
|
final assetCountExp = _db.asset.id.count();
|
||||||
|
final createdTimeExp = _db.asset.createdTime;
|
||||||
|
final monthYearExp = _db.asset.createdTime.strftime('%m-%Y');
|
||||||
|
|
||||||
|
final query = _db.asset.selectOnly()
|
||||||
|
..addColumns([assetCountExp, createdTimeExp])
|
||||||
|
..groupBy([monthYearExp])
|
||||||
|
..orderBy([OrderingTerm.desc(createdTimeExp)]);
|
||||||
|
|
||||||
|
int lastAssetOffset = 0;
|
||||||
|
|
||||||
|
return query
|
||||||
|
.expand((row) {
|
||||||
|
final createdTime = row.read<DateTime>(createdTimeExp)!;
|
||||||
|
final assetCount = row.read(assetCountExp)!;
|
||||||
|
final assetOffset = lastAssetOffset;
|
||||||
|
lastAssetOffset += assetCount;
|
||||||
|
|
||||||
|
return [
|
||||||
|
RenderListMonthHeaderElement(date: createdTime),
|
||||||
|
RenderListAssetElement(
|
||||||
|
date: createdTime,
|
||||||
|
assetCount: assetCount,
|
||||||
|
assetOffset: assetOffset,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.watch()
|
||||||
|
.map((elements) => RenderList(elements: elements));
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ class StoreDriftRepository with LogMixin implements IStoreRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<bool> set<T, U>(StoreKey<T, U> key, T value) async {
|
FutureOr<bool> upsert<T, U>(StoreKey<T, U> key, T value) async {
|
||||||
try {
|
try {
|
||||||
final storeValue = key.converter.toPrimitive(value);
|
final storeValue = key.converter.toPrimitive(value);
|
||||||
final intValue = (key.type == int) ? storeValue as int : null;
|
final intValue = (key.type == int) ? storeValue as int : null;
|
||||||
@ -61,7 +61,7 @@ class StoreDriftRepository with LogMixin implements IStoreRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<void> clearStore() async {
|
FutureOr<void> deleteAll() async {
|
||||||
await _db.managers.store.delete();
|
await _db.managers.store.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class UserDriftRepository with LogMixin implements IUserRepository {
|
|||||||
const UserDriftRepository(this._db);
|
const UserDriftRepository(this._db);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<User?> fetch(String userId) async {
|
FutureOr<User?> getForId(String userId) async {
|
||||||
return await _db.managers.user
|
return await _db.managers.user
|
||||||
.filter((f) => f.id.equals(userId))
|
.filter((f) => f.id.equals(userId))
|
||||||
.map(_toModel)
|
.map(_toModel)
|
||||||
@ -21,7 +21,7 @@ class UserDriftRepository with LogMixin implements IUserRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<bool> add(User user) async {
|
FutureOr<bool> upsert(User user) async {
|
||||||
try {
|
try {
|
||||||
await _db.into(_db.user).insertOnConflictUpdate(
|
await _db.into(_db.user).insertOnConflictUpdate(
|
||||||
UserCompanion.insert(
|
UserCompanion.insert(
|
||||||
|
@ -6,16 +6,16 @@ class AppSettingService {
|
|||||||
|
|
||||||
const AppSettingService(this._store);
|
const AppSettingService(this._store);
|
||||||
|
|
||||||
Future<T> getSetting<T>(AppSetting<T> setting) async {
|
Future<T> get<T>(AppSetting<T> setting) async {
|
||||||
final value = await _store.tryGet(setting.storeKey);
|
final value = await _store.tryGet(setting.storeKey);
|
||||||
return value ?? setting.defaultValue;
|
return value ?? setting.defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> setSetting<T>(AppSetting<T> setting, T value) async {
|
Future<bool> upsert<T>(AppSetting<T> setting, T value) async {
|
||||||
return await _store.set(setting.storeKey, value);
|
return await _store.upsert(setting.storeKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<T> watchSetting<T>(AppSetting<T> setting) {
|
Stream<T> watch<T>(AppSetting<T> setting) {
|
||||||
return _store
|
return _store
|
||||||
.watch(setting.storeKey)
|
.watch(setting.storeKey)
|
||||||
.map((value) => value ?? setting.defaultValue);
|
.map((value) => value ?? setting.defaultValue);
|
||||||
|
@ -16,7 +16,7 @@ import 'package:openapi/api.dart';
|
|||||||
class AssetSyncService with LogMixin {
|
class AssetSyncService with LogMixin {
|
||||||
const AssetSyncService();
|
const AssetSyncService();
|
||||||
|
|
||||||
Future<bool> doFullRemoteSyncForUserDrift(
|
Future<bool> performFullRemoteSyncForUser(
|
||||||
User user, {
|
User user, {
|
||||||
DateTime? updatedUtil,
|
DateTime? updatedUtil,
|
||||||
int? limit,
|
int? limit,
|
||||||
@ -49,12 +49,11 @@ class AssetSyncService with LogMixin {
|
|||||||
final assetsFromServer =
|
final assetsFromServer =
|
||||||
assets.map(Asset.remote).sorted(Asset.compareByRemoteId);
|
assets.map(Asset.remote).sorted(Asset.compareByRemoteId);
|
||||||
|
|
||||||
final assetsInDb =
|
final assetsInDb = await di<IAssetRepository>().getForRemoteIds(
|
||||||
await di<IAssetRepository>().fetchRemoteAssetsForIds(
|
|
||||||
assetsFromServer.map((a) => a.remoteId!).toList(),
|
assetsFromServer.map((a) => a.remoteId!).toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
await _syncAssetsToDbDrift(
|
await _syncAssetsToDb(
|
||||||
assetsFromServer,
|
assetsFromServer,
|
||||||
assetsInDb,
|
assetsInDb,
|
||||||
Asset.compareByRemoteId,
|
Asset.compareByRemoteId,
|
||||||
@ -73,7 +72,7 @@ class AssetSyncService with LogMixin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _syncAssetsToDbDrift(
|
Future<void> _syncAssetsToDb(
|
||||||
List<Asset> newAssets,
|
List<Asset> newAssets,
|
||||||
List<Asset> existingAssets,
|
List<Asset> existingAssets,
|
||||||
Comparator<Asset> compare, {
|
Comparator<Asset> compare, {
|
||||||
@ -88,9 +87,9 @@ class AssetSyncService with LogMixin {
|
|||||||
|
|
||||||
final assetsToAdd = toAdd.followedBy(toUpdate);
|
final assetsToAdd = toAdd.followedBy(toUpdate);
|
||||||
|
|
||||||
await di<IAssetRepository>().addAll(assetsToAdd);
|
await di<IAssetRepository>().upsertAll(assetsToAdd);
|
||||||
await di<IAssetRepository>()
|
await di<IAssetRepository>()
|
||||||
.deleteAssetsForIds(assetsToRemove.map((a) => a.id).toList());
|
.deleteIds(assetsToRemove.map((a) => a.id).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a triple (toAdd, toUpdate, toRemove)
|
/// Returns a triple (toAdd, toUpdate, toRemove)
|
||||||
|
@ -107,7 +107,7 @@ class LoginService with LogMixin {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> tryLoginFromSplash() async {
|
Future<bool> tryAutoLogin() async {
|
||||||
final serverEndpoint =
|
final serverEndpoint =
|
||||||
await di<IStoreRepository>().tryGet(StoreKey.serverEndpoint);
|
await di<IStoreRepository>().tryGet(StoreKey.serverEndpoint);
|
||||||
if (serverEndpoint == null) {
|
if (serverEndpoint == null) {
|
||||||
|
@ -50,7 +50,7 @@ class StoreUserConverter extends IStoreConverter<User, String> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<User?> fromPrimitive(String value) async {
|
Future<User?> fromPrimitive(String value) async {
|
||||||
return await di<IUserRepository>().fetch(value);
|
return await di<IUserRepository>().getForId(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -37,7 +37,7 @@ class _ImSwitchListTileState<T> extends State<ImSwitchListTile<T>> {
|
|||||||
|
|
||||||
final value = T != bool ? widget.toAppSetting!(enabled) : enabled as T;
|
final value = T != bool ? widget.toAppSetting!(enabled) : enabled as T;
|
||||||
if (value != null &&
|
if (value != null &&
|
||||||
await _appSettingService.setSetting(widget.setting, value) &&
|
await _appSettingService.upsert(widget.setting, value) &&
|
||||||
context.mounted) {
|
context.mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
isEnabled = enabled;
|
isEnabled = enabled;
|
||||||
@ -48,7 +48,7 @@ class _ImSwitchListTileState<T> extends State<ImSwitchListTile<T>> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_appSettingService.getSetting(widget.setting).then((value) {
|
_appSettingService.get(widget.setting).then((value) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
isEnabled = T != bool ? widget.fromAppSetting!(value) : value as bool;
|
isEnabled = T != bool ? widget.fromAppSetting!(value) : value as bool;
|
||||||
|
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:immich_mobile/domain/interfaces/asset.interface.dart';
|
import 'package:immich_mobile/domain/interfaces/asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/renderlist.interface.dart';
|
||||||
import 'package:immich_mobile/presentation/components/grid/immich_asset_grid.state.dart';
|
import 'package:immich_mobile/presentation/components/grid/immich_asset_grid.state.dart';
|
||||||
import 'package:immich_mobile/presentation/components/grid/immich_asset_grid.widget.dart';
|
import 'package:immich_mobile/presentation/components/grid/immich_asset_grid.widget.dart';
|
||||||
import 'package:immich_mobile/service_locator.dart';
|
import 'package:immich_mobile/service_locator.dart';
|
||||||
@ -15,8 +16,8 @@ class HomePage extends StatelessWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: BlocProvider(
|
body: BlocProvider(
|
||||||
create: (_) => ImmichAssetGridCubit(
|
create: (_) => ImmichAssetGridCubit(
|
||||||
renderStream: di<IAssetRepository>().watchRenderList(),
|
renderStream: di<IRenderListRepository>().watchAll(),
|
||||||
assetProvider: di<IAssetRepository>().fetchAssets,
|
assetProvider: di<IAssetRepository>().getAll,
|
||||||
),
|
),
|
||||||
child: const ImAssetGrid(),
|
child: const ImAssetGrid(),
|
||||||
),
|
),
|
||||||
|
@ -65,7 +65,7 @@ class LoginPageCubit extends Cubit<LoginPageState> with LogMixin {
|
|||||||
// Check for /.well-known/immich
|
// Check for /.well-known/immich
|
||||||
url = await loginService.resolveEndpoint(uri);
|
url = await loginService.resolveEndpoint(uri);
|
||||||
|
|
||||||
di<IStoreRepository>().set(StoreKey.serverEndpoint, url);
|
di<IStoreRepository>().upsert(StoreKey.serverEndpoint, url);
|
||||||
ServiceLocator.registerApiClient(url);
|
ServiceLocator.registerApiClient(url);
|
||||||
ServiceLocator.registerPostValidationServices();
|
ServiceLocator.registerPostValidationServices();
|
||||||
ServiceLocator.registerPostGlobalStates();
|
ServiceLocator.registerPostGlobalStates();
|
||||||
@ -123,7 +123,7 @@ class LoginPageCubit extends Cubit<LoginPageState> with LogMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _postLogin(String accessToken) async {
|
Future<void> _postLogin(String accessToken) async {
|
||||||
await di<IStoreRepository>().set(StoreKey.accessToken, accessToken);
|
await di<IStoreRepository>().upsert(StoreKey.accessToken, accessToken);
|
||||||
|
|
||||||
/// Set token to interceptor
|
/// Set token to interceptor
|
||||||
await di<ImmichApiClient>().init(accessToken: accessToken);
|
await di<ImmichApiClient>().init(accessToken: accessToken);
|
||||||
@ -136,10 +136,10 @@ class LoginPageCubit extends Cubit<LoginPageState> with LogMixin {
|
|||||||
|
|
||||||
// Register user
|
// Register user
|
||||||
ServiceLocator.registerCurrentUser(user);
|
ServiceLocator.registerCurrentUser(user);
|
||||||
await di<IUserRepository>().add(user);
|
await di<IUserRepository>().upsert(user);
|
||||||
// Remove and Sync assets in background
|
// Remove and Sync assets in background
|
||||||
await di<IAssetRepository>().clearAll();
|
await di<IAssetRepository>().deleteAll();
|
||||||
unawaited(di<AssetSyncService>().doFullRemoteSyncForUserDrift(user));
|
unawaited(di<AssetSyncService>().performFullRemoteSyncForUser(user));
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
isValidationInProgress: false,
|
isValidationInProgress: false,
|
||||||
|
@ -10,9 +10,8 @@ class AppThemeCubit extends Cubit<AppTheme> {
|
|||||||
late final StreamSubscription _appSettingSubscription;
|
late final StreamSubscription _appSettingSubscription;
|
||||||
|
|
||||||
AppThemeCubit(this._appSettings) : super(AppTheme.blue) {
|
AppThemeCubit(this._appSettings) : super(AppTheme.blue) {
|
||||||
_appSettingSubscription = _appSettings
|
_appSettingSubscription =
|
||||||
.watchSetting(AppSetting.appTheme)
|
_appSettings.watch(AppSetting.appTheme).listen((theme) => emit(theme));
|
||||||
.listen((theme) => emit(theme));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -3,8 +3,10 @@ import 'dart:async';
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:immich_mobile/domain/services/asset_sync.service.dart';
|
||||||
import 'package:immich_mobile/domain/services/login.service.dart';
|
import 'package:immich_mobile/domain/services/login.service.dart';
|
||||||
import 'package:immich_mobile/presentation/components/image/immich_logo.widget.dart';
|
import 'package:immich_mobile/presentation/components/image/immich_logo.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/modules/common/states/current_user.state.dart';
|
||||||
import 'package:immich_mobile/presentation/modules/login/states/login_page.state.dart';
|
import 'package:immich_mobile/presentation/modules/login/states/login_page.state.dart';
|
||||||
import 'package:immich_mobile/presentation/router/router.dart';
|
import 'package:immich_mobile/presentation/router/router.dart';
|
||||||
import 'package:immich_mobile/service_locator.dart';
|
import 'package:immich_mobile/service_locator.dart';
|
||||||
@ -49,7 +51,9 @@ class _SplashScreenState extends State<SplashScreenPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _tryLogin() async {
|
Future<void> _tryLogin() async {
|
||||||
if (await di<LoginService>().tryLoginFromSplash() && mounted) {
|
if (await di<LoginService>().tryAutoLogin() && mounted) {
|
||||||
|
unawaited(di<AssetSyncService>()
|
||||||
|
.performFullRemoteSyncForUser(di<CurrentUserCubit>().state));
|
||||||
unawaited(context.replaceRoute(const TabControllerRoute()));
|
unawaited(context.replaceRoute(const TabControllerRoute()));
|
||||||
} else {
|
} else {
|
||||||
unawaited(context.replaceRoute(const LoginRoute()));
|
unawaited(context.replaceRoute(const LoginRoute()));
|
||||||
|
@ -69,7 +69,7 @@ class ServiceLocator {
|
|||||||
_registerFactory<AppSettingService>(() => AppSettingService(di()));
|
_registerFactory<AppSettingService>(() => AppSettingService(di()));
|
||||||
_registerFactory<IUserRepository>(() => UserDriftRepository(di()));
|
_registerFactory<IUserRepository>(() => UserDriftRepository(di()));
|
||||||
_registerFactory<IAssetRepository>(
|
_registerFactory<IAssetRepository>(
|
||||||
() => RemoteAssetDriftRepository(di()),
|
() => AssetDriftRepository(di()),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Services
|
/// Services
|
||||||
|
@ -53,7 +53,7 @@ class LogManager {
|
|||||||
_timer = null;
|
_timer = null;
|
||||||
final buffer = _msgBuffer;
|
final buffer = _msgBuffer;
|
||||||
_msgBuffer = [];
|
_msgBuffer = [];
|
||||||
di<ILogRepository>().addAll(buffer);
|
di<ILogRepository>().createAll(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
@ -78,7 +78,7 @@ class LogManager {
|
|||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_timer = null;
|
_timer = null;
|
||||||
_msgBuffer.clear();
|
_msgBuffer.clear();
|
||||||
di<ILogRepository>().clear();
|
di<ILogRepository>().deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setGlobalErrorCallbacks() {
|
static void setGlobalErrorCallbacks() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user