Skip to content

Commit

Permalink
LA-971 added explanation for storage permission
Browse files Browse the repository at this point in the history
  • Loading branch information
KhaledNjim committed Jan 7, 2025
1 parent a442c6a commit 7f963bd
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 18 deletions.
7 changes: 7 additions & 0 deletions lib/presentation/localizations/app_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3113,6 +3113,13 @@ class AppLocalizations {
'Linshare requests camera and microphone permissions to capture photos and videos and phone state permission to handle pausing while recording during calls ',
name: 'explain_camera_permission');
}

String get explain_storage_permission {
return Intl.message(
'Linshare requests storage permission to let you upload files from your file system, ensuring you can easily share your documents, photos, and videos.',
name: 'explain_storage_permission',
);
}
}

class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
Expand Down
3 changes: 2 additions & 1 deletion lib/presentation/util/audio_recorder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class AudioRecorder {
try {
if (!await PermissionService.arePermissionsGranted(
[Permission.microphone, Permission.phone])) {
final confirmExplanation = await PermissionDialog.showPermissionDialog(
final confirmExplanation =
await PermissionDialog.showPermissionExplanationDialog(
context,
Center(
child: Icon(Icons.warning, color: Colors.orange, size: 40),
Expand Down
38 changes: 34 additions & 4 deletions lib/presentation/util/local_file_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,46 @@
// <http://www.gnu.org/licenses/> for the GNU Affero General Public License version
// 3 and <http://www.linshare.org/licenses/LinShare-License_AfferoGPL-v3.pdf> for
// the Additional Terms applicable to LinShare software.

import 'dart:io';
import 'package:dartz/dartz.dart';
import 'package:domain/domain.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:linshare_flutter_app/presentation/localizations/app_localizations.dart';
import 'package:linshare_flutter_app/presentation/util/permission_service.dart';
import 'package:linshare_flutter_app/presentation/view/dialog/permission_dialog.dart';
import 'package:permission_handler/permission_handler.dart';

class LocalFilePicker {

Future<Either<Failure, FilePickerSuccessViewState>> pickFiles({FileType fileType = FileType.any}) async {
Future<Either<Failure, FilePickerSuccessViewState>> pickFiles(
BuildContext context,
{FileType fileType = FileType.any}) async {
try {
final filesResult = await FilePicker.platform.pickFiles(type: fileType, allowMultiple: true);
if (Platform.isAndroid && await PermissionService.isAndroid32AndLower()) {
final permissionStatus = await Permission.storage.status;
if (!permissionStatus.isGranted) {
final confirmExplanation =
await PermissionDialog.showPermissionExplanationDialog(
context,
Center(
child:
Icon(Icons.warning, color: Colors.orange, size: 40),
),
AppLocalizations.of(context)
.explain_storage_permission) ??
false;
if (!confirmExplanation) {
return Left(FilePickerFailure(Exception('Permission denied')));
}
final requestedPermission = await PermissionService
.tryToGetPermissionForStorageForAndroid32AndLower();
if (requestedPermission != PermissionStatus.granted) {
return Left(FilePickerFailure(Exception('Permission denied')));
}
}
}
final filesResult = await FilePicker.platform
.pickFiles(type: fileType, allowMultiple: true);
if (filesResult != null && filesResult.files.isNotEmpty) {
final filesInfoResult = filesResult.files.map((platformFile) {
return FileInfo(
Expand Down
3 changes: 2 additions & 1 deletion lib/presentation/util/media_picker_from_camera.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class MediaPickerFromCamera {
try {
if (!await PermissionService.arePermissionsGranted(
[Permission.camera, Permission.microphone])) {
final confirmExplanation = await PermissionDialog.showPermissionDialog(
final confirmExplanation =
await PermissionDialog.showPermissionExplanationDialog(
context,
Center(
child: Icon(Icons.warning, color: Colors.orange, size: 40),
Expand Down
17 changes: 16 additions & 1 deletion lib/presentation/util/permission_service.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:device_info/device_info.dart';
import 'package:permission_handler/permission_handler.dart';

class PermissionService {

static Future<bool> arePermissionsGranted(
List<Permission> permissions) async {
for (var permission in permissions) {
Expand All @@ -21,6 +21,7 @@ class PermissionService {
final status = await Permission.microphone.request();
return status;
}

static Future<PermissionStatus> tryToGetPermissionForPhoneState() async {
final status = await Permission.phone.request();
return status;
Expand Down Expand Up @@ -49,4 +50,18 @@ class PermissionService {

return PermissionStatus.denied;
}

static Future<PermissionStatus>
tryToGetPermissionForStorageForAndroid32AndLower() async {
final status = await Permission.storage.request();
return status;
}

static Future<bool> isAndroid32AndLower() async {
final deviceInfoPlugin = DeviceInfoPlugin();
final androidInfo = await deviceInfoPlugin.androidInfo;
final apiLevel = androidInfo.version.sdkInt;
return apiLevel <= 32;
}

}
2 changes: 1 addition & 1 deletion lib/presentation/view/dialog/permission_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:linshare_flutter_app/presentation/localizations/app_localizations.dart';

class PermissionDialog {
static Future<bool?> showPermissionDialog(
static Future<bool?> showPermissionExplanationDialog(
BuildContext context, Widget title, String content) async {
return showDialog<bool>(
barrierDismissible: false,
Expand Down
3 changes: 2 additions & 1 deletion lib/presentation/widget/myspace/my_space_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,8 @@ class MySpaceViewModel extends BaseViewModel {
ThunkAction<AppState> _pickFileAction(BuildContext context, FileType fileType) {
return (Store<AppState> store) async {
store.dispatch(OutsideAppAction(outsideAppType: ActionOutsideAppType.PICKING_FILE));
await _localFilePicker.pickFiles(fileType: fileType)
await _localFilePicker
.pickFiles(context, fileType: fileType)
.then((result) {
store.dispatch(OutsideAppAction(outsideAppType: ActionOutsideAppType.NONE));
result.fold(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,16 +439,17 @@ class SharedSpaceDocumentNodeViewModel extends BaseViewModel {
store.dispatch(_handleUploadFileMenuAction(context, actionTiles));
}

void openFilePickerByType(FileType fileType) {
void openFilePickerByType(FileType fileType, BuildContext context) {
_appNavigation.popBack();
store.dispatch(_pickFileAction(fileType));
store.dispatch(_pickFileAction(fileType, context));
}

ThunkAction<AppState> _pickFileAction(FileType fileType) {
ThunkAction<AppState> _pickFileAction(
FileType fileType, BuildContext context) {
return (Store<AppState> store) async {
store.dispatch(OutsideAppAction(outsideAppType: ActionOutsideAppType.PICKING_FILE));
await _localFilePicker
.pickFiles(fileType: fileType)
.pickFiles(context, fileType: fileType)
.then((result) {
store.dispatch(OutsideAppAction(outsideAppType: ActionOutsideAppType.NONE));
result.fold(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,8 @@ class _SharedSpaceDocumentWidgetState extends State<SharedSpaceDocumentWidget> {
Key('pick_photo_and_video_context_menu_action'),
SvgPicture.asset(imagePath.icPhotoLibrary, width: 24, height: 24, fit: BoxFit.fill,color: AppColor.primaryColor,),
AppLocalizations.of(context).photos_and_videos)
.onActionClick((_) => sharedSpaceDocumentViewModel.openFilePickerByType(FileType.media))
.onActionClick((_) => sharedSpaceDocumentViewModel.openFilePickerByType(
FileType.media, context))
.build();
}

Expand All @@ -935,7 +936,8 @@ class _SharedSpaceDocumentWidgetState extends State<SharedSpaceDocumentWidget> {
color: AppColor.primaryColor,
),
AppLocalizations.of(context).browse)
.onActionClick((_) => sharedSpaceDocumentViewModel.openFilePickerByType(FileType.any))
.onActionClick((_) => sharedSpaceDocumentViewModel.openFilePickerByType(
FileType.any, context))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ class UploadFileViewModel extends BaseViewModel {
if (permissionStatus.isGranted) {
_contactSuggestionSource = ContactSuggestionSource.all;
} else if (!permissionStatus.isPermanentlyDenied) {
final confirmExplanation = await PermissionDialog.showPermissionDialog(
final confirmExplanation =
await PermissionDialog.showPermissionExplanationDialog(
context,
Center(
child: Icon(Icons.warning, color: Colors.orange, size: 40),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,8 @@ class UploadRequestCreationViewModel extends BaseViewModel {
if (permissionStatus.isGranted) {
_contactSuggestionSource = ContactSuggestionSource.all;
} else if (!permissionStatus.isPermanentlyDenied) {
final confirmExplanation = await PermissionDialog.showPermissionDialog(
final confirmExplanation =
await PermissionDialog.showPermissionExplanationDialog(
context,
Center(
child: Icon(Icons.warning, color: Colors.orange, size: 40),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ class AddRecipientsUploadRequestGroupViewModel extends BaseViewModel {
if (permissionStatus.isGranted) {
_contactSuggestionSource = ContactSuggestionSource.all;
} else if (!permissionStatus.isPermanentlyDenied) {
final confirmExplanation = await PermissionDialog.showPermissionDialog(
final confirmExplanation =
await PermissionDialog.showPermissionExplanationDialog(
context,
Center(
child: Icon(Icons.warning, color: Colors.orange, size: 40),
Expand Down

0 comments on commit 7f963bd

Please sign in to comment.