From d310c77fc8772cbd10f5775ebbbe1c653b1a72b9 Mon Sep 17 00:00:00 2001 From: Matthias Rupp Date: Mon, 17 Oct 2022 14:53:27 +0200 Subject: [PATCH] Add album list response caching --- mobile/lib/constants/hive_box.dart | 4 ++ mobile/lib/main.dart | 1 + .../album/providers/album.provider.dart | 22 +++++++- .../album/services/album_cache.service.dart | 38 +++++++++++++ .../home/services/asset_cache.service.dart | 56 +++++++++++++------ .../providers/authentication.provider.dart | 5 ++ .../lib/shared/providers/asset.provider.dart | 4 +- 7 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 mobile/lib/modules/album/services/album_cache.service.dart diff --git a/mobile/lib/constants/hive_box.dart b/mobile/lib/constants/hive_box.dart index 4b69f6d753..e58ca2caf6 100644 --- a/mobile/lib/constants/hive_box.dart +++ b/mobile/lib/constants/hive_box.dart @@ -29,3 +29,7 @@ const String backupRequireCharging = "immichBackupRequireCharging"; // Key 3 // Asset cache const String assetListCacheBox = "assetListCacheBox"; const String assetListCachedAssets = "assetListCachedAssets"; + +// Album cache +const String albumListCacheBox = "albumListCacheBox"; +const String albumListCachedAssets = "albumListCachedAssets"; diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 22231e5eed..2b79e4fbae 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -38,6 +38,7 @@ void main() async { await Hive.openBox(hiveGithubReleaseInfoBox); await Hive.openBox(userSettingInfoBox); await Hive.openBox(assetListCacheBox); + await Hive.openBox(albumListCacheBox); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( diff --git a/mobile/lib/modules/album/providers/album.provider.dart b/mobile/lib/modules/album/providers/album.provider.dart index f86ffa3ee5..85e3b8cbcd 100644 --- a/mobile/lib/modules/album/providers/album.provider.dart +++ b/mobile/lib/modules/album/providers/album.provider.dart @@ -1,22 +1,35 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/modules/album/services/album.service.dart'; +import 'package:immich_mobile/modules/album/services/album_cache.service.dart'; import 'package:openapi/api.dart'; class AlbumNotifier extends StateNotifier> { - AlbumNotifier(this._albumService) : super([]); + AlbumNotifier(this._albumService, this._albumCacheService) : super([]); final AlbumService _albumService; + final AlbumCacheService _albumCacheService; + + _cacheState() { + _albumCacheService.put(state); + } getAllAlbums() async { + + if (_albumCacheService.isValid() && state.isEmpty) { + state = await _albumCacheService.getAsync(); + } + List? albums = await _albumService.getAlbums(isShared: false); if (albums != null) { state = albums; + _cacheState(); } } deleteAlbum(String albumId) { state = state.where((album) => album.id != albumId).toList(); + _cacheState(); } Future createAlbum( @@ -28,6 +41,8 @@ class AlbumNotifier extends StateNotifier> { if (album != null) { state = [...state, album]; + _cacheState(); + return album; } return null; @@ -36,5 +51,8 @@ class AlbumNotifier extends StateNotifier> { final albumProvider = StateNotifierProvider>((ref) { - return AlbumNotifier(ref.watch(albumServiceProvider)); + return AlbumNotifier( + ref.watch(albumServiceProvider), + ref.watch(albumCacheServiceProvider), + ); }); diff --git a/mobile/lib/modules/album/services/album_cache.service.dart b/mobile/lib/modules/album/services/album_cache.service.dart new file mode 100644 index 0000000000..f4e5974afd --- /dev/null +++ b/mobile/lib/modules/album/services/album_cache.service.dart @@ -0,0 +1,38 @@ + +import 'package:collection/collection.dart'; +import 'package:flutter/foundation.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/hive_box.dart'; +import 'package:immich_mobile/modules/home/services/asset_cache.service.dart'; +import 'package:openapi/api.dart'; + +class AlbumCacheService extends JsonCache> { + AlbumCacheService() : super(albumListCacheBox, albumListCachedAssets); + + @override + void put(List data) { + putRawData(data.map((e) => e.toJson()).toList()); + } + + @override + List get() { + try { + final mapList = readRawData() as List; + + final responseData = mapList + .map((e) => AlbumResponseDto.fromJson(e)) + .whereNotNull() + .toList(); + + return responseData; + } catch (e) { + debugPrint(e.toString()); + return []; + } + } + +} + +final albumCacheServiceProvider = Provider( + (ref) => AlbumCacheService(), +); diff --git a/mobile/lib/modules/home/services/asset_cache.service.dart b/mobile/lib/modules/home/services/asset_cache.service.dart index f5250f38e7..232ae68bfb 100644 --- a/mobile/lib/modules/home/services/asset_cache.service.dart +++ b/mobile/lib/modules/home/services/asset_cache.service.dart @@ -4,36 +4,55 @@ import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:http/http.dart'; import 'package:immich_mobile/constants/hive_box.dart'; import 'package:openapi/api.dart'; -final assetCacheServiceProvider = Provider( - (ref) => AssetCacheService(), -); +abstract class JsonCache { + final String boxName; + final String valueKey; + final Box _cacheBox; -class AssetCacheService { - final _cacheBox = Hive.box(assetListCacheBox); + JsonCache(this.boxName, this.valueKey) : _cacheBox = Hive.box(boxName); bool isValid() { - return _cacheBox.containsKey(assetListCachedAssets) && - _cacheBox.get(assetListCachedAssets) is String; + return _cacheBox.containsKey(valueKey) && _cacheBox.get(valueKey) is String; } void invalidate() { _cacheBox.clear(); } - void putAssets(List assets) { - final mapList = assets.map((e) => e.toJson()).toList(); - final jsonString = json.encode(mapList); - - _cacheBox.put(assetListCachedAssets, jsonString); + void putRawData(dynamic data) { + final jsonString = json.encode(data); + _cacheBox.put(valueKey, jsonString); } - List getAssets() { + dynamic readRawData() { + return json.decode(_cacheBox.get(valueKey)); + } + + void put(T data); + + T get(); + + Future getAsync() async { + return Future.microtask(() => get()); + } +} + +class AssetCacheService extends JsonCache> { + AssetCacheService() : super(assetListCacheBox, assetListCachedAssets); + + @override + void put(List data) { + putRawData(data.map((e) => e.toJson()).toList()); + } + + @override + List get() { try { - final jsonString = _cacheBox.get(assetListCachedAssets); - final mapList = json.decode(jsonString) as List; + final mapList = readRawData() as List; final responseData = mapList .map((e) => AssetResponseDto.fromJson(e)) @@ -48,7 +67,8 @@ class AssetCacheService { } } - Future> getAssetsAsync() async { - return Future.microtask(() => getAssets()); - } } + +final assetCacheServiceProvider = Provider( + (ref) => AssetCacheService(), +); diff --git a/mobile/lib/modules/login/providers/authentication.provider.dart b/mobile/lib/modules/login/providers/authentication.provider.dart index f86a9735fc..8b8f039853 100644 --- a/mobile/lib/modules/login/providers/authentication.provider.dart +++ b/mobile/lib/modules/login/providers/authentication.provider.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; +import 'package:immich_mobile/modules/album/services/album_cache.service.dart'; import 'package:immich_mobile/modules/home/services/asset_cache.service.dart'; import 'package:immich_mobile/modules/login/models/authentication_state.model.dart'; import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart'; @@ -17,6 +18,7 @@ class AuthenticationNotifier extends StateNotifier { this._backupService, this._apiService, this._assetCacheService, + this._albumCacheService, ) : super( AuthenticationState( deviceId: "", @@ -44,6 +46,7 @@ class AuthenticationNotifier extends StateNotifier { final BackupService _backupService; final ApiService _apiService; final AssetCacheService _assetCacheService; + final AlbumCacheService _albumCacheService; Future login( String email, @@ -155,6 +158,7 @@ class AuthenticationNotifier extends StateNotifier { Hive.box(userInfoBox).delete(accessTokenKey); state = state.copyWith(isAuthenticated: false); _assetCacheService.invalidate(); + _albumCacheService.invalidate(); return true; } @@ -201,5 +205,6 @@ final authenticationProvider = ref.watch(backupServiceProvider), ref.watch(apiServiceProvider), ref.watch(assetCacheServiceProvider), + ref.watch(albumCacheServiceProvider), ); }); diff --git a/mobile/lib/shared/providers/asset.provider.dart b/mobile/lib/shared/providers/asset.provider.dart index f0c90c74f1..572f72c463 100644 --- a/mobile/lib/shared/providers/asset.provider.dart +++ b/mobile/lib/shared/providers/asset.provider.dart @@ -17,7 +17,7 @@ class AssetNotifier extends StateNotifier> { AssetNotifier(this._assetService, this._assetCacheService) : super([]); _cacheState() { - _assetCacheService.putAssets(state); + _assetCacheService.put(state); } getAllAsset() async { @@ -26,7 +26,7 @@ class AssetNotifier extends StateNotifier> { if (_assetCacheService.isValid() && state.isEmpty) { stopwatch.start(); - state = await _assetCacheService.getAssetsAsync(); + state = await _assetCacheService.getAsync(); debugPrint("Reading assets from cache: ${stopwatch.elapsedMilliseconds}ms"); stopwatch.reset(); }