You've already forked immich
							
							
				mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 00:18:28 +02:00 
			
		
		
		
	Mobile performance improvements (#417)
* First performance tweaks (caching and rendering improvemetns) * Revert asset response caching * 3-step image loading in asset viewer * Prevent panning and zooming until full-scale version is loaded * Loading indicator * Adapt to gallery PR * Cleanup * Dart format * Fix exif sheet * Disable three stage loading until settings are available
This commit is contained in:
		| @@ -1,6 +1,8 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:flutter_displaymode/flutter_displaymode.dart'; | ||||
| import 'package:hive_flutter/hive_flutter.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:immich_mobile/constants/immich_colors.dart'; | ||||
| @@ -49,6 +51,10 @@ void main() async { | ||||
|     Locale('it', 'IT'), | ||||
|   ]; | ||||
|  | ||||
|   if (kReleaseMode) { | ||||
|     await FlutterDisplayMode.setHighRefreshRate(); | ||||
|   } | ||||
|  | ||||
|   runApp( | ||||
|     EasyLocalization( | ||||
|       supportedLocales: locales, | ||||
|   | ||||
| @@ -8,6 +8,7 @@ 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/utils/image_url_builder.dart'; | ||||
| import 'package:openapi/api.dart'; | ||||
|  | ||||
| class AlbumViewerThumbnail extends HookConsumerWidget { | ||||
| @@ -24,8 +25,7 @@ class AlbumViewerThumbnail extends HookConsumerWidget { | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final cacheKey = useState(1); | ||||
|     var box = Hive.box(userInfoBox); | ||||
|     var thumbnailRequestUrl = | ||||
|         '${box.get(serverEndpointKey)}/asset/thumbnail/${asset.id}'; | ||||
|     var thumbnailRequestUrl = getThumbnailUrl(asset); | ||||
|     var deviceId = ref.watch(authenticationProvider).deviceId; | ||||
|     final selectedAssetsInAlbumViewer = | ||||
|         ref.watch(assetSelectionProvider).selectedAssetsInAlbumViewer; | ||||
| @@ -37,7 +37,6 @@ class AlbumViewerThumbnail extends HookConsumerWidget { | ||||
|         GalleryViewerRoute( | ||||
|           asset: asset, | ||||
|           assetList: assetList, | ||||
|           thumbnailRequestUrl: thumbnailRequestUrl, | ||||
|         ), | ||||
|       ); | ||||
|     } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ 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/utils/image_url_builder.dart'; | ||||
| import 'package:openapi/api.dart'; | ||||
|  | ||||
| class SharedAlbumThumbnailImage extends HookConsumerWidget { | ||||
| @@ -17,8 +18,6 @@ class SharedAlbumThumbnailImage extends HookConsumerWidget { | ||||
|     final cacheKey = useState(1); | ||||
|  | ||||
|     var box = Hive.box(userInfoBox); | ||||
|     var thumbnailRequestUrl = | ||||
|         '${box.get(serverEndpointKey)}/asset/thumbnail/${asset.id}'; | ||||
|  | ||||
|     return GestureDetector( | ||||
|       onTap: () { | ||||
| @@ -32,7 +31,7 @@ class SharedAlbumThumbnailImage extends HookConsumerWidget { | ||||
|             height: 500, | ||||
|             memCacheHeight: 500, | ||||
|             fit: BoxFit.cover, | ||||
|             imageUrl: thumbnailRequestUrl, | ||||
|             imageUrl: getThumbnailUrl(asset), | ||||
|             httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"}, | ||||
|             fadeInDuration: const Duration(milliseconds: 250), | ||||
|             progressIndicatorBuilder: (context, url, downloadProgress) => | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import 'package:flutter/cupertino.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:photo_view/photo_view.dart'; | ||||
|  | ||||
| enum _RemoteImageStatus { empty, thumbnail, full } | ||||
| enum _RemoteImageStatus { empty, thumbnail, preview, full } | ||||
|  | ||||
| class _RemotePhotoViewState extends State<RemotePhotoView> { | ||||
|   late CachedNetworkImageProvider _imageProvider; | ||||
| @@ -15,13 +15,16 @@ class _RemotePhotoViewState extends State<RemotePhotoView> { | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     bool allowMoving = _status == _RemoteImageStatus.full; | ||||
|     return PhotoView( | ||||
|  | ||||
|     return IgnorePointer( | ||||
|       ignoring: !allowMoving, | ||||
|       child: PhotoView( | ||||
|         imageProvider: _imageProvider, | ||||
|         minScale: PhotoViewComputedScale.contained, | ||||
|       maxScale: allowMoving ? 1.0 : PhotoViewComputedScale.contained, | ||||
|         enablePanAlways: true, | ||||
|         scaleStateChangedCallback: _scaleStateChanged, | ||||
|         onScaleEnd: _onScaleListener, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| @@ -52,6 +55,14 @@ class _RemotePhotoViewState extends State<RemotePhotoView> { | ||||
|     widget.isZoomedFunction(); | ||||
|   } | ||||
|  | ||||
|   void _fireStartLoadingEvent() { | ||||
|     if (widget.onLoadingStart != null) widget.onLoadingStart!(); | ||||
|   } | ||||
|  | ||||
|   void _fireFinishedLoadingEvent() { | ||||
|     if (widget.onLoadingCompleted != null) widget.onLoadingCompleted!(); | ||||
|   } | ||||
|  | ||||
|   CachedNetworkImageProvider _authorizedImageProvider(String url) { | ||||
|     return CachedNetworkImageProvider( | ||||
|       url, | ||||
| @@ -64,14 +75,25 @@ class _RemotePhotoViewState extends State<RemotePhotoView> { | ||||
|     _RemoteImageStatus newStatus, | ||||
|     CachedNetworkImageProvider provider, | ||||
|   ) { | ||||
|     // Transition to same status is forbidden | ||||
|     if (_status == newStatus) return; | ||||
|     // Transition full -> thumbnail is forbidden | ||||
|  | ||||
|     if (_status == _RemoteImageStatus.full && | ||||
|         newStatus == _RemoteImageStatus.thumbnail) return; | ||||
|  | ||||
|     if (_status == _RemoteImageStatus.preview && | ||||
|         newStatus == _RemoteImageStatus.thumbnail) return; | ||||
|  | ||||
|     if (_status == _RemoteImageStatus.full && | ||||
|         newStatus == _RemoteImageStatus.preview) return; | ||||
|  | ||||
|     if (!mounted) return; | ||||
|  | ||||
|     if (newStatus != _RemoteImageStatus.full) { | ||||
|       _fireStartLoadingEvent(); | ||||
|     } else { | ||||
|       _fireFinishedLoadingEvent(); | ||||
|     } | ||||
|  | ||||
|     setState(() { | ||||
|       _status = newStatus; | ||||
|       _imageProvider = provider; | ||||
| @@ -92,6 +114,16 @@ class _RemotePhotoViewState extends State<RemotePhotoView> { | ||||
|       }), | ||||
|     ); | ||||
|  | ||||
|     if (widget.previewUrl != null) { | ||||
|       CachedNetworkImageProvider previewProvider = | ||||
|           _authorizedImageProvider(widget.previewUrl!); | ||||
|       previewProvider.resolve(const ImageConfiguration()).addListener( | ||||
|         ImageStreamListener((ImageInfo imageInfo, _) { | ||||
|           _performStateTransition(_RemoteImageStatus.preview, previewProvider); | ||||
|         }), | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     CachedNetworkImageProvider fullProvider = | ||||
|         _authorizedImageProvider(widget.imageUrl); | ||||
|     fullProvider.resolve(const ImageConfiguration()).addListener( | ||||
| @@ -109,8 +141,8 @@ class _RemotePhotoViewState extends State<RemotePhotoView> { | ||||
| } | ||||
|  | ||||
| class RemotePhotoView extends StatefulWidget { | ||||
|   const RemotePhotoView({ | ||||
|     Key? key, | ||||
|   const RemotePhotoView( | ||||
|       {Key? key, | ||||
|       required this.thumbnailUrl, | ||||
|       required this.imageUrl, | ||||
|       required this.authToken, | ||||
| @@ -118,11 +150,17 @@ class RemotePhotoView extends StatefulWidget { | ||||
|       required this.isZoomedListener, | ||||
|       required this.onSwipeDown, | ||||
|       required this.onSwipeUp, | ||||
|   }) : super(key: key); | ||||
|       this.previewUrl, | ||||
|       this.onLoadingCompleted, | ||||
|       this.onLoadingStart}) | ||||
|       : super(key: key); | ||||
|  | ||||
|   final String thumbnailUrl; | ||||
|   final String imageUrl; | ||||
|   final String authToken; | ||||
|   final String? previewUrl; | ||||
|   final Function? onLoadingCompleted; | ||||
|   final Function? onLoadingStart; | ||||
|  | ||||
|   final void Function() onSwipeDown; | ||||
|   final void Function() onSwipeUp; | ||||
|   | ||||
| @@ -11,11 +11,13 @@ class TopControlAppBar extends ConsumerWidget with PreferredSizeWidget { | ||||
|     required this.asset, | ||||
|     required this.onMoreInfoPressed, | ||||
|     required this.onDownloadPressed, | ||||
|     this.loading = false | ||||
|   }) : super(key: key); | ||||
|  | ||||
|   final AssetResponseDto asset; | ||||
|   final Function onMoreInfoPressed; | ||||
|   final Function onDownloadPressed; | ||||
|   final bool loading; | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
| @@ -35,6 +37,14 @@ class TopControlAppBar extends ConsumerWidget with PreferredSizeWidget { | ||||
|         ), | ||||
|       ), | ||||
|       actions: [ | ||||
|         if (loading) Center( | ||||
|           child: Container( | ||||
|             margin: const EdgeInsets.symmetric(horizontal: 15.0), | ||||
|             width: iconSize, | ||||
|             height: iconSize, | ||||
|             child: const CircularProgressIndicator(strokeWidth: 2.0), | ||||
|           ), | ||||
|         ) , | ||||
|         IconButton( | ||||
|           iconSize: iconSize, | ||||
|           splashRadius: iconSize, | ||||
|   | ||||
| @@ -17,13 +17,13 @@ import 'package:openapi/api.dart'; | ||||
| class GalleryViewerPage extends HookConsumerWidget { | ||||
|   late List<AssetResponseDto> assetList; | ||||
|   final AssetResponseDto asset; | ||||
|   final String thumbnailRequestUrl; | ||||
|  | ||||
|   static const _threeStageLoading = false; | ||||
|  | ||||
|   GalleryViewerPage({ | ||||
|     Key? key, | ||||
|     required this.assetList, | ||||
|     required this.asset, | ||||
|     required this.thumbnailRequestUrl, | ||||
|   }) : super(key: key); | ||||
|  | ||||
|   AssetResponseDto? assetDetail; | ||||
| @@ -32,6 +32,7 @@ class GalleryViewerPage extends HookConsumerWidget { | ||||
|     final Box<dynamic> box = Hive.box(userInfoBox); | ||||
|  | ||||
|     int indexOfAsset = assetList.indexOf(asset); | ||||
|     final loading = useState(false); | ||||
|  | ||||
|     @override | ||||
|     void initState(int index) { | ||||
| @@ -74,6 +75,7 @@ class GalleryViewerPage extends HookConsumerWidget { | ||||
|     return Scaffold( | ||||
|       backgroundColor: Colors.black, | ||||
|       appBar: TopControlAppBar( | ||||
|         loading: loading.value, | ||||
|         asset: assetList[indexOfAsset], | ||||
|         onMoreInfoPressed: () { | ||||
|           showInfo(); | ||||
| @@ -98,15 +100,14 @@ class GalleryViewerPage extends HookConsumerWidget { | ||||
|             getAssetExif(); | ||||
|             if (assetList[index].type == AssetTypeEnum.IMAGE) { | ||||
|               return ImageViewerPage( | ||||
|                 thumbnailUrl: | ||||
|                     '${box.get(serverEndpointKey)}/asset/thumbnail/${assetList[index].id}', | ||||
|                 imageUrl: | ||||
|                     '${box.get(serverEndpointKey)}/asset/file?aid=${assetList[index].deviceAssetId}&did=${assetList[index].deviceId}&isThumb=false', | ||||
|                 authToken: 'Bearer ${box.get(accessTokenKey)}', | ||||
|                 isZoomedFunction: isZoomedMethod, | ||||
|                 isZoomedListener: isZoomedListener, | ||||
|                 onLoadingCompleted: () => loading.value = false, | ||||
|                 onLoadingStart: () => loading.value = _threeStageLoading, | ||||
|                 asset: assetList[index], | ||||
|                 heroTag: assetList[index].id, | ||||
|                 threeStageLoading: _threeStageLoading | ||||
|               ); | ||||
|             } else { | ||||
|               return SwipeDetector( | ||||
|   | ||||
| @@ -8,27 +8,30 @@ 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/utils/image_url_builder.dart'; | ||||
| import 'package:openapi/api.dart'; | ||||
|  | ||||
| // ignore: must_be_immutable | ||||
| class ImageViewerPage extends HookConsumerWidget { | ||||
|   final String imageUrl; | ||||
|   final String heroTag; | ||||
|   final String thumbnailUrl; | ||||
|   final AssetResponseDto asset; | ||||
|   final String authToken; | ||||
|   final ValueNotifier<bool> isZoomedListener; | ||||
|   final void Function() isZoomedFunction; | ||||
|   final void Function() onLoadingCompleted; | ||||
|   final void Function() onLoadingStart; | ||||
|   final bool threeStageLoading; | ||||
|  | ||||
|   ImageViewerPage({ | ||||
|     Key? key, | ||||
|     required this.imageUrl, | ||||
|     required this.heroTag, | ||||
|     required this.thumbnailUrl, | ||||
|     required this.asset, | ||||
|     required this.authToken, | ||||
|     required this.isZoomedFunction, | ||||
|     required this.isZoomedListener, | ||||
|     required this.onLoadingCompleted, | ||||
|     required this.onLoadingStart, | ||||
|     required this.threeStageLoading, | ||||
|   }) : super(key: key); | ||||
|  | ||||
|   AssetResponseDto? assetDetail; | ||||
| @@ -68,14 +71,18 @@ class ImageViewerPage extends HookConsumerWidget { | ||||
|           child: Hero( | ||||
|             tag: heroTag, | ||||
|             child: RemotePhotoView( | ||||
|               thumbnailUrl: thumbnailUrl, | ||||
|               imageUrl: imageUrl, | ||||
|                 thumbnailUrl: getThumbnailUrl(asset), | ||||
|                 imageUrl: getImageUrl(asset), | ||||
|                 previewUrl: threeStageLoading | ||||
|                     ? getThumbnailUrl(asset, type: ThumbnailFormat.JPEG) | ||||
|                     : null, | ||||
|                 authToken: authToken, | ||||
|                 isZoomedFunction: isZoomedFunction, | ||||
|                 isZoomedListener: isZoomedListener, | ||||
|                 onSwipeDown: () => AutoRouter.of(context).pop(), | ||||
|                 onSwipeUp: () => showInfo(), | ||||
|             ), | ||||
|                 onLoadingCompleted: onLoadingCompleted, | ||||
|                 onLoadingStart: onLoadingStart), | ||||
|           ), | ||||
|         ), | ||||
|         if (downloadAssetStatus == DownloadAssetStatus.loading) | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import 'package:immich_mobile/constants/hive_box.dart'; | ||||
| import 'package:immich_mobile/modules/home/providers/home_page_state.provider.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'; | ||||
|  | ||||
| class ThumbnailImage extends HookConsumerWidget { | ||||
| @@ -23,8 +24,7 @@ class ThumbnailImage extends HookConsumerWidget { | ||||
|     final cacheKey = useState(1); | ||||
|  | ||||
|     var box = Hive.box(userInfoBox); | ||||
|     var thumbnailRequestUrl = | ||||
|         '${box.get(serverEndpointKey)}/asset/thumbnail/${asset.id}'; | ||||
|     var thumbnailRequestUrl = getThumbnailUrl(asset); | ||||
|     var selectedAsset = ref.watch(homePageStateProvider).selectedItems; | ||||
|     var isMultiSelectEnable = | ||||
|         ref.watch(homePageStateProvider).isMultiSelectEnable; | ||||
| @@ -65,7 +65,6 @@ class ThumbnailImage extends HookConsumerWidget { | ||||
|           AutoRouter.of(context).push( | ||||
|             GalleryViewerRoute( | ||||
|               assetList: assetList, | ||||
|               thumbnailRequestUrl: thumbnailRequestUrl, | ||||
|               asset: asset, | ||||
|             ), | ||||
|           ); | ||||
|   | ||||
| @@ -76,6 +76,7 @@ class HomePage extends HookConsumerWidget { | ||||
|  | ||||
|           imageGridGroup.add( | ||||
|             DailyTitleText( | ||||
|               key: Key('${dateGroup.toString()}title'), | ||||
|               isoDate: dateGroup, | ||||
|               assetGroup: immichAssetList, | ||||
|             ), | ||||
|   | ||||
| @@ -46,10 +46,7 @@ class _$AppRouter extends RootStackRouter { | ||||
|       return MaterialPageX<dynamic>( | ||||
|           routeData: routeData, | ||||
|           child: GalleryViewerPage( | ||||
|               key: args.key, | ||||
|               assetList: args.assetList, | ||||
|               asset: args.asset, | ||||
|               thumbnailRequestUrl: args.thumbnailRequestUrl)); | ||||
|               key: args.key, assetList: args.assetList, asset: args.asset)); | ||||
|     }, | ||||
|     ImageViewerRoute.name: (routeData) { | ||||
|       final args = routeData.argsAs<ImageViewerRouteArgs>(); | ||||
| @@ -57,13 +54,14 @@ class _$AppRouter extends RootStackRouter { | ||||
|           routeData: routeData, | ||||
|           child: ImageViewerPage( | ||||
|               key: args.key, | ||||
|               imageUrl: args.imageUrl, | ||||
|               heroTag: args.heroTag, | ||||
|               thumbnailUrl: args.thumbnailUrl, | ||||
|               asset: args.asset, | ||||
|               authToken: args.authToken, | ||||
|               isZoomedFunction: args.isZoomedFunction, | ||||
|               isZoomedListener: args.isZoomedListener)); | ||||
|               isZoomedListener: args.isZoomedListener, | ||||
|               onLoadingCompleted: args.onLoadingCompleted, | ||||
|               onLoadingStart: args.onLoadingStart, | ||||
|               threeStageLoading: args.threeStageLoading)); | ||||
|     }, | ||||
|     VideoViewerRoute.name: (routeData) { | ||||
|       final args = routeData.argsAs<VideoViewerRouteArgs>(); | ||||
| @@ -258,25 +256,18 @@ class GalleryViewerRoute extends PageRouteInfo<GalleryViewerRouteArgs> { | ||||
|   GalleryViewerRoute( | ||||
|       {Key? key, | ||||
|       required List<AssetResponseDto> assetList, | ||||
|       required AssetResponseDto asset, | ||||
|       required String thumbnailRequestUrl}) | ||||
|       required AssetResponseDto asset}) | ||||
|       : super(GalleryViewerRoute.name, | ||||
|             path: '/gallery-viewer-page', | ||||
|             args: GalleryViewerRouteArgs( | ||||
|                 key: key, | ||||
|                 assetList: assetList, | ||||
|                 asset: asset, | ||||
|                 thumbnailRequestUrl: thumbnailRequestUrl)); | ||||
|                 key: key, assetList: assetList, asset: asset)); | ||||
|  | ||||
|   static const String name = 'GalleryViewerRoute'; | ||||
| } | ||||
|  | ||||
| class GalleryViewerRouteArgs { | ||||
|   const GalleryViewerRouteArgs( | ||||
|       {this.key, | ||||
|       required this.assetList, | ||||
|       required this.asset, | ||||
|       required this.thumbnailRequestUrl}); | ||||
|       {this.key, required this.assetList, required this.asset}); | ||||
|  | ||||
|   final Key? key; | ||||
|  | ||||
| @@ -284,11 +275,9 @@ class GalleryViewerRouteArgs { | ||||
|  | ||||
|   final AssetResponseDto asset; | ||||
|  | ||||
|   final String thumbnailRequestUrl; | ||||
|  | ||||
|   @override | ||||
|   String toString() { | ||||
|     return 'GalleryViewerRouteArgs{key: $key, assetList: $assetList, asset: $asset, thumbnailRequestUrl: $thumbnailRequestUrl}'; | ||||
|     return 'GalleryViewerRouteArgs{key: $key, assetList: $assetList, asset: $asset}'; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -297,24 +286,26 @@ class GalleryViewerRouteArgs { | ||||
| class ImageViewerRoute extends PageRouteInfo<ImageViewerRouteArgs> { | ||||
|   ImageViewerRoute( | ||||
|       {Key? key, | ||||
|       required String imageUrl, | ||||
|       required String heroTag, | ||||
|       required String thumbnailUrl, | ||||
|       required AssetResponseDto asset, | ||||
|       required String authToken, | ||||
|       required void Function() isZoomedFunction, | ||||
|       required ValueNotifier<bool> isZoomedListener}) | ||||
|       required ValueNotifier<bool> isZoomedListener, | ||||
|       required void Function() onLoadingCompleted, | ||||
|       required void Function() onLoadingStart, | ||||
|       required bool threeStageLoading}) | ||||
|       : super(ImageViewerRoute.name, | ||||
|             path: '/image-viewer-page', | ||||
|             args: ImageViewerRouteArgs( | ||||
|                 key: key, | ||||
|                 imageUrl: imageUrl, | ||||
|                 heroTag: heroTag, | ||||
|                 thumbnailUrl: thumbnailUrl, | ||||
|                 asset: asset, | ||||
|                 authToken: authToken, | ||||
|                 isZoomedFunction: isZoomedFunction, | ||||
|                 isZoomedListener: isZoomedListener)); | ||||
|                 isZoomedListener: isZoomedListener, | ||||
|                 onLoadingCompleted: onLoadingCompleted, | ||||
|                 onLoadingStart: onLoadingStart, | ||||
|                 threeStageLoading: threeStageLoading)); | ||||
|  | ||||
|   static const String name = 'ImageViewerRoute'; | ||||
| } | ||||
| @@ -322,22 +313,19 @@ class ImageViewerRoute extends PageRouteInfo<ImageViewerRouteArgs> { | ||||
| class ImageViewerRouteArgs { | ||||
|   const ImageViewerRouteArgs( | ||||
|       {this.key, | ||||
|       required this.imageUrl, | ||||
|       required this.heroTag, | ||||
|       required this.thumbnailUrl, | ||||
|       required this.asset, | ||||
|       required this.authToken, | ||||
|       required this.isZoomedFunction, | ||||
|       required this.isZoomedListener}); | ||||
|       required this.isZoomedListener, | ||||
|       required this.onLoadingCompleted, | ||||
|       required this.onLoadingStart, | ||||
|       required this.threeStageLoading}); | ||||
|  | ||||
|   final Key? key; | ||||
|  | ||||
|   final String imageUrl; | ||||
|  | ||||
|   final String heroTag; | ||||
|  | ||||
|   final String thumbnailUrl; | ||||
|  | ||||
|   final AssetResponseDto asset; | ||||
|  | ||||
|   final String authToken; | ||||
| @@ -346,9 +334,15 @@ class ImageViewerRouteArgs { | ||||
|  | ||||
|   final ValueNotifier<bool> isZoomedListener; | ||||
|  | ||||
|   final void Function() onLoadingCompleted; | ||||
|  | ||||
|   final void Function() onLoadingStart; | ||||
|  | ||||
|   final bool threeStageLoading; | ||||
|  | ||||
|   @override | ||||
|   String toString() { | ||||
|     return 'ImageViewerRouteArgs{key: $key, imageUrl: $imageUrl, heroTag: $heroTag, thumbnailUrl: $thumbnailUrl, asset: $asset, authToken: $authToken, isZoomedFunction: $isZoomedFunction, isZoomedListener: $isZoomedListener}'; | ||||
|     return 'ImageViewerRouteArgs{key: $key, heroTag: $heroTag, asset: $asset, authToken: $authToken, isZoomedFunction: $isZoomedFunction, isZoomedListener: $isZoomedListener, onLoadingCompleted: $onLoadingCompleted, onLoadingStart: $onLoadingStart, threeStageLoading: $threeStageLoading}'; | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								mobile/lib/utils/image_url_builder.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mobile/lib/utils/image_url_builder.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| import 'package:hive/hive.dart'; | ||||
| import 'package:openapi/api.dart'; | ||||
|  | ||||
| import '../constants/hive_box.dart'; | ||||
|  | ||||
| String getThumbnailUrl(final AssetResponseDto asset, | ||||
|     {ThumbnailFormat type = ThumbnailFormat.WEBP}) { | ||||
|   final box = Hive.box(userInfoBox); | ||||
|  | ||||
|   return '${box.get(serverEndpointKey)}/asset/thumbnail/${asset.id}?format=${type.value}'; | ||||
| } | ||||
|  | ||||
| String getImageUrl(final AssetResponseDto asset) { | ||||
|   final box = Hive.box(userInfoBox); | ||||
|   return '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=false'; | ||||
| } | ||||
| @@ -328,6 +328,13 @@ packages: | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "3.3.0" | ||||
|   flutter_displaymode: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: flutter_displaymode | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "0.4.0" | ||||
|   flutter_hooks: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|   | ||||
| @@ -41,6 +41,7 @@ dependencies: | ||||
|   http: 0.13.4 | ||||
|   cancellation_token_http: ^1.1.0 | ||||
|   easy_localization: ^3.0.1 | ||||
|   flutter_displaymode: ^0.4.0 | ||||
|  | ||||
|   path: ^1.8.1 | ||||
|   path_provider: ^2.0.11 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user