From 371ab393313157bcd6bd0278122b509bdb0e1c8d Mon Sep 17 00:00:00 2001 From: Daniel Hurd Date: Wed, 25 Dec 2024 17:01:30 +1300 Subject: [PATCH 1/2] fix(mobile): check and request permissions when saving files to prevent hard crash --- .../asset_viewer/download.provider.dart | 2 +- mobile/lib/services/download.service.dart | 56 ++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/mobile/lib/providers/asset_viewer/download.provider.dart b/mobile/lib/providers/asset_viewer/download.provider.dart index 68b120c38a756..028ff8ab42c48 100644 --- a/mobile/lib/providers/asset_viewer/download.provider.dart +++ b/mobile/lib/providers/asset_viewer/download.provider.dart @@ -141,7 +141,7 @@ class DownloadStateNotifier extends StateNotifier { } void downloadAsset(Asset asset, BuildContext context) async { - await _downloadService.download(asset); + await _downloadService.download(asset, context: context); } void cancelDownload(String id) async { diff --git a/mobile/lib/services/download.service.dart b/mobile/lib/services/download.service.dart index 7cf6f309e98fe..c517738b0141f 100644 --- a/mobile/lib/services/download.service.dart +++ b/mobile/lib/services/download.service.dart @@ -13,6 +13,9 @@ import 'package:immich_mobile/repositories/file_media.repository.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/utils/download.dart'; import 'package:logging/logging.dart'; +import 'package:permission_handler/permission_handler.dart' as ph; +import 'package:flutter/material.dart'; +import 'package:easy_localization/easy_localization.dart'; final downloadServiceProvider = Provider( (ref) => DownloadService( @@ -158,7 +161,11 @@ class DownloadService { return await FileDownloader().cancelTaskWithId(id); } - Future download(Asset asset) async { + Future download(Asset asset, {BuildContext? context}) async { + if (!await _handlePermission(context)) { + return; + } + if (asset.isImage && asset.livePhotoVideoId != null && Platform.isIOS) { await _downloadRepository.download( _buildDownloadTask( @@ -196,6 +203,53 @@ class DownloadService { } } + Future _handlePermission(BuildContext? context) async { + final permission = await ph.Permission.photos.status; + if (permission.isDenied || permission.isPermanentlyDenied) { + if (context == null) return false; + + final bool? shouldRequest = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('permission_onboarding_request').tr(), + content: const Text('permission_onboarding_permission_denied').tr(), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('cancel').tr(), + ), + TextButton( + onPressed: () => Navigator.pop(context, true), + child: Text( + permission.isPermanentlyDenied + ? 'permission_onboarding_go_to_settings' + : 'permission_onboarding_grant_permission', + ).tr(), + ), + ], + ); + }, + ); + + if (shouldRequest == true) { + if (permission.isPermanentlyDenied) { + await ph.openAppSettings(); + return false; + } + + final result = await ph.Permission.photos.request(); + if (!result.isGranted) { + return false; + } + } else { + return false; + } + } + + return true; + } + DownloadTask _buildDownloadTask( String id, String filename, { From 22db564b9af135c50b7728910a00ae3fba4c9275 Mon Sep 17 00:00:00 2001 From: Daniel Hurd Date: Wed, 25 Dec 2024 17:20:26 +1300 Subject: [PATCH 2/2] centering up the text in the permission dialog --- mobile/lib/services/download.service.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mobile/lib/services/download.service.dart b/mobile/lib/services/download.service.dart index c517738b0141f..9ce98a84625c1 100644 --- a/mobile/lib/services/download.service.dart +++ b/mobile/lib/services/download.service.dart @@ -212,8 +212,14 @@ class DownloadService { context: context, builder: (context) { return AlertDialog( - title: const Text('permission_onboarding_request').tr(), - content: const Text('permission_onboarding_permission_denied').tr(), + title: const Text( + 'permission_onboarding_request', + textAlign: TextAlign.center, + ).tr(), + content: const Text( + 'permission_onboarding_permission_denied', + textAlign: TextAlign.center, + ).tr(), actions: [ TextButton( onPressed: () => Navigator.pop(context, false),