From aaecd7de293f021d7c292e038a4712d0bf12ff04 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 13 Jun 2023 18:45:26 +0530 Subject: [PATCH 1/2] feat(ui): add support for `MessageInput.allowedAttachmentPickerTypes`. Signed-off-by: xsahil03x --- .../stream_attachment_picker.dart | 180 +++++++++--------- ...stream_attachment_picker_bottom_sheet.dart | 3 + .../message_input/stream_message_input.dart | 10 +- 3 files changed, 105 insertions(+), 88 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart index c3de7e13..6c8f1f59 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker.dart @@ -693,6 +693,7 @@ Widget mobileAttachmentPickerBuilder({ required BuildContext context, required StreamAttachmentPickerController controller, Iterable? customOptions, + List allowedTypes = AttachmentPickerType.values, ThumbnailSize attachmentThumbnailSize = const ThumbnailSize(400, 400), ThumbnailFormat attachmentThumbnailFormat = ThumbnailFormat.jpeg, int attachmentThumbnailQuality = 100, @@ -702,74 +703,76 @@ Widget mobileAttachmentPickerBuilder({ controller: controller, onSendAttachments: Navigator.of(context).pop, options: { - if (customOptions != null) ...customOptions, - AttachmentPickerOption( - key: 'gallery-picker', - icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(), - supportedTypes: [ - AttachmentPickerType.images, - AttachmentPickerType.videos, - ], - optionViewBuilder: (context, controller) { - final selectedIds = controller.value.map((it) => it.id); - return StreamGalleryPicker( - selectedMediaItems: selectedIds, - mediaThumbnailSize: attachmentThumbnailSize, - mediaThumbnailFormat: attachmentThumbnailFormat, - mediaThumbnailQuality: attachmentThumbnailQuality, - mediaThumbnailScale: attachmentThumbnailScale, - onMediaItemSelected: (media) async { - if (selectedIds.contains(media.id)) { - return controller.removeAssetAttachment(media); - } - return controller.addAssetAttachment(media); - }, - ); - }, - ), - AttachmentPickerOption( - key: 'file-picker', - icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(), - supportedTypes: [AttachmentPickerType.files], - optionViewBuilder: (context, controller) { - return StreamFilePicker( - onFilePicked: (file) async { - if (file != null) await controller.addAttachment(file); - return Navigator.pop(context, controller.value); - }, - ); - }, - ), - AttachmentPickerOption( - key: 'image-picker', - icon: StreamSvgIcon.camera(size: 36).toIconThemeSvgIcon(), - supportedTypes: [AttachmentPickerType.images], - optionViewBuilder: (context, controller) { - return StreamImagePicker( - onImagePicked: (image) async { - if (image != null) { - await controller.addAttachment(image); - } - return Navigator.pop(context, controller.value); - }, - ); - }, - ), - AttachmentPickerOption( - key: 'video-picker', - icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(), - supportedTypes: [AttachmentPickerType.videos], - optionViewBuilder: (context, controller) { - return StreamVideoPicker( - onVideoPicked: (video) async { - if (video != null) { - await controller.addAttachment(video); - } - return Navigator.pop(context, controller.value); - }, - ); - }, - ), + ...{ + if (customOptions != null) ...customOptions, + AttachmentPickerOption( + key: 'gallery-picker', + icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(), + supportedTypes: [ + AttachmentPickerType.images, + AttachmentPickerType.videos, + ], + optionViewBuilder: (context, controller) { + final selectedIds = controller.value.map((it) => it.id); + return StreamGalleryPicker( + selectedMediaItems: selectedIds, + mediaThumbnailSize: attachmentThumbnailSize, + mediaThumbnailFormat: attachmentThumbnailFormat, + mediaThumbnailQuality: attachmentThumbnailQuality, + mediaThumbnailScale: attachmentThumbnailScale, + onMediaItemSelected: (media) async { + if (selectedIds.contains(media.id)) { + return controller.removeAssetAttachment(media); + } + return controller.addAssetAttachment(media); + }, + ); + }, + ), + AttachmentPickerOption( + key: 'file-picker', + icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(), + supportedTypes: [AttachmentPickerType.files], + optionViewBuilder: (context, controller) { + return StreamFilePicker( + onFilePicked: (file) async { + if (file != null) await controller.addAttachment(file); + return Navigator.pop(context, controller.value); + }, + ); + }, + ), + AttachmentPickerOption( + key: 'image-picker', + icon: StreamSvgIcon.camera(size: 36).toIconThemeSvgIcon(), + supportedTypes: [AttachmentPickerType.images], + optionViewBuilder: (context, controller) { + return StreamImagePicker( + onImagePicked: (image) async { + if (image != null) { + await controller.addAttachment(image); + } + return Navigator.pop(context, controller.value); + }, + ); + }, + ), + AttachmentPickerOption( + key: 'video-picker', + icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(), + supportedTypes: [AttachmentPickerType.videos], + optionViewBuilder: (context, controller) { + return StreamVideoPicker( + onVideoPicked: (video) async { + if (video != null) { + await controller.addAttachment(video); + } + return Navigator.pop(context, controller.value); + }, + ); + }, + ), + }..where((option) => option.supportedTypes.every(allowedTypes.contains)), }, ); } @@ -779,6 +782,7 @@ Widget webOrDesktopAttachmentPickerBuilder({ required BuildContext context, required StreamAttachmentPickerController controller, Iterable? customOptions, + List allowedTypes = AttachmentPickerType.values, ThumbnailSize attachmentThumbnailSize = const ThumbnailSize(400, 400), ThumbnailFormat attachmentThumbnailFormat = ThumbnailFormat.jpeg, int attachmentThumbnailQuality = 100, @@ -787,25 +791,27 @@ Widget webOrDesktopAttachmentPickerBuilder({ return StreamWebOrDesktopAttachmentPickerBottomSheet( controller: controller, options: { - if (customOptions != null) ...customOptions, - WebOrDesktopAttachmentPickerOption( - key: 'image-picker', - type: AttachmentPickerType.images, - icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(), - title: context.translations.uploadAPhotoLabel, - ), - WebOrDesktopAttachmentPickerOption( - key: 'video-picker', - type: AttachmentPickerType.videos, - icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(), - title: context.translations.uploadAVideoLabel, - ), - WebOrDesktopAttachmentPickerOption( - key: 'file-picker', - type: AttachmentPickerType.files, - icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(), - title: context.translations.uploadAFileLabel, - ), + ...{ + if (customOptions != null) ...customOptions, + WebOrDesktopAttachmentPickerOption( + key: 'image-picker', + type: AttachmentPickerType.images, + icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(), + title: context.translations.uploadAPhotoLabel, + ), + WebOrDesktopAttachmentPickerOption( + key: 'video-picker', + type: AttachmentPickerType.videos, + icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(), + title: context.translations.uploadAVideoLabel, + ), + WebOrDesktopAttachmentPickerOption( + key: 'file-picker', + type: AttachmentPickerType.files, + icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(), + title: context.translations.uploadAFileLabel, + ), + }.where((option) => option.supportedTypes.every(allowedTypes.contains)), }, onOptionTap: (context, controller, option) async { final attachment = await StreamAttachmentHandler.instance.pickFile( diff --git a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart index 11fb966b..bc53e4db 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/attachment_picker/stream_attachment_picker_bottom_sheet.dart @@ -66,6 +66,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; Future showStreamAttachmentPickerModalBottomSheet({ required BuildContext context, Iterable? customOptions, + List allowedTypes = AttachmentPickerType.values, List? initialAttachments, StreamAttachmentPickerController? controller, Color? backgroundColor, @@ -117,6 +118,7 @@ Future showStreamAttachmentPickerModalBottomSheet({ return webOrDesktopAttachmentPickerBuilder.call( context: context, controller: controller, + allowedTypes: allowedTypes, customOptions: customOptions?.map( WebOrDesktopAttachmentPickerOption.fromAttachmentPickerOption, ), @@ -130,6 +132,7 @@ Future showStreamAttachmentPickerModalBottomSheet({ return mobileAttachmentPickerBuilder.call( context: context, controller: controller, + allowedTypes: allowedTypes, customOptions: customOptions, attachmentThumbnailSize: attachmentThumbnailSize, attachmentThumbnailFormat: attachmentThumbnailFormat, diff --git a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart index c3a7f7ef..cca0ab19 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart @@ -122,6 +122,7 @@ class StreamMessageInput extends StatefulWidget { this.maxAttachmentSize = kDefaultMaxAttachmentSize, this.onError, this.attachmentLimit = 10, + this.allowedAttachmentPickerTypes = AttachmentPickerType.values, this.onAttachmentLimitExceed, this.attachmentButtonBuilder, this.commandButtonBuilder, @@ -233,6 +234,12 @@ class StreamMessageInput extends StatefulWidget { /// A limit for the no. of attachments that can be sent with a single message. final int attachmentLimit; + /// The list of allowed attachment types which can be picked using the + /// attachment button. + /// + /// By default, all the attachment types are allowed. + final List allowedAttachmentPickerTypes; + /// A callback for when the [attachmentLimit] is exceeded. /// /// This will override the default error alert behaviour. @@ -771,8 +778,9 @@ class StreamMessageInputState extends State Future _onAttachmentButtonPressed() async { final attachments = await showStreamAttachmentPickerModalBottomSheet( context: context, - initialAttachments: _effectiveController.attachments, useRootNavigator: true, + allowedTypes: widget.allowedAttachmentPickerTypes, + initialAttachments: _effectiveController.attachments, ); if (attachments != null) { From e0abad2e94a225997cd56267be0af55325ff3d54 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 13 Jun 2023 18:49:50 +0530 Subject: [PATCH 2/2] chore: update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 9f901bf4..b026f9b3 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -7,6 +7,21 @@ - [[#1605]](https://github.com/GetStream/stream-chat-flutter/issues/1605) Fixed Null exception is thrown on message list for unread messages when `ScrollToBottomButton` is pressed. +✅ Added + +- Added support for `StreamMessageInput.allowedAttachmentPickerTypes` to specify the allowed attachment picker types. + [#1601](https://github.com/GetStream/stream-chat-flutter/issues/1376) + + ```dart + StreamMessageInput( + ..., + allowedAttachmentPickerTypes: const [ + AttachmentPickerType.files, + AttachmentPickerType.images, + ], + ) + ``` + ## 6.3.0 🐞 Fixed