Merge pull request #616 from GetStream/feat/message-input-action-builders
feat(ui): add support for `attachmentButtonBuilder`, `commandButtonBuilder`
This commit is contained in:
@@ -2,21 +2,35 @@
|
|||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|
||||||
- [#516](https://github.com/GetStream/stream-chat-flutter/issues/516): Added `StreamChatThemeData.placeholderUserImage` for
|
- [#516](https://github.com/GetStream/stream-chat-flutter/issues/516):
|
||||||
building a widget when the `UserAvatar` image is loading
|
Added `StreamChatThemeData.placeholderUserImage` for building a widget when the `UserAvatar` image
|
||||||
|
is loading
|
||||||
- Added a `backgroundColor` property to the following widgets:
|
- Added a `backgroundColor` property to the following widgets:
|
||||||
- `ChannelHeader`
|
- `ChannelHeader`
|
||||||
- `ChannelListHeader`
|
- `ChannelListHeader`
|
||||||
- `GalleryHeader`
|
- `GalleryHeader`
|
||||||
- `GalleryFooter`
|
- `GalleryFooter`
|
||||||
- `ThreadHeader`
|
- `ThreadHeader`
|
||||||
|
|
||||||
|
- Added `MessageInput.attachmentButtonBuilder` and `MessageInput.commandButtonBuilder` for more
|
||||||
|
customizations.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
typedef ActionButtonBuilder = Widget Function(
|
||||||
|
BuildContext context,
|
||||||
|
IconButton defaultActionButton,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
> **_NOTE:_** The last parameter is the default `ActionButton`
|
||||||
|
You can call `.copyWith` to customize just a subset of properties.
|
||||||
|
|
||||||
🔄 Changed
|
🔄 Changed
|
||||||
|
|
||||||
Theming has been upgraded! Most theme classes now have `InheritedTheme` classes
|
Theming has been upgraded! Most theme classes now have `InheritedTheme` classes associated with
|
||||||
associated with them, and have been upgraded with some goodies like `lerp` functions.
|
them, and have been upgraded with some goodies like `lerp` functions. Here's the full naming
|
||||||
Here's the full naming breakdown:
|
breakdown:
|
||||||
|
|
||||||
* `AvatarTheme` is now `AvatarThemeData`
|
* `AvatarTheme` is now `AvatarThemeData`
|
||||||
* `ChannelHeaderTheme` is now `ChannelHeaderThemeData`
|
* `ChannelHeaderTheme` is now `ChannelHeaderThemeData`
|
||||||
* `ChannelListHeaderTheme` is now `ChannelListHeaderThemeData`
|
* `ChannelListHeaderTheme` is now `ChannelListHeaderThemeData`
|
||||||
@@ -32,8 +46,9 @@ Here's the full naming breakdown:
|
|||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|
||||||
- [#590](https://github.com/GetStream/stream-chat-flutter/issues/590): livestream use case, no members when sending message
|
- [#590](https://github.com/GetStream/stream-chat-flutter/issues/590): livestream use case, no
|
||||||
|
members when sending message
|
||||||
|
|
||||||
## 2.1.1
|
## 2.1.1
|
||||||
|
|
||||||
- Updated core dependency
|
- Updated core dependency
|
||||||
@@ -50,7 +65,8 @@ Here's the full naming breakdown:
|
|||||||
🔄 Changed
|
🔄 Changed
|
||||||
|
|
||||||
- `StreamChat.of(context).user` is now deprecated in favor of `StreamChat.of(context).currentUser`.
|
- `StreamChat.of(context).user` is now deprecated in favor of `StreamChat.of(context).currentUser`.
|
||||||
- `StreamChat.of(context).userStream` is now deprecated in favor of `StreamChat.of(context).currentUserStream`.
|
- `StreamChat.of(context).userStream` is now deprecated in favor
|
||||||
|
of `StreamChat.of(context).currentUserStream`.
|
||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|
||||||
@@ -64,17 +80,17 @@ Here's the full naming breakdown:
|
|||||||
- Renamed `ChannelImage` to `ChannelAvatar`
|
- Renamed `ChannelImage` to `ChannelAvatar`
|
||||||
- Updated `StreamChatThemeData.reactionIcons` to accept custom builder
|
- Updated `StreamChatThemeData.reactionIcons` to accept custom builder
|
||||||
- Renamed `ColorTheme` properties to reflect the purpose of the colors
|
- Renamed `ColorTheme` properties to reflect the purpose of the colors
|
||||||
- `ColorTheme.black` -> `ColorTheme.textHighEmphasis`
|
- `ColorTheme.black` -> `ColorTheme.textHighEmphasis`
|
||||||
- `ColorTheme.grey` -> `ColorTheme.textLowEmphasis`
|
- `ColorTheme.grey` -> `ColorTheme.textLowEmphasis`
|
||||||
- `ColorTheme.greyGainsboro` -> `ColorTheme.disabled`
|
- `ColorTheme.greyGainsboro` -> `ColorTheme.disabled`
|
||||||
- `ColorTheme.greyWhisper` -> `ColorTheme.borders`
|
- `ColorTheme.greyWhisper` -> `ColorTheme.borders`
|
||||||
- `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg`
|
- `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg`
|
||||||
- `ColorTheme.whiteSnow` -> `ColorTheme.appBg`
|
- `ColorTheme.whiteSnow` -> `ColorTheme.appBg`
|
||||||
- `ColorTheme.white` -> `ColorTheme.barsBg`
|
- `ColorTheme.white` -> `ColorTheme.barsBg`
|
||||||
- `ColorTheme.blueAlice` -> `ColorTheme.linkBg`
|
- `ColorTheme.blueAlice` -> `ColorTheme.linkBg`
|
||||||
- `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary`
|
- `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary`
|
||||||
- `ColorTheme.accentRed` -> `ColorTheme.accentError`
|
- `ColorTheme.accentRed` -> `ColorTheme.accentError`
|
||||||
- `ColorTheme.accentGreen` -> `ColorTheme.accentInfo`
|
- `ColorTheme.accentGreen` -> `ColorTheme.accentInfo`
|
||||||
|
|
||||||
- `ChannelListCore` options property is removed in favor of individual properties
|
- `ChannelListCore` options property is removed in favor of individual properties
|
||||||
- `options.state` -> bool state
|
- `options.state` -> bool state
|
||||||
@@ -95,7 +111,7 @@ typedef MessageBuilder = Widget Function(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
the last parameter is the default `MessageWidget`
|
> **_NOTE:_** the last parameter is the default `MessageWidget`
|
||||||
You can call `.copyWith` to customize just a subset of properties
|
You can call `.copyWith` to customize just a subset of properties
|
||||||
|
|
||||||
|
|
||||||
@@ -103,7 +119,8 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
|
|
||||||
- Added video compress options (frame and quality) to `MessageInput`
|
- Added video compress options (frame and quality) to `MessageInput`
|
||||||
- TypingIndicator now has a property called `parentId` to show typing indicator specific to threads
|
- TypingIndicator now has a property called `parentId` to show typing indicator specific to threads
|
||||||
- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView header/footer
|
- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView
|
||||||
|
header/footer
|
||||||
- `MessageWidget` accepts a `userAvatarBuilder`
|
- `MessageWidget` accepts a `userAvatarBuilder`
|
||||||
- Added pinMessage ui support
|
- Added pinMessage ui support
|
||||||
- Added `MessageListView.threadSeparatorBuilder` property
|
- Added `MessageListView.threadSeparatorBuilder` property
|
||||||
@@ -112,10 +129,12 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|
||||||
- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text box when editing
|
- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text
|
||||||
message
|
box when editing message
|
||||||
- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator use case
|
- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator
|
||||||
- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without a reload
|
use case
|
||||||
|
- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without
|
||||||
|
a reload
|
||||||
- `MessageListView` not rendering if the user is not a member of the channel
|
- `MessageListView` not rendering if the user is not a member of the channel
|
||||||
- Fix `MessageInput` overflow when there are no actions
|
- Fix `MessageInput` overflow when there are no actions
|
||||||
- Minor fixes and improvements
|
- Minor fixes and improvements
|
||||||
@@ -125,17 +144,17 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
🛑️ Breaking Changes from `2.0.0-nullsafety.8`
|
🛑️ Breaking Changes from `2.0.0-nullsafety.8`
|
||||||
|
|
||||||
- Renamed `ColorTheme` properties to reflect the purpose of the colors
|
- Renamed `ColorTheme` properties to reflect the purpose of the colors
|
||||||
- `ColorTheme.black` -> `ColorTheme.textHighEmphasis`
|
- `ColorTheme.black` -> `ColorTheme.textHighEmphasis`
|
||||||
- `ColorTheme.grey` -> `ColorTheme.textLowEmphasis`
|
- `ColorTheme.grey` -> `ColorTheme.textLowEmphasis`
|
||||||
- `ColorTheme.greyGainsboro` -> `ColorTheme.disabled`
|
- `ColorTheme.greyGainsboro` -> `ColorTheme.disabled`
|
||||||
- `ColorTheme.greyWhisper` -> `ColorTheme.borders`
|
- `ColorTheme.greyWhisper` -> `ColorTheme.borders`
|
||||||
- `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg`
|
- `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg`
|
||||||
- `ColorTheme.whiteSnow` -> `ColorTheme.appBg`
|
- `ColorTheme.whiteSnow` -> `ColorTheme.appBg`
|
||||||
- `ColorTheme.white` -> `ColorTheme.barsBg`
|
- `ColorTheme.white` -> `ColorTheme.barsBg`
|
||||||
- `ColorTheme.blueAlice` -> `ColorTheme.linkBg`
|
- `ColorTheme.blueAlice` -> `ColorTheme.linkBg`
|
||||||
- `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary`
|
- `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary`
|
||||||
- `ColorTheme.accentRed` -> `ColorTheme.accentError`
|
- `ColorTheme.accentRed` -> `ColorTheme.accentError`
|
||||||
- `ColorTheme.accentGreen` -> `ColorTheme.accentInfo`
|
- `ColorTheme.accentGreen` -> `ColorTheme.accentInfo`
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|
||||||
@@ -162,21 +181,24 @@ typedef MessageBuilder = Widget Function(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
the last parameter is the default `MessageWidget`
|
> **_NOTE:_** The last parameter is the default `MessageWidget`
|
||||||
You can call `.copyWith` to customize just a subset of properties
|
You can call `.copyWith` to customize just a subset of properties.
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|
||||||
- TypingIndicator now has a property called `parentId` to show typing indicator specific to threads
|
- TypingIndicator now has a property called `parentId` to show typing indicator specific to threads
|
||||||
- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView header/footer
|
- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView
|
||||||
|
header/footer
|
||||||
- `MessageWidget` accepts a `userAvatarBuilder`
|
- `MessageWidget` accepts a `userAvatarBuilder`
|
||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|
||||||
- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text box when editing
|
- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text
|
||||||
message
|
box when editing message
|
||||||
- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator use case
|
- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator
|
||||||
- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without a reload
|
use case
|
||||||
|
- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without
|
||||||
|
a reload
|
||||||
- `MessageListView` not rendering if the user is not a member of the channel
|
- `MessageListView` not rendering if the user is not a member of the channel
|
||||||
|
|
||||||
## 2.0.0-nullsafety.7
|
## 2.0.0-nullsafety.7
|
||||||
@@ -246,7 +268,8 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
- Show error messages as system and keep them in the message input
|
- Show error messages as system and keep them in the message input
|
||||||
- Remove notification badge logic
|
- Remove notification badge logic
|
||||||
- Use shimmer while loading images
|
- Use shimmer while loading images
|
||||||
- Polished `StreamChatTheme` adding more options and a new `MessageInputTheme` dedicated to `MessageInput`
|
- Polished `StreamChatTheme` adding more options and a new `MessageInputTheme` dedicated
|
||||||
|
to `MessageInput`
|
||||||
- Add possibility to specify custom message actions using `MessageWidget.customActions`
|
- Add possibility to specify custom message actions using `MessageWidget.customActions`
|
||||||
- Added `MessageListView.onAttachmentTap` callback
|
- Added `MessageListView.onAttachmentTap` callback
|
||||||
- Fixed message newline issue
|
- Fixed message newline issue
|
||||||
@@ -303,7 +326,8 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
- Improved api documentation
|
- Improved api documentation
|
||||||
- Updated `stream_chat` dependency to `^1.0.0-beta`
|
- Updated `stream_chat` dependency to `^1.0.0-beta`
|
||||||
- Extracted sample app into dedicated [repo](https://github.com/GetStream/flutter-samples)
|
- Extracted sample app into dedicated [repo](https://github.com/GetStream/flutter-samples)
|
||||||
- Reimplemented existing widgets using [stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core)
|
- Reimplemented existing widgets
|
||||||
|
using [stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core)
|
||||||
|
|
||||||
## 0.2.21
|
## 0.2.21
|
||||||
|
|
||||||
@@ -320,8 +344,8 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
|
|
||||||
## 0.2.20+2
|
## 0.2.20+2
|
||||||
|
|
||||||
- Added `shouldAddChannel` to ChannelsBloc in order to check if a channel has to be added to the list when a new message
|
- Added `shouldAddChannel` to ChannelsBloc in order to check if a channel has to be added to the
|
||||||
arrives
|
list when a new message arrives
|
||||||
|
|
||||||
## 0.2.20+1
|
## 0.2.20+1
|
||||||
|
|
||||||
@@ -355,7 +379,8 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
|
|
||||||
## 0.2.16
|
## 0.2.16
|
||||||
|
|
||||||
- Do not wrap channel preview builder. Users will have to implement they're custom onTap/onLongPress implementation
|
- Do not wrap channel preview builder. Users will have to implement they're custom onTap/onLongPress
|
||||||
|
implementation
|
||||||
- Make public autofocus field of the TextField of message_input
|
- Make public autofocus field of the TextField of message_input
|
||||||
|
|
||||||
## 0.2.15
|
## 0.2.15
|
||||||
@@ -540,10 +565,11 @@ You can call `.copyWith` to customize just a subset of properties
|
|||||||
|
|
||||||
## 0.2.1-alpha+1
|
## 0.2.1-alpha+1
|
||||||
|
|
||||||
- Removed the additional `Navigator` in `StreamChat` widget. It was added to make the app have the `StreamChat` widget
|
- Removed the additional `Navigator` in `StreamChat` widget. It was added to make the app have
|
||||||
as ancestor in every route. Now the recommended way to add `StreamChat` to your app is using the `builder` property of
|
the `StreamChat` widget as ancestor in every route. Now the recommended way to add `StreamChat` to
|
||||||
your `MaterialApp` widget. Otherwise you can use it in the usual way, but you need to add a `StreamChat` widget to
|
your app is using the `builder` property of your `MaterialApp` widget. Otherwise you can use it in
|
||||||
every route of your app. Read [this issue](https://github.com/GetStream/stream-chat-flutter/issues/47) for more
|
the usual way, but you need to add a `StreamChat` widget to every route of your app.
|
||||||
|
Read [this issue](https://github.com/GetStream/stream-chat-flutter/issues/47) for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
@@ -645,8 +671,8 @@ Widget build(BuildContext context) {
|
|||||||
|
|
||||||
- Add gesture (vertical drag down) to close the keyboard
|
- Add gesture (vertical drag down) to close the keyboard
|
||||||
|
|
||||||
- Add keyboard type parameters (set it to TextInputType.text to show the submit button that will even close the
|
- Add keyboard type parameters (set it to TextInputType.text to show the submit button that will
|
||||||
keyboard)
|
even close the keyboard)
|
||||||
|
|
||||||
The property showVideoFullScreen was added mainly because of this issue brianegan/chewie#261
|
The property showVideoFullScreen was added mainly because of this issue brianegan/chewie#261
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ extension PlatformFileX on PlatformFile {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
/// Extension on [InputDecoration]
|
||||||
extension InputDecorationX on InputDecoration {
|
extension InputDecorationX on InputDecoration {
|
||||||
///
|
/// Merges this [InputDecoration] with the [other]
|
||||||
InputDecoration merge(InputDecoration? other) {
|
InputDecoration merge(InputDecoration? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
@@ -123,3 +123,50 @@ extension FlipBorder on BorderRadius {
|
|||||||
bottomRight: bottomLeft)
|
bottomRight: bottomLeft)
|
||||||
: this;
|
: this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extension on [IconButton]
|
||||||
|
extension IconButtonX on IconButton {
|
||||||
|
/// Creates a copy of [IconButton] with specified attributes overridden.
|
||||||
|
IconButton copyWith({
|
||||||
|
double? iconSize,
|
||||||
|
VisualDensity? visualDensity,
|
||||||
|
EdgeInsetsGeometry? padding,
|
||||||
|
AlignmentGeometry? alignment,
|
||||||
|
double? splashRadius,
|
||||||
|
Color? color,
|
||||||
|
Color? focusColor,
|
||||||
|
Color? hoverColor,
|
||||||
|
Color? highlightColor,
|
||||||
|
Color? splashColor,
|
||||||
|
Color? disabledColor,
|
||||||
|
void Function()? onPressed,
|
||||||
|
MouseCursor? mouseCursor,
|
||||||
|
FocusNode? focusNode,
|
||||||
|
bool? autofocus,
|
||||||
|
String? tooltip,
|
||||||
|
bool? enableFeedback,
|
||||||
|
BoxConstraints? constraints,
|
||||||
|
Widget? icon,
|
||||||
|
}) =>
|
||||||
|
IconButton(
|
||||||
|
iconSize: iconSize ?? this.iconSize,
|
||||||
|
visualDensity: visualDensity ?? this.visualDensity,
|
||||||
|
padding: padding ?? this.padding,
|
||||||
|
alignment: alignment ?? this.alignment,
|
||||||
|
splashRadius: splashRadius ?? this.splashRadius,
|
||||||
|
color: color ?? this.color,
|
||||||
|
focusColor: focusColor ?? this.focusColor,
|
||||||
|
hoverColor: hoverColor ?? this.hoverColor,
|
||||||
|
highlightColor: highlightColor ?? this.highlightColor,
|
||||||
|
splashColor: splashColor ?? this.splashColor,
|
||||||
|
disabledColor: disabledColor ?? this.disabledColor,
|
||||||
|
onPressed: onPressed ?? this.onPressed,
|
||||||
|
mouseCursor: mouseCursor ?? this.mouseCursor,
|
||||||
|
focusNode: focusNode ?? this.focusNode,
|
||||||
|
autofocus: autofocus ?? this.autofocus,
|
||||||
|
tooltip: tooltip ?? this.tooltip,
|
||||||
|
enableFeedback: enableFeedback ?? this.enableFeedback,
|
||||||
|
constraints: constraints ?? this.constraints,
|
||||||
|
icon: icon ?? this.icon,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ typedef MentionTileBuilder = Widget Function(
|
|||||||
Member member,
|
Member member,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Widget builder for action button.
|
||||||
|
///
|
||||||
|
/// [defaultActionButton] is the default [IconButton] configuration,
|
||||||
|
/// use [defaultActionButton.copyWith] to easily customize it.
|
||||||
|
typedef ActionButtonBuilder = Widget Function(
|
||||||
|
BuildContext context,
|
||||||
|
IconButton defaultActionButton,
|
||||||
|
);
|
||||||
|
|
||||||
/// Location for actions on the [MessageInput]
|
/// Location for actions on the [MessageInput]
|
||||||
enum ActionsLocation {
|
enum ActionsLocation {
|
||||||
/// Align to left
|
/// Align to left
|
||||||
@@ -164,6 +173,8 @@ class MessageInput extends StatefulWidget {
|
|||||||
this.compressedVideoQuality = VideoQuality.DefaultQuality,
|
this.compressedVideoQuality = VideoQuality.DefaultQuality,
|
||||||
this.compressedVideoFrameRate = 30,
|
this.compressedVideoFrameRate = 30,
|
||||||
this.onError,
|
this.onError,
|
||||||
|
this.attachmentButtonBuilder,
|
||||||
|
this.commandButtonBuilder,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Message to edit
|
/// Message to edit
|
||||||
@@ -247,6 +258,18 @@ class MessageInput extends StatefulWidget {
|
|||||||
/// A callback for error reporting
|
/// A callback for error reporting
|
||||||
final ErrorListener? onError;
|
final ErrorListener? onError;
|
||||||
|
|
||||||
|
/// Builder for customizing the attachment button.
|
||||||
|
///
|
||||||
|
/// The builder contains the default [IconButton] that can be customized by
|
||||||
|
/// calling `.copyWith`.
|
||||||
|
final ActionButtonBuilder? attachmentButtonBuilder;
|
||||||
|
|
||||||
|
/// Builder for customizing the command button.
|
||||||
|
///
|
||||||
|
/// The builder contains the default [IconButton] that can be customized by
|
||||||
|
/// calling `.copyWith`.
|
||||||
|
final ActionButtonBuilder? commandButtonBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MessageInputState createState() => MessageInputState();
|
MessageInputState createState() => MessageInputState();
|
||||||
|
|
||||||
@@ -403,11 +426,11 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (!_commandEnabled &&
|
if (!_commandEnabled &&
|
||||||
widget.actionsLocation == ActionsLocation.left)
|
widget.actionsLocation == ActionsLocation.left)
|
||||||
_buildExpandActionsButton(),
|
_buildExpandActionsButton(context),
|
||||||
_buildTextInput(context),
|
_buildTextInput(context),
|
||||||
if (!_commandEnabled &&
|
if (!_commandEnabled &&
|
||||||
widget.actionsLocation == ActionsLocation.right)
|
widget.actionsLocation == ActionsLocation.right)
|
||||||
_buildExpandActionsButton(),
|
_buildExpandActionsButton(context),
|
||||||
if (widget.sendButtonLocation == SendButtonLocation.outside)
|
if (widget.sendButtonLocation == SendButtonLocation.outside)
|
||||||
_animateSendButton(context),
|
_animateSendButton(context),
|
||||||
],
|
],
|
||||||
@@ -490,7 +513,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildExpandActionsButton() {
|
Widget _buildExpandActionsButton(BuildContext context) {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
@@ -528,12 +551,13 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (!widget.disableAttachments) _buildAttachmentButton(),
|
if (!widget.disableAttachments)
|
||||||
|
_buildAttachmentButton(context),
|
||||||
if (widget.showCommandsButton &&
|
if (widget.showCommandsButton &&
|
||||||
widget.editMessage == null &&
|
widget.editMessage == null &&
|
||||||
channel.state != null &&
|
channel.state != null &&
|
||||||
channel.config?.commands.isNotEmpty == true)
|
channel.config?.commands.isNotEmpty == true)
|
||||||
_buildCommandButton(),
|
_buildCommandButton(context),
|
||||||
...widget.actions ?? [],
|
...widget.actions ?? [],
|
||||||
].insertBetween(const SizedBox(width: 8)),
|
].insertBetween(const SizedBox(width: 8)),
|
||||||
),
|
),
|
||||||
@@ -669,9 +693,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
: (widget.actionsLocation == ActionsLocation.leftInside
|
: (widget.actionsLocation == ActionsLocation.leftInside
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [_buildExpandActionsButton(context)],
|
||||||
_buildExpandActionsButton(),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
: null),
|
: null),
|
||||||
suffixIconConstraints: const BoxConstraints.tightFor(height: 40),
|
suffixIconConstraints: const BoxConstraints.tightFor(height: 40),
|
||||||
@@ -697,7 +719,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
if (!_commandEnabled &&
|
if (!_commandEnabled &&
|
||||||
widget.actionsLocation == ActionsLocation.rightInside)
|
widget.actionsLocation == ActionsLocation.rightInside)
|
||||||
_buildExpandActionsButton(),
|
_buildExpandActionsButton(context),
|
||||||
if (widget.sendButtonLocation == SendButtonLocation.inside)
|
if (widget.sendButtonLocation == SendButtonLocation.inside)
|
||||||
_animateSendButton(context),
|
_animateSendButton(context),
|
||||||
],
|
],
|
||||||
@@ -1681,10 +1703,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCommandButton() {
|
Widget _buildCommandButton(BuildContext context) {
|
||||||
final s = textEditingController.text.trim();
|
final s = textEditingController.text.trim();
|
||||||
|
final defaultButton = IconButton(
|
||||||
return IconButton(
|
|
||||||
icon: StreamSvgIcon.lightning(
|
icon: StreamSvgIcon.lightning(
|
||||||
color: s.isNotEmpty
|
color: s.isNotEmpty
|
||||||
? _streamChatTheme.colorTheme.disabled
|
? _streamChatTheme.colorTheme.disabled
|
||||||
@@ -1722,38 +1743,46 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return widget.commandButtonBuilder?.call(context, defaultButton) ??
|
||||||
|
defaultButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAttachmentButton() => IconButton(
|
Widget _buildAttachmentButton(BuildContext context) {
|
||||||
icon: StreamSvgIcon.attach(
|
final defaultButton = IconButton(
|
||||||
color: _openFilePickerSection
|
icon: StreamSvgIcon.attach(
|
||||||
? _messageInputTheme.actionButtonColor
|
color: _openFilePickerSection
|
||||||
: _messageInputTheme.actionButtonIdleColor,
|
? _messageInputTheme.actionButtonColor
|
||||||
),
|
: _messageInputTheme.actionButtonIdleColor,
|
||||||
padding: const EdgeInsets.all(0),
|
),
|
||||||
constraints: const BoxConstraints.tightFor(
|
padding: const EdgeInsets.all(0),
|
||||||
height: 24,
|
constraints: const BoxConstraints.tightFor(
|
||||||
width: 24,
|
height: 24,
|
||||||
),
|
width: 24,
|
||||||
splashRadius: 24,
|
),
|
||||||
onPressed: () async {
|
splashRadius: 24,
|
||||||
_emojiOverlay?.remove();
|
onPressed: () async {
|
||||||
_emojiOverlay = null;
|
_emojiOverlay?.remove();
|
||||||
_commandsOverlay?.remove();
|
_emojiOverlay = null;
|
||||||
_commandsOverlay = null;
|
_commandsOverlay?.remove();
|
||||||
_mentionsOverlay?.remove();
|
_commandsOverlay = null;
|
||||||
_mentionsOverlay = null;
|
_mentionsOverlay?.remove();
|
||||||
|
_mentionsOverlay = null;
|
||||||
|
|
||||||
if (_openFilePickerSection) {
|
if (_openFilePickerSection) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_openFilePickerSection = false;
|
_openFilePickerSection = false;
|
||||||
_filePickerSize = _kMinMediaPickerSize;
|
_filePickerSize = _kMinMediaPickerSize;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
showAttachmentModal();
|
showAttachmentModal();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return widget.attachmentButtonBuilder?.call(context, defaultButton) ??
|
||||||
|
defaultButton;
|
||||||
|
}
|
||||||
|
|
||||||
/// Show the attachment modal, making the user choose where to
|
/// Show the attachment modal, making the user choose where to
|
||||||
/// pick a media from
|
/// pick a media from
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export 'src/channel_preview.dart';
|
|||||||
export 'src/connection_status_builder.dart';
|
export 'src/connection_status_builder.dart';
|
||||||
export 'src/date_divider.dart';
|
export 'src/date_divider.dart';
|
||||||
export 'src/deleted_message.dart';
|
export 'src/deleted_message.dart';
|
||||||
|
export 'src/extension.dart' show IconButtonX;
|
||||||
export 'src/full_screen_media.dart';
|
export 'src/full_screen_media.dart';
|
||||||
export 'src/gallery_footer.dart';
|
export 'src/gallery_footer.dart';
|
||||||
export 'src/gallery_header.dart';
|
export 'src/gallery_header.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user