mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat(server): trash asset (#4015)
* refactor(server): delete assets endpoint * fix: formatting * chore: cleanup * chore: open api * chore(mobile): replace DeleteAssetDTO with BulkIdsDTOs * feat: trash an asset * chore(server): formatting * chore: open api * chore: wording * chore: open-api * feat(server): add withDeleted to getAssets queries * WIP: mobile-recycle-bin * feat(server): recycle-bin to system config * feat(web): use recycle-bin system config * chore(server): domain assetcore removed * chore(server): rename recycle-bin to trash * chore(web): rename recycle-bin to trash * chore(server): always send soft deleted assets for getAllByUserId * chore(web): formatting * feat(server): permanent delete assets older than trashed period * feat(web): trash empty placeholder image * feat(server): empty trash * feat(web): empty trash * WIP: mobile-recycle-bin * refactor(server): empty / restore trash to separate endpoint * test(server): handle failures * test(server): fix e2e server-info test * test(server): deletion test refactor * feat(mobile): use map settings from server-config to enable / disable map * feat(mobile): trash asset * fix(server): operations on assets in trash * feat(web): show trash statistics * fix(web): handle trash enabled * fix(mobile): restore updates from trash * fix(server): ignore trashed assets for person * fix(server): add / remove search index when trashed / restored * chore(web): format * fix(server): asset service test * fix(server): include trashed assts for duplicates from uploads * feat(mobile): no dialog for trash, always dialog for permanent delete * refactor(mobile): use isar where instead of dart filter * refactor(mobile): asset provide - handle deletes in single db txn * chore(mobile): review changes * feat(web): confirmation before empty trash * server: review changes * fix(server): handle library changes * fix: filter external assets from getting trashed / deleted * fix(server): empty-bin * feat: broadcast config update events through ws * change order of trash button on mobile * styling * fix(mobile): do not show trashed toast for local only assets --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
		| @@ -57,39 +57,44 @@ const AssetSchema = CollectionSchema( | ||||
|       name: r'isFavorite', | ||||
|       type: IsarType.bool, | ||||
|     ), | ||||
|     r'livePhotoVideoId': PropertySchema( | ||||
|     r'isTrashed': PropertySchema( | ||||
|       id: 8, | ||||
|       name: r'isTrashed', | ||||
|       type: IsarType.bool, | ||||
|     ), | ||||
|     r'livePhotoVideoId': PropertySchema( | ||||
|       id: 9, | ||||
|       name: r'livePhotoVideoId', | ||||
|       type: IsarType.string, | ||||
|     ), | ||||
|     r'localId': PropertySchema( | ||||
|       id: 9, | ||||
|       id: 10, | ||||
|       name: r'localId', | ||||
|       type: IsarType.string, | ||||
|     ), | ||||
|     r'ownerId': PropertySchema( | ||||
|       id: 10, | ||||
|       id: 11, | ||||
|       name: r'ownerId', | ||||
|       type: IsarType.long, | ||||
|     ), | ||||
|     r'remoteId': PropertySchema( | ||||
|       id: 11, | ||||
|       id: 12, | ||||
|       name: r'remoteId', | ||||
|       type: IsarType.string, | ||||
|     ), | ||||
|     r'type': PropertySchema( | ||||
|       id: 12, | ||||
|       id: 13, | ||||
|       name: r'type', | ||||
|       type: IsarType.byte, | ||||
|       enumMap: _AssettypeEnumValueMap, | ||||
|     ), | ||||
|     r'updatedAt': PropertySchema( | ||||
|       id: 13, | ||||
|       id: 14, | ||||
|       name: r'updatedAt', | ||||
|       type: IsarType.dateTime, | ||||
|     ), | ||||
|     r'width': PropertySchema( | ||||
|       id: 14, | ||||
|       id: 15, | ||||
|       name: r'width', | ||||
|       type: IsarType.int, | ||||
|     ) | ||||
| @@ -196,13 +201,14 @@ void _assetSerialize( | ||||
|   writer.writeInt(offsets[5], object.height); | ||||
|   writer.writeBool(offsets[6], object.isArchived); | ||||
|   writer.writeBool(offsets[7], object.isFavorite); | ||||
|   writer.writeString(offsets[8], object.livePhotoVideoId); | ||||
|   writer.writeString(offsets[9], object.localId); | ||||
|   writer.writeLong(offsets[10], object.ownerId); | ||||
|   writer.writeString(offsets[11], object.remoteId); | ||||
|   writer.writeByte(offsets[12], object.type.index); | ||||
|   writer.writeDateTime(offsets[13], object.updatedAt); | ||||
|   writer.writeInt(offsets[14], object.width); | ||||
|   writer.writeBool(offsets[8], object.isTrashed); | ||||
|   writer.writeString(offsets[9], object.livePhotoVideoId); | ||||
|   writer.writeString(offsets[10], object.localId); | ||||
|   writer.writeLong(offsets[11], object.ownerId); | ||||
|   writer.writeString(offsets[12], object.remoteId); | ||||
|   writer.writeByte(offsets[13], object.type.index); | ||||
|   writer.writeDateTime(offsets[14], object.updatedAt); | ||||
|   writer.writeInt(offsets[15], object.width); | ||||
| } | ||||
|  | ||||
| Asset _assetDeserialize( | ||||
| @@ -221,14 +227,15 @@ Asset _assetDeserialize( | ||||
|     id: id, | ||||
|     isArchived: reader.readBool(offsets[6]), | ||||
|     isFavorite: reader.readBool(offsets[7]), | ||||
|     livePhotoVideoId: reader.readStringOrNull(offsets[8]), | ||||
|     localId: reader.readStringOrNull(offsets[9]), | ||||
|     ownerId: reader.readLong(offsets[10]), | ||||
|     remoteId: reader.readStringOrNull(offsets[11]), | ||||
|     type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[12])] ?? | ||||
|     isTrashed: reader.readBool(offsets[8]), | ||||
|     livePhotoVideoId: reader.readStringOrNull(offsets[9]), | ||||
|     localId: reader.readStringOrNull(offsets[10]), | ||||
|     ownerId: reader.readLong(offsets[11]), | ||||
|     remoteId: reader.readStringOrNull(offsets[12]), | ||||
|     type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[13])] ?? | ||||
|         AssetType.other, | ||||
|     updatedAt: reader.readDateTime(offsets[13]), | ||||
|     width: reader.readIntOrNull(offsets[14]), | ||||
|     updatedAt: reader.readDateTime(offsets[14]), | ||||
|     width: reader.readIntOrNull(offsets[15]), | ||||
|   ); | ||||
|   return object; | ||||
| } | ||||
| @@ -257,19 +264,21 @@ P _assetDeserializeProp<P>( | ||||
|     case 7: | ||||
|       return (reader.readBool(offset)) as P; | ||||
|     case 8: | ||||
|       return (reader.readStringOrNull(offset)) as P; | ||||
|       return (reader.readBool(offset)) as P; | ||||
|     case 9: | ||||
|       return (reader.readStringOrNull(offset)) as P; | ||||
|     case 10: | ||||
|       return (reader.readLong(offset)) as P; | ||||
|     case 11: | ||||
|       return (reader.readStringOrNull(offset)) as P; | ||||
|     case 11: | ||||
|       return (reader.readLong(offset)) as P; | ||||
|     case 12: | ||||
|       return (reader.readStringOrNull(offset)) as P; | ||||
|     case 13: | ||||
|       return (_AssettypeValueEnumMap[reader.readByteOrNull(offset)] ?? | ||||
|           AssetType.other) as P; | ||||
|     case 13: | ||||
|       return (reader.readDateTime(offset)) as P; | ||||
|     case 14: | ||||
|       return (reader.readDateTime(offset)) as P; | ||||
|     case 15: | ||||
|       return (reader.readIntOrNull(offset)) as P; | ||||
|     default: | ||||
|       throw IsarError('Unknown property with id $propertyId'); | ||||
| @@ -1290,6 +1299,16 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterFilterCondition> isTrashedEqualTo( | ||||
|       bool value) { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addFilterCondition(FilterCondition.equalTo( | ||||
|         property: r'isTrashed', | ||||
|         value: value, | ||||
|       )); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterFilterCondition> livePhotoVideoIdIsNull() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addFilterCondition(const FilterCondition.isNull( | ||||
| @@ -2058,6 +2077,18 @@ extension AssetQuerySortBy on QueryBuilder<Asset, Asset, QSortBy> { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterSortBy> sortByIsTrashed() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addSortBy(r'isTrashed', Sort.asc); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterSortBy> sortByIsTrashedDesc() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addSortBy(r'isTrashed', Sort.desc); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterSortBy> sortByLivePhotoVideoId() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addSortBy(r'livePhotoVideoId', Sort.asc); | ||||
| @@ -2252,6 +2283,18 @@ extension AssetQuerySortThenBy on QueryBuilder<Asset, Asset, QSortThenBy> { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterSortBy> thenByIsTrashed() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addSortBy(r'isTrashed', Sort.asc); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterSortBy> thenByIsTrashedDesc() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addSortBy(r'isTrashed', Sort.desc); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QAfterSortBy> thenByLivePhotoVideoId() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addSortBy(r'livePhotoVideoId', Sort.asc); | ||||
| @@ -2388,6 +2431,12 @@ extension AssetQueryWhereDistinct on QueryBuilder<Asset, Asset, QDistinct> { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QDistinct> distinctByIsTrashed() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addDistinctBy(r'isTrashed'); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, Asset, QDistinct> distinctByLivePhotoVideoId( | ||||
|       {bool caseSensitive = true}) { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
| @@ -2490,6 +2539,12 @@ extension AssetQueryProperty on QueryBuilder<Asset, Asset, QQueryProperty> { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, bool, QQueryOperations> isTrashedProperty() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addPropertyName(r'isTrashed'); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   QueryBuilder<Asset, String?, QQueryOperations> livePhotoVideoIdProperty() { | ||||
|     return QueryBuilder.apply(this, (query) { | ||||
|       return query.addPropertyName(r'livePhotoVideoId'); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user