From 11562903775971d4bd735e740548d7491c793fb3 Mon Sep 17 00:00:00 2001 From: Matthias Rupp Date: Fri, 14 Oct 2022 23:57:55 +0200 Subject: [PATCH] Add asset response cache --- mobile/lib/constants/hive_box.dart | 4 + mobile/lib/main.dart | 1 + .../home/services/asset_cache.service.dart | 84 +++++++++++++++++++ .../lib/shared/providers/asset.provider.dart | 13 ++- 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 mobile/lib/modules/home/services/asset_cache.service.dart diff --git a/mobile/lib/constants/hive_box.dart b/mobile/lib/constants/hive_box.dart index 7faf6555f6..4b69f6d753 100644 --- a/mobile/lib/constants/hive_box.dart +++ b/mobile/lib/constants/hive_box.dart @@ -25,3 +25,7 @@ const String backgroundBackupInfoBox = "immichBackgroundBackupInfoBox"; // Box const String backupFailedSince = "immichBackupFailedSince"; // Key 1 const String backupRequireWifi = "immichBackupRequireWifi"; // Key 2 const String backupRequireCharging = "immichBackupRequireCharging"; // Key 3 + +// Asset cache +const String assetListCacheBox = "assetListCacheBox"; +const String assetListCachedAssets = "assetListCachedAssets"; diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index ee5209b5c2..22231e5eed 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -37,6 +37,7 @@ void main() async { await Hive.openBox(hiveBackupInfoBox); await Hive.openBox(hiveGithubReleaseInfoBox); await Hive.openBox(userSettingInfoBox); + await Hive.openBox(assetListCacheBox); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( diff --git a/mobile/lib/modules/home/services/asset_cache.service.dart b/mobile/lib/modules/home/services/asset_cache.service.dart new file mode 100644 index 0000000000..694bb50c9b --- /dev/null +++ b/mobile/lib/modules/home/services/asset_cache.service.dart @@ -0,0 +1,84 @@ +import 'package:collection/collection.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/hive_box.dart'; +import 'package:openapi/api.dart'; + +final assetCacheServiceProvider = Provider( + (ref) => AssetCacheService(), +); + +typedef CacheEntry = Map; +typedef CacheList = List; + +class AssetCacheService { + final _cacheBox = Hive.box(assetListCacheBox); + + bool isValid() { + return _cacheBox.containsKey(assetListCachedAssets) && _rawGet().isNotEmpty; + } + + void putAssets(List assets) { + _rawPut(assets.map((e) => _serialize(e)).toList()); + } + + List getAssets() { + return _rawGet().map((e) => _deserialize(e)).whereNotNull().toList(); + } + + Future> getAssetsAsync() async { + return Future.microtask(() => getAssets()); + } + + List _rawGet() { + return _cacheBox.get(assetListCachedAssets) as List; + } + + void _rawPut(CacheList data) { + _cacheBox.put(assetListCachedAssets, data); + } + + CacheEntry _serialize(AssetResponseDto a) { + return { + "id": a.id, + "cat": a.createdAt, + "did": a.deviceAssetId, + "oid": a.ownerId, + "dev": a.deviceId, + "dur": a.duration, + "mat": a.modifiedAt, + "opa": a.originalPath, + "typ": a.type.value, + "exif": a.exifInfo?.toJson(), + "fav": a.isFavorite, + "evp": a.encodedVideoPath, + "mim": a.mimeType, + "rsp": a.resizePath, + "wbp": a.webpPath, + }; + } + + AssetResponseDto? _deserialize(CacheEntry map) { + try { + return AssetResponseDto( + type: AssetTypeEnum.values + .firstWhere((element) => element.value == map["typ"]), + id: map["id"], + deviceAssetId: map["did"], + ownerId: map["oid"], + deviceId: map["dev"], + originalPath: map["opa"], + resizePath: map["rsp"], + createdAt: map["cat"], + modifiedAt: map["mat"], + isFavorite: map["fav"], + mimeType: map["mim"], + duration: map["dur"], + webpPath: map["wbp"], + encodedVideoPath: map["evp"], + ); + } catch (e) { + return null; + } + } +} diff --git a/mobile/lib/shared/providers/asset.provider.dart b/mobile/lib/shared/providers/asset.provider.dart index 6329995ade..5b09935df6 100644 --- a/mobile/lib/shared/providers/asset.provider.dart +++ b/mobile/lib/shared/providers/asset.provider.dart @@ -1,6 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/modules/home/services/asset.service.dart'; +import 'package:immich_mobile/modules/home/services/asset_cache.service.dart'; import 'package:immich_mobile/shared/services/device_info.service.dart'; import 'package:collection/collection.dart'; import 'package:intl/intl.dart'; @@ -9,15 +10,22 @@ import 'package:photo_manager/photo_manager.dart'; class AssetNotifier extends StateNotifier> { final AssetService _assetService; + final AssetCacheService _assetCacheService; + final DeviceInfoService _deviceInfoService = DeviceInfoService(); - AssetNotifier(this._assetService) : super([]); + AssetNotifier(this._assetService, this._assetCacheService) : super([]); getAllAsset() async { + if (_assetCacheService.isValid() && state.isEmpty) { + state = await _assetCacheService.getAssetsAsync(); + } + var allAssets = await _assetService.getAllAsset(); if (allAssets != null) { state = allAssets; + _assetCacheService.putAssets(allAssets); } } @@ -70,7 +78,8 @@ class AssetNotifier extends StateNotifier> { final assetProvider = StateNotifierProvider>((ref) { - return AssetNotifier(ref.watch(assetServiceProvider)); + return AssetNotifier( + ref.watch(assetServiceProvider), ref.watch(assetCacheServiceProvider)); }); final assetGroupByDateTimeProvider = StateProvider((ref) {