feat(mobile): show local assets (#905)

* introduce Asset as composition of AssetResponseDTO and AssetEntity

* filter out duplicate assets (that are both local and remote, take only remote for now)

* only allow remote images to be added to albums

* introduce ImmichImage to render Asset using local or remote data

* optimized deletion of local assets

* local video file playback

* allow multiple methods to wait on background service finished

* skip local assets when adding to album from home screen

* fix and optimize delete

* show gray box placeholder for local assets

* add comments

* fix bug: duplicate assets in state after onNewAssetUploaded
This commit is contained in:
Fynn Petersen-Frey
2022-11-08 18:00:24 +01:00
committed by GitHub
parent 99da181cfc
commit 1633af7af6
41 changed files with 830 additions and 514 deletions

View File

@@ -1,18 +1,15 @@
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: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/routing/router.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
import 'package:openapi/api.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/ui/immich_image.dart';
class ThumbnailImage extends HookConsumerWidget {
final AssetResponseDto asset;
final List<AssetResponseDto> assetList;
final Asset asset;
final List<Asset> assetList;
final bool showStorageIndicator;
final bool useGrayBoxPlaceholder;
final bool isSelected;
@@ -34,12 +31,9 @@ class ThumbnailImage extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
var box = Hive.box(userInfoBox);
var thumbnailRequestUrl = getThumbnailUrl(asset);
var deviceId = ref.watch(authenticationProvider).deviceId;
Widget buildSelectionIcon(AssetResponseDto asset) {
Widget buildSelectionIcon(Asset asset) {
if (isSelected) {
return Icon(
Icons.check_circle,
@@ -87,41 +81,11 @@ class ThumbnailImage extends HookConsumerWidget {
)
: const Border(),
),
child: CachedNetworkImage(
cacheKey: 'thumbnail-image-${asset.id}',
child: ImmichImage(
asset,
width: 300,
height: 300,
memCacheHeight: 200,
maxWidthDiskCache: 200,
maxHeightDiskCache: 200,
fit: BoxFit.cover,
imageUrl: thumbnailRequestUrl,
httpHeaders: {
"Authorization": "Bearer ${box.get(accessTokenKey)}"
},
fadeInDuration: const Duration(milliseconds: 250),
progressIndicatorBuilder: (context, url, downloadProgress) {
if (useGrayBoxPlaceholder) {
return const DecoratedBox(
decoration: BoxDecoration(color: Colors.grey),
);
}
return Transform.scale(
scale: 0.2,
child: CircularProgressIndicator(
value: downloadProgress.progress,
),
);
},
errorWidget: (context, url, error) {
debugPrint("Error getting thumbnail $url = $error");
CachedNetworkImage.evictFromCache(thumbnailRequestUrl);
return Icon(
Icons.image_not_supported_outlined,
color: Theme.of(context).primaryColor,
);
},
useGrayBoxPlaceholder: useGrayBoxPlaceholder,
),
),
if (multiselectEnabled)
@@ -137,14 +101,16 @@ class ThumbnailImage extends HookConsumerWidget {
right: 10,
bottom: 5,
child: Icon(
(deviceId != asset.deviceId)
? Icons.cloud_done_outlined
: Icons.photo_library_rounded,
asset.isRemote
? (deviceId == asset.deviceId
? Icons.cloud_done_outlined
: Icons.cloud_outlined)
: Icons.cloud_off_outlined,
color: Colors.white,
size: 18,
),
),
if (asset.type != AssetTypeEnum.IMAGE)
if (!asset.isImage)
Positioned(
top: 5,
right: 5,