mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
fix: handle edited assets for merged/local assets
This commit is contained in:
@@ -0,0 +1 @@
|
||||
enum AssetEditAction { rotate, crop, mirror, other }
|
||||
@@ -22,6 +22,7 @@ sealed class BaseAsset {
|
||||
final int? durationInSeconds;
|
||||
final bool isFavorite;
|
||||
final String? livePhotoVideoId;
|
||||
final bool isEdited;
|
||||
|
||||
const BaseAsset({
|
||||
required this.name,
|
||||
@@ -34,6 +35,7 @@ sealed class BaseAsset {
|
||||
this.durationInSeconds,
|
||||
this.isFavorite = false,
|
||||
this.livePhotoVideoId,
|
||||
required this.isEdited,
|
||||
});
|
||||
|
||||
bool get isImage => type == AssetType.image;
|
||||
|
||||
@@ -28,6 +28,7 @@ class LocalAsset extends BaseAsset {
|
||||
this.adjustmentTime,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
required super.isEdited,
|
||||
}) : remoteAssetId = remoteId;
|
||||
|
||||
@override
|
||||
@@ -107,6 +108,7 @@ class LocalAsset extends BaseAsset {
|
||||
DateTime? adjustmentTime,
|
||||
double? latitude,
|
||||
double? longitude,
|
||||
bool? isEdited,
|
||||
}) {
|
||||
return LocalAsset(
|
||||
id: id ?? this.id,
|
||||
@@ -125,6 +127,7 @@ class LocalAsset extends BaseAsset {
|
||||
adjustmentTime: adjustmentTime ?? this.adjustmentTime,
|
||||
latitude: latitude ?? this.latitude,
|
||||
longitude: longitude ?? this.longitude,
|
||||
isEdited: isEdited ?? this.isEdited,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ class RemoteAsset extends BaseAsset {
|
||||
this.visibility = AssetVisibility.timeline,
|
||||
super.livePhotoVideoId,
|
||||
this.stackId,
|
||||
required super.isEdited,
|
||||
}) : localAssetId = localId;
|
||||
|
||||
@override
|
||||
@@ -61,6 +62,7 @@ class RemoteAsset extends BaseAsset {
|
||||
stackId: ${stackId ?? "<NA>"},
|
||||
checksum: $checksum,
|
||||
livePhotoVideoId: ${livePhotoVideoId ?? "<NA>"},
|
||||
isEdited: $isEdited,
|
||||
}''';
|
||||
}
|
||||
|
||||
@@ -104,6 +106,7 @@ class RemoteAsset extends BaseAsset {
|
||||
AssetVisibility? visibility,
|
||||
String? livePhotoVideoId,
|
||||
String? stackId,
|
||||
bool? isEdited,
|
||||
}) {
|
||||
return RemoteAsset(
|
||||
id: id ?? this.id,
|
||||
@@ -122,6 +125,7 @@ class RemoteAsset extends BaseAsset {
|
||||
visibility: visibility ?? this.visibility,
|
||||
livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId,
|
||||
stackId: stackId ?? this.stackId,
|
||||
isEdited: isEdited ?? this.isEdited,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,5 +436,6 @@ extension PlatformToLocalAsset on PlatformAsset {
|
||||
adjustmentTime: tryFromSecondsSinceEpoch(adjustmentTime, isUtc: true),
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
isEdited: false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class SearchService {
|
||||
}
|
||||
|
||||
return SearchResult(
|
||||
assets: response.assets.items.map((e) => e.toDto()).toList(),
|
||||
assets: response.assets.items.map((e) => e.toDto(false)).toList(),
|
||||
nextPage: response.assets.nextPage?.toInt(),
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
@@ -54,7 +54,7 @@ class SearchService {
|
||||
}
|
||||
|
||||
extension on AssetResponseDto {
|
||||
RemoteAsset toDto() {
|
||||
RemoteAsset toDto(bool isEdited) {
|
||||
return RemoteAsset(
|
||||
id: id,
|
||||
name: originalFileName,
|
||||
@@ -77,6 +77,8 @@ extension on AssetResponseDto {
|
||||
thumbHash: thumbhash,
|
||||
localId: null,
|
||||
type: type.toAssetType(),
|
||||
// its a remote asset so it will always show the edited version
|
||||
isEdited: isEdited,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,10 @@ class SyncStreamService {
|
||||
return;
|
||||
case SyncEntityType.assetDeleteV1:
|
||||
return _syncStreamRepository.deleteAssetsV1(data.cast());
|
||||
case SyncEntityType.assetEditV1:
|
||||
return _syncStreamRepository.updateAssetEditsV1(data.cast());
|
||||
case SyncEntityType.assetEditDeleteV1:
|
||||
return _syncStreamRepository.deleteAssetEditsV1(data.cast());
|
||||
case SyncEntityType.assetExifV1:
|
||||
return _syncStreamRepository.updateAssetsExifV1(data.cast());
|
||||
case SyncEntityType.assetMetadataV1:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/asset_edit.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||
|
||||
class AssetEditEntity extends Table with DriftDefaultsMixin {
|
||||
const AssetEditEntity();
|
||||
|
||||
TextColumn get id => text()();
|
||||
|
||||
TextColumn get assetId => text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
|
||||
|
||||
IntColumn get action => intEnum<AssetEditAction>()();
|
||||
|
||||
BlobColumn get parameters => blob().map(editParameterConverter)();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {id};
|
||||
}
|
||||
|
||||
final JsonTypeConverter2<Map<String, Object?>, Uint8List, Object?> editParameterConverter = TypeConverter.jsonb(
|
||||
fromJson: (json) => json as Map<String, Object?>,
|
||||
);
|
||||
@@ -0,0 +1,678 @@
|
||||
// dart format width=80
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:immich_mobile/infrastructure/entities/asset_edit.entity.drift.dart'
|
||||
as i1;
|
||||
import 'package:immich_mobile/domain/models/asset/asset_edit.model.dart' as i2;
|
||||
import 'dart:typed_data' as i3;
|
||||
import 'package:immich_mobile/infrastructure/entities/asset_edit.entity.dart'
|
||||
as i4;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
|
||||
as i5;
|
||||
import 'package:drift/internal/modular.dart' as i6;
|
||||
|
||||
typedef $$AssetEditEntityTableCreateCompanionBuilder =
|
||||
i1.AssetEditEntityCompanion Function({
|
||||
required String id,
|
||||
required String assetId,
|
||||
required i2.AssetEditAction action,
|
||||
required Map<String, Object?> parameters,
|
||||
});
|
||||
typedef $$AssetEditEntityTableUpdateCompanionBuilder =
|
||||
i1.AssetEditEntityCompanion Function({
|
||||
i0.Value<String> id,
|
||||
i0.Value<String> assetId,
|
||||
i0.Value<i2.AssetEditAction> action,
|
||||
i0.Value<Map<String, Object?>> parameters,
|
||||
});
|
||||
|
||||
final class $$AssetEditEntityTableReferences
|
||||
extends
|
||||
i0.BaseReferences<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$AssetEditEntityTable,
|
||||
i1.AssetEditEntityData
|
||||
> {
|
||||
$$AssetEditEntityTableReferences(
|
||||
super.$_db,
|
||||
super.$_table,
|
||||
super.$_typedResult,
|
||||
);
|
||||
|
||||
static i5.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$AssetEditEntityTable>('asset_edit_entity')
|
||||
.assetId,
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
);
|
||||
|
||||
i5.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
final $_column = $_itemColumn<String>('asset_id')!;
|
||||
|
||||
final manager = i5
|
||||
.$$RemoteAssetEntityTableTableManager(
|
||||
$_db,
|
||||
i6.ReadDatabaseContainer(
|
||||
$_db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
)
|
||||
.filter((f) => f.id.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_assetIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
return i0.ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: [item]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class $$AssetEditEntityTableFilterComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$AssetEditEntityTable> {
|
||||
$$AssetEditEntityTableFilterComposer({
|
||||
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.ColumnWithTypeConverterFilters<i2.AssetEditAction, i2.AssetEditAction, int>
|
||||
get action => $composableBuilder(
|
||||
column: $table.action,
|
||||
builder: (column) => i0.ColumnWithTypeConverterFilters(column),
|
||||
);
|
||||
|
||||
i0.ColumnWithTypeConverterFilters<
|
||||
Map<String, Object?>,
|
||||
Map<String, Object>,
|
||||
i3.Uint8List
|
||||
>
|
||||
get parameters => $composableBuilder(
|
||||
column: $table.parameters,
|
||||
builder: (column) => i0.ColumnWithTypeConverterFilters(column),
|
||||
);
|
||||
|
||||
i5.$$RemoteAssetEntityTableFilterComposer get assetId {
|
||||
final i5.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.assetId,
|
||||
referencedTable: i6.ReadDatabaseContainer(
|
||||
$db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder:
|
||||
(
|
||||
joinBuilder, {
|
||||
$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
}) => i5.$$RemoteAssetEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer(
|
||||
$db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
),
|
||||
);
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$AssetEditEntityTableOrderingComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$AssetEditEntityTable> {
|
||||
$$AssetEditEntityTableOrderingComposer({
|
||||
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<int> get action => $composableBuilder(
|
||||
column: $table.action,
|
||||
builder: (column) => i0.ColumnOrderings(column),
|
||||
);
|
||||
|
||||
i0.ColumnOrderings<i3.Uint8List> get parameters => $composableBuilder(
|
||||
column: $table.parameters,
|
||||
builder: (column) => i0.ColumnOrderings(column),
|
||||
);
|
||||
|
||||
i5.$$RemoteAssetEntityTableOrderingComposer get assetId {
|
||||
final i5.$$RemoteAssetEntityTableOrderingComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.assetId,
|
||||
referencedTable: i6.ReadDatabaseContainer(
|
||||
$db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder:
|
||||
(
|
||||
joinBuilder, {
|
||||
$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
}) => i5.$$RemoteAssetEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer(
|
||||
$db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
),
|
||||
);
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$AssetEditEntityTableAnnotationComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$AssetEditEntityTable> {
|
||||
$$AssetEditEntityTableAnnotationComposer({
|
||||
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.GeneratedColumnWithTypeConverter<i2.AssetEditAction, int> get action =>
|
||||
$composableBuilder(column: $table.action, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumnWithTypeConverter<Map<String, Object?>, i3.Uint8List>
|
||||
get parameters => $composableBuilder(
|
||||
column: $table.parameters,
|
||||
builder: (column) => column,
|
||||
);
|
||||
|
||||
i5.$$RemoteAssetEntityTableAnnotationComposer get assetId {
|
||||
final i5.$$RemoteAssetEntityTableAnnotationComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.assetId,
|
||||
referencedTable: i6.ReadDatabaseContainer(
|
||||
$db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder:
|
||||
(
|
||||
joinBuilder, {
|
||||
$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
}) => i5.$$RemoteAssetEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer(
|
||||
$db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
),
|
||||
);
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$AssetEditEntityTableTableManager
|
||||
extends
|
||||
i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$AssetEditEntityTable,
|
||||
i1.AssetEditEntityData,
|
||||
i1.$$AssetEditEntityTableFilterComposer,
|
||||
i1.$$AssetEditEntityTableOrderingComposer,
|
||||
i1.$$AssetEditEntityTableAnnotationComposer,
|
||||
$$AssetEditEntityTableCreateCompanionBuilder,
|
||||
$$AssetEditEntityTableUpdateCompanionBuilder,
|
||||
(i1.AssetEditEntityData, i1.$$AssetEditEntityTableReferences),
|
||||
i1.AssetEditEntityData,
|
||||
i0.PrefetchHooks Function({bool assetId})
|
||||
> {
|
||||
$$AssetEditEntityTableTableManager(
|
||||
i0.GeneratedDatabase db,
|
||||
i1.$AssetEditEntityTable table,
|
||||
) : super(
|
||||
i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
createFilteringComposer: () =>
|
||||
i1.$$AssetEditEntityTableFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
i1.$$AssetEditEntityTableOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () => i1
|
||||
.$$AssetEditEntityTableAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback:
|
||||
({
|
||||
i0.Value<String> id = const i0.Value.absent(),
|
||||
i0.Value<String> assetId = const i0.Value.absent(),
|
||||
i0.Value<i2.AssetEditAction> action = const i0.Value.absent(),
|
||||
i0.Value<Map<String, Object?>> parameters =
|
||||
const i0.Value.absent(),
|
||||
}) => i1.AssetEditEntityCompanion(
|
||||
id: id,
|
||||
assetId: assetId,
|
||||
action: action,
|
||||
parameters: parameters,
|
||||
),
|
||||
createCompanionCallback:
|
||||
({
|
||||
required String id,
|
||||
required String assetId,
|
||||
required i2.AssetEditAction action,
|
||||
required Map<String, Object?> parameters,
|
||||
}) => i1.AssetEditEntityCompanion.insert(
|
||||
id: id,
|
||||
assetId: assetId,
|
||||
action: action,
|
||||
parameters: parameters,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
.map(
|
||||
(e) => (
|
||||
e.readTable(table),
|
||||
i1.$$AssetEditEntityTableReferences(db, table, e),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
prefetchHooksCallback: ({assetId = 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 (assetId) {
|
||||
state =
|
||||
state.withJoin(
|
||||
currentTable: table,
|
||||
currentColumn: table.assetId,
|
||||
referencedTable: i1
|
||||
.$$AssetEditEntityTableReferences
|
||||
._assetIdTable(db),
|
||||
referencedColumn: i1
|
||||
.$$AssetEditEntityTableReferences
|
||||
._assetIdTable(db)
|
||||
.id,
|
||||
)
|
||||
as T;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
getPrefetchedDataCallback: (items) async {
|
||||
return [];
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
typedef $$AssetEditEntityTableProcessedTableManager =
|
||||
i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$AssetEditEntityTable,
|
||||
i1.AssetEditEntityData,
|
||||
i1.$$AssetEditEntityTableFilterComposer,
|
||||
i1.$$AssetEditEntityTableOrderingComposer,
|
||||
i1.$$AssetEditEntityTableAnnotationComposer,
|
||||
$$AssetEditEntityTableCreateCompanionBuilder,
|
||||
$$AssetEditEntityTableUpdateCompanionBuilder,
|
||||
(i1.AssetEditEntityData, i1.$$AssetEditEntityTableReferences),
|
||||
i1.AssetEditEntityData,
|
||||
i0.PrefetchHooks Function({bool assetId})
|
||||
>;
|
||||
|
||||
class $AssetEditEntityTable extends i4.AssetEditEntity
|
||||
with i0.TableInfo<$AssetEditEntityTable, i1.AssetEditEntityData> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$AssetEditEntityTable(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 _assetIdMeta = const i0.VerificationMeta(
|
||||
'assetId',
|
||||
);
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> assetId = i0.GeneratedColumn<String>(
|
||||
'asset_id',
|
||||
aliasedName,
|
||||
false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES remote_asset_entity (id) ON DELETE CASCADE',
|
||||
),
|
||||
);
|
||||
@override
|
||||
late final i0.GeneratedColumnWithTypeConverter<i2.AssetEditAction, int>
|
||||
action =
|
||||
i0.GeneratedColumn<int>(
|
||||
'action',
|
||||
aliasedName,
|
||||
false,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
).withConverter<i2.AssetEditAction>(
|
||||
i1.$AssetEditEntityTable.$converteraction,
|
||||
);
|
||||
@override
|
||||
late final i0.GeneratedColumnWithTypeConverter<
|
||||
Map<String, Object?>,
|
||||
i3.Uint8List
|
||||
>
|
||||
parameters =
|
||||
i0.GeneratedColumn<i3.Uint8List>(
|
||||
'parameters',
|
||||
aliasedName,
|
||||
false,
|
||||
type: i0.DriftSqlType.blob,
|
||||
requiredDuringInsert: true,
|
||||
).withConverter<Map<String, Object?>>(
|
||||
i1.$AssetEditEntityTable.$converterparameters,
|
||||
);
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [id, assetId, action, parameters];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'asset_edit_entity';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(
|
||||
i0.Insertable<i1.AssetEditEntityData> 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('asset_id')) {
|
||||
context.handle(
|
||||
_assetIdMeta,
|
||||
assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta),
|
||||
);
|
||||
} else if (isInserting) {
|
||||
context.missing(_assetIdMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
i1.AssetEditEntityData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.AssetEditEntityData(
|
||||
id: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.string,
|
||||
data['${effectivePrefix}id'],
|
||||
)!,
|
||||
assetId: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.string,
|
||||
data['${effectivePrefix}asset_id'],
|
||||
)!,
|
||||
action: i1.$AssetEditEntityTable.$converteraction.fromSql(
|
||||
attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.int,
|
||||
data['${effectivePrefix}action'],
|
||||
)!,
|
||||
),
|
||||
parameters: i1.$AssetEditEntityTable.$converterparameters.fromSql(
|
||||
attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.blob,
|
||||
data['${effectivePrefix}parameters'],
|
||||
)!,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$AssetEditEntityTable createAlias(String alias) {
|
||||
return $AssetEditEntityTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static i0.JsonTypeConverter2<i2.AssetEditAction, int, int> $converteraction =
|
||||
const i0.EnumIndexConverter<i2.AssetEditAction>(
|
||||
i2.AssetEditAction.values,
|
||||
);
|
||||
static i0.JsonTypeConverter2<Map<String, Object?>, i3.Uint8List, Object?>
|
||||
$converterparameters = i4.editParameterConverter;
|
||||
@override
|
||||
bool get withoutRowId => true;
|
||||
@override
|
||||
bool get isStrict => true;
|
||||
}
|
||||
|
||||
class AssetEditEntityData extends i0.DataClass
|
||||
implements i0.Insertable<i1.AssetEditEntityData> {
|
||||
final String id;
|
||||
final String assetId;
|
||||
final i2.AssetEditAction action;
|
||||
final Map<String, Object?> parameters;
|
||||
const AssetEditEntityData({
|
||||
required this.id,
|
||||
required this.assetId,
|
||||
required this.action,
|
||||
required this.parameters,
|
||||
});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['id'] = i0.Variable<String>(id);
|
||||
map['asset_id'] = i0.Variable<String>(assetId);
|
||||
{
|
||||
map['action'] = i0.Variable<int>(
|
||||
i1.$AssetEditEntityTable.$converteraction.toSql(action),
|
||||
);
|
||||
}
|
||||
{
|
||||
map['parameters'] = i0.Variable<i3.Uint8List>(
|
||||
i1.$AssetEditEntityTable.$converterparameters.toSql(parameters),
|
||||
);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
factory AssetEditEntityData.fromJson(
|
||||
Map<String, dynamic> json, {
|
||||
i0.ValueSerializer? serializer,
|
||||
}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return AssetEditEntityData(
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
assetId: serializer.fromJson<String>(json['assetId']),
|
||||
action: i1.$AssetEditEntityTable.$converteraction.fromJson(
|
||||
serializer.fromJson<int>(json['action']),
|
||||
),
|
||||
parameters: i1.$AssetEditEntityTable.$converterparameters.fromJson(
|
||||
serializer.fromJson<Object?>(json['parameters']),
|
||||
),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<String>(id),
|
||||
'assetId': serializer.toJson<String>(assetId),
|
||||
'action': serializer.toJson<int>(
|
||||
i1.$AssetEditEntityTable.$converteraction.toJson(action),
|
||||
),
|
||||
'parameters': serializer.toJson<Object?>(
|
||||
i1.$AssetEditEntityTable.$converterparameters.toJson(parameters),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
i1.AssetEditEntityData copyWith({
|
||||
String? id,
|
||||
String? assetId,
|
||||
i2.AssetEditAction? action,
|
||||
Map<String, Object?>? parameters,
|
||||
}) => i1.AssetEditEntityData(
|
||||
id: id ?? this.id,
|
||||
assetId: assetId ?? this.assetId,
|
||||
action: action ?? this.action,
|
||||
parameters: parameters ?? this.parameters,
|
||||
);
|
||||
AssetEditEntityData copyWithCompanion(i1.AssetEditEntityCompanion data) {
|
||||
return AssetEditEntityData(
|
||||
id: data.id.present ? data.id.value : this.id,
|
||||
assetId: data.assetId.present ? data.assetId.value : this.assetId,
|
||||
action: data.action.present ? data.action.value : this.action,
|
||||
parameters: data.parameters.present
|
||||
? data.parameters.value
|
||||
: this.parameters,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('AssetEditEntityData(')
|
||||
..write('id: $id, ')
|
||||
..write('assetId: $assetId, ')
|
||||
..write('action: $action, ')
|
||||
..write('parameters: $parameters')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, assetId, action, parameters);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.AssetEditEntityData &&
|
||||
other.id == this.id &&
|
||||
other.assetId == this.assetId &&
|
||||
other.action == this.action &&
|
||||
other.parameters == this.parameters);
|
||||
}
|
||||
|
||||
class AssetEditEntityCompanion
|
||||
extends i0.UpdateCompanion<i1.AssetEditEntityData> {
|
||||
final i0.Value<String> id;
|
||||
final i0.Value<String> assetId;
|
||||
final i0.Value<i2.AssetEditAction> action;
|
||||
final i0.Value<Map<String, Object?>> parameters;
|
||||
const AssetEditEntityCompanion({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.assetId = const i0.Value.absent(),
|
||||
this.action = const i0.Value.absent(),
|
||||
this.parameters = const i0.Value.absent(),
|
||||
});
|
||||
AssetEditEntityCompanion.insert({
|
||||
required String id,
|
||||
required String assetId,
|
||||
required i2.AssetEditAction action,
|
||||
required Map<String, Object?> parameters,
|
||||
}) : id = i0.Value(id),
|
||||
assetId = i0.Value(assetId),
|
||||
action = i0.Value(action),
|
||||
parameters = i0.Value(parameters);
|
||||
static i0.Insertable<i1.AssetEditEntityData> custom({
|
||||
i0.Expression<String>? id,
|
||||
i0.Expression<String>? assetId,
|
||||
i0.Expression<int>? action,
|
||||
i0.Expression<i3.Uint8List>? parameters,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (assetId != null) 'asset_id': assetId,
|
||||
if (action != null) 'action': action,
|
||||
if (parameters != null) 'parameters': parameters,
|
||||
});
|
||||
}
|
||||
|
||||
i1.AssetEditEntityCompanion copyWith({
|
||||
i0.Value<String>? id,
|
||||
i0.Value<String>? assetId,
|
||||
i0.Value<i2.AssetEditAction>? action,
|
||||
i0.Value<Map<String, Object?>>? parameters,
|
||||
}) {
|
||||
return i1.AssetEditEntityCompanion(
|
||||
id: id ?? this.id,
|
||||
assetId: assetId ?? this.assetId,
|
||||
action: action ?? this.action,
|
||||
parameters: parameters ?? this.parameters,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = i0.Variable<String>(id.value);
|
||||
}
|
||||
if (assetId.present) {
|
||||
map['asset_id'] = i0.Variable<String>(assetId.value);
|
||||
}
|
||||
if (action.present) {
|
||||
map['action'] = i0.Variable<int>(
|
||||
i1.$AssetEditEntityTable.$converteraction.toSql(action.value),
|
||||
);
|
||||
}
|
||||
if (parameters.present) {
|
||||
map['parameters'] = i0.Variable<i3.Uint8List>(
|
||||
i1.$AssetEditEntityTable.$converterparameters.toSql(parameters.value),
|
||||
);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('AssetEditEntityCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('assetId: $assetId, ')
|
||||
..write('action: $action, ')
|
||||
..write('parameters: $parameters')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
|
||||
}
|
||||
|
||||
extension LocalAssetEntityDataDomainExtension on LocalAssetEntityData {
|
||||
LocalAsset toDto({String? remoteId}) => LocalAsset(
|
||||
LocalAsset toDto(bool isEdited, {String? remoteId}) => LocalAsset(
|
||||
id: id,
|
||||
name: name,
|
||||
checksum: checksum,
|
||||
@@ -47,5 +47,6 @@ extension LocalAssetEntityDataDomainExtension on LocalAssetEntityData {
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
cloudId: iCloudId,
|
||||
isEdited: isEdited,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'stack.entity.dart';
|
||||
import 'local_asset.entity.dart';
|
||||
import 'local_album.entity.dart';
|
||||
import 'local_album_asset.entity.dart';
|
||||
import 'asset_edit.entity.dart';
|
||||
|
||||
mergedAsset:
|
||||
SELECT
|
||||
@@ -26,6 +27,7 @@ SELECT
|
||||
NULL as latitude,
|
||||
NULL as longitude,
|
||||
NULL as adjustmentTime
|
||||
CASE WHEN EXISTS (SELECT 1 FROM asset_edit_entity aee WHERE aee.asset_id = rae.id) THEN 1 ELSE 0 END as is_edited
|
||||
FROM
|
||||
remote_asset_entity rae
|
||||
LEFT JOIN
|
||||
@@ -62,6 +64,7 @@ SELECT
|
||||
lae.latitude,
|
||||
lae.longitude,
|
||||
lae.adjustment_time
|
||||
0 as is_edited
|
||||
FROM
|
||||
local_asset_entity lae
|
||||
WHERE NOT EXISTS (
|
||||
|
||||
@@ -49,7 +49,7 @@ class RemoteAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin
|
||||
}
|
||||
|
||||
extension RemoteAssetEntityDataDomainEx on RemoteAssetEntityData {
|
||||
RemoteAsset toDto({String? localId}) => RemoteAsset(
|
||||
RemoteAsset toDto(bool isEdited, {String? localId}) => RemoteAsset(
|
||||
id: id,
|
||||
name: name,
|
||||
ownerId: ownerId,
|
||||
@@ -66,5 +66,6 @@ extension RemoteAssetEntityDataDomainEx on RemoteAssetEntityData {
|
||||
livePhotoVideoId: livePhotoVideoId,
|
||||
localId: localId,
|
||||
stackId: stackId,
|
||||
isEdited: isEdited,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,5 +45,6 @@ extension TrashedLocalAssetEntityDataDomainExtension on TrashedLocalAssetEntityD
|
||||
height: height,
|
||||
width: width,
|
||||
orientation: orientation,
|
||||
isEdited: false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -112,6 +112,13 @@ class DriftBackupRepository extends DriftDatabaseRepository {
|
||||
query.where((lae) => lae.checksum.isNotNull());
|
||||
}
|
||||
|
||||
return query.map((localAsset) => localAsset.toDto()).get();
|
||||
final assetsQuery = query.join([
|
||||
leftOuterJoin(_db.remoteAssetEntity, _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum)),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
]);
|
||||
|
||||
return assetsQuery
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:drift/drift.dart';
|
||||
import 'package:drift_flutter/drift_flutter.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/asset_edit.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
|
||||
@@ -66,6 +67,7 @@ class IsarDatabaseRepository implements IDatabaseRepository {
|
||||
AssetFaceEntity,
|
||||
StoreEntity,
|
||||
TrashedLocalAssetEntity,
|
||||
AssetEditEntity,
|
||||
],
|
||||
include: {'package:immich_mobile/infrastructure/entities/merged_asset.drift'},
|
||||
)
|
||||
|
||||
@@ -188,10 +188,17 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
final query =
|
||||
_db.localAlbumAssetEntity.select().join([
|
||||
innerJoin(_db.localAssetEntity, _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id)),
|
||||
leftOuterJoin(
|
||||
_db.remoteAssetEntity,
|
||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(_db.localAlbumAssetEntity.albumId.equals(albumId))
|
||||
..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]);
|
||||
return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
Future<List<String>> getAssetIds(String albumId) {
|
||||
@@ -239,11 +246,18 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
final query =
|
||||
_db.localAlbumAssetEntity.select().join([
|
||||
innerJoin(_db.localAssetEntity, _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id)),
|
||||
leftOuterJoin(
|
||||
_db.remoteAssetEntity,
|
||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(_db.localAlbumAssetEntity.albumId.equals(albumId) & _db.localAssetEntity.checksum.isNull())
|
||||
..orderBy([OrderingTerm.asc(_db.localAssetEntity.id)]);
|
||||
|
||||
return query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
Future<void> updateCloudMapping(Map<String, String> cloudMapping) {
|
||||
@@ -417,12 +431,19 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
final query =
|
||||
_db.localAlbumAssetEntity.select().join([
|
||||
innerJoin(_db.localAssetEntity, _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id)),
|
||||
leftOuterJoin(
|
||||
_db.remoteAssetEntity,
|
||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(_db.localAlbumAssetEntity.albumId.equals(albumId))
|
||||
..orderBy([OrderingTerm.desc(_db.localAssetEntity.createdAt)])
|
||||
..limit(1);
|
||||
|
||||
final results = await query.map((row) => row.readTable(_db.localAssetEntity).toDto()).get();
|
||||
final results = await query
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
|
||||
return results.isNotEmpty ? results.first : null;
|
||||
}
|
||||
|
||||
@@ -23,10 +23,11 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
_db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])..where(_db.localAssetEntity.id.equals(id));
|
||||
|
||||
return query.map((row) {
|
||||
final asset = row.readTable(_db.localAssetEntity).toDto();
|
||||
final asset = row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null);
|
||||
return asset.copyWith(remoteId: row.read(_db.remoteAssetEntity.id));
|
||||
});
|
||||
}
|
||||
@@ -34,9 +35,14 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
Future<LocalAsset?> get(String id) => _assetSelectable(id).getSingleOrNull();
|
||||
|
||||
Future<List<LocalAsset?>> getByChecksum(String checksum) {
|
||||
final query = _db.localAssetEntity.select()..where((lae) => lae.checksum.equals(checksum));
|
||||
final query = _db.localAssetEntity.select().join([
|
||||
leftOuterJoin(_db.remoteAssetEntity, _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum)),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])..where(_db.localAssetEntity.checksum.equals(checksum));
|
||||
|
||||
return query.map((row) => row.toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
Stream<LocalAsset?> watch(String id) => _assetSelectable(id).watchSingleOrNull();
|
||||
@@ -70,9 +76,14 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
|
||||
Future<LocalAsset?> getById(String id) {
|
||||
final query = _db.localAssetEntity.select()..where((lae) => lae.id.equals(id));
|
||||
final query = _db.localAssetEntity.select().join([
|
||||
leftOuterJoin(_db.remoteAssetEntity, _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum)),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])..where(_db.localAssetEntity.id.equals(id));
|
||||
|
||||
return query.map((row) => row.toDto()).getSingleOrNull();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.getSingleOrNull();
|
||||
}
|
||||
|
||||
Future<int> getCount() {
|
||||
@@ -114,6 +125,11 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
await (_db.select(_db.localAlbumAssetEntity).join([
|
||||
innerJoin(_db.localAlbumEntity, _db.localAlbumAssetEntity.albumId.equalsExp(_db.localAlbumEntity.id)),
|
||||
innerJoin(_db.localAssetEntity, _db.localAlbumAssetEntity.assetId.equalsExp(_db.localAssetEntity.id)),
|
||||
leftOuterJoin(
|
||||
_db.remoteAssetEntity,
|
||||
_db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum),
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])..where(
|
||||
_db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) &
|
||||
_db.localAssetEntity.checksum.isIn(slice),
|
||||
@@ -123,7 +139,7 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
for (final row in rows) {
|
||||
final albumId = row.readTable(_db.localAlbumAssetEntity).albumId;
|
||||
final assetData = row.readTable(_db.localAssetEntity);
|
||||
final asset = assetData.toDto();
|
||||
final asset = assetData.toDto(row.readTableOrNull(_db.assetEditEntity) != null);
|
||||
(result[albumId] ??= <LocalAsset>[]).add(asset);
|
||||
}
|
||||
}
|
||||
@@ -149,6 +165,7 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
|
||||
final query = _db.localAssetEntity.select().join([
|
||||
innerJoin(_db.remoteAssetEntity, _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum)),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
]);
|
||||
|
||||
Expression<bool> whereClause =
|
||||
@@ -172,7 +189,9 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
query.where(whereClause);
|
||||
|
||||
final rows = await query.get();
|
||||
return rows.map((row) => row.readTable(_db.localAssetEntity).toDto()).toList();
|
||||
return rows
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<List<LocalAsset>> getEmptyCloudIdAssets() {
|
||||
|
||||
@@ -22,6 +22,7 @@ class DriftMemoryRepository extends DriftDatabaseRepository {
|
||||
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||
_db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline),
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(_db.memoryEntity.ownerId.equals(ownerId))
|
||||
..where(_db.memoryEntity.deletedAt.isNull())
|
||||
@@ -42,9 +43,9 @@ class DriftMemoryRepository extends DriftDatabaseRepository {
|
||||
|
||||
final existingMemory = memoriesMap[memory.id];
|
||||
if (existingMemory != null) {
|
||||
existingMemory.assets.add(asset.toDto());
|
||||
existingMemory.assets.add(asset.toDto(row.readTableOrNull(_db.assetEditEntity) != null));
|
||||
} else {
|
||||
final assets = [asset.toDto()];
|
||||
final assets = [asset.toDto(row.readTableOrNull(_db.assetEditEntity) != null)];
|
||||
memoriesMap[memory.id] = memory.toDto().copyWith(assets: assets);
|
||||
}
|
||||
}
|
||||
@@ -62,6 +63,7 @@ class DriftMemoryRepository extends DriftDatabaseRepository {
|
||||
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||
_db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline),
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(_db.memoryEntity.id.equals(memoryId))
|
||||
..where(_db.memoryEntity.deletedAt.isNull())
|
||||
@@ -78,7 +80,7 @@ class DriftMemoryRepository extends DriftDatabaseRepository {
|
||||
|
||||
for (final row in rows) {
|
||||
final asset = row.readTable(_db.remoteAssetEntity);
|
||||
assets.add(asset.toDto());
|
||||
assets.add(asset.toDto(row.readTableOrNull(_db.assetEditEntity) != null));
|
||||
}
|
||||
|
||||
return memory.toDto().copyWith(assets: assets);
|
||||
|
||||
@@ -233,9 +233,12 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository {
|
||||
Future<List<RemoteAsset>> getAssets(String albumId) {
|
||||
final query = _db.remoteAlbumAssetEntity.select().join([
|
||||
innerJoin(_db.remoteAssetEntity, _db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId)),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])..where(_db.remoteAlbumAssetEntity.albumId.equals(albumId));
|
||||
|
||||
return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
Future<int> addAssets(String albumId, List<String> assetIds) async {
|
||||
|
||||
@@ -17,17 +17,21 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
||||
|
||||
/// For testing purposes
|
||||
Future<List<RemoteAsset>> getSome(String userId) {
|
||||
final query = _db.remoteAssetEntity.select()
|
||||
..where(
|
||||
(row) =>
|
||||
final query =
|
||||
_db.remoteAssetEntity.select().join([
|
||||
leftOuterJoin(_db.assetEditEntity, _db.remoteAssetEntity.id.equalsExp(_db.assetEditEntity.assetId)),
|
||||
])
|
||||
..where(
|
||||
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||
_db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline),
|
||||
)
|
||||
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||
..limit(10);
|
||||
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||
_db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline),
|
||||
)
|
||||
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
|
||||
..limit(10);
|
||||
|
||||
return query.map((row) => row.toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
SingleOrNullSelectable<RemoteAsset?> _assetSelectable(String id) {
|
||||
@@ -38,12 +42,14 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.remoteAssetEntity.id.equalsExp(_db.assetEditEntity.assetId)),
|
||||
])
|
||||
..where(_db.remoteAssetEntity.id.equals(id))
|
||||
..limit(1);
|
||||
|
||||
return query.map((row) {
|
||||
final asset = row.readTable(_db.remoteAssetEntity).toDto();
|
||||
final isEdited = row.readTableOrNull(_db.assetEditEntity) != null;
|
||||
final asset = row.readTable(_db.remoteAssetEntity).toDto(isEdited);
|
||||
return asset.copyWith(localId: row.read(_db.localAssetEntity.id));
|
||||
});
|
||||
}
|
||||
@@ -57,9 +63,13 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
|
||||
Future<RemoteAsset?> getByChecksum(String checksum) {
|
||||
final query = _db.remoteAssetEntity.select()..where((row) => row.checksum.equals(checksum));
|
||||
final query = _db.remoteAssetEntity.select().join([
|
||||
leftOuterJoin(_db.assetEditEntity, _db.remoteAssetEntity.id.equalsExp(_db.assetEditEntity.assetId)),
|
||||
])..where(_db.remoteAssetEntity.checksum.equals(checksum));
|
||||
|
||||
return query.map((row) => row.toDto()).getSingleOrNull();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.getSingleOrNull();
|
||||
}
|
||||
|
||||
Future<List<RemoteAsset>> getStackChildren(RemoteAsset asset) {
|
||||
@@ -68,11 +78,16 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
||||
return Future.value(const []);
|
||||
}
|
||||
|
||||
final query = _db.remoteAssetEntity.select()
|
||||
..where((row) => row.stackId.equals(stackId) & row.id.equals(asset.id).not())
|
||||
..orderBy([(row) => OrderingTerm.desc(row.createdAt)]);
|
||||
final query =
|
||||
_db.remoteAssetEntity.select().join([
|
||||
leftOuterJoin(_db.assetEditEntity, _db.remoteAssetEntity.id.equalsExp(_db.assetEditEntity.assetId)),
|
||||
])
|
||||
..where(_db.remoteAssetEntity.stackId.equals(stackId) & _db.remoteAssetEntity.id.equals(asset.id).not())
|
||||
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]);
|
||||
|
||||
return query.map((row) => row.toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
Future<ExifInfo?> getExif(String id) {
|
||||
|
||||
@@ -44,6 +44,7 @@ class SyncApiRepository {
|
||||
SyncRequestType.authUsersV1,
|
||||
SyncRequestType.usersV1,
|
||||
SyncRequestType.assetsV1,
|
||||
SyncRequestType.assetEditsV1,
|
||||
SyncRequestType.assetExifsV1,
|
||||
SyncRequestType.assetMetadataV1,
|
||||
SyncRequestType.partnersV1,
|
||||
@@ -148,6 +149,8 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
|
||||
SyncEntityType.partnerDeleteV1: SyncPartnerDeleteV1.fromJson,
|
||||
SyncEntityType.assetV1: SyncAssetV1.fromJson,
|
||||
SyncEntityType.assetDeleteV1: SyncAssetDeleteV1.fromJson,
|
||||
SyncEntityType.assetEditV1: SyncAssetEditV1.fromJson,
|
||||
SyncEntityType.assetEditDeleteV1: SyncAssetEditDeleteV1.fromJson,
|
||||
SyncEntityType.assetExifV1: SyncAssetExifV1.fromJson,
|
||||
SyncEntityType.assetMetadataV1: SyncAssetMetadataV1.fromJson,
|
||||
SyncEntityType.assetMetadataDeleteV1: SyncAssetMetadataDeleteV1.fromJson,
|
||||
|
||||
@@ -4,10 +4,12 @@ import 'package:collection/collection.dart';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/constants/constants.dart';
|
||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/asset_edit.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/memory.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/domain/models/user_metadata.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/asset_edit.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/asset_face.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/auth_user.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||
@@ -26,8 +28,8 @@ import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole, UserMetadataKey;
|
||||
import 'package:openapi/api.dart' hide AssetVisibility, AlbumUserRole, UserMetadataKey;
|
||||
import 'package:openapi/api.dart' as api show AssetVisibility, AlbumUserRole, UserMetadataKey, AssetEditAction;
|
||||
import 'package:openapi/api.dart' hide AssetVisibility, AlbumUserRole, UserMetadataKey, AssetEditAction;
|
||||
|
||||
class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
final Logger _logger = Logger('DriftSyncStreamRepository');
|
||||
@@ -215,6 +217,40 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateAssetEditsV1(Iterable<SyncAssetEditV1> data) async {
|
||||
print('Updating asset edits V1: ${data.length} items');
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final edit in data) {
|
||||
final companion = AssetEditEntityCompanion(
|
||||
id: Value(edit.id),
|
||||
assetId: Value(edit.assetId),
|
||||
action: Value(edit.action.toAssetEditAction()),
|
||||
parameters: Value(edit.parameters as Map<String, Object?>),
|
||||
);
|
||||
|
||||
batch.insert(_db.assetEditEntity, companion, onConflict: DoUpdate((_) => companion));
|
||||
}
|
||||
});
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Error: updateAssetEditsV1', error, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteAssetEditsV1(Iterable<SyncAssetEditDeleteV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final edit in data) {
|
||||
batch.deleteWhere(_db.assetEditEntity, (row) => row.assetId.equals(edit.assetId));
|
||||
}
|
||||
});
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Error: deleteAssetEditsV1', error, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data, {String debugLabel = 'user'}) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
@@ -764,3 +800,12 @@ extension on String {
|
||||
extension on UserAvatarColor {
|
||||
AvatarColor? toAvatarColor() => AvatarColor.values.firstWhereOrNull((c) => c.name == value);
|
||||
}
|
||||
|
||||
extension on api.AssetEditAction {
|
||||
AssetEditAction toAssetEditAction() => switch (this) {
|
||||
api.AssetEditAction.crop => AssetEditAction.crop,
|
||||
api.AssetEditAction.rotate => AssetEditAction.rotate,
|
||||
api.AssetEditAction.mirror => AssetEditAction.rotate,
|
||||
_ => AssetEditAction.other,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
durationInSeconds: row.durationInSeconds,
|
||||
livePhotoVideoId: row.livePhotoVideoId,
|
||||
stackId: row.stackId,
|
||||
isEdited: row.isEdited == 1,
|
||||
)
|
||||
: LocalAsset(
|
||||
id: row.localId!,
|
||||
@@ -88,6 +89,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
latitude: row.latitude,
|
||||
longitude: row.longitude,
|
||||
adjustmentTime: row.adjustmentTime,
|
||||
isEdited: false,
|
||||
),
|
||||
)
|
||||
.get();
|
||||
@@ -148,6 +150,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
_db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..addColumns([_db.remoteAssetEntity.id])
|
||||
..where(_db.localAlbumAssetEntity.albumId.equals(albumId))
|
||||
@@ -155,7 +158,11 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
..limit(count, offset: offset);
|
||||
|
||||
return query
|
||||
.map((row) => row.readTable(_db.localAssetEntity).toDto(remoteId: row.read(_db.remoteAssetEntity.id)))
|
||||
.map(
|
||||
(row) => row
|
||||
.readTable(_db.localAssetEntity)
|
||||
.toDto(row.readTableOrNull(_db.assetEditEntity) != null, remoteId: row.read(_db.remoteAssetEntity.id)),
|
||||
)
|
||||
.get();
|
||||
}
|
||||
|
||||
@@ -236,6 +243,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])..where(_db.remoteAssetEntity.deletedAt.isNull() & _db.remoteAlbumAssetEntity.albumId.equals(albumId));
|
||||
|
||||
if (isAscending) {
|
||||
@@ -247,7 +255,11 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
query.limit(count, offset: offset);
|
||||
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(localId: row.read(_db.localAssetEntity.id)))
|
||||
.map(
|
||||
(row) => row
|
||||
.readTable(_db.remoteAssetEntity)
|
||||
.toDto(row.readTableOrNull(_db.assetEditEntity) != null, localId: row.read(_db.localAssetEntity.id)),
|
||||
)
|
||||
.get();
|
||||
}
|
||||
|
||||
@@ -376,6 +388,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
_db.remoteExifEntity.assetId.equalsExp(_db.remoteAssetEntity.id),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(
|
||||
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||
@@ -384,7 +397,9 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
)
|
||||
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
|
||||
..limit(count, offset: offset);
|
||||
return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
Stream<List<Bucket>> _watchPersonBucket(String userId, String personId, {GroupAssetsBy groupBy = GroupAssetsBy.day}) {
|
||||
@@ -452,6 +467,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
_db.assetFaceEntity.assetId.equalsExp(_db.remoteAssetEntity.id),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(
|
||||
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||
@@ -462,7 +478,9 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
|
||||
..limit(count, offset: offset);
|
||||
|
||||
return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
TimelineQuery map(String userId, LatLngBounds bounds, GroupAssetsBy groupBy) => (
|
||||
@@ -522,6 +540,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
_db.remoteExifEntity.assetId.equalsExp(_db.remoteAssetEntity.id),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..where(
|
||||
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||
@@ -531,7 +550,9 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
)
|
||||
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
|
||||
..limit(count, offset: offset);
|
||||
return query.map((row) => row.readTable(_db.remoteAssetEntity).toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@@ -589,6 +610,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||
useColumns: false,
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])
|
||||
..addColumns([_db.localAssetEntity.id])
|
||||
..where(filter(_db.remoteAssetEntity))
|
||||
@@ -596,15 +618,24 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
..limit(count, offset: offset);
|
||||
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(localId: row.read(_db.localAssetEntity.id)))
|
||||
.map(
|
||||
(row) => row
|
||||
.readTable(_db.remoteAssetEntity)
|
||||
.toDto(row.readTableOrNull(_db.assetEditEntity) != null, localId: row.read(_db.localAssetEntity.id)),
|
||||
)
|
||||
.get();
|
||||
} else {
|
||||
final query = _db.remoteAssetEntity.select()
|
||||
..where(filter)
|
||||
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||
..limit(count, offset: offset);
|
||||
final query =
|
||||
_db.remoteAssetEntity.select().join([
|
||||
leftOuterJoin(_db.assetEditEntity, _db.remoteAssetEntity.id.equalsExp(_db.assetEditEntity.assetId)),
|
||||
])
|
||||
..where(filter(_db.remoteAssetEntity))
|
||||
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
|
||||
..limit(count, offset: offset);
|
||||
|
||||
return query.map((row) => row.toDto()).get();
|
||||
return query
|
||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto(row.readTableOrNull(_db.assetEditEntity) != null))
|
||||
.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,6 +271,7 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||
_db.remoteAssetEntity,
|
||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||
),
|
||||
leftOuterJoin(_db.assetEditEntity, _db.assetEditEntity.assetId.equalsExp(_db.remoteAssetEntity.id)),
|
||||
])..where(
|
||||
_db.localAlbumEntity.backupSelection.equalsValue(BackupSelection.selected) &
|
||||
_db.remoteAssetEntity.deletedAt.isNotNull(),
|
||||
@@ -279,7 +280,8 @@ class DriftTrashedLocalAssetRepository extends DriftDatabaseRepository {
|
||||
|
||||
for (final row in rows) {
|
||||
final albumId = row.readTable(_db.localAlbumAssetEntity).albumId;
|
||||
final asset = row.readTable(_db.localAssetEntity).toDto();
|
||||
final hasEdits = row.readTableOrNull(_db.assetEditEntity) != null;
|
||||
final asset = row.readTable(_db.localAssetEntity).toDto(hasEdits);
|
||||
(result[albumId] ??= <LocalAsset>[]).add(asset);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ class _AssetPropertiesSectionState extends ConsumerState<_AssetPropertiesSection
|
||||
),
|
||||
_PropertyItem(label: 'Is Favorite', value: asset.isFavorite.toString()),
|
||||
_PropertyItem(label: 'Live Photo Video ID', value: asset.livePhotoVideoId),
|
||||
_PropertyItem(label: 'Is Edited', value: asset.isEdited.toString()),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,4 +136,4 @@ ImageProvider? getThumbnailImageProvider(BaseAsset asset, {Size size = kThumbnai
|
||||
}
|
||||
|
||||
bool _shouldUseLocalAsset(BaseAsset asset) =>
|
||||
asset.hasLocal && (!asset.hasRemote || !AppSetting.get(Setting.preferRemoteImage));
|
||||
asset.hasLocal && !asset.isEdited && (!asset.hasRemote || !AppSetting.get(Setting.preferRemoteImage));
|
||||
|
||||
@@ -69,6 +69,7 @@ class CastNotifier extends StateNotifier<CastManagerState> {
|
||||
: AssetType.other,
|
||||
createdAt: asset.fileCreatedAt,
|
||||
updatedAt: asset.updatedAt,
|
||||
isEdited: false,
|
||||
);
|
||||
|
||||
_gCastService.loadMedia(remoteAsset, reload);
|
||||
|
||||
@@ -25,6 +25,7 @@ class FileMediaRepository {
|
||||
type: AssetType.image,
|
||||
createdAt: entity.createDateTime,
|
||||
updatedAt: entity.modifiedDateTime,
|
||||
isEdited: false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Generated
+2
@@ -560,6 +560,8 @@ Class | Method | HTTP request | Description
|
||||
- [SyncAlbumUserV1](doc//SyncAlbumUserV1.md)
|
||||
- [SyncAlbumV1](doc//SyncAlbumV1.md)
|
||||
- [SyncAssetDeleteV1](doc//SyncAssetDeleteV1.md)
|
||||
- [SyncAssetEditDeleteV1](doc//SyncAssetEditDeleteV1.md)
|
||||
- [SyncAssetEditV1](doc//SyncAssetEditV1.md)
|
||||
- [SyncAssetExifV1](doc//SyncAssetExifV1.md)
|
||||
- [SyncAssetFaceDeleteV1](doc//SyncAssetFaceDeleteV1.md)
|
||||
- [SyncAssetFaceV1](doc//SyncAssetFaceV1.md)
|
||||
|
||||
Generated
+2
@@ -306,6 +306,8 @@ part 'model/sync_album_user_delete_v1.dart';
|
||||
part 'model/sync_album_user_v1.dart';
|
||||
part 'model/sync_album_v1.dart';
|
||||
part 'model/sync_asset_delete_v1.dart';
|
||||
part 'model/sync_asset_edit_delete_v1.dart';
|
||||
part 'model/sync_asset_edit_v1.dart';
|
||||
part 'model/sync_asset_exif_v1.dart';
|
||||
part 'model/sync_asset_face_delete_v1.dart';
|
||||
part 'model/sync_asset_face_v1.dart';
|
||||
|
||||
Generated
+4
@@ -660,6 +660,10 @@ class ApiClient {
|
||||
return SyncAlbumV1.fromJson(value);
|
||||
case 'SyncAssetDeleteV1':
|
||||
return SyncAssetDeleteV1.fromJson(value);
|
||||
case 'SyncAssetEditDeleteV1':
|
||||
return SyncAssetEditDeleteV1.fromJson(value);
|
||||
case 'SyncAssetEditV1':
|
||||
return SyncAssetEditV1.fromJson(value);
|
||||
case 'SyncAssetExifV1':
|
||||
return SyncAssetExifV1.fromJson(value);
|
||||
case 'SyncAssetFaceDeleteV1':
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.18
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class SyncAssetEditDeleteV1 {
|
||||
/// Returns a new [SyncAssetEditDeleteV1] instance.
|
||||
SyncAssetEditDeleteV1({
|
||||
required this.assetId,
|
||||
});
|
||||
|
||||
String assetId;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is SyncAssetEditDeleteV1 &&
|
||||
other.assetId == assetId;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(assetId.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SyncAssetEditDeleteV1[assetId=$assetId]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'assetId'] = this.assetId;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [SyncAssetEditDeleteV1] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static SyncAssetEditDeleteV1? fromJson(dynamic value) {
|
||||
upgradeDto(value, "SyncAssetEditDeleteV1");
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return SyncAssetEditDeleteV1(
|
||||
assetId: mapValueOfType<String>(json, r'assetId')!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<SyncAssetEditDeleteV1> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <SyncAssetEditDeleteV1>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = SyncAssetEditDeleteV1.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, SyncAssetEditDeleteV1> mapFromJson(dynamic json) {
|
||||
final map = <String, SyncAssetEditDeleteV1>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = SyncAssetEditDeleteV1.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of SyncAssetEditDeleteV1-objects as value to a dart map
|
||||
static Map<String, List<SyncAssetEditDeleteV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<SyncAssetEditDeleteV1>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = SyncAssetEditDeleteV1.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'assetId',
|
||||
};
|
||||
}
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.18
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
class SyncAssetEditV1 {
|
||||
/// Returns a new [SyncAssetEditV1] instance.
|
||||
SyncAssetEditV1({
|
||||
required this.action,
|
||||
required this.assetId,
|
||||
required this.id,
|
||||
required this.parameters,
|
||||
});
|
||||
|
||||
AssetEditAction action;
|
||||
|
||||
String assetId;
|
||||
|
||||
String id;
|
||||
|
||||
Object parameters;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is SyncAssetEditV1 &&
|
||||
other.action == action &&
|
||||
other.assetId == assetId &&
|
||||
other.id == id &&
|
||||
other.parameters == parameters;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(action.hashCode) +
|
||||
(assetId.hashCode) +
|
||||
(id.hashCode) +
|
||||
(parameters.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SyncAssetEditV1[action=$action, assetId=$assetId, id=$id, parameters=$parameters]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'action'] = this.action;
|
||||
json[r'assetId'] = this.assetId;
|
||||
json[r'id'] = this.id;
|
||||
json[r'parameters'] = this.parameters;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [SyncAssetEditV1] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static SyncAssetEditV1? fromJson(dynamic value) {
|
||||
upgradeDto(value, "SyncAssetEditV1");
|
||||
if (value is Map) {
|
||||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return SyncAssetEditV1(
|
||||
action: AssetEditAction.fromJson(json[r'action'])!,
|
||||
assetId: mapValueOfType<String>(json, r'assetId')!,
|
||||
id: mapValueOfType<String>(json, r'id')!,
|
||||
parameters: mapValueOfType<Object>(json, r'parameters')!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<SyncAssetEditV1> listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <SyncAssetEditV1>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = SyncAssetEditV1.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, SyncAssetEditV1> mapFromJson(dynamic json) {
|
||||
final map = <String, SyncAssetEditV1>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = SyncAssetEditV1.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of SyncAssetEditV1-objects as value to a dart map
|
||||
static Map<String, List<SyncAssetEditV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<SyncAssetEditV1>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
// ignore: parameter_assignments
|
||||
json = json.cast<String, dynamic>();
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = SyncAssetEditV1.listFromJson(entry.value, growable: growable,);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'action',
|
||||
'assetId',
|
||||
'id',
|
||||
'parameters',
|
||||
};
|
||||
}
|
||||
|
||||
+6
@@ -28,6 +28,8 @@ class SyncEntityType {
|
||||
static const userDeleteV1 = SyncEntityType._(r'UserDeleteV1');
|
||||
static const assetV1 = SyncEntityType._(r'AssetV1');
|
||||
static const assetDeleteV1 = SyncEntityType._(r'AssetDeleteV1');
|
||||
static const assetEditV1 = SyncEntityType._(r'AssetEditV1');
|
||||
static const assetEditDeleteV1 = SyncEntityType._(r'AssetEditDeleteV1');
|
||||
static const assetExifV1 = SyncEntityType._(r'AssetExifV1');
|
||||
static const assetMetadataV1 = SyncEntityType._(r'AssetMetadataV1');
|
||||
static const assetMetadataDeleteV1 = SyncEntityType._(r'AssetMetadataDeleteV1');
|
||||
@@ -78,6 +80,8 @@ class SyncEntityType {
|
||||
userDeleteV1,
|
||||
assetV1,
|
||||
assetDeleteV1,
|
||||
assetEditV1,
|
||||
assetEditDeleteV1,
|
||||
assetExifV1,
|
||||
assetMetadataV1,
|
||||
assetMetadataDeleteV1,
|
||||
@@ -163,6 +167,8 @@ class SyncEntityTypeTypeTransformer {
|
||||
case r'UserDeleteV1': return SyncEntityType.userDeleteV1;
|
||||
case r'AssetV1': return SyncEntityType.assetV1;
|
||||
case r'AssetDeleteV1': return SyncEntityType.assetDeleteV1;
|
||||
case r'AssetEditV1': return SyncEntityType.assetEditV1;
|
||||
case r'AssetEditDeleteV1': return SyncEntityType.assetEditDeleteV1;
|
||||
case r'AssetExifV1': return SyncEntityType.assetExifV1;
|
||||
case r'AssetMetadataV1': return SyncEntityType.assetMetadataV1;
|
||||
case r'AssetMetadataDeleteV1': return SyncEntityType.assetMetadataDeleteV1;
|
||||
|
||||
+3
@@ -29,6 +29,7 @@ class SyncRequestType {
|
||||
static const albumAssetsV1 = SyncRequestType._(r'AlbumAssetsV1');
|
||||
static const albumAssetExifsV1 = SyncRequestType._(r'AlbumAssetExifsV1');
|
||||
static const assetsV1 = SyncRequestType._(r'AssetsV1');
|
||||
static const assetEditsV1 = SyncRequestType._(r'AssetEditsV1');
|
||||
static const assetExifsV1 = SyncRequestType._(r'AssetExifsV1');
|
||||
static const assetMetadataV1 = SyncRequestType._(r'AssetMetadataV1');
|
||||
static const authUsersV1 = SyncRequestType._(r'AuthUsersV1');
|
||||
@@ -52,6 +53,7 @@ class SyncRequestType {
|
||||
albumAssetsV1,
|
||||
albumAssetExifsV1,
|
||||
assetsV1,
|
||||
assetEditsV1,
|
||||
assetExifsV1,
|
||||
assetMetadataV1,
|
||||
authUsersV1,
|
||||
@@ -110,6 +112,7 @@ class SyncRequestTypeTypeTransformer {
|
||||
case r'AlbumAssetsV1': return SyncRequestType.albumAssetsV1;
|
||||
case r'AlbumAssetExifsV1': return SyncRequestType.albumAssetExifsV1;
|
||||
case r'AssetsV1': return SyncRequestType.assetsV1;
|
||||
case r'AssetEditsV1': return SyncRequestType.assetEditsV1;
|
||||
case r'AssetExifsV1': return SyncRequestType.assetExifsV1;
|
||||
case r'AssetMetadataV1': return SyncRequestType.assetMetadataV1;
|
||||
case r'AuthUsersV1': return SyncRequestType.authUsersV1;
|
||||
|
||||
Vendored
+2
@@ -64,6 +64,7 @@ abstract final class LocalAssetStub {
|
||||
type: AssetType.image,
|
||||
createdAt: DateTime(2025),
|
||||
updatedAt: DateTime(2025, 2),
|
||||
isEdited: false,
|
||||
);
|
||||
|
||||
static final image2 = LocalAsset(
|
||||
@@ -72,5 +73,6 @@ abstract final class LocalAssetStub {
|
||||
type: AssetType.image,
|
||||
createdAt: DateTime(2000),
|
||||
updatedAt: DateTime(20021),
|
||||
isEdited: false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ abstract final class TestUtils {
|
||||
isFavorite: false,
|
||||
width: width,
|
||||
height: height,
|
||||
isEdited: false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -154,6 +155,7 @@ abstract final class TestUtils {
|
||||
width: width,
|
||||
height: height,
|
||||
orientation: orientation,
|
||||
isEdited: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ class MediumFactory {
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
String? checksum,
|
||||
bool? isEdited,
|
||||
}) {
|
||||
final random = Random();
|
||||
|
||||
@@ -27,6 +28,7 @@ class MediumFactory {
|
||||
type: type ?? AssetType.image,
|
||||
createdAt: createdAt ?? DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)),
|
||||
updatedAt: updatedAt ?? DateTime.fromMillisecondsSinceEpoch(random.nextInt(1000000000)),
|
||||
isEdited: isEdited ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ LocalAsset createLocalAsset({
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
bool isFavorite = false,
|
||||
bool isEdited = false,
|
||||
}) {
|
||||
return LocalAsset(
|
||||
id: 'local-id',
|
||||
@@ -23,6 +24,7 @@ LocalAsset createLocalAsset({
|
||||
createdAt: createdAt ?? DateTime.now(),
|
||||
updatedAt: updatedAt ?? DateTime.now(),
|
||||
isFavorite: isFavorite,
|
||||
isEdited: isEdited,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ RemoteAsset createRemoteAsset({
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
bool isFavorite = false,
|
||||
bool isEdited = false,
|
||||
}) {
|
||||
return RemoteAsset(
|
||||
id: 'remote-id',
|
||||
@@ -45,6 +48,7 @@ RemoteAsset createRemoteAsset({
|
||||
createdAt: createdAt ?? DateTime.now(),
|
||||
updatedAt: updatedAt ?? DateTime.now(),
|
||||
isFavorite: isFavorite,
|
||||
isEdited: isEdited,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user