mirror of
https://github.com/immich-app/immich.git
synced 2025-11-02 18:47:07 -05:00
167 lines
6.0 KiB
Dart
167 lines
6.0 KiB
Dart
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:http/http.dart';
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:immich_mobile/constants/enums.dart';
|
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|
import 'package:immich_mobile/domain/models/stack.model.dart';
|
|
import 'package:immich_mobile/entities/asset.entity.dart' hide AssetType;
|
|
import 'package:immich_mobile/extensions/string_extensions.dart';
|
|
import 'package:immich_mobile/providers/api.provider.dart';
|
|
import 'package:immich_mobile/repositories/api.repository.dart';
|
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
|
import 'package:openapi/api.dart' as api show AssetVisibility;
|
|
import 'package:openapi/api.dart' hide AssetVisibility;
|
|
|
|
final assetApiRepositoryProvider = Provider(
|
|
(ref) => AssetApiRepository(
|
|
ref.watch(apiServiceProvider).assetsApi,
|
|
ref.watch(apiServiceProvider).searchApi,
|
|
ref.watch(apiServiceProvider).stacksApi,
|
|
ref.watch(apiServiceProvider).trashApi,
|
|
),
|
|
);
|
|
|
|
class AssetApiRepository extends ApiRepository {
|
|
final AssetsApi _api;
|
|
final SearchApi _searchApi;
|
|
final StacksApi _stacksApi;
|
|
final TrashApi _trashApi;
|
|
|
|
AssetApiRepository(this._api, this._searchApi, this._stacksApi, this._trashApi);
|
|
|
|
Future<Asset> update(String id, {String? description}) async {
|
|
final response = await checkNull(_api.updateAsset(id, UpdateAssetDto(description: description)));
|
|
return Asset.remote(response);
|
|
}
|
|
|
|
Future<List<Asset>> search({List<String> personIds = const []}) async {
|
|
// TODO this always fetches all assets, change API and usage to actually do pagination
|
|
final List<Asset> result = [];
|
|
bool hasNext = true;
|
|
int currentPage = 1;
|
|
while (hasNext) {
|
|
final response = await checkNull(
|
|
_searchApi.searchAssets(MetadataSearchDto(personIds: personIds, page: currentPage, size: 1000)),
|
|
);
|
|
result.addAll(response.assets.items.map(Asset.remote));
|
|
hasNext = response.assets.nextPage != null;
|
|
currentPage++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Future<void> delete(List<String> ids, bool force) async {
|
|
return _api.deleteAssets(AssetBulkDeleteDto(ids: ids, force: force));
|
|
}
|
|
|
|
Future<void> restoreTrash(List<String> ids) async {
|
|
await _trashApi.restoreAssets(BulkIdsDto(ids: ids));
|
|
}
|
|
|
|
Future<void> updateVisibility(List<String> ids, AssetVisibilityEnum visibility) async {
|
|
return _api.updateAssets(AssetBulkUpdateDto(ids: ids, visibility: _mapVisibility(visibility)));
|
|
}
|
|
|
|
Future<void> updateFavorite(List<String> ids, bool isFavorite) async {
|
|
return _api.updateAssets(AssetBulkUpdateDto(ids: ids, isFavorite: isFavorite));
|
|
}
|
|
|
|
Future<void> updateLocation(List<String> ids, LatLng location) async {
|
|
return _api.updateAssets(AssetBulkUpdateDto(ids: ids, latitude: location.latitude, longitude: location.longitude));
|
|
}
|
|
|
|
Future<void> updateDateTime(List<String> ids, DateTime dateTime) async {
|
|
return _api.updateAssets(AssetBulkUpdateDto(ids: ids, dateTimeOriginal: dateTime.toIso8601String()));
|
|
}
|
|
|
|
Future<StackResponse> stack(List<String> ids) async {
|
|
final responseDto = await checkNull(_stacksApi.createStack(StackCreateDto(assetIds: ids)));
|
|
|
|
return responseDto.toStack();
|
|
}
|
|
|
|
Future<void> unStack(List<String> ids) async {
|
|
return _stacksApi.deleteStacks(BulkIdsDto(ids: ids));
|
|
}
|
|
|
|
Future<Response> downloadAsset(String id) {
|
|
return _api.downloadAssetWithHttpInfo(id);
|
|
}
|
|
|
|
_mapVisibility(AssetVisibilityEnum visibility) => switch (visibility) {
|
|
AssetVisibilityEnum.timeline => AssetVisibility.timeline,
|
|
AssetVisibilityEnum.hidden => AssetVisibility.hidden,
|
|
AssetVisibilityEnum.locked => AssetVisibility.locked,
|
|
AssetVisibilityEnum.archive => AssetVisibility.archive,
|
|
};
|
|
|
|
Future<String?> getAssetMIMEType(String assetId) async {
|
|
final response = await checkNull(_api.getAssetInfo(assetId));
|
|
|
|
// we need to get the MIME of the thumbnail once that gets added to the API
|
|
return response.originalMimeType;
|
|
}
|
|
|
|
Future<void> updateDescription(String assetId, String description) {
|
|
return _api.updateAsset(assetId, UpdateAssetDto(description: description));
|
|
}
|
|
|
|
Future<String?> uploadAsset(XFile file) async {
|
|
final lastModified = await file.lastModified();
|
|
final deviceAssetId = "MOBILE-${file.name}-${lastModified.millisecondsSinceEpoch}";
|
|
|
|
final multipart = MultipartFile.fromBytes(
|
|
'assetData', // field should be 'assetData' to match the backend API
|
|
await file.readAsBytes(),
|
|
filename: file.name,
|
|
);
|
|
|
|
final asset = await _api.uploadAsset(multipart, deviceAssetId, "MOBILE", lastModified, lastModified);
|
|
return asset?.id;
|
|
}
|
|
}
|
|
|
|
extension on StackResponseDto {
|
|
StackResponse toStack() {
|
|
return StackResponse(id: id, primaryAssetId: primaryAssetId, assetIds: assets.map((asset) => asset.id).toList());
|
|
}
|
|
}
|
|
|
|
extension RemoteAssetDtoExt on AssetResponseDto {
|
|
RemoteAsset toDto() {
|
|
return RemoteAsset(
|
|
id: id,
|
|
name: originalFileName,
|
|
checksum: checksum,
|
|
createdAt: fileCreatedAt,
|
|
updatedAt: updatedAt,
|
|
ownerId: ownerId,
|
|
visibility: switch (visibility) {
|
|
api.AssetVisibility.timeline => AssetVisibility.timeline,
|
|
api.AssetVisibility.hidden => AssetVisibility.hidden,
|
|
api.AssetVisibility.archive => AssetVisibility.archive,
|
|
api.AssetVisibility.locked => AssetVisibility.locked,
|
|
_ => AssetVisibility.timeline,
|
|
},
|
|
durationInSeconds: duration.toDuration()?.inSeconds ?? 0,
|
|
height: exifInfo?.exifImageHeight?.toInt(),
|
|
width: exifInfo?.exifImageWidth?.toInt(),
|
|
isFavorite: isFavorite,
|
|
livePhotoVideoId: livePhotoVideoId,
|
|
thumbHash: thumbhash,
|
|
localId: null,
|
|
type: type.toType(),
|
|
);
|
|
}
|
|
}
|
|
|
|
extension on AssetTypeEnum {
|
|
AssetType toType() => switch (this) {
|
|
AssetTypeEnum.IMAGE => AssetType.image,
|
|
AssetTypeEnum.VIDEO => AssetType.video,
|
|
AssetTypeEnum.AUDIO => AssetType.audio,
|
|
AssetTypeEnum.OTHER => AssetType.other,
|
|
_ => throw Exception('Unknown AssetType value: $this'),
|
|
};
|
|
}
|