mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	fix/cache read write error ios16 (#691)
* Fix(mobile) cache read/write issue, cannot load image on ios16 * Update
This commit is contained in:
		@@ -364,7 +364,7 @@
 | 
			
		||||
				DEVELOPMENT_TEAM = 2F67MQ8R79;
 | 
			
		||||
				ENABLE_BITCODE = NO;
 | 
			
		||||
				INFOPLIST_FILE = Runner/Info.plist;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 | 
			
		||||
				LD_RUNPATH_SEARCH_PATHS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
@@ -499,7 +499,7 @@
 | 
			
		||||
				DEVELOPMENT_TEAM = 2F67MQ8R79;
 | 
			
		||||
				ENABLE_BITCODE = NO;
 | 
			
		||||
				INFOPLIST_FILE = Runner/Info.plist;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 | 
			
		||||
				LD_RUNPATH_SEARCH_PATHS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
@@ -526,7 +526,7 @@
 | 
			
		||||
				DEVELOPMENT_TEAM = 2F67MQ8R79;
 | 
			
		||||
				ENABLE_BITCODE = NO;
 | 
			
		||||
				INFOPLIST_FILE = Runner/Info.plist;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 | 
			
		||||
				LD_RUNPATH_SEARCH_PATHS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hive/hive.dart';
 | 
			
		||||
import 'package:immich_mobile/constants/hive_box.dart';
 | 
			
		||||
import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/image_url_builder.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
@@ -15,11 +14,9 @@ class AlbumThumbnailCard extends StatelessWidget {
 | 
			
		||||
  const AlbumThumbnailCard({
 | 
			
		||||
    Key? key,
 | 
			
		||||
    required this.album,
 | 
			
		||||
    required this.cacheService,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  final AlbumResponseDto album;
 | 
			
		||||
  final CacheService cacheService;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
@@ -39,7 +36,6 @@ class AlbumThumbnailCard extends StatelessWidget {
 | 
			
		||||
            ClipRRect(
 | 
			
		||||
              borderRadius: BorderRadius.circular(8),
 | 
			
		||||
              child: CachedNetworkImage(
 | 
			
		||||
                cacheManager: cacheService.getCache(CacheType.albumThumbnail),
 | 
			
		||||
                memCacheHeight: max(400, cardSize.toInt() * 3),
 | 
			
		||||
                width: cardSize,
 | 
			
		||||
                height: cardSize,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,12 @@
 | 
			
		||||
import 'package:auto_route/auto_route.dart';
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.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:immich_mobile/modules/login/providers/authentication.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/image_url_builder.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
@@ -17,13 +14,11 @@ class AlbumViewerThumbnail extends HookConsumerWidget {
 | 
			
		||||
  final AssetResponseDto asset;
 | 
			
		||||
  final List<AssetResponseDto> assetList;
 | 
			
		||||
  final bool showStorageIndicator;
 | 
			
		||||
  final BaseCacheManager? cacheManager;
 | 
			
		||||
 | 
			
		||||
  const AlbumViewerThumbnail({
 | 
			
		||||
    Key? key,
 | 
			
		||||
    required this.asset,
 | 
			
		||||
    required this.assetList,
 | 
			
		||||
    this.cacheManager,
 | 
			
		||||
    this.showStorageIndicator = true,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
@@ -126,7 +121,6 @@ class AlbumViewerThumbnail extends HookConsumerWidget {
 | 
			
		||||
      return Container(
 | 
			
		||||
        decoration: BoxDecoration(border: drawBorderColor()),
 | 
			
		||||
        child: CachedNetworkImage(
 | 
			
		||||
          cacheManager: cacheManager,
 | 
			
		||||
          cacheKey: asset.id,
 | 
			
		||||
          width: 300,
 | 
			
		||||
          height: 300,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,9 @@
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.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:immich_mobile/modules/album/providers/asset_selection.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/image_url_builder.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
@@ -24,7 +22,6 @@ class SelectionThumbnailImage extends HookConsumerWidget {
 | 
			
		||||
    var newAssetsForAlbum =
 | 
			
		||||
        ref.watch(assetSelectionProvider).selectedAdditionalAssetsForAlbum;
 | 
			
		||||
    var isAlbumExist = ref.watch(assetSelectionProvider).isAlbumExist;
 | 
			
		||||
    final cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
 | 
			
		||||
    Widget _buildSelectionIcon(AssetResponseDto asset) {
 | 
			
		||||
      var isSelected = selectedAsset.map((item) => item.id).contains(asset.id);
 | 
			
		||||
@@ -114,7 +111,6 @@ class SelectionThumbnailImage extends HookConsumerWidget {
 | 
			
		||||
          Container(
 | 
			
		||||
            decoration: BoxDecoration(border: drawBorderColor()),
 | 
			
		||||
            child: CachedNetworkImage(
 | 
			
		||||
              cacheManager: cacheService.getCache(CacheType.thumbnail),
 | 
			
		||||
              cacheKey: asset.id,
 | 
			
		||||
              width: 150,
 | 
			
		||||
              height: 150,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,8 @@
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.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:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/image_url_builder.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
@@ -16,7 +14,6 @@ class SharedAlbumThumbnailImage extends HookConsumerWidget {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
    var box = Hive.box(userInfoBox);
 | 
			
		||||
 | 
			
		||||
    return GestureDetector(
 | 
			
		||||
@@ -26,7 +23,6 @@ class SharedAlbumThumbnailImage extends HookConsumerWidget {
 | 
			
		||||
      child: Stack(
 | 
			
		||||
        children: [
 | 
			
		||||
          CachedNetworkImage(
 | 
			
		||||
            cacheManager: cacheService.getCache(CacheType.thumbnail),
 | 
			
		||||
            cacheKey: asset.id,
 | 
			
		||||
            width: 500,
 | 
			
		||||
            height: 500,
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ import 'package:immich_mobile/modules/album/ui/album_viewer_thumbnail.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
 | 
			
		||||
import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/ui/immich_sliver_persistent_app_bar_delegate.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
 | 
			
		||||
@@ -192,7 +191,6 @@ class AlbumViewerPage extends HookConsumerWidget {
 | 
			
		||||
      final appSettingService = ref.watch(appSettingsServiceProvider);
 | 
			
		||||
      final bool showStorageIndicator =
 | 
			
		||||
          appSettingService.getSetting(AppSettingsEnum.storageIndicator);
 | 
			
		||||
      final cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
 | 
			
		||||
      if (albumInfo.assets.isNotEmpty) {
 | 
			
		||||
        return SliverPadding(
 | 
			
		||||
@@ -207,7 +205,6 @@ class AlbumViewerPage extends HookConsumerWidget {
 | 
			
		||||
            delegate: SliverChildBuilderDelegate(
 | 
			
		||||
              (BuildContext context, int index) {
 | 
			
		||||
                return AlbumViewerThumbnail(
 | 
			
		||||
                  cacheManager: cacheService.getCache(CacheType.thumbnail),
 | 
			
		||||
                  asset: albumInfo.assets[index],
 | 
			
		||||
                  assetList: albumInfo.assets,
 | 
			
		||||
                  showStorageIndicator: showStorageIndicator,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/album/providers/album.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/album/ui/album_thumbnail_card.dart';
 | 
			
		||||
import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
 | 
			
		||||
class LibraryPage extends HookConsumerWidget {
 | 
			
		||||
  const LibraryPage({Key? key}) : super(key: key);
 | 
			
		||||
@@ -14,7 +13,6 @@ class LibraryPage extends HookConsumerWidget {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final albums = ref.watch(albumProvider);
 | 
			
		||||
    final cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
 | 
			
		||||
    useEffect(
 | 
			
		||||
      () {
 | 
			
		||||
@@ -104,7 +102,6 @@ class LibraryPage extends HookConsumerWidget {
 | 
			
		||||
                  _buildCreateAlbumButton(),
 | 
			
		||||
                  for (var album in albums)
 | 
			
		||||
                    AlbumThumbnailCard(
 | 
			
		||||
                      cacheService: cacheService,
 | 
			
		||||
                      album: album,
 | 
			
		||||
                    ),
 | 
			
		||||
                ],
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ import 'package:immich_mobile/constants/hive_box.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/album/ui/sharing_sliver_appbar.dart';
 | 
			
		||||
import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/image_url_builder.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
@@ -21,7 +20,6 @@ class SharingPage extends HookConsumerWidget {
 | 
			
		||||
    var box = Hive.box(userInfoBox);
 | 
			
		||||
    var thumbnailRequestUrl = '${box.get(serverEndpointKey)}/asset/thumbnail';
 | 
			
		||||
    final List<AlbumResponseDto> sharedAlbums = ref.watch(sharedAlbumProvider);
 | 
			
		||||
    final CacheService cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
 | 
			
		||||
    useEffect(
 | 
			
		||||
      () {
 | 
			
		||||
@@ -47,8 +45,6 @@ class SharingPage extends HookConsumerWidget {
 | 
			
		||||
                  height: 60,
 | 
			
		||||
                  memCacheHeight: 200,
 | 
			
		||||
                  fit: BoxFit.cover,
 | 
			
		||||
                  cacheManager:
 | 
			
		||||
                      cacheService.getCache(CacheType.sharedAlbumThumbnail),
 | 
			
		||||
                  imageUrl: getAlbumThumbnailUrl(album),
 | 
			
		||||
                  cacheKey: album.albumThumbnailAssetId,
 | 
			
		||||
                  httpHeaders: {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:flutter/cupertino.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
 | 
			
		||||
import 'package:photo_view/photo_view.dart';
 | 
			
		||||
 | 
			
		||||
enum _RemoteImageStatus { empty, thumbnail, preview, full }
 | 
			
		||||
@@ -70,13 +69,11 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
 | 
			
		||||
  CachedNetworkImageProvider _authorizedImageProvider(
 | 
			
		||||
    String url,
 | 
			
		||||
    String cacheKey,
 | 
			
		||||
    BaseCacheManager? cacheManager,
 | 
			
		||||
  ) {
 | 
			
		||||
    return CachedNetworkImageProvider(
 | 
			
		||||
      url,
 | 
			
		||||
      headers: {"Authorization": widget.authToken},
 | 
			
		||||
      cacheKey: cacheKey,
 | 
			
		||||
      cacheManager: cacheManager,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -113,7 +110,6 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
 | 
			
		||||
    thumbnailProvider = _authorizedImageProvider(
 | 
			
		||||
      widget.thumbnailUrl,
 | 
			
		||||
      widget.cacheKey,
 | 
			
		||||
      widget.thumbnailCacheManager,
 | 
			
		||||
    );
 | 
			
		||||
    _imageProvider = thumbnailProvider;
 | 
			
		||||
 | 
			
		||||
@@ -130,7 +126,6 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
 | 
			
		||||
      previewProvider = _authorizedImageProvider(
 | 
			
		||||
        widget.previewUrl!,
 | 
			
		||||
        "${widget.cacheKey}_previewStage",
 | 
			
		||||
        widget.previewCacheManager,
 | 
			
		||||
      );
 | 
			
		||||
      previewProvider.resolve(const ImageConfiguration()).addListener(
 | 
			
		||||
        ImageStreamListener((ImageInfo imageInfo, _) {
 | 
			
		||||
@@ -142,7 +137,6 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
 | 
			
		||||
    fullProvider = _authorizedImageProvider(
 | 
			
		||||
      widget.imageUrl,
 | 
			
		||||
      "${widget.cacheKey}_fullStage",
 | 
			
		||||
      widget.fullCacheManager,
 | 
			
		||||
    );
 | 
			
		||||
    fullProvider.resolve(const ImageConfiguration()).addListener(
 | 
			
		||||
      ImageStreamListener((ImageInfo imageInfo, _) {
 | 
			
		||||
@@ -184,9 +178,6 @@ class RemotePhotoView extends StatefulWidget {
 | 
			
		||||
    this.previewUrl,
 | 
			
		||||
    required this.onLoadingCompleted,
 | 
			
		||||
    required this.onLoadingStart,
 | 
			
		||||
    this.thumbnailCacheManager,
 | 
			
		||||
    this.previewCacheManager,
 | 
			
		||||
    this.fullCacheManager,
 | 
			
		||||
    required this.cacheKey,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
@@ -196,9 +187,6 @@ class RemotePhotoView extends StatefulWidget {
 | 
			
		||||
  final String? previewUrl;
 | 
			
		||||
  final Function onLoadingCompleted;
 | 
			
		||||
  final Function onLoadingStart;
 | 
			
		||||
  final BaseCacheManager? thumbnailCacheManager;
 | 
			
		||||
  final BaseCacheManager? previewCacheManager;
 | 
			
		||||
  final BaseCacheManager? fullCacheManager;
 | 
			
		||||
  final String cacheKey;
 | 
			
		||||
 | 
			
		||||
  final void Function() onSwipeDown;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ import 'package:immich_mobile/modules/asset_viewer/ui/download_loading_indicator
 | 
			
		||||
import 'package:immich_mobile/modules/asset_viewer/ui/exif_bottom_sheet.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/asset_viewer/ui/remote_photo_view.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/home/services/asset.service.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/image_url_builder.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
@@ -41,7 +40,6 @@ class ImageViewerPage extends HookConsumerWidget {
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final downloadAssetStatus =
 | 
			
		||||
        ref.watch(imageViewerStateProvider).downloadAssetStatus;
 | 
			
		||||
    final cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
 | 
			
		||||
    getAssetExif() async {
 | 
			
		||||
      assetDetail =
 | 
			
		||||
@@ -87,12 +85,6 @@ class ImageViewerPage extends HookConsumerWidget {
 | 
			
		||||
              onSwipeUp: () => showInfo(),
 | 
			
		||||
              onLoadingCompleted: onLoadingCompleted,
 | 
			
		||||
              onLoadingStart: onLoadingStart,
 | 
			
		||||
              thumbnailCacheManager:
 | 
			
		||||
                  cacheService.getCache(CacheType.thumbnail),
 | 
			
		||||
              previewCacheManager:
 | 
			
		||||
                  cacheService.getCache(CacheType.imageViewerPreview),
 | 
			
		||||
              fullCacheManager:
 | 
			
		||||
                  cacheService.getCache(CacheType.imageViewerFull),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/home/ui/thumbnail_image.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
@@ -10,13 +9,11 @@ class ImageGrid extends ConsumerWidget {
 | 
			
		||||
  final List<AssetResponseDto> sortedAssetGroup;
 | 
			
		||||
  final int tilesPerRow;
 | 
			
		||||
  final bool showStorageIndicator;
 | 
			
		||||
  final BaseCacheManager? cacheManager;
 | 
			
		||||
 | 
			
		||||
  ImageGrid({
 | 
			
		||||
    Key? key,
 | 
			
		||||
    required this.assetGroup,
 | 
			
		||||
    required this.sortedAssetGroup,
 | 
			
		||||
    this.cacheManager,
 | 
			
		||||
    this.tilesPerRow = 4,
 | 
			
		||||
    this.showStorageIndicator = true,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
@@ -39,7 +36,6 @@ class ImageGrid extends ConsumerWidget {
 | 
			
		||||
            child: Stack(
 | 
			
		||||
              children: [
 | 
			
		||||
                ThumbnailImage(
 | 
			
		||||
                  cacheManager: cacheManager,
 | 
			
		||||
                  asset: assetGroup[index],
 | 
			
		||||
                  assetList: sortedAssetGroup,
 | 
			
		||||
                  showStorageIndicator: showStorageIndicator,
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,6 @@ import 'package:auto_route/auto_route.dart';
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter/services.dart';
 | 
			
		||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.dart';
 | 
			
		||||
import 'package:hive_flutter/hive_flutter.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/constants/hive_box.dart';
 | 
			
		||||
@@ -17,13 +15,11 @@ class ThumbnailImage extends HookConsumerWidget {
 | 
			
		||||
  final AssetResponseDto asset;
 | 
			
		||||
  final List<AssetResponseDto> assetList;
 | 
			
		||||
  final bool showStorageIndicator;
 | 
			
		||||
  final BaseCacheManager? cacheManager;
 | 
			
		||||
 | 
			
		||||
  const ThumbnailImage({
 | 
			
		||||
    Key? key,
 | 
			
		||||
    required this.asset,
 | 
			
		||||
    required this.assetList,
 | 
			
		||||
    this.cacheManager,
 | 
			
		||||
    this.showStorageIndicator = true,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
@@ -96,7 +92,6 @@ class ThumbnailImage extends HookConsumerWidget {
 | 
			
		||||
              ),
 | 
			
		||||
              child: CachedNetworkImage(
 | 
			
		||||
                cacheKey: asset.id,
 | 
			
		||||
                cacheManager: cacheManager,
 | 
			
		||||
                width: 300,
 | 
			
		||||
                height: 300,
 | 
			
		||||
                memCacheHeight: asset.type == AssetTypeEnum.IMAGE ? 250 : 400,
 | 
			
		||||
@@ -114,7 +109,7 @@ class ThumbnailImage extends HookConsumerWidget {
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
                errorWidget: (context, url, error) {
 | 
			
		||||
                  debugPrint("Error getting thumbnail $url = $error");
 | 
			
		||||
                  // debugPrint("Error getting thumbnail $url = $error");
 | 
			
		||||
                  return Icon(
 | 
			
		||||
                    Icons.image_not_supported_outlined,
 | 
			
		||||
                    color: Theme.of(context).primaryColor,
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ import 'package:immich_mobile/modules/settings/services/app_settings.service.dar
 | 
			
		||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/cache.service.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
class HomePage extends HookConsumerWidget {
 | 
			
		||||
@@ -25,7 +24,6 @@ class HomePage extends HookConsumerWidget {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final appSettingService = ref.watch(appSettingsServiceProvider);
 | 
			
		||||
    final cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
 | 
			
		||||
    ScrollController scrollController = useScrollController();
 | 
			
		||||
    var assetGroupByDateTime = ref.watch(assetGroupByDateTimeProvider);
 | 
			
		||||
@@ -91,7 +89,6 @@ class HomePage extends HookConsumerWidget {
 | 
			
		||||
 | 
			
		||||
            imageGridGroup.add(
 | 
			
		||||
              ImageGrid(
 | 
			
		||||
                cacheManager: cacheService.getCache(CacheType.thumbnail),
 | 
			
		||||
                assetGroup: immichAssetList,
 | 
			
		||||
                sortedAssetGroup: sortedAssetList,
 | 
			
		||||
                tilesPerRow:
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@ class CacheSettings extends HookConsumerWidget {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final CacheService cacheService = ref.watch(cacheServiceProvider);
 | 
			
		||||
 | 
			
		||||
    final clearCacheState = useState(false);
 | 
			
		||||
 | 
			
		||||
    Future<void> clearCache() async {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ import 'package:easy_localization/easy_localization.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/ui/asset_list_settings/asset_list_settings.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/ui/cache_settings/cache_settings.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/ui/image_viewer_quality_setting/image_viewer_quality_setting.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/ui/notification_setting/notification_setting.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/ui/theme_setting/theme_setting.dart';
 | 
			
		||||
@@ -42,7 +41,6 @@ class SettingsPage extends HookConsumerWidget {
 | 
			
		||||
              const ImageViewerQualitySetting(),
 | 
			
		||||
              const ThemeSetting(),
 | 
			
		||||
              const AssetListSettings(),
 | 
			
		||||
              const CacheSettings(),
 | 
			
		||||
              if (Platform.isAndroid) const NotificationSetting(),
 | 
			
		||||
            ],
 | 
			
		||||
          ).toList(),
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import 'package:immich_mobile/utils/immich_cache_info_repository.dart';
 | 
			
		||||
enum CacheType {
 | 
			
		||||
  // Shared cache for asset thumbnails in various modules
 | 
			
		||||
  thumbnail,
 | 
			
		||||
 | 
			
		||||
  imageViewerPreview,
 | 
			
		||||
  imageViewerFull,
 | 
			
		||||
  albumThumbnail,
 | 
			
		||||
@@ -67,7 +66,10 @@ class CacheService {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  BaseCacheManager _getDefaultCache(
 | 
			
		||||
      String cacheName, int size, CacheInfoRepository repo) {
 | 
			
		||||
    String cacheName,
 | 
			
		||||
    int size,
 | 
			
		||||
    CacheInfoRepository repo,
 | 
			
		||||
  ) {
 | 
			
		||||
    return CacheManager(
 | 
			
		||||
      Config(
 | 
			
		||||
        cacheName,
 | 
			
		||||
 
 | 
			
		||||
@@ -115,4 +115,3 @@ lib/model/user_count_response_dto.dart
 | 
			
		||||
lib/model/user_response_dto.dart
 | 
			
		||||
lib/model/validate_access_token_response_dto.dart
 | 
			
		||||
pubspec.yaml
 | 
			
		||||
test/asset_count_by_user_id_response_dto_test.dart
 | 
			
		||||
 
 | 
			
		||||
@@ -76,69 +76,72 @@ class AssetResponseDto {
 | 
			
		||||
  SmartInfoResponseDto? smartInfo;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is AssetResponseDto &&
 | 
			
		||||
     other.type == type &&
 | 
			
		||||
     other.id == id &&
 | 
			
		||||
     other.deviceAssetId == deviceAssetId &&
 | 
			
		||||
     other.ownerId == ownerId &&
 | 
			
		||||
     other.deviceId == deviceId &&
 | 
			
		||||
     other.originalPath == originalPath &&
 | 
			
		||||
     other.resizePath == resizePath &&
 | 
			
		||||
     other.createdAt == createdAt &&
 | 
			
		||||
     other.modifiedAt == modifiedAt &&
 | 
			
		||||
     other.isFavorite == isFavorite &&
 | 
			
		||||
     other.mimeType == mimeType &&
 | 
			
		||||
     other.duration == duration &&
 | 
			
		||||
     other.webpPath == webpPath &&
 | 
			
		||||
     other.encodedVideoPath == encodedVideoPath &&
 | 
			
		||||
     other.exifInfo == exifInfo &&
 | 
			
		||||
     other.smartInfo == smartInfo;
 | 
			
		||||
  bool operator ==(Object other) =>
 | 
			
		||||
      identical(this, other) ||
 | 
			
		||||
      other is AssetResponseDto &&
 | 
			
		||||
          other.type == type &&
 | 
			
		||||
          other.id == id &&
 | 
			
		||||
          other.deviceAssetId == deviceAssetId &&
 | 
			
		||||
          other.ownerId == ownerId &&
 | 
			
		||||
          other.deviceId == deviceId &&
 | 
			
		||||
          other.originalPath == originalPath &&
 | 
			
		||||
          other.resizePath == resizePath &&
 | 
			
		||||
          other.createdAt == createdAt &&
 | 
			
		||||
          other.modifiedAt == modifiedAt &&
 | 
			
		||||
          other.isFavorite == isFavorite &&
 | 
			
		||||
          other.mimeType == mimeType &&
 | 
			
		||||
          other.duration == duration &&
 | 
			
		||||
          other.webpPath == webpPath &&
 | 
			
		||||
          other.encodedVideoPath == encodedVideoPath &&
 | 
			
		||||
          other.exifInfo == exifInfo &&
 | 
			
		||||
          other.smartInfo == smartInfo;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (type.hashCode) +
 | 
			
		||||
    (id.hashCode) +
 | 
			
		||||
    (deviceAssetId.hashCode) +
 | 
			
		||||
    (ownerId.hashCode) +
 | 
			
		||||
    (deviceId.hashCode) +
 | 
			
		||||
    (originalPath.hashCode) +
 | 
			
		||||
    (resizePath == null ? 0 : resizePath!.hashCode) +
 | 
			
		||||
    (createdAt.hashCode) +
 | 
			
		||||
    (modifiedAt.hashCode) +
 | 
			
		||||
    (isFavorite.hashCode) +
 | 
			
		||||
    (mimeType == null ? 0 : mimeType!.hashCode) +
 | 
			
		||||
    (duration.hashCode) +
 | 
			
		||||
    (webpPath == null ? 0 : webpPath!.hashCode) +
 | 
			
		||||
    (encodedVideoPath == null ? 0 : encodedVideoPath!.hashCode) +
 | 
			
		||||
    (exifInfo == null ? 0 : exifInfo!.hashCode) +
 | 
			
		||||
    (smartInfo == null ? 0 : smartInfo!.hashCode);
 | 
			
		||||
      // ignore: unnecessary_parenthesis
 | 
			
		||||
      (type.hashCode) +
 | 
			
		||||
      (id.hashCode) +
 | 
			
		||||
      (deviceAssetId.hashCode) +
 | 
			
		||||
      (ownerId.hashCode) +
 | 
			
		||||
      (deviceId.hashCode) +
 | 
			
		||||
      (originalPath.hashCode) +
 | 
			
		||||
      (resizePath == null ? 0 : resizePath!.hashCode) +
 | 
			
		||||
      (createdAt.hashCode) +
 | 
			
		||||
      (modifiedAt.hashCode) +
 | 
			
		||||
      (isFavorite.hashCode) +
 | 
			
		||||
      (mimeType == null ? 0 : mimeType!.hashCode) +
 | 
			
		||||
      (duration.hashCode) +
 | 
			
		||||
      (webpPath == null ? 0 : webpPath!.hashCode) +
 | 
			
		||||
      (encodedVideoPath == null ? 0 : encodedVideoPath!.hashCode) +
 | 
			
		||||
      (exifInfo == null ? 0 : exifInfo!.hashCode) +
 | 
			
		||||
      (smartInfo == null ? 0 : smartInfo!.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, createdAt=$createdAt, modifiedAt=$modifiedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo]';
 | 
			
		||||
  String toString() =>
 | 
			
		||||
      'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, createdAt=$createdAt, modifiedAt=$modifiedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final _json = <String, dynamic>{};
 | 
			
		||||
      _json[r'type'] = type;
 | 
			
		||||
      _json[r'id'] = id;
 | 
			
		||||
      _json[r'deviceAssetId'] = deviceAssetId;
 | 
			
		||||
      _json[r'ownerId'] = ownerId;
 | 
			
		||||
      _json[r'deviceId'] = deviceId;
 | 
			
		||||
      _json[r'originalPath'] = originalPath;
 | 
			
		||||
    _json[r'type'] = type;
 | 
			
		||||
    _json[r'id'] = id;
 | 
			
		||||
    _json[r'deviceAssetId'] = deviceAssetId;
 | 
			
		||||
    _json[r'ownerId'] = ownerId;
 | 
			
		||||
    _json[r'deviceId'] = deviceId;
 | 
			
		||||
    _json[r'originalPath'] = originalPath;
 | 
			
		||||
    if (resizePath != null) {
 | 
			
		||||
      _json[r'resizePath'] = resizePath;
 | 
			
		||||
    } else {
 | 
			
		||||
      _json[r'resizePath'] = null;
 | 
			
		||||
    }
 | 
			
		||||
      _json[r'createdAt'] = createdAt;
 | 
			
		||||
      _json[r'modifiedAt'] = modifiedAt;
 | 
			
		||||
      _json[r'isFavorite'] = isFavorite;
 | 
			
		||||
    _json[r'createdAt'] = createdAt;
 | 
			
		||||
    _json[r'modifiedAt'] = modifiedAt;
 | 
			
		||||
    _json[r'isFavorite'] = isFavorite;
 | 
			
		||||
    if (mimeType != null) {
 | 
			
		||||
      _json[r'mimeType'] = mimeType;
 | 
			
		||||
    } else {
 | 
			
		||||
      _json[r'mimeType'] = null;
 | 
			
		||||
    }
 | 
			
		||||
      _json[r'duration'] = duration;
 | 
			
		||||
    _json[r'duration'] = duration;
 | 
			
		||||
    if (webpPath != null) {
 | 
			
		||||
      _json[r'webpPath'] = webpPath;
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -172,13 +175,15 @@ class AssetResponseDto {
 | 
			
		||||
      // Ensure that the map contains the required keys.
 | 
			
		||||
      // Note 1: the values aren't checked for validity beyond being non-null.
 | 
			
		||||
      // Note 2: this code is stripped in release mode!
 | 
			
		||||
      assert(() {
 | 
			
		||||
        requiredKeys.forEach((key) {
 | 
			
		||||
          assert(json.containsKey(key), 'Required key "AssetResponseDto[$key]" is missing from JSON.');
 | 
			
		||||
          assert(json[key] != null, 'Required key "AssetResponseDto[$key]" has a null value in JSON.');
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }());
 | 
			
		||||
      // assert(() {
 | 
			
		||||
      //   requiredKeys.forEach((key) {
 | 
			
		||||
      //     assert(json.containsKey(key),
 | 
			
		||||
      //         'Required key "AssetResponseDto[$key]" is missing from JSON.');
 | 
			
		||||
      //     assert(json[key] != null,
 | 
			
		||||
      //         'Required key "AssetResponseDto[$key]" has a null value in JSON.');
 | 
			
		||||
      //   });
 | 
			
		||||
      //   return true;
 | 
			
		||||
      // }());
 | 
			
		||||
 | 
			
		||||
      return AssetResponseDto(
 | 
			
		||||
        type: AssetTypeEnum.fromJson(json[r'type'])!,
 | 
			
		||||
@@ -202,7 +207,10 @@ class AssetResponseDto {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<AssetResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
  static List<AssetResponseDto>? listFromJson(
 | 
			
		||||
    dynamic json, {
 | 
			
		||||
    bool growable = false,
 | 
			
		||||
  }) {
 | 
			
		||||
    final result = <AssetResponseDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
@@ -230,12 +238,18 @@ class AssetResponseDto {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of AssetResponseDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<AssetResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
  static Map<String, List<AssetResponseDto>> mapListFromJson(
 | 
			
		||||
    dynamic json, {
 | 
			
		||||
    bool growable = false,
 | 
			
		||||
  }) {
 | 
			
		||||
    final map = <String, List<AssetResponseDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = AssetResponseDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
        final value = AssetResponseDto.listFromJson(
 | 
			
		||||
          entry.value,
 | 
			
		||||
          growable: growable,
 | 
			
		||||
        );
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
@@ -262,4 +276,3 @@ class AssetResponseDto {
 | 
			
		||||
    'encodedVideoPath',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -126,21 +126,21 @@ packages:
 | 
			
		||||
      name: cached_network_image
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "3.2.1"
 | 
			
		||||
    version: "3.2.2"
 | 
			
		||||
  cached_network_image_platform_interface:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: cached_network_image_platform_interface
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "1.0.0"
 | 
			
		||||
    version: "2.0.0"
 | 
			
		||||
  cached_network_image_web:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: cached_network_image_web
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "1.0.1"
 | 
			
		||||
    version: "1.0.2"
 | 
			
		||||
  cancellation_token:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@@ -1343,5 +1343,5 @@ packages:
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "3.1.1"
 | 
			
		||||
sdks:
 | 
			
		||||
  dart: ">=2.17.0 <3.0.0"
 | 
			
		||||
  flutter: ">=3.0.0"
 | 
			
		||||
  dart: ">=2.18.0 <3.0.0"
 | 
			
		||||
  flutter: ">=3.3.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ dependencies:
 | 
			
		||||
  hive: ^2.2.1
 | 
			
		||||
  hive_flutter: ^1.1.0
 | 
			
		||||
  dio: ^4.0.4
 | 
			
		||||
  cached_network_image: ^3.2.1
 | 
			
		||||
  cached_network_image: ^3.2.2
 | 
			
		||||
  percent_indicator: ^4.2.2
 | 
			
		||||
  intl: ^0.17.0
 | 
			
		||||
  auto_route: ^4.0.1
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user