fix: add more actions locations, merge actions and add showCommandsButton option (#333)
* add more actions locations and merge actions * remove print * fix command chip * fix ui * rotate icon
This commit is contained in:
@@ -12,12 +12,12 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import 'package:stream_chat_flutter/src/video_service.dart';
|
||||
import 'package:stream_chat_flutter/src/media_list_view.dart';
|
||||
import 'package:stream_chat_flutter/src/message_list_view.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
||||
import 'package:stream_chat_flutter/src/video_service.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
import 'package:substring_highlight/substring_highlight.dart';
|
||||
|
||||
@@ -35,6 +35,8 @@ typedef AttachmentThumbnailBuilder = Widget Function(
|
||||
enum ActionsLocation {
|
||||
left,
|
||||
right,
|
||||
leftInside,
|
||||
rightInside,
|
||||
}
|
||||
|
||||
enum DefaultAttachmentTypes {
|
||||
@@ -122,6 +124,7 @@ class MessageInput extends StatefulWidget {
|
||||
this.hideSendAsDm = false,
|
||||
this.idleSendButton,
|
||||
this.activeSendButton,
|
||||
this.showCommandsButton = true,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Message to edit
|
||||
@@ -149,6 +152,9 @@ class MessageInput extends StatefulWidget {
|
||||
/// If true the attachments button will not be displayed
|
||||
final bool disableAttachments;
|
||||
|
||||
/// Use this property to hide/show the commands button
|
||||
final bool showCommandsButton;
|
||||
|
||||
/// Hide send as dm checkbox
|
||||
final bool hideSendAsDm;
|
||||
|
||||
@@ -336,12 +342,11 @@ class MessageInputState extends State<MessageInput> {
|
||||
direction: Axis.horizontal,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
if (!_commandEnabled) _buildExpandActionsButton(),
|
||||
if (widget.actionsLocation == ActionsLocation.left)
|
||||
...widget.actions ?? [],
|
||||
if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left)
|
||||
_buildExpandActionsButton(),
|
||||
_buildTextInput(context),
|
||||
if (widget.actionsLocation == ActionsLocation.right)
|
||||
...widget.actions ?? [],
|
||||
if (!_commandEnabled && widget.actionsLocation == ActionsLocation.right)
|
||||
_buildExpandActionsButton(),
|
||||
if (widget.sendButtonLocation == SendButtonLocation.outside)
|
||||
_animateSendButton(context),
|
||||
],
|
||||
@@ -421,18 +426,15 @@ class MessageInputState extends State<MessageInput> {
|
||||
child: widget.activeSendButton,
|
||||
)
|
||||
: _buildSendButton(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: AnimatedCrossFade(
|
||||
crossFadeState: (_messageIsPresent || _attachments.isNotEmpty)
|
||||
? CrossFadeState.showFirst
|
||||
: CrossFadeState.showSecond,
|
||||
firstChild: sendButton,
|
||||
secondChild: widget.idleSendButton ?? _buildIdleSendButton(context),
|
||||
duration:
|
||||
StreamChatTheme.of(context).messageInputTheme.sendAnimationDuration,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
return AnimatedCrossFade(
|
||||
crossFadeState: (_messageIsPresent || _attachments.isNotEmpty)
|
||||
? CrossFadeState.showFirst
|
||||
: CrossFadeState.showSecond,
|
||||
firstChild: sendButton,
|
||||
secondChild: widget.idleSendButton ?? _buildIdleSendButton(context),
|
||||
duration:
|
||||
StreamChatTheme.of(context).messageInputTheme.sendAnimationDuration,
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -445,8 +447,15 @@ class MessageInputState extends State<MessageInput> {
|
||||
: CrossFadeState.showSecond,
|
||||
firstChild: IconButton(
|
||||
onPressed: () => setState(() => _actionsShrunk = false),
|
||||
icon: StreamSvgIcon.emptyCircleLeft(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
icon: Transform.rotate(
|
||||
alignment: Alignment.center,
|
||||
angle: (widget.actionsLocation == ActionsLocation.right ||
|
||||
widget.actionsLocation == ActionsLocation.rightInside)
|
||||
? pi
|
||||
: 0,
|
||||
child: StreamSvgIcon.emptyCircleLeft(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: BoxConstraints.tightFor(
|
||||
@@ -457,10 +466,12 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
secondChild: FittedBox(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
if (!widget.disableAttachments) _buildAttachmentButton(),
|
||||
if (widget.editMessage == null &&
|
||||
if (widget.showCommandsButton &&
|
||||
widget.editMessage == null &&
|
||||
StreamChannel.of(context)
|
||||
.channel
|
||||
?.config
|
||||
@@ -468,6 +479,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
?.isNotEmpty ==
|
||||
true)
|
||||
_buildCommandButton(),
|
||||
...widget.actions ?? [],
|
||||
].insertBetween(const SizedBox(width: 8)),
|
||||
),
|
||||
),
|
||||
@@ -565,51 +577,75 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.fromLTRB(16, 12, 13, 11),
|
||||
prefixIconConstraints: BoxConstraints.tight(Size(78, 24)),
|
||||
suffixIconConstraints: BoxConstraints.tight(Size(40, 40)),
|
||||
prefixIcon: _commandEnabled
|
||||
? Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: theme.colorTheme.accentBlue,
|
||||
),
|
||||
margin: const EdgeInsets.only(right: 4, left: 8),
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
StreamSvgIcon.lightning(
|
||||
color: Colors.white,
|
||||
size: 16.0,
|
||||
),
|
||||
Text(
|
||||
_chosenCommand?.name?.toUpperCase() ?? '',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnoteBold
|
||||
.copyWith(
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
constraints: BoxConstraints.tight(Size(64, 24)),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: theme.colorTheme.accentBlue,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
StreamSvgIcon.lightning(
|
||||
color: Colors.white,
|
||||
size: 16.0,
|
||||
),
|
||||
Text(
|
||||
_chosenCommand?.name?.toUpperCase() ?? '',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnoteBold
|
||||
.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
: (widget.actionsLocation == ActionsLocation.leftInside
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
_buildExpandActionsButton(),
|
||||
],
|
||||
)
|
||||
: null),
|
||||
suffixIconConstraints: BoxConstraints.tightFor(height: 40),
|
||||
prefixIconConstraints: BoxConstraints.tightFor(height: 40),
|
||||
suffixIcon: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (_commandEnabled)
|
||||
IconButton(
|
||||
icon: StreamSvgIcon.closeSmall(),
|
||||
splashRadius: 24,
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 24,
|
||||
width: 24,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: IconButton(
|
||||
icon: StreamSvgIcon.closeSmall(),
|
||||
splashRadius: 24,
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() => _commandEnabled = false);
|
||||
},
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() => _commandEnabled = false);
|
||||
},
|
||||
),
|
||||
if (!_commandEnabled &&
|
||||
widget.actionsLocation == ActionsLocation.rightInside)
|
||||
_buildExpandActionsButton(),
|
||||
if (widget.sendButtonLocation == SendButtonLocation.inside)
|
||||
_animateSendButton(context),
|
||||
],
|
||||
@@ -619,7 +655,13 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
Timer _debounce;
|
||||
|
||||
String _previousValue;
|
||||
void _onChanged(BuildContext context, String s) {
|
||||
if (s == _previousValue) {
|
||||
return;
|
||||
}
|
||||
_previousValue = s;
|
||||
|
||||
if (_debounce?.isActive == true) _debounce.cancel();
|
||||
_debounce = Timer(
|
||||
const Duration(milliseconds: 350),
|
||||
@@ -631,7 +673,11 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
setState(() {
|
||||
_messageIsPresent = s.trim().isNotEmpty;
|
||||
_actionsShrunk = s.trim().isNotEmpty;
|
||||
_actionsShrunk = s.trim().isNotEmpty &&
|
||||
((widget.actions?.length ?? 0) +
|
||||
(widget.showCommandsButton ? 1 : 0) +
|
||||
(widget.disableAttachments ? 0 : 1) >
|
||||
1);
|
||||
});
|
||||
|
||||
_commandsOverlay?.remove();
|
||||
@@ -1684,13 +1730,19 @@ class MessageInputState extends State<MessageInput> {
|
||||
}
|
||||
|
||||
Widget _buildCommandButton() {
|
||||
final s = textEditingController.text.trim();
|
||||
|
||||
return IconButton(
|
||||
icon: StreamSvgIcon.lightning(
|
||||
color: _commandsOverlay != null
|
||||
? StreamChatTheme.of(context).messageInputTheme.actionButtonColor
|
||||
: StreamChatTheme.of(context)
|
||||
.messageInputTheme
|
||||
.actionButtonIdleColor,
|
||||
color: s.isNotEmpty
|
||||
? StreamChatTheme.of(context).colorTheme.greyGainsboro
|
||||
: (_commandsOverlay != null
|
||||
? StreamChatTheme.of(context)
|
||||
.messageInputTheme
|
||||
.actionButtonColor
|
||||
: StreamChatTheme.of(context)
|
||||
.messageInputTheme
|
||||
.actionButtonIdleColor),
|
||||
),
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: BoxConstraints.tightFor(
|
||||
@@ -1711,7 +1763,9 @@ class MessageInputState extends State<MessageInput> {
|
||||
if (_commandsOverlay == null) {
|
||||
setState(() {
|
||||
_commandsOverlay = _buildCommandsOverlayEntry();
|
||||
Overlay.of(context).insert(_commandsOverlay);
|
||||
if (_commandsOverlay != null) {
|
||||
Overlay.of(context).insert(_commandsOverlay);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
@@ -1965,24 +2019,31 @@ class MessageInputState extends State<MessageInput> {
|
||||
}
|
||||
|
||||
Widget _buildIdleSendButton(BuildContext context) {
|
||||
return StreamSvgIcon(
|
||||
assetName: _getIdleSendIcon(),
|
||||
color: StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor,
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: StreamSvgIcon(
|
||||
assetName: _getIdleSendIcon(),
|
||||
color:
|
||||
StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSendButton(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: sendMessage,
|
||||
padding: const EdgeInsets.all(0),
|
||||
splashRadius: 24,
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
icon: StreamSvgIcon(
|
||||
assetName: _getSendIcon(),
|
||||
color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor,
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: IconButton(
|
||||
onPressed: sendMessage,
|
||||
padding: const EdgeInsets.all(0),
|
||||
splashRadius: 24,
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
icon: StreamSvgIcon(
|
||||
assetName: _getSendIcon(),
|
||||
color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user