Merge pull request #1608 from GetStream/feat/allowed-attachment-picker-types

This commit is contained in:
Sahil Kumar
2023-06-13 19:00:35 +05:30
committed by GitHub
4 changed files with 120 additions and 88 deletions
+15
View File
@@ -7,6 +7,21 @@
- [[#1605]](https://github.com/GetStream/stream-chat-flutter/issues/1605) Fixed Null exception is thrown on message list - [[#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. 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 ## 6.3.0
🐞 Fixed 🐞 Fixed
@@ -693,6 +693,7 @@ Widget mobileAttachmentPickerBuilder({
required BuildContext context, required BuildContext context,
required StreamAttachmentPickerController controller, required StreamAttachmentPickerController controller,
Iterable<AttachmentPickerOption>? customOptions, Iterable<AttachmentPickerOption>? customOptions,
List<AttachmentPickerType> allowedTypes = AttachmentPickerType.values,
ThumbnailSize attachmentThumbnailSize = const ThumbnailSize(400, 400), ThumbnailSize attachmentThumbnailSize = const ThumbnailSize(400, 400),
ThumbnailFormat attachmentThumbnailFormat = ThumbnailFormat.jpeg, ThumbnailFormat attachmentThumbnailFormat = ThumbnailFormat.jpeg,
int attachmentThumbnailQuality = 100, int attachmentThumbnailQuality = 100,
@@ -702,74 +703,76 @@ Widget mobileAttachmentPickerBuilder({
controller: controller, controller: controller,
onSendAttachments: Navigator.of(context).pop, onSendAttachments: Navigator.of(context).pop,
options: { options: {
if (customOptions != null) ...customOptions, ...{
AttachmentPickerOption( if (customOptions != null) ...customOptions,
key: 'gallery-picker', AttachmentPickerOption(
icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(), key: 'gallery-picker',
supportedTypes: [ icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(),
AttachmentPickerType.images, supportedTypes: [
AttachmentPickerType.videos, AttachmentPickerType.images,
], AttachmentPickerType.videos,
optionViewBuilder: (context, controller) { ],
final selectedIds = controller.value.map((it) => it.id); optionViewBuilder: (context, controller) {
return StreamGalleryPicker( final selectedIds = controller.value.map((it) => it.id);
selectedMediaItems: selectedIds, return StreamGalleryPicker(
mediaThumbnailSize: attachmentThumbnailSize, selectedMediaItems: selectedIds,
mediaThumbnailFormat: attachmentThumbnailFormat, mediaThumbnailSize: attachmentThumbnailSize,
mediaThumbnailQuality: attachmentThumbnailQuality, mediaThumbnailFormat: attachmentThumbnailFormat,
mediaThumbnailScale: attachmentThumbnailScale, mediaThumbnailQuality: attachmentThumbnailQuality,
onMediaItemSelected: (media) async { mediaThumbnailScale: attachmentThumbnailScale,
if (selectedIds.contains(media.id)) { onMediaItemSelected: (media) async {
return controller.removeAssetAttachment(media); if (selectedIds.contains(media.id)) {
} return controller.removeAssetAttachment(media);
return controller.addAssetAttachment(media); }
}, return controller.addAssetAttachment(media);
); },
}, );
), },
AttachmentPickerOption( ),
key: 'file-picker', AttachmentPickerOption(
icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(), key: 'file-picker',
supportedTypes: [AttachmentPickerType.files], icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(),
optionViewBuilder: (context, controller) { supportedTypes: [AttachmentPickerType.files],
return StreamFilePicker( optionViewBuilder: (context, controller) {
onFilePicked: (file) async { return StreamFilePicker(
if (file != null) await controller.addAttachment(file); onFilePicked: (file) async {
return Navigator.pop(context, controller.value); if (file != null) await controller.addAttachment(file);
}, return Navigator.pop(context, controller.value);
); },
}, );
), },
AttachmentPickerOption( ),
key: 'image-picker', AttachmentPickerOption(
icon: StreamSvgIcon.camera(size: 36).toIconThemeSvgIcon(), key: 'image-picker',
supportedTypes: [AttachmentPickerType.images], icon: StreamSvgIcon.camera(size: 36).toIconThemeSvgIcon(),
optionViewBuilder: (context, controller) { supportedTypes: [AttachmentPickerType.images],
return StreamImagePicker( optionViewBuilder: (context, controller) {
onImagePicked: (image) async { return StreamImagePicker(
if (image != null) { onImagePicked: (image) async {
await controller.addAttachment(image); if (image != null) {
} await controller.addAttachment(image);
return Navigator.pop(context, controller.value); }
}, return Navigator.pop(context, controller.value);
); },
}, );
), },
AttachmentPickerOption( ),
key: 'video-picker', AttachmentPickerOption(
icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(), key: 'video-picker',
supportedTypes: [AttachmentPickerType.videos], icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(),
optionViewBuilder: (context, controller) { supportedTypes: [AttachmentPickerType.videos],
return StreamVideoPicker( optionViewBuilder: (context, controller) {
onVideoPicked: (video) async { return StreamVideoPicker(
if (video != null) { onVideoPicked: (video) async {
await controller.addAttachment(video); if (video != null) {
} await controller.addAttachment(video);
return Navigator.pop(context, controller.value); }
}, return Navigator.pop(context, controller.value);
); },
}, );
), },
),
}..where((option) => option.supportedTypes.every(allowedTypes.contains)),
}, },
); );
} }
@@ -779,6 +782,7 @@ Widget webOrDesktopAttachmentPickerBuilder({
required BuildContext context, required BuildContext context,
required StreamAttachmentPickerController controller, required StreamAttachmentPickerController controller,
Iterable<WebOrDesktopAttachmentPickerOption>? customOptions, Iterable<WebOrDesktopAttachmentPickerOption>? customOptions,
List<AttachmentPickerType> allowedTypes = AttachmentPickerType.values,
ThumbnailSize attachmentThumbnailSize = const ThumbnailSize(400, 400), ThumbnailSize attachmentThumbnailSize = const ThumbnailSize(400, 400),
ThumbnailFormat attachmentThumbnailFormat = ThumbnailFormat.jpeg, ThumbnailFormat attachmentThumbnailFormat = ThumbnailFormat.jpeg,
int attachmentThumbnailQuality = 100, int attachmentThumbnailQuality = 100,
@@ -787,25 +791,27 @@ Widget webOrDesktopAttachmentPickerBuilder({
return StreamWebOrDesktopAttachmentPickerBottomSheet( return StreamWebOrDesktopAttachmentPickerBottomSheet(
controller: controller, controller: controller,
options: { options: {
if (customOptions != null) ...customOptions, ...{
WebOrDesktopAttachmentPickerOption( if (customOptions != null) ...customOptions,
key: 'image-picker', WebOrDesktopAttachmentPickerOption(
type: AttachmentPickerType.images, key: 'image-picker',
icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(), type: AttachmentPickerType.images,
title: context.translations.uploadAPhotoLabel, icon: StreamSvgIcon.pictures(size: 36).toIconThemeSvgIcon(),
), title: context.translations.uploadAPhotoLabel,
WebOrDesktopAttachmentPickerOption( ),
key: 'video-picker', WebOrDesktopAttachmentPickerOption(
type: AttachmentPickerType.videos, key: 'video-picker',
icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(), type: AttachmentPickerType.videos,
title: context.translations.uploadAVideoLabel, icon: StreamSvgIcon.record(size: 36).toIconThemeSvgIcon(),
), title: context.translations.uploadAVideoLabel,
WebOrDesktopAttachmentPickerOption( ),
key: 'file-picker', WebOrDesktopAttachmentPickerOption(
type: AttachmentPickerType.files, key: 'file-picker',
icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(), type: AttachmentPickerType.files,
title: context.translations.uploadAFileLabel, icon: StreamSvgIcon.files(size: 36).toIconThemeSvgIcon(),
), title: context.translations.uploadAFileLabel,
),
}.where((option) => option.supportedTypes.every(allowedTypes.contains)),
}, },
onOptionTap: (context, controller, option) async { onOptionTap: (context, controller, option) async {
final attachment = await StreamAttachmentHandler.instance.pickFile( final attachment = await StreamAttachmentHandler.instance.pickFile(
@@ -66,6 +66,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
Future<T?> showStreamAttachmentPickerModalBottomSheet<T>({ Future<T?> showStreamAttachmentPickerModalBottomSheet<T>({
required BuildContext context, required BuildContext context,
Iterable<AttachmentPickerOption>? customOptions, Iterable<AttachmentPickerOption>? customOptions,
List<AttachmentPickerType> allowedTypes = AttachmentPickerType.values,
List<Attachment>? initialAttachments, List<Attachment>? initialAttachments,
StreamAttachmentPickerController? controller, StreamAttachmentPickerController? controller,
Color? backgroundColor, Color? backgroundColor,
@@ -117,6 +118,7 @@ Future<T?> showStreamAttachmentPickerModalBottomSheet<T>({
return webOrDesktopAttachmentPickerBuilder.call( return webOrDesktopAttachmentPickerBuilder.call(
context: context, context: context,
controller: controller, controller: controller,
allowedTypes: allowedTypes,
customOptions: customOptions?.map( customOptions: customOptions?.map(
WebOrDesktopAttachmentPickerOption.fromAttachmentPickerOption, WebOrDesktopAttachmentPickerOption.fromAttachmentPickerOption,
), ),
@@ -130,6 +132,7 @@ Future<T?> showStreamAttachmentPickerModalBottomSheet<T>({
return mobileAttachmentPickerBuilder.call( return mobileAttachmentPickerBuilder.call(
context: context, context: context,
controller: controller, controller: controller,
allowedTypes: allowedTypes,
customOptions: customOptions, customOptions: customOptions,
attachmentThumbnailSize: attachmentThumbnailSize, attachmentThumbnailSize: attachmentThumbnailSize,
attachmentThumbnailFormat: attachmentThumbnailFormat, attachmentThumbnailFormat: attachmentThumbnailFormat,
@@ -122,6 +122,7 @@ class StreamMessageInput extends StatefulWidget {
this.maxAttachmentSize = kDefaultMaxAttachmentSize, this.maxAttachmentSize = kDefaultMaxAttachmentSize,
this.onError, this.onError,
this.attachmentLimit = 10, this.attachmentLimit = 10,
this.allowedAttachmentPickerTypes = AttachmentPickerType.values,
this.onAttachmentLimitExceed, this.onAttachmentLimitExceed,
this.attachmentButtonBuilder, this.attachmentButtonBuilder,
this.commandButtonBuilder, 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. /// A limit for the no. of attachments that can be sent with a single message.
final int attachmentLimit; 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<AttachmentPickerType> allowedAttachmentPickerTypes;
/// A callback for when the [attachmentLimit] is exceeded. /// A callback for when the [attachmentLimit] is exceeded.
/// ///
/// This will override the default error alert behaviour. /// This will override the default error alert behaviour.
@@ -771,8 +778,9 @@ class StreamMessageInputState extends State<StreamMessageInput>
Future<void> _onAttachmentButtonPressed() async { Future<void> _onAttachmentButtonPressed() async {
final attachments = await showStreamAttachmentPickerModalBottomSheet( final attachments = await showStreamAttachmentPickerModalBottomSheet(
context: context, context: context,
initialAttachments: _effectiveController.attachments,
useRootNavigator: true, useRootNavigator: true,
allowedTypes: widget.allowedAttachmentPickerTypes,
initialAttachments: _effectiveController.attachments,
); );
if (attachments != null) { if (attachments != null) {