Merge pull request #1608 from GetStream/feat/allowed-attachment-picker-types
This commit is contained in:
@@ -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
|
||||||
|
|||||||
+93
-87
@@ -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(
|
||||||
|
|||||||
+3
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user