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