diff --git a/assets/images/ic_photos_setting.svg b/assets/images/ic_photos_setting.svg new file mode 100644 index 0000000000..e61dbe95ef --- /dev/null +++ b/assets/images/ic_photos_setting.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index e9ad0a1607..d2a8626375 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2638,5 +2638,7 @@ } }, "addACaption": "Add a caption...", - "noImagesFound": "No Images found" + "noImagesFound": "No Images found", + "captionForImagesIsNotSupportYet": "Caption for images is not support yet.", + "tapToAllowAccessToYourGallery": "Tap to allow access to your Gallery" } \ No newline at end of file diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 4bc7ec33be..9aa28f7db1 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -4,8 +4,8 @@ import 'dart:io'; import 'package:fluffychat/di/global/get_it_initializer.dart'; import 'package:fluffychat/pages/forward/forward.dart'; import 'package:fluffychat/utils/network_connection_service.dart'; -import 'package:collection/collection.dart'; import 'package:fluffychat/presentation/extensions/asset_entity_extension.dart'; +import 'package:fluffychat/utils/voip/permission_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; @@ -21,6 +21,7 @@ import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:image_picker/image_picker.dart'; import 'package:linagora_design_flutter/images_picker/images_picker.dart' hide ImagePicker; import 'package:matrix/matrix.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:record/record.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -35,7 +36,6 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/ios_badge_client_extensio import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/matrix.dart'; -import 'package:photo_manager/photo_manager.dart'; import '../../utils/account_bundles.dart'; import '../../utils/localized_exception_extension.dart'; import '../../utils/matrix_sdk_extensions/matrix_file_extension.dart'; @@ -418,9 +418,6 @@ class ChatController extends State { for (final entity in selectedAssets) { await sendImage(entity); } - - imagePickerController.clearAssetCounter(); - numberSelectedImagesNotifier.value = 0; } void openCameraAction() async { @@ -1162,6 +1159,15 @@ class ChatController extends State { editEvent = null; }); + Future? getCurrentPhotoPermission() { + return PermissionHandlerService().requestPermissionForPhotoActions(); + } + + void removeAllImageSelected() { + imagePickerController.clearAssetCounter(); + numberSelectedImagesNotifier.value = 0; + } + @override Widget build(BuildContext context) => ChatView(this); } diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart index c53cbb032e..d884e60335 100644 --- a/lib/pages/chat/chat_input_row.dart +++ b/lib/pages/chat/chat_input_row.dart @@ -1,5 +1,7 @@ + import 'package:fluffychat/pages/chat/chat_input_row_style.dart'; import 'package:fluffychat/resource/image_paths.dart'; +import 'package:fluffychat/utils/voip/permission_service.dart'; import 'package:fluffychat/widgets/twake_components/twake_icon_button.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -7,10 +9,10 @@ import 'package:flutter/services.dart'; import 'package:animations/animations.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:keyboard_shortcuts/keyboard_shortcuts.dart'; import 'package:linagora_design_flutter/colors/linagora_ref_colors.dart'; +import 'package:linagora_design_flutter/colors/linagora_sys_colors.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; @@ -18,6 +20,7 @@ import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/avatar/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:linagora_design_flutter/images_picker/images_picker.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'chat.dart'; import 'input_bar.dart'; @@ -89,10 +92,16 @@ class ChatInputRow extends StatelessWidget { tooltip: L10n.of(context)!.more, margin: const EdgeInsets.only(right: 4.0), icon: Icons.add_circle_outline, - onPressed: () => showImagesPickerBottomSheet( - controller: controller, - context: context, - ), + onPressed: () async { + final currentPermission = await controller.getCurrentPhotoPermission(); + if (currentPermission != null) { + showImagesPickerBottomSheet( + controller: controller, + context: context, + permissionStatus: currentPermission + ).whenComplete(() => controller.removeAllImageSelected()); + } + }, ), if (controller.matrix!.isMultiAccount && controller.matrix!.hasComplexBundles && @@ -260,14 +269,17 @@ class _ChatAccountPicker extends StatelessWidget { } } -void showImagesPickerBottomSheet({ +Future showImagesPickerBottomSheet({ required BuildContext context, required ChatController controller, -}) { - ImagePicker.showImagesGridBottomSheet( + required PermissionStatus permissionStatus, +}) async { + return await ImagePicker.showImagesGridBottomSheet( context: context, controller: controller.imagePickerController, backgroundImageCamera: const AssetImage("assets/verification.png"), + permissionStatus: permissionStatus, + assetBackgroundColor: LinagoraSysColors.material().background, counterImageBuilder: (counterImage) { if (counterImage == 0) { return const SizedBox.shrink(); @@ -285,9 +297,6 @@ void showImagesPickerBottomSheet({ ), ); }, - noImagesWidget: Center( - child: Text(L10n.of(context)!.noImagesFound), - ), bottomWidget: ValueListenableBuilder( valueListenable: controller.numberSelectedImagesNotifier, builder: (context, value, child) { @@ -316,7 +325,7 @@ void showImagesPickerBottomSheet({ Expanded( child: TextFormField( onTap: () => Fluttertoast.showToast( - msg: "Caption for images is not support yet.", + msg: L10n.of(context)!.captionForImagesIsNotSupportYet, gravity: ToastGravity.CENTER, ), decoration: InputDecoration( @@ -372,6 +381,20 @@ void showImagesPickerBottomSheet({ const SizedBox(height: 8.0,), ], ), - ) - ); + ), + goToSettingsWidget: Column( + children: [ + SvgPicture.asset(ImagePaths.icPhotosSettingPermission, + width: 40, + height: 40, + ), + Text(L10n.of(context)!.tapToAllowAccessToYourGallery, + style: Theme.of(context).textTheme.titleSmall?.copyWith( + color: LinagoraRefColors.material().neutral + ), + textAlign: TextAlign.center, + ), + ], + ), + ); } \ No newline at end of file diff --git a/lib/resource/image_paths.dart b/lib/resource/image_paths.dart index 75c40c1b09..c4718808e1 100644 --- a/lib/resource/image_paths.dart +++ b/lib/resource/image_paths.dart @@ -17,6 +17,7 @@ class ImagePaths { static String get icStatus => _getImagePath('ic_status.svg'); static String get icEmptyGroupChat => _getImagePath('ic_empty_group_chat.svg'); static String get icTwakeLogo => _getImagePath('ic_twake_logo.svg'); + static String get icPhotosSettingPermission => _getImagePath('ic_photos_setting.svg'); static String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/utils/voip/permission_service.dart b/lib/utils/voip/permission_service.dart index 1e4ad2dbdc..2c07cd2106 100644 --- a/lib/utils/voip/permission_service.dart +++ b/lib/utils/voip/permission_service.dart @@ -11,37 +11,39 @@ class PermissionHandlerService { PermissionHandlerService._internal(); - Future requestPermissionForPhotoActions() { + Future? requestPermissionForPhotoActions() { if (Platform.isIOS) { return _handlePhotosPermissionIOSAction(); - } else { + } else if (Platform.isAndroid) { return _handlePhotosPermissionAndroidAction(); + } else { + return null; } } Future _handlePhotosPermissionIOSAction() async { final currentStatus = await Permission.photos.status; - return _handlePermission(currentStatus); + return _handlePhotoPermission(currentStatus); } Future _handlePhotosPermissionAndroidAction() async { final currentStatus = await Permission.storage.status; - return _handlePermission(currentStatus); + return _handlePhotoPermission(currentStatus); } - - Future _handlePermission(PermissionStatus currentStatus) async { + Future _handlePhotoPermission(PermissionStatus currentStatus) async { switch (currentStatus) { + case PermissionStatus.permanentlyDenied: case PermissionStatus.denied: - case PermissionStatus.limited: final newStatus = Platform.isIOS - ? await Permission.mediaLibrary.request() + ? await Permission.photos.request() : await Permission.storage.request(); return newStatus.isGranted ? PermissionStatus.granted : newStatus; case PermissionStatus.granted: + case PermissionStatus.limited: + case PermissionStatus.provisional: case PermissionStatus.restricted: - case PermissionStatus.permanentlyDenied: return currentStatus; } } diff --git a/pubspec.lock b/pubspec.lock index 2f11b1e166..05443b428a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1326,7 +1326,7 @@ packages: description: path: "." ref: master - resolved-ref: "80f53ebbd3b74d82ab5f6dcc26faa584326967f9" + resolved-ref: "0882d42be9324e14777fe99b9760546989bf8b73" url: "git@github.com:linagora/linagora-design-flutter.git" source: git version: "0.0.1" @@ -1670,10 +1670,10 @@ packages: dependency: transitive description: name: permission_handler_platform_interface - sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + sha256: de20a5c3269229c1ae2e5a6b822f6cb59578b23e8255c93fbeebfc82116e6b11 url: "https://pub.dev" source: hosted - version: "3.9.0" + version: "3.10.0" permission_handler_windows: dependency: transitive description: