From a76ecf5bc2edf77ea7e64c9b90308460ce3372fa Mon Sep 17 00:00:00 2001 From: KhaledNjim Date: Thu, 19 Dec 2024 19:56:35 +0100 Subject: [PATCH] LA-971 added explanation for contact permission --- .../localizations/app_localizations.dart | 20 +++++++++++++++ .../view/dialog/permission_dialog.dart | 25 +++++++++++++++++++ .../upload_file/upload_file_viewmodel.dart | 15 ++++++++--- .../upload_file/upload_file_widget.dart | 1 + .../upload_request_creation_viewmodel.dart | 16 +++++++++--- .../upload_request_creation_widget.dart | 1 + ...pients_upload_request_group_viewmodel.dart | 18 ++++++++++--- ...ecipients_upload_request_group_widget.dart | 3 ++- 8 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 lib/presentation/view/dialog/permission_dialog.dart diff --git a/lib/presentation/localizations/app_localizations.dart b/lib/presentation/localizations/app_localizations.dart index 140c8e093..665ea9b23 100644 --- a/lib/presentation/localizations/app_localizations.dart +++ b/lib/presentation/localizations/app_localizations.dart @@ -3082,6 +3082,26 @@ class AppLocalizations { name: 'are_you_sure_you_want_to_discard_recording', ); } + String get allow { + return Intl.message( + 'Allow', + name: 'allow', + ); + } + + String get not_now { + return Intl.message( + 'Not now', + name: 'not_now', + ); + } + + String get explain_contact_permission { + return Intl.message( + 'LinShare requests access to your contacts solely to provide autocomplete suggestions when you are adding a recipient to share files or collaborate with others. Please note that your contacts are not synchronized with the server.', + name: 'explain_contact_permission', + ); + } } class AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/presentation/view/dialog/permission_dialog.dart b/lib/presentation/view/dialog/permission_dialog.dart new file mode 100644 index 000000000..bccd6c394 --- /dev/null +++ b/lib/presentation/view/dialog/permission_dialog.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:linshare_flutter_app/presentation/localizations/app_localizations.dart'; + +class PermissionDialog { + static Future showPermissionDialog( + BuildContext context, Widget title, String content) async { + return showDialog( + barrierDismissible: false, + context: context, + builder: (context) => AlertDialog( + title: title, + content: Text(content), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(AppLocalizations.of(context).not_now), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text(AppLocalizations.of(context).allow), + ), + ], + )); + } +} diff --git a/lib/presentation/widget/upload_file/upload_file_viewmodel.dart b/lib/presentation/widget/upload_file/upload_file_viewmodel.dart index 71ca52590..f2c5769c3 100644 --- a/lib/presentation/widget/upload_file/upload_file_viewmodel.dart +++ b/lib/presentation/widget/upload_file/upload_file_viewmodel.dart @@ -41,6 +41,7 @@ import 'package:linshare_flutter_app/presentation/redux/states/app_state.dart'; import 'package:linshare_flutter_app/presentation/util/extensions/media_type_extension.dart'; import 'package:linshare_flutter_app/presentation/util/router/app_navigation.dart'; import 'package:linshare_flutter_app/presentation/util/router/route_paths.dart'; +import 'package:linshare_flutter_app/presentation/view/dialog/permission_dialog.dart'; import 'package:linshare_flutter_app/presentation/widget/base/base_viewmodel.dart'; import 'package:linshare_flutter_app/presentation/widget/destination_picker/destination_picker_action/choose_destination_picker_action.dart'; import 'package:linshare_flutter_app/presentation/widget/destination_picker/destination_picker_action/negative_destination_picker_action.dart'; @@ -117,8 +118,6 @@ class UploadFileViewModel extends BaseViewModel { break; } }); - - Future.delayed(Duration(milliseconds: 500), () => _checkContactPermission()); } void backToMySpace() { @@ -338,11 +337,21 @@ class UploadFileViewModel extends BaseViewModel { store.dispatch(MySpaceClearSelectedDocumentsAction()); } - void _checkContactPermission() async { + void checkContactPermission(BuildContext context) async { final permissionStatus = await Permission.contacts.status; if (permissionStatus.isGranted) { _contactSuggestionSource = ContactSuggestionSource.all; } else if (!permissionStatus.isPermanentlyDenied) { + final confirmExplanation = await PermissionDialog.showPermissionDialog( + context, + Center( + child: Icon(Icons.warning, color: Colors.orange, size: 40), + ), + AppLocalizations.of(context).explain_contact_permission) ?? + false; + if (!confirmExplanation) { + return; + } final requestedPermission = await Permission.contacts.request(); _contactSuggestionSource = requestedPermission == PermissionStatus.granted ? ContactSuggestionSource.all diff --git a/lib/presentation/widget/upload_file/upload_file_widget.dart b/lib/presentation/widget/upload_file/upload_file_widget.dart index 06980a61f..35bbc0885 100644 --- a/lib/presentation/widget/upload_file/upload_file_widget.dart +++ b/lib/presentation/widget/upload_file/upload_file_widget.dart @@ -68,6 +68,7 @@ class _UploadFileWidgetState extends State { void initState() { super.initState(); uploadFileViewModel.cancelSelection(); + uploadFileViewModel.checkContactPermission(context); } @override diff --git a/lib/presentation/widget/upload_request_creation/upload_request_creation_viewmodel.dart b/lib/presentation/widget/upload_request_creation/upload_request_creation_viewmodel.dart index e947c9483..1212e797f 100644 --- a/lib/presentation/widget/upload_request_creation/upload_request_creation_viewmodel.dart +++ b/lib/presentation/widget/upload_request_creation/upload_request_creation_viewmodel.dart @@ -54,6 +54,7 @@ import 'package:linshare_flutter_app/presentation/util/extensions/list_functiona import 'package:linshare_flutter_app/presentation/util/extensions/string_extensions.dart'; import 'package:linshare_flutter_app/presentation/util/router/app_navigation.dart'; import 'package:linshare_flutter_app/presentation/util/value_notifier_common.dart'; +import 'package:linshare_flutter_app/presentation/view/dialog/permission_dialog.dart'; import 'package:linshare_flutter_app/presentation/view/modal_sheets/modal_card.dart'; import 'package:linshare_flutter_app/presentation/view/modal_sheets/reach_limitation_alert.dart'; import 'package:linshare_flutter_app/presentation/widget/base/base_viewmodel.dart'; @@ -63,6 +64,7 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:redux/src/store.dart'; import 'package:rxdart/rxdart.dart'; + class UploadRequestCreationViewModel extends BaseViewModel { final AppNavigation _appNavigation; @@ -146,8 +148,6 @@ class UploadRequestCreationViewModel extends BaseViewModel { }).listen((event) { event ? _enableCreateButton.add(true) : _enableCreateButton.add(false); }); - - Future.delayed(Duration(milliseconds: 500), () => _checkContactPermission()); } void _disposeValueNotifier() { @@ -534,11 +534,21 @@ class UploadRequestCreationViewModel extends BaseViewModel { ); } - void _checkContactPermission() async { + void checkContactPermission(BuildContext context) async { final permissionStatus = await Permission.contacts.status; if (permissionStatus.isGranted) { _contactSuggestionSource = ContactSuggestionSource.all; } else if (!permissionStatus.isPermanentlyDenied) { + final confirmExplanation = await PermissionDialog.showPermissionDialog( + context, + Center( + child: Icon(Icons.warning, color: Colors.orange, size: 40), + ), + AppLocalizations.of(context).explain_contact_permission) ?? + false; + if (!confirmExplanation) { + return; + } final requestedPermission = await Permission.contacts.request(); _contactSuggestionSource = requestedPermission == PermissionStatus.granted ? ContactSuggestionSource.all diff --git a/lib/presentation/widget/upload_request_creation/upload_request_creation_widget.dart b/lib/presentation/widget/upload_request_creation/upload_request_creation_widget.dart index 92b88414d..41bff0728 100644 --- a/lib/presentation/widget/upload_request_creation/upload_request_creation_widget.dart +++ b/lib/presentation/widget/upload_request_creation/upload_request_creation_widget.dart @@ -73,6 +73,7 @@ class _UploadRequestCreationWidgetState extends State _checkContactPermission()); - } + : super(store); void initState(AddRecipientsUploadRequestGroupArgument argument) { store.dispatch(_getAllUploadRequests(argument.uploadRequestGroup.uploadRequestGroupId)); @@ -187,11 +187,21 @@ class AddRecipientsUploadRequestGroupViewModel extends BaseViewModel { } } - void _checkContactPermission() async { + void checkContactPermission(BuildContext context) async { final permissionStatus = await Permission.contacts.status; if (permissionStatus.isGranted) { _contactSuggestionSource = ContactSuggestionSource.all; } else if (!permissionStatus.isPermanentlyDenied) { + final confirmExplanation = await PermissionDialog.showPermissionDialog( + context, + Center( + child: Icon(Icons.warning, color: Colors.orange, size: 40), + ), + AppLocalizations.of(context).explain_contact_permission) ?? + false; + if (!confirmExplanation) { + return; + } final requestedPermission = await Permission.contacts.request(); _contactSuggestionSource = requestedPermission == PermissionStatus.granted ? ContactSuggestionSource.all diff --git a/lib/presentation/widget/upload_request_group_add_recipient/add_recipients_upload_request_group_widget.dart b/lib/presentation/widget/upload_request_group_add_recipient/add_recipients_upload_request_group_widget.dart index 35dea4c52..7c1ca6fec 100644 --- a/lib/presentation/widget/upload_request_group_add_recipient/add_recipients_upload_request_group_widget.dart +++ b/lib/presentation/widget/upload_request_group_add_recipient/add_recipients_upload_request_group_widget.dart @@ -64,13 +64,14 @@ class _AddSharedSpaceMemberWidgetState extends State