feat: remove asset from memory

This commit is contained in:
martabal 2023-10-17 00:23:24 +02:00
parent 1890c0ab6b
commit b9c0a3c641
No known key found for this signature in database
GPG key ID: C00196E3148A52BD
19 changed files with 222 additions and 5 deletions

View file

@ -399,6 +399,12 @@ export interface AssetBulkUpdateDto {
* @memberof AssetBulkUpdateDto * @memberof AssetBulkUpdateDto
*/ */
'isFavorite'?: boolean; 'isFavorite'?: boolean;
/**
*
* @type {boolean}
* @memberof AssetBulkUpdateDto
*/
'isShownInMemory'?: boolean;
} }
/** /**
* *
@ -682,6 +688,12 @@ export interface AssetResponseDto {
* @memberof AssetResponseDto * @memberof AssetResponseDto
*/ */
'isReadOnly': boolean; 'isReadOnly': boolean;
/**
*
* @type {boolean}
* @memberof AssetResponseDto
*/
'isShownInMemory': boolean;
/** /**
* *
* @type {boolean} * @type {boolean}

View file

@ -11,6 +11,7 @@ Name | Type | Description | Notes
**ids** | **List<String>** | | [default to const []] **ids** | **List<String>** | | [default to const []]
**isArchived** | **bool** | | [optional] **isArchived** | **bool** | | [optional]
**isFavorite** | **bool** | | [optional] **isFavorite** | **bool** | | [optional]
**isShownInMemory** | **bool** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View file

@ -22,6 +22,7 @@ Name | Type | Description | Notes
**isFavorite** | **bool** | | **isFavorite** | **bool** | |
**isOffline** | **bool** | | **isOffline** | **bool** | |
**isReadOnly** | **bool** | | **isReadOnly** | **bool** | |
**isShownInMemory** | **bool** | |
**isTrashed** | **bool** | | **isTrashed** | **bool** | |
**libraryId** | **String** | | **libraryId** | **String** | |
**livePhotoVideoId** | **String** | | [optional] **livePhotoVideoId** | **String** | | [optional]

View file

@ -16,6 +16,7 @@ class AssetBulkUpdateDto {
this.ids = const [], this.ids = const [],
this.isArchived, this.isArchived,
this.isFavorite, this.isFavorite,
this.isShownInMemory,
}); });
List<String> ids; List<String> ids;
@ -36,21 +37,31 @@ class AssetBulkUpdateDto {
/// ///
bool? isFavorite; bool? isFavorite;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? isShownInMemory;
@override @override
bool operator ==(Object other) => identical(this, other) || other is AssetBulkUpdateDto && bool operator ==(Object other) => identical(this, other) || other is AssetBulkUpdateDto &&
other.ids == ids && other.ids == ids &&
other.isArchived == isArchived && other.isArchived == isArchived &&
other.isFavorite == isFavorite; other.isFavorite == isFavorite &&
other.isShownInMemory == isShownInMemory;
@override @override
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(ids.hashCode) + (ids.hashCode) +
(isArchived == null ? 0 : isArchived!.hashCode) + (isArchived == null ? 0 : isArchived!.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode); (isFavorite == null ? 0 : isFavorite!.hashCode) +
(isShownInMemory == null ? 0 : isShownInMemory!.hashCode);
@override @override
String toString() => 'AssetBulkUpdateDto[ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite]'; String toString() => 'AssetBulkUpdateDto[ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite, isShownInMemory=$isShownInMemory]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@ -65,6 +76,11 @@ class AssetBulkUpdateDto {
} else { } else {
// json[r'isFavorite'] = null; // json[r'isFavorite'] = null;
} }
if (this.isShownInMemory != null) {
json[r'isShownInMemory'] = this.isShownInMemory;
} else {
// json[r'isShownInMemory'] = null;
}
return json; return json;
} }
@ -81,6 +97,7 @@ class AssetBulkUpdateDto {
: const [], : const [],
isArchived: mapValueOfType<bool>(json, r'isArchived'), isArchived: mapValueOfType<bool>(json, r'isArchived'),
isFavorite: mapValueOfType<bool>(json, r'isFavorite'), isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
isShownInMemory: mapValueOfType<bool>(json, r'isShownInMemory'),
); );
} }
return null; return null;

View file

@ -27,6 +27,7 @@ class AssetResponseDto {
required this.isFavorite, required this.isFavorite,
required this.isOffline, required this.isOffline,
required this.isReadOnly, required this.isReadOnly,
required this.isShownInMemory,
required this.isTrashed, required this.isTrashed,
required this.libraryId, required this.libraryId,
this.livePhotoVideoId, this.livePhotoVideoId,
@ -79,6 +80,8 @@ class AssetResponseDto {
bool isReadOnly; bool isReadOnly;
bool isShownInMemory;
bool isTrashed; bool isTrashed;
String libraryId; String libraryId;
@ -137,6 +140,7 @@ class AssetResponseDto {
other.isFavorite == isFavorite && other.isFavorite == isFavorite &&
other.isOffline == isOffline && other.isOffline == isOffline &&
other.isReadOnly == isReadOnly && other.isReadOnly == isReadOnly &&
other.isShownInMemory == isShownInMemory &&
other.isTrashed == isTrashed && other.isTrashed == isTrashed &&
other.libraryId == libraryId && other.libraryId == libraryId &&
other.livePhotoVideoId == livePhotoVideoId && other.livePhotoVideoId == livePhotoVideoId &&
@ -170,6 +174,7 @@ class AssetResponseDto {
(isFavorite.hashCode) + (isFavorite.hashCode) +
(isOffline.hashCode) + (isOffline.hashCode) +
(isReadOnly.hashCode) + (isReadOnly.hashCode) +
(isShownInMemory.hashCode) +
(isTrashed.hashCode) + (isTrashed.hashCode) +
(libraryId.hashCode) + (libraryId.hashCode) +
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) + (livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
@ -187,7 +192,7 @@ class AssetResponseDto {
(updatedAt.hashCode); (updatedAt.hashCode);
@override @override
String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, isReadOnly=$isReadOnly, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, tags=$tags, thumbhash=$thumbhash, type=$type, updatedAt=$updatedAt]'; String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, isReadOnly=$isReadOnly, isShownInMemory=$isShownInMemory, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, tags=$tags, thumbhash=$thumbhash, type=$type, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@ -209,6 +214,7 @@ class AssetResponseDto {
json[r'isFavorite'] = this.isFavorite; json[r'isFavorite'] = this.isFavorite;
json[r'isOffline'] = this.isOffline; json[r'isOffline'] = this.isOffline;
json[r'isReadOnly'] = this.isReadOnly; json[r'isReadOnly'] = this.isReadOnly;
json[r'isShownInMemory'] = this.isShownInMemory;
json[r'isTrashed'] = this.isTrashed; json[r'isTrashed'] = this.isTrashed;
json[r'libraryId'] = this.libraryId; json[r'libraryId'] = this.libraryId;
if (this.livePhotoVideoId != null) { if (this.livePhotoVideoId != null) {
@ -265,6 +271,7 @@ class AssetResponseDto {
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!, isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
isOffline: mapValueOfType<bool>(json, r'isOffline')!, isOffline: mapValueOfType<bool>(json, r'isOffline')!,
isReadOnly: mapValueOfType<bool>(json, r'isReadOnly')!, isReadOnly: mapValueOfType<bool>(json, r'isReadOnly')!,
isShownInMemory: mapValueOfType<bool>(json, r'isShownInMemory')!,
isTrashed: mapValueOfType<bool>(json, r'isTrashed')!, isTrashed: mapValueOfType<bool>(json, r'isTrashed')!,
libraryId: mapValueOfType<String>(json, r'libraryId')!, libraryId: mapValueOfType<String>(json, r'libraryId')!,
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'), livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
@ -340,6 +347,7 @@ class AssetResponseDto {
'isFavorite', 'isFavorite',
'isOffline', 'isOffline',
'isReadOnly', 'isReadOnly',
'isShownInMemory',
'isTrashed', 'isTrashed',
'libraryId', 'libraryId',
'localDateTime', 'localDateTime',

View file

@ -31,6 +31,11 @@ void main() {
// TODO // TODO
}); });
// bool isShownInMemory
test('to test the property `isShownInMemory`', () async {
// TODO
});
}); });

View file

@ -87,6 +87,11 @@ void main() {
// TODO // TODO
}); });
// bool isShownInMemory
test('to test the property `isShownInMemory`', () async {
// TODO
});
// bool isTrashed // bool isTrashed
test('to test the property `isTrashed`', () async { test('to test the property `isTrashed`', () async {
// TODO // TODO

View file

@ -5696,6 +5696,9 @@
}, },
"isFavorite": { "isFavorite": {
"type": "boolean" "type": "boolean"
},
"isShownInMemory": {
"type": "boolean"
} }
}, },
"required": [ "required": [
@ -5903,6 +5906,9 @@
"isReadOnly": { "isReadOnly": {
"type": "boolean" "type": "boolean"
}, },
"isShownInMemory": {
"type": "boolean"
},
"isTrashed": { "isTrashed": {
"type": "boolean" "type": "boolean"
}, },
@ -5971,6 +5977,7 @@
"fileCreatedAt", "fileCreatedAt",
"fileModifiedAt", "fileModifiedAt",
"updatedAt", "updatedAt",
"isShownInMemory",
"isFavorite", "isFavorite",
"isArchived", "isArchived",
"isTrashed", "isTrashed",

View file

@ -165,7 +165,7 @@ export class AssetService {
const assets = await this.assetRepository.getByDayOfYear(authUser.id, dto); const assets = await this.assetRepository.getByDayOfYear(authUser.id, dto);
return _.chain(assets) return _.chain(assets)
.filter((asset) => asset.localDateTime.getFullYear() < currentYear) .filter((asset) => asset.localDateTime.getFullYear() < currentYear && asset.isShownInMemory)
.map((asset) => { .map((asset) => {
const years = currentYear - asset.localDateTime.getFullYear(); const years = currentYear - asset.localDateTime.getFullYear();

View file

@ -11,6 +11,10 @@ export class AssetBulkUpdateDto extends BulkIdsDto {
@Optional() @Optional()
@IsBoolean() @IsBoolean()
isArchived?: boolean; isArchived?: boolean;
@Optional()
@IsBoolean()
isShownInMemory?: boolean;
} }
export class UpdateAssetDto { export class UpdateAssetDto {

View file

@ -30,6 +30,7 @@ export class AssetResponseDto extends SanitizedAssetResponseDto {
fileCreatedAt!: Date; fileCreatedAt!: Date;
fileModifiedAt!: Date; fileModifiedAt!: Date;
updatedAt!: Date; updatedAt!: Date;
isShownInMemory!: boolean;
isFavorite!: boolean; isFavorite!: boolean;
isArchived!: boolean; isArchived!: boolean;
isTrashed!: boolean; isTrashed!: boolean;
@ -77,6 +78,7 @@ export function mapAsset(entity: AssetEntity, stripMetadata = false): AssetRespo
fileModifiedAt: entity.fileModifiedAt, fileModifiedAt: entity.fileModifiedAt,
localDateTime: entity.localDateTime, localDateTime: entity.localDateTime,
updatedAt: entity.updatedAt, updatedAt: entity.updatedAt,
isShownInMemory: entity.isShownInMemory,
isFavorite: entity.isFavorite, isFavorite: entity.isFavorite,
isArchived: entity.isArchived, isArchived: entity.isArchived,
isTrashed: !!entity.deletedAt, isTrashed: !!entity.deletedAt,

View file

@ -106,6 +106,9 @@ export class AssetEntity {
@Column({ type: 'boolean', default: false }) @Column({ type: 'boolean', default: false })
isOffline!: boolean; isOffline!: boolean;
@Column({ type: 'boolean', default: true })
isShownInMemory!: boolean;
@Column({ type: 'bytea' }) @Column({ type: 'bytea' })
@Index() @Index()
checksum!: Buffer; // sha1 checksum checksum!: Buffer; // sha1 checksum

View file

@ -0,0 +1,28 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class RemoveFromMemory1697484859613 implements MigrationInterface {
name = 'RemoveFromMemory1697484859613'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "isSkipMotion" TO "isShownInMemory"`);
await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "PK_6df76ab2eb6f5b57b7c2f1fc684"`);
await queryRunner.query(`ALTER TABLE "asset_faces" DROP COLUMN "id"`);
await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "PK_bf339a24070dac7e71304ec530a" PRIMARY KEY ("assetId", "personId")`);
await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "FK_95ad7106dd7b484275443f580f9"`);
await queryRunner.query(`ALTER TABLE "asset_faces" ALTER COLUMN "personId" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "isShownInMemory" SET DEFAULT true`);
await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "FK_95ad7106dd7b484275443f580f9" FOREIGN KEY ("personId") REFERENCES "person"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "FK_95ad7106dd7b484275443f580f9"`);
await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "isShownInMemory" SET DEFAULT false`);
await queryRunner.query(`ALTER TABLE "asset_faces" ALTER COLUMN "personId" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "FK_95ad7106dd7b484275443f580f9" FOREIGN KEY ("personId") REFERENCES "person"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "asset_faces" DROP CONSTRAINT "PK_bf339a24070dac7e71304ec530a"`);
await queryRunner.query(`ALTER TABLE "asset_faces" ADD "id" uuid NOT NULL DEFAULT uuid_generate_v4()`);
await queryRunner.query(`ALTER TABLE "asset_faces" ADD CONSTRAINT "PK_6df76ab2eb6f5b57b7c2f1fc684" PRIMARY KEY ("id")`);
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "isShownInMemory" TO "isSkipMotion"`);
}
}

View file

@ -24,6 +24,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
duration: null, duration: null,
@ -59,6 +60,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
duration: null, duration: null,
@ -98,6 +100,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -134,6 +137,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -173,6 +177,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -212,6 +217,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -251,6 +257,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -291,6 +298,7 @@ export const assetStub = {
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
deletedAt: null, deletedAt: null,
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -329,6 +337,7 @@ export const assetStub = {
createdAt: new Date('2015-02-23T05:06:29.716Z'), createdAt: new Date('2015-02-23T05:06:29.716Z'),
updatedAt: new Date('2015-02-23T05:06:29.716Z'), updatedAt: new Date('2015-02-23T05:06:29.716Z'),
localDateTime: new Date('2015-02-23T05:06:29.716Z'), localDateTime: new Date('2015-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isExternal: false, isExternal: false,
@ -369,6 +378,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -439,6 +449,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: false, isFavorite: false,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,
@ -479,6 +490,7 @@ export const assetStub = {
createdAt: new Date('2023-02-23T05:06:29.716Z'), createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'), updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'), localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isShownInMemory: true,
isFavorite: true, isFavorite: true,
isArchived: false, isArchived: false,
isReadOnly: false, isReadOnly: false,

View file

@ -51,6 +51,7 @@ const assetResponse: AssetResponseDto = {
resized: false, resized: false,
thumbhash: null, thumbhash: null,
fileModifiedAt: today, fileModifiedAt: today,
isShownInMemory: true,
isExternal: false, isExternal: false,
isReadOnly: false, isReadOnly: false,
isOffline: false, isOffline: false,
@ -191,6 +192,7 @@ export const sharedLinkStub = {
localDateTime: today, localDateTime: today,
createdAt: today, createdAt: today,
updatedAt: today, updatedAt: today,
isShownInMemory: true,
isFavorite: false, isFavorite: false,
isArchived: false, isArchived: false,
isExternal: false, isExternal: false,

View file

@ -399,6 +399,12 @@ export interface AssetBulkUpdateDto {
* @memberof AssetBulkUpdateDto * @memberof AssetBulkUpdateDto
*/ */
'isFavorite'?: boolean; 'isFavorite'?: boolean;
/**
*
* @type {boolean}
* @memberof AssetBulkUpdateDto
*/
'isShownInMemory'?: boolean;
} }
/** /**
* *
@ -682,6 +688,12 @@ export interface AssetResponseDto {
* @memberof AssetResponseDto * @memberof AssetResponseDto
*/ */
'isReadOnly': boolean; 'isReadOnly': boolean;
/**
*
* @type {boolean}
* @memberof AssetResponseDto
*/
'isShownInMemory': boolean;
/** /**
* *
* @type {boolean} * @type {boolean}

View file

@ -49,6 +49,7 @@
asProfileImage: void; asProfileImage: void;
runJob: AssetJobName; runJob: AssetJobName;
playSlideShow: void; playSlideShow: void;
enableMemories: void;
}>(); }>();
let contextMenuPosition = { x: 0, y: 0 }; let contextMenuPosition = { x: 0, y: 0 };
@ -185,6 +186,9 @@
text={api.getAssetJobName(AssetJobName.TranscodeVideo)} text={api.getAssetJobName(AssetJobName.TranscodeVideo)}
/> />
{/if} {/if}
{#if !asset.isShownInMemory}
<MenuOption on:click={() => dispatch('enableMemories')} text="Show in memories" />
{/if}
{/if} {/if}
</ContextMenu> </ContextMenu>
{/if} {/if}

View file

@ -346,6 +346,20 @@
} }
}; };
const handleEnableMemories = async () => {
try {
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids: [asset.id], isShownInMemory: true } });
notificationController.show({
message: `Asset can be shown in memories`,
type: NotificationType.Info,
});
asset.isShownInMemory = true;
} catch (error) {
handleError(error, "Can't remove asset from memory");
}
};
const handleStopSlideshow = async () => { const handleStopSlideshow = async () => {
try { try {
await document.exitFullscreen(); await document.exitFullscreen();
@ -408,6 +422,7 @@
on:asProfileImage={() => (isShowProfileImageCrop = true)} on:asProfileImage={() => (isShowProfileImageCrop = true)}
on:runJob={({ detail: job }) => handleRunJob(job)} on:runJob={({ detail: job }) => handleRunJob(job)}
on:playSlideShow={handlePlaySlideshow} on:playSlideShow={handlePlaySlideshow}
on:enableMemories={handleEnableMemories}
/> />
{/if} {/if}
</div> </div>

View file

@ -20,6 +20,12 @@
import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte'; import IntersectionObserver from '$lib/components/asset-viewer/intersection-observer.svelte';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import { tweened } from 'svelte/motion'; import { tweened } from 'svelte/motion';
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import { clickOutside } from '$lib/utils/click-outside';
import { handleError } from '$lib/utils/handle-error';
import { NotificationType, notificationController } from '../shared-components/notification/notification';
const parseIndex = (s: string | null, max: number | null) => Math.max(Math.min(parseInt(s ?? '') || 0, max ?? 0), 0); const parseIndex = (s: string | null, max: number | null) => Math.max(Math.min(parseInt(s ?? '') || 0, max ?? 0), 0);
@ -58,6 +64,69 @@
let paused = false; let paused = false;
let isShowAssetOptions = false;
let contextMenuPosition = { x: 0, y: 0 };
const updateMemoryStoreAsset = () => {
if ($memoryStore && $memoryStore[memoryIndex].assets[assetIndex]) {
memoryStore.update((memoryStore) => {
const updatedMemoryStore = [...memoryStore];
if (memoryIndex >= 0 && memoryIndex < updatedMemoryStore.length) {
const memoryItem = updatedMemoryStore[memoryIndex];
if (assetIndex >= 0 && memoryItem.assets.length > 1) {
memoryItem.assets.splice(assetIndex, 1);
}
}
return updatedMemoryStore; // Return the updated memoryStore
});
}
};
const updateMemoryStoreMemory = () => {
if ($memoryStore && $memoryStore[memoryIndex].assets[assetIndex]) {
memoryStore.update((memoryStore) => {
const updatedMemoryStore = [...memoryStore];
updatedMemoryStore.splice(memoryIndex, 1);
return updatedMemoryStore; // Return the updated memoryStore
});
}
};
const removeFromMemory = async () => {
try {
await api.assetApi.updateAssets({ assetBulkUpdateDto: { ids: [currentAsset.id], isShownInMemory: false } });
notificationController.show({
message: `Removed asset from memory`,
type: NotificationType.Info,
});
if (currentMemory?.assets.length === 1) {
if ($memoryStore?.length === 1) {
goto(AppRoute.PHOTOS);
} else {
if ($memoryStore?.length === memoryIndex + 1) {
toPreviousMemory();
} else {
toNextMemory();
}
updateMemoryStoreAsset();
updateMemoryStoreMemory();
}
} else {
updateMemoryStoreAsset();
}
isShowAssetOptions = false;
} catch (error) {
handleError(error, "Can't remove asset from memory");
}
};
const handleRemoveFromMemory = () => {
isShowAssetOptions = !isShowAssetOptions;
};
// Play or pause progress when the paused state changes. // Play or pause progress when the paused state changes.
$: paused ? pause() : play(); $: paused ? pause() : play();
@ -222,6 +291,16 @@
{currentAsset.exifInfo?.country || ''} {currentAsset.exifInfo?.country || ''}
</p> </p>
</div> </div>
<div class="absolute right-8 top-4 text-sm font-medium text-white">
<div use:clickOutside on:outclick={() => (isShowAssetOptions = false)}>
<CircleIconButton isOpacity={true} logo={DotsVertical} on:click={handleRemoveFromMemory} title="More" />
{#if isShowAssetOptions}
<ContextMenu {...contextMenuPosition} direction="left">
<MenuOption on:click={removeFromMemory} text="Remove from memories" />
</ContextMenu>
{/if}
</div>
</div>
</div> </div>
</div> </div>