mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
feature(mobile): allow app to be used offline (#1932)
* feature(mobile): allow app to be used offline * translatable server/network error message * adjust profile drawer error message * call getAllAsset after cold app starts * fix analyzer error * update asset state if length differs --------- Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
parent
54831878e0
commit
04955a4123
@ -101,6 +101,7 @@
|
|||||||
"common_change_password": "Change Password",
|
"common_change_password": "Change Password",
|
||||||
"common_create_new_album": "Create new album",
|
"common_create_new_album": "Create new album",
|
||||||
"common_shared": "Shared",
|
"common_shared": "Shared",
|
||||||
|
"common_server_error": "Please check your network connection, make sure the server is reachable and app/server versions are compatible.",
|
||||||
"control_bottom_app_bar_add_to_album": "Add to album",
|
"control_bottom_app_bar_add_to_album": "Add to album",
|
||||||
"control_bottom_app_bar_album_info": "{} items",
|
"control_bottom_app_bar_album_info": "{} items",
|
||||||
"control_bottom_app_bar_album_info_shared": "{} items · Shared",
|
"control_bottom_app_bar_album_info_shared": "{} items · Shared",
|
||||||
|
@ -52,6 +52,8 @@ class AlbumThumbnailListTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},
|
httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},
|
||||||
cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
|
cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
|
||||||
|
errorWidget: (context, url, error) =>
|
||||||
|
const Icon(Icons.image_not_supported_outlined),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import 'package:immich_mobile/shared/services/asset.service.dart';
|
|||||||
import 'package:immich_mobile/modules/home/ui/delete_dialog.dart';
|
import 'package:immich_mobile/modules/home/ui/delete_dialog.dart';
|
||||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.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/modules/settings/services/app_settings.service.dart';
|
||||||
|
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
||||||
import 'package:immich_mobile/shared/ui/photo_view/photo_view_gallery.dart';
|
import 'package:immich_mobile/shared/ui/photo_view/photo_view_gallery.dart';
|
||||||
import 'package:immich_mobile/shared/ui/photo_view/src/photo_view_computed_scale.dart';
|
import 'package:immich_mobile/shared/ui/photo_view/src/photo_view_computed_scale.dart';
|
||||||
import 'package:immich_mobile/shared/ui/photo_view/src/photo_view_scale_state.dart';
|
import 'package:immich_mobile/shared/ui/photo_view/src/photo_view_scale_state.dart';
|
||||||
@ -38,8 +39,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.assetList,
|
required this.assetList,
|
||||||
required this.asset,
|
required this.asset,
|
||||||
}) : controller =
|
}) : controller = PageController(initialPage: assetList.indexOf(asset));
|
||||||
PageController(initialPage: assetList.indexOf(asset));
|
|
||||||
|
|
||||||
Asset? assetDetail;
|
Asset? assetDetail;
|
||||||
|
|
||||||
@ -139,12 +139,16 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void precacheNextImage(int index) {
|
void precacheNextImage(int index) {
|
||||||
if (index < assetList.length && index > 0) {
|
if (index < assetList.length && index >= 0) {
|
||||||
final asset = assetList[index];
|
final asset = assetList[index];
|
||||||
|
|
||||||
if (asset.isLocal) {
|
if (asset.isLocal) {
|
||||||
// Preload the local asset
|
// Preload the local asset
|
||||||
precacheImage(localImageProvider(asset), context);
|
precacheImage(localImageProvider(asset), context);
|
||||||
} else {
|
} else {
|
||||||
|
onError(Object exception, StackTrace? stackTrace) {
|
||||||
|
// swallow error silently
|
||||||
|
}
|
||||||
// Probably load WEBP either way
|
// Probably load WEBP either way
|
||||||
precacheImage(
|
precacheImage(
|
||||||
remoteThumbnailImageProvider(
|
remoteThumbnailImageProvider(
|
||||||
@ -152,6 +156,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
api.ThumbnailFormat.WEBP,
|
api.ThumbnailFormat.WEBP,
|
||||||
),
|
),
|
||||||
context,
|
context,
|
||||||
|
onError: onError,
|
||||||
);
|
);
|
||||||
if (isLoadPreview.value) {
|
if (isLoadPreview.value) {
|
||||||
// Precache the JPEG thumbnail
|
// Precache the JPEG thumbnail
|
||||||
@ -161,6 +166,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
api.ThumbnailFormat.JPEG,
|
api.ThumbnailFormat.JPEG,
|
||||||
),
|
),
|
||||||
context,
|
context,
|
||||||
|
onError: onError,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (isLoadOriginal.value) {
|
if (isLoadOriginal.value) {
|
||||||
@ -168,6 +174,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
precacheImage(
|
precacheImage(
|
||||||
originalImageProvider(asset),
|
originalImageProvider(asset),
|
||||||
context,
|
context,
|
||||||
|
onError: onError,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,27 +357,37 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
type: api.ThumbnailFormat.WEBP,
|
type: api.ThumbnailFormat.WEBP,
|
||||||
),
|
),
|
||||||
httpHeaders: {'Authorization': authToken},
|
httpHeaders: {'Authorization': authToken},
|
||||||
progressIndicatorBuilder: (_, __, ___) => const Center(
|
progressIndicatorBuilder: (_, __, ___) =>
|
||||||
|
const Center(
|
||||||
child: ImmichLoadingIndicator(),
|
child: ImmichLoadingIndicator(),
|
||||||
),
|
),
|
||||||
fadeInDuration: const Duration(milliseconds: 0),
|
fadeInDuration: const Duration(milliseconds: 0),
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
|
errorWidget: (context, url, error) =>
|
||||||
|
const Icon(Icons.image_not_supported_outlined),
|
||||||
);
|
);
|
||||||
|
|
||||||
return CachedNetworkImage(
|
if (isLoadOriginal.value) {
|
||||||
imageUrl: getThumbnailUrl(
|
// loading the preview in the loadingBuilder only
|
||||||
asset,
|
// makes sense if the original is loaded in the builder
|
||||||
type: api.ThumbnailFormat.JPEG,
|
return CachedNetworkImage(
|
||||||
),
|
imageUrl: getThumbnailUrl(
|
||||||
cacheKey: getThumbnailCacheKey(
|
asset,
|
||||||
asset,
|
type: api.ThumbnailFormat.JPEG,
|
||||||
type: api.ThumbnailFormat.JPEG,
|
),
|
||||||
),
|
cacheKey: getThumbnailCacheKey(
|
||||||
httpHeaders: {'Authorization': authToken},
|
asset,
|
||||||
fit: BoxFit.contain,
|
type: api.ThumbnailFormat.JPEG,
|
||||||
fadeInDuration: const Duration(milliseconds: 0),
|
),
|
||||||
placeholder: (_, __) => webPThumbnail,
|
httpHeaders: {'Authorization': authToken},
|
||||||
);
|
fit: BoxFit.contain,
|
||||||
|
fadeInDuration: const Duration(milliseconds: 0),
|
||||||
|
placeholder: (_, __) => webPThumbnail,
|
||||||
|
errorWidget: (_, __, ___) => webPThumbnail,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return webPThumbnail;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Image(
|
return Image(
|
||||||
image: localThumbnailImageProvider(asset),
|
image: localThumbnailImageProvider(asset),
|
||||||
@ -389,17 +406,23 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
} else {
|
} else {
|
||||||
if (isLoadOriginal.value) {
|
if (isLoadOriginal.value) {
|
||||||
provider = originalImageProvider(assetList[index]);
|
provider = originalImageProvider(assetList[index]);
|
||||||
} else {
|
} else if (isLoadPreview.value) {
|
||||||
provider = remoteThumbnailImageProvider(
|
provider = remoteThumbnailImageProvider(
|
||||||
assetList[index],
|
assetList[index],
|
||||||
api.ThumbnailFormat.JPEG,
|
api.ThumbnailFormat.JPEG,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
provider = remoteThumbnailImageProvider(
|
||||||
|
assetList[index],
|
||||||
|
api.ThumbnailFormat.WEBP,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PhotoViewGalleryPageOptions(
|
return PhotoViewGalleryPageOptions(
|
||||||
onDragStart: (_, details, __) =>
|
onDragStart: (_, details, __) =>
|
||||||
localPosition = details.localPosition,
|
localPosition = details.localPosition,
|
||||||
onDragUpdate: (_, details, __) => handleSwipeUpDown(details),
|
onDragUpdate: (_, details, __) =>
|
||||||
|
handleSwipeUpDown(details),
|
||||||
onTapDown: (_, __, ___) =>
|
onTapDown: (_, __, ___) =>
|
||||||
showAppBar.value = !showAppBar.value,
|
showAppBar.value = !showAppBar.value,
|
||||||
imageProvider: provider,
|
imageProvider: provider,
|
||||||
@ -409,12 +432,17 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||||||
filterQuality: FilterQuality.high,
|
filterQuality: FilterQuality.high,
|
||||||
tightMode: true,
|
tightMode: true,
|
||||||
minScale: PhotoViewComputedScale.contained,
|
minScale: PhotoViewComputedScale.contained,
|
||||||
|
errorBuilder: (context, error, stackTrace) => ImmichImage(
|
||||||
|
assetList[indexOfAsset.value],
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return PhotoViewGalleryPageOptions.customChild(
|
return PhotoViewGalleryPageOptions.customChild(
|
||||||
onDragStart: (_, details, __) =>
|
onDragStart: (_, details, __) =>
|
||||||
localPosition = details.localPosition,
|
localPosition = details.localPosition,
|
||||||
onDragUpdate: (_, details, __) => handleSwipeUpDown(details),
|
onDragUpdate: (_, details, __) =>
|
||||||
|
handleSwipeUpDown(details),
|
||||||
heroAttributes: PhotoViewHeroAttributes(
|
heroAttributes: PhotoViewHeroAttributes(
|
||||||
tag: assetList[index].id,
|
tag: assetList[index].id,
|
||||||
),
|
),
|
||||||
|
@ -66,6 +66,8 @@ class HomePageAppBar extends ConsumerWidget with PreferredSizeWidget {
|
|||||||
image:
|
image:
|
||||||
'$endpoint/user/profile-image/${authState.userId}?d=${dummy++}',
|
'$endpoint/user/profile-image/${authState.userId}?d=${dummy++}',
|
||||||
fadeInDuration: const Duration(milliseconds: 200),
|
fadeInDuration: const Duration(milliseconds: 200),
|
||||||
|
imageErrorBuilder: (context, error, stackTrace) =>
|
||||||
|
Image.memory(kTransparentImage),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -40,6 +40,8 @@ class ProfileDrawerHeader extends HookConsumerWidget {
|
|||||||
image:
|
image:
|
||||||
'$endpoint/user/profile-image/${authState.userId}?d=${dummy++}',
|
'$endpoint/user/profile-image/${authState.userId}?d=${dummy++}',
|
||||||
fadeInDuration: const Duration(milliseconds: 200),
|
fadeInDuration: const Duration(milliseconds: 200),
|
||||||
|
imageErrorBuilder: (context, error, stackTrace) =>
|
||||||
|
Image.memory(kTransparentImage),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -106,7 +106,9 @@ class ServerInfoBox extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"${serverInfoState.serverVersion.major}.${serverInfoState.serverVersion.minor}.${serverInfoState.serverVersion.patch_}",
|
serverInfoState.serverVersion.major > 0
|
||||||
|
? "${serverInfoState.serverVersion.major}.${serverInfoState.serverVersion.minor}.${serverInfoState.serverVersion.patch_}"
|
||||||
|
: "?",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Colors.grey[500],
|
color: Colors.grey[500],
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
@ -145,7 +147,14 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
required String serverUrl,
|
required String serverUrl,
|
||||||
}) async {
|
}) async {
|
||||||
_apiService.setAccessToken(accessToken);
|
_apiService.setAccessToken(accessToken);
|
||||||
var userResponseDto = await _apiService.userApi.getMyUserInfo();
|
UserResponseDto? userResponseDto;
|
||||||
|
try {
|
||||||
|
userResponseDto = await _apiService.userApi.getMyUserInfo();
|
||||||
|
} on ApiException catch (e) {
|
||||||
|
if (e.innerException is SocketException) {
|
||||||
|
state = state.copyWith(isAuthenticated: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (userResponseDto != null) {
|
if (userResponseDto != null) {
|
||||||
var userInfoHiveBox = await Hive.openBox(userInfoBox);
|
var userInfoHiveBox = await Hive.openBox(userInfoBox);
|
||||||
@ -200,7 +209,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
state = state.copyWith(deviceInfo: deviceInfo);
|
state = state.copyWith(deviceInfo: deviceInfo);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("ERROR Register Device Info: $e");
|
debugPrint("ERROR Register Device Info: $e");
|
||||||
return false;
|
return e is ApiException && e.innerException is SocketException;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -53,6 +53,8 @@ class ThumbnailWithInfo extends StatelessWidget {
|
|||||||
httpHeaders: {
|
httpHeaders: {
|
||||||
"Authorization": "Bearer ${box.get(accessTokenKey)}"
|
"Authorization": "Bearer ${box.get(accessTokenKey)}"
|
||||||
},
|
},
|
||||||
|
errorWidget: (context, url, error) =>
|
||||||
|
const Icon(Icons.image_not_supported_outlined),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Center(
|
: Center(
|
||||||
|
@ -119,7 +119,10 @@ class SearchResultPage extends HookConsumerWidget {
|
|||||||
settings.getSetting(AppSettingsEnum.storageIndicator);
|
settings.getSetting(AppSettingsEnum.storageIndicator);
|
||||||
|
|
||||||
if (searchResultPageState.isError) {
|
if (searchResultPageState.isError) {
|
||||||
return const Text("Error");
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: const Text("common_server_error").tr(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchResultPageState.isLoading) {
|
if (searchResultPageState.isLoading) {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.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/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/services/api.service.dart';
|
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class AuthGuard extends AutoRouteGuard {
|
class AuthGuard extends AutoRouteGuard {
|
||||||
final ApiService _apiService;
|
final ApiService _apiService;
|
||||||
@ -11,11 +12,6 @@ class AuthGuard extends AutoRouteGuard {
|
|||||||
@override
|
@override
|
||||||
void onNavigation(NavigationResolver resolver, StackRouter router) async {
|
void onNavigation(NavigationResolver resolver, StackRouter router) async {
|
||||||
try {
|
try {
|
||||||
// temporary fix for race condition that the _apiService
|
|
||||||
// get called before accessToken is set
|
|
||||||
var userInfoHiveBox = await Hive.openBox(userInfoBox);
|
|
||||||
var accessToken = userInfoHiveBox.get(accessTokenKey);
|
|
||||||
_apiService.setAccessToken(accessToken);
|
|
||||||
var res = await _apiService.authenticationApi.validateAccessToken();
|
var res = await _apiService.authenticationApi.validateAccessToken();
|
||||||
|
|
||||||
if (res != null && res.authStatus) {
|
if (res != null && res.authStatus) {
|
||||||
@ -23,9 +19,15 @@ class AuthGuard extends AutoRouteGuard {
|
|||||||
} else {
|
} else {
|
||||||
router.replaceAll([const LoginRoute()]);
|
router.replaceAll([const LoginRoute()]);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} on ApiException catch (e) {
|
||||||
debugPrint("Error [onNavigation] ${e.toString()}");
|
if (e.code == HttpStatus.badRequest &&
|
||||||
router.replaceAll([const LoginRoute()]);
|
e.innerException is SocketException) {
|
||||||
|
// offline?
|
||||||
|
resolver.next(true);
|
||||||
|
} else {
|
||||||
|
debugPrint("Error [onNavigation] ${e.toString()}");
|
||||||
|
router.replaceAll([const LoginRoute()]);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,10 @@ class AssetNotifier extends StateNotifier<AssetsState> {
|
|||||||
final bool newLocal = await _albumService.refreshDeviceAlbums();
|
final bool newLocal = await _albumService.refreshDeviceAlbums();
|
||||||
log.info("Load assets: ${stopwatch.elapsedMilliseconds}ms");
|
log.info("Load assets: ${stopwatch.elapsedMilliseconds}ms");
|
||||||
stopwatch.reset();
|
stopwatch.reset();
|
||||||
if (!newRemote && !newLocal) {
|
if (!newRemote &&
|
||||||
|
!newLocal &&
|
||||||
|
state.allAssets.length ==
|
||||||
|
await _db.assets.filter().ownerIdEqualTo(me.isarId).count()) {
|
||||||
log.info("state is already up-to-date");
|
log.info("state is already up-to-date");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:immich_mobile/shared/models/server_info_state.model.dart';
|
import 'package:immich_mobile/shared/models/server_info_state.model.dart';
|
||||||
@ -28,8 +29,7 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
|||||||
if (serverVersion == null) {
|
if (serverVersion == null) {
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
isVersionMismatch: true,
|
isVersionMismatch: true,
|
||||||
versionMismatchErrorMessage:
|
versionMismatchErrorMessage: "common_server_error".tr(),
|
||||||
"Server is out of date. Some functionalities might not working correctly. Download and rebuild server",
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,17 @@ import 'package:photo_manager/photo_manager.dart';
|
|||||||
class ImmichImage extends StatelessWidget {
|
class ImmichImage extends StatelessWidget {
|
||||||
const ImmichImage(
|
const ImmichImage(
|
||||||
this.asset, {
|
this.asset, {
|
||||||
required this.width,
|
this.width,
|
||||||
required this.height,
|
this.height,
|
||||||
|
this.fit = BoxFit.cover,
|
||||||
this.useGrayBoxPlaceholder = false,
|
this.useGrayBoxPlaceholder = false,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
final Asset? asset;
|
final Asset? asset;
|
||||||
final bool useGrayBoxPlaceholder;
|
final bool useGrayBoxPlaceholder;
|
||||||
final double width;
|
final double? width;
|
||||||
final double height;
|
final double? height;
|
||||||
|
final BoxFit fit;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -47,7 +49,7 @@ class ImmichImage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
fit: BoxFit.cover,
|
fit: fit,
|
||||||
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
|
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
|
||||||
if (wasSynchronouslyLoaded || frame != null) {
|
if (wasSynchronouslyLoaded || frame != null) {
|
||||||
return child;
|
return child;
|
||||||
@ -93,7 +95,7 @@ class ImmichImage extends StatelessWidget {
|
|||||||
// keeping memCacheWidth, memCacheHeight, maxWidthDiskCache and
|
// keeping memCacheWidth, memCacheHeight, maxWidthDiskCache and
|
||||||
// maxHeightDiskCache = null allows to simply store the webp thumbnail
|
// maxHeightDiskCache = null allows to simply store the webp thumbnail
|
||||||
// from the server and use it for all rendered thumbnail sizes
|
// from the server and use it for all rendered thumbnail sizes
|
||||||
fit: BoxFit.cover,
|
fit: fit,
|
||||||
fadeInDuration: const Duration(milliseconds: 250),
|
fadeInDuration: const Duration(milliseconds: 250),
|
||||||
progressIndicatorBuilder: (context, url, downloadProgress) {
|
progressIndicatorBuilder: (context, url, downloadProgress) {
|
||||||
if (useGrayBoxPlaceholder) {
|
if (useGrayBoxPlaceholder) {
|
||||||
|
@ -21,31 +21,30 @@ class SplashScreenPage extends HookConsumerWidget {
|
|||||||
Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).get(savedLoginInfoKey);
|
Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).get(savedLoginInfoKey);
|
||||||
|
|
||||||
void performLoggingIn() async {
|
void performLoggingIn() async {
|
||||||
try {
|
bool isSuccess = false;
|
||||||
if (loginInfo != null) {
|
if (loginInfo != null) {
|
||||||
|
try {
|
||||||
// Resolve API server endpoint from user provided serverUrl
|
// Resolve API server endpoint from user provided serverUrl
|
||||||
await apiService.resolveAndSetEndpoint(loginInfo.serverUrl);
|
await apiService.resolveAndSetEndpoint(loginInfo.serverUrl);
|
||||||
|
} catch (e) {
|
||||||
var isSuccess = await ref
|
// okay, try to continue anyway if offline
|
||||||
.read(authenticationProvider.notifier)
|
|
||||||
.setSuccessLoginInfo(
|
|
||||||
accessToken: loginInfo.accessToken,
|
|
||||||
serverUrl: loginInfo.serverUrl,
|
|
||||||
);
|
|
||||||
if (isSuccess) {
|
|
||||||
final hasPermission = await ref
|
|
||||||
.read(galleryPermissionNotifier.notifier)
|
|
||||||
.hasPermission;
|
|
||||||
if (hasPermission) {
|
|
||||||
// Resume backup (if enable) then navigate
|
|
||||||
ref.watch(backupProvider.notifier).resumeBackup();
|
|
||||||
}
|
|
||||||
AutoRouter.of(context).replace(const TabControllerRoute());
|
|
||||||
} else {
|
|
||||||
AutoRouter.of(context).replace(const LoginRoute());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (_) {
|
|
||||||
|
isSuccess =
|
||||||
|
await ref.read(authenticationProvider.notifier).setSuccessLoginInfo(
|
||||||
|
accessToken: loginInfo.accessToken,
|
||||||
|
serverUrl: loginInfo.serverUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isSuccess) {
|
||||||
|
final hasPermission =
|
||||||
|
await ref.read(galleryPermissionNotifier.notifier).hasPermission;
|
||||||
|
if (hasPermission) {
|
||||||
|
// Resume backup (if enable) then navigate
|
||||||
|
ref.watch(backupProvider.notifier).resumeBackup();
|
||||||
|
}
|
||||||
|
AutoRouter.of(context).replace(const TabControllerRoute());
|
||||||
|
} else {
|
||||||
AutoRouter.of(context).replace(const LoginRoute());
|
AutoRouter.of(context).replace(const LoginRoute());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user