mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +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:
parent
46f4905259
commit
b46e834220
@ -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(
|
||||
imageProvider: _imageProvider,
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
maxScale: allowMoving ? 1.0 : PhotoViewComputedScale.contained,
|
||||
enablePanAlways: true,
|
||||
scaleStateChangedCallback: _scaleStateChanged,
|
||||
onScaleEnd: _onScaleListener,
|
||||
|
||||
return IgnorePointer(
|
||||
ignoring: !allowMoving,
|
||||
child: PhotoView(
|
||||
imageProvider: _imageProvider,
|
||||
minScale: 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,20 +141,26 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
|
||||
}
|
||||
|
||||
class RemotePhotoView extends StatefulWidget {
|
||||
const RemotePhotoView({
|
||||
Key? key,
|
||||
required this.thumbnailUrl,
|
||||
required this.imageUrl,
|
||||
required this.authToken,
|
||||
required this.isZoomedFunction,
|
||||
required this.isZoomedListener,
|
||||
required this.onSwipeDown,
|
||||
required this.onSwipeUp,
|
||||
}) : super(key: key);
|
||||
const RemotePhotoView(
|
||||
{Key? key,
|
||||
required this.thumbnailUrl,
|
||||
required this.imageUrl,
|
||||
required this.authToken,
|
||||
required this.isZoomedFunction,
|
||||
required this.isZoomedListener,
|
||||
required this.onSwipeDown,
|
||||
required this.onSwipeUp,
|
||||
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,
|
||||
authToken: authToken,
|
||||
isZoomedFunction: isZoomedFunction,
|
||||
isZoomedListener: isZoomedListener,
|
||||
onSwipeDown: () => AutoRouter.of(context).pop(),
|
||||
onSwipeUp: () => showInfo(),
|
||||
),
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user