diff --git a/mobile/lib/providers/asset_viewer/download.provider.dart b/mobile/lib/providers/asset_viewer/download.provider.dart index 68b120c38a..028ff8ab42 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 7cf6f309e9..c517738b01 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, {