mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 02:27:08 -04:00 
			
		
		
		
	* refactor(mobile): add AssetState and proper asset updating * generate files --------- Co-authored-by: Fynn Petersen-Frey <zoodyy@users.noreply.github.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
		
			
				
	
	
		
			142 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'dart:async';
 | |
| 
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:hooks_riverpod/hooks_riverpod.dart';
 | |
| import 'package:immich_mobile/shared/models/asset.dart';
 | |
| import 'package:immich_mobile/shared/models/exif_info.dart';
 | |
| import 'package:immich_mobile/shared/models/store.dart';
 | |
| import 'package:immich_mobile/shared/providers/api.provider.dart';
 | |
| import 'package:immich_mobile/shared/providers/db.provider.dart';
 | |
| import 'package:immich_mobile/shared/services/api.service.dart';
 | |
| import 'package:immich_mobile/shared/services/sync.service.dart';
 | |
| import 'package:immich_mobile/utils/openapi_extensions.dart';
 | |
| import 'package:immich_mobile/utils/tuple.dart';
 | |
| import 'package:isar/isar.dart';
 | |
| import 'package:logging/logging.dart';
 | |
| import 'package:openapi/api.dart';
 | |
| 
 | |
| final assetServiceProvider = Provider(
 | |
|   (ref) => AssetService(
 | |
|     ref.watch(apiServiceProvider),
 | |
|     ref.watch(syncServiceProvider),
 | |
|     ref.watch(dbProvider),
 | |
|   ),
 | |
| );
 | |
| 
 | |
| class AssetService {
 | |
|   final ApiService _apiService;
 | |
|   final SyncService _syncService;
 | |
|   final log = Logger('AssetService');
 | |
|   final Isar _db;
 | |
| 
 | |
|   AssetService(
 | |
|     this._apiService,
 | |
|     this._syncService,
 | |
|     this._db,
 | |
|   );
 | |
| 
 | |
|   /// Checks the server for updated assets and updates the local database if
 | |
|   /// required. Returns `true` if there were any changes.
 | |
|   Future<bool> refreshRemoteAssets() async {
 | |
|     final Stopwatch sw = Stopwatch()..start();
 | |
|     final int numOwnedRemoteAssets = await _db.assets
 | |
|         .where()
 | |
|         .remoteIdIsNotNull()
 | |
|         .filter()
 | |
|         .ownerIdEqualTo(Store.get(StoreKey.currentUser).isarId)
 | |
|         .count();
 | |
|     final bool changes = await _syncService.syncRemoteAssetsToDb(
 | |
|       () async => (await _getRemoteAssets(hasCache: numOwnedRemoteAssets > 0))
 | |
|           ?.map(Asset.remote)
 | |
|           .toList(),
 | |
|     );
 | |
|     debugPrint("refreshRemoteAssets full took ${sw.elapsedMilliseconds}ms");
 | |
|     return changes;
 | |
|   }
 | |
| 
 | |
|   /// Returns `null` if the server state did not change, else list of assets
 | |
|   Future<List<AssetResponseDto>?> _getRemoteAssets({
 | |
|     required bool hasCache,
 | |
|   }) async {
 | |
|     try {
 | |
|       final etag = hasCache ? Store.tryGet(StoreKey.assetETag) : null;
 | |
|       final Pair<List<AssetResponseDto>, String?>? remote =
 | |
|           await _apiService.assetApi.getAllAssetsWithETag(eTag: etag);
 | |
|       if (remote == null) {
 | |
|         return null;
 | |
|       }
 | |
|       if (remote.second != null && remote.second != etag) {
 | |
|         Store.put(StoreKey.assetETag, remote.second);
 | |
|       }
 | |
|       return remote.first;
 | |
|     } catch (e, stack) {
 | |
|       log.severe('Error while getting remote assets', e, stack);
 | |
|       return null;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<List<DeleteAssetResponseDto>?> deleteAssets(
 | |
|     Iterable<Asset> deleteAssets,
 | |
|   ) async {
 | |
|     try {
 | |
|       final List<String> payload = [];
 | |
| 
 | |
|       for (final asset in deleteAssets) {
 | |
|         payload.add(asset.remoteId!);
 | |
|       }
 | |
| 
 | |
|       return await _apiService.assetApi
 | |
|           .deleteAsset(DeleteAssetDto(ids: payload));
 | |
|     } catch (e) {
 | |
|       debugPrint("Error getAllAsset  ${e.toString()}");
 | |
|       return null;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /// Loads the exif information from the database. If there is none, loads
 | |
|   /// the exif info from the server (remote assets only)
 | |
|   Future<Asset> loadExif(Asset a) async {
 | |
|     a.exifInfo ??= await _db.exifInfos.get(a.id);
 | |
|     if (a.exifInfo?.iso == null) {
 | |
|       if (a.isRemote) {
 | |
|         final dto = await _apiService.assetApi.getAssetById(a.remoteId!);
 | |
|         if (dto != null && dto.exifInfo != null) {
 | |
|           a.exifInfo = Asset.remote(dto).exifInfo!.copyWith(id: a.id);
 | |
|           if (a.isInDb) {
 | |
|             _db.writeTxn(() => a.put(_db));
 | |
|           } else {
 | |
|             debugPrint("[loadExif] parameter Asset is not from DB!");
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         // TODO implement local exif info parsing
 | |
|       }
 | |
|     }
 | |
|     return a;
 | |
|   }
 | |
| 
 | |
|   Future<Asset?> updateAsset(
 | |
|     Asset asset,
 | |
|     UpdateAssetDto updateAssetDto,
 | |
|   ) async {
 | |
|     final dto =
 | |
|         await _apiService.assetApi.updateAsset(asset.remoteId!, updateAssetDto);
 | |
|     if (dto != null) {
 | |
|       final updated = asset.updatedCopy(Asset.remote(dto));
 | |
|       if (updated.isInDb) {
 | |
|         await _db.writeTxn(() => updated.put(_db));
 | |
|       }
 | |
|       return updated;
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   Future<Asset?> changeFavoriteStatus(Asset asset, bool isFavorite) {
 | |
|     return updateAsset(asset, UpdateAssetDto(isFavorite: isFavorite));
 | |
|   }
 | |
| 
 | |
|   Future<Asset?> changeArchiveStatus(Asset asset, bool isArchive) {
 | |
|     return updateAsset(asset, UpdateAssetDto(isArchived: isArchive));
 | |
|   }
 | |
| }
 |