add message_actions_modal.dart

This commit is contained in:
Salvatore Giordano
2020-08-27 16:22:22 +02:00
parent cd1af89fc0
commit 0997867944
4 changed files with 306 additions and 25 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 18H4.242H4.243L17.678 4.565C18.0684 4.1745 18.0684 3.5415 17.678 3.151L14.849 0.322C14.4585 -0.0683821 13.8255 -0.0683821 13.435 0.322L0 13.757V18ZM12.728 3.858L14.142 5.272L15.556 3.858L14.142 2.444L12.728 3.858ZM12.728 6.686L11.314 5.272L2 14.586V16H3.414L12.728 6.686Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 443 B

+278
View File
@@ -0,0 +1,278 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/reaction_picker.dart';
import 'package:stream_chat_flutter/src/stream_channel.dart';
import '../stream_chat_flutter.dart';
import 'message_input.dart';
import 'stream_chat.dart';
class MessageActionsModal extends StatelessWidget {
final Widget Function(BuildContext, Message) editMessageInputBuilder;
final void Function(Message) onThreadTap;
final Message message;
final MessageTheme messageTheme;
final bool showReactions;
final bool showDeleteMessage;
final bool showEditMessage;
final bool showReply;
final bool reverse;
final ShapeBorder messageShape;
final Map<String, String> reactionToEmoji = const {
'love': '❤️',
'haha': '😂',
'like': '👍',
'sad': '😕',
'angry': '😡',
'wow': '😲',
};
const MessageActionsModal({
Key key,
@required this.message,
@required this.messageTheme,
this.showReactions,
this.showDeleteMessage,
this.showEditMessage,
this.onThreadTap,
this.showReply,
this.editMessageInputBuilder,
this.messageShape,
this.reverse,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final channel = StreamChannel.of(context).channel;
return Stack(
children: [
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
Navigator.pop(context);
},
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Container(
color: Colors.transparent,
),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (showReactions &&
(message.status == MessageSendingStatus.SENT ||
message.status == null))
ReactionPicker(
channel: channel,
reactionToEmoji: reactionToEmoji,
message: message,
),
AbsorbPointer(
child: MessageWidget(
reverse: reverse,
message: message,
messageTheme: messageTheme,
showReactions: false,
showUsername: false,
showReplyIndicator: false,
showTimestamp: false,
showSendingIndicator: DisplayWidget.gone,
shape: messageShape,
),
),
SizedBox(
height: 8,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 48.0,
),
child: Material(
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: ListTile.divideTiles(
context: context,
tiles: [
if (showEditMessage) _buildEditMessage(context),
if (showReply &&
(message.status == MessageSendingStatus.SENT ||
message.status == null) &&
message.parentId == null)
_buildReplyButton(context),
if (showDeleteMessage) _buildDeleteButton(context),
],
).toList(),
),
),
)
],
),
],
);
}
Widget _buildDeleteButton(BuildContext context) {
return ListTile(
title: Text(
'Delete message',
style:
Theme.of(context).textTheme.headline6.copyWith(color: Colors.red),
),
leading: Icon(
Icons.delete_outline,
color: Colors.red,
),
onTap: () {
Navigator.pop(context);
StreamChat.of(context).client.deleteMessage(
message,
StreamChannel.of(context).channel.cid,
);
},
);
}
Widget _buildEditMessage(BuildContext context) {
return ListTile(
title: Text(
'Edit message',
style: Theme.of(context).textTheme.headline6,
),
leading: SvgPicture.asset(
'assets/icon_edit.svg',
alignment: Alignment.center,
package: 'stream_chat_flutter',
color: StreamChatTheme.of(context).primaryIconTheme.color,
width: 17,
),
onTap: () async {
Navigator.pop(context);
_showEditBottomSheet(context);
},
);
}
void _showEditBottomSheet(BuildContext context) {
final channel = StreamChannel.of(context).channel;
showModalBottomSheet(
context: context,
elevation: 2,
clipBehavior: Clip.hardEdge,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32),
),
),
builder: (context) {
return StreamChannel(
channel: channel,
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 16.0,
left: 16.0,
right: 16.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Edit message',
style: Theme.of(context).textTheme.headline6,
),
Container(
height: 30,
padding: const EdgeInsets.all(2.0),
child: AspectRatio(
aspectRatio: 1,
child: RawMaterialButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
elevation: 0,
highlightElevation: 0,
focusElevation: 0,
disabledElevation: 0,
hoverElevation: 0,
onPressed: () {
Navigator.of(context).pop();
},
fillColor:
Theme.of(context).brightness == Brightness.dark
? Colors.white.withOpacity(.1)
: Colors.black.withOpacity(.1),
padding: EdgeInsets.all(4),
child: Icon(
Icons.close,
size: 15,
color: StreamChatTheme.of(context)
.primaryIconTheme
.color,
),
),
),
),
],
),
),
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: editMessageInputBuilder != null
? editMessageInputBuilder(context, message)
: MessageInput(
editMessage: message,
onMessageSent: (_) {
FocusScope.of(context).unfocus();
Navigator.pop(context);
},
),
),
],
),
);
},
);
}
Widget _buildReplyButton(BuildContext context) {
return ListTile(
title: Text(
'Start a thread',
style: Theme.of(context).textTheme.headline6,
),
leading: Icon(
Icons.reply,
color: StreamChatTheme.of(context).primaryIconTheme.color,
),
onTap: () {
Navigator.pop(context);
if (onThreadTap != null) {
onThreadTap(message);
}
},
);
}
}
+24 -24
View File
@@ -6,10 +6,10 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:jiffy/jiffy.dart';
import 'package:stream_chat_flutter/src/message_actions_modal.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'image_group.dart';
import 'message_actions_bottom_sheet.dart';
import 'message_text.dart';
typedef AttachmentBuilder = Widget Function(BuildContext, Message, Attachment);
@@ -492,21 +492,17 @@ class _MessageWidgetState extends State<MessageWidget> {
);
}
void _showMessageBottomSheet(BuildContext context) {
void _showMessageModalBottomSheet(BuildContext context) {
final channel = StreamChannel.of(context).channel;
showModalBottomSheet(
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32),
),
),
showDialog(
context: context,
builder: (context) {
return StreamChannel(
channel: channel,
child: MessageActionsBottomSheet(
child: MessageActionsModal(
messageTheme: widget.messageTheme,
messageShape: widget.shape ?? _getDefaultShape(context),
reverse: widget.reverse,
showDeleteMessage: widget.showDeleteMessage,
message: widget.message,
editMessageInputBuilder: widget.editMessageInputBuilder,
@@ -520,6 +516,21 @@ class _MessageWidgetState extends State<MessageWidget> {
});
}
ContinuousRectangleBorder _getDefaultShape(BuildContext context) {
return ContinuousRectangleBorder(
side: widget.attachmentBorderSide ??
widget.borderSide ??
BorderSide(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white.withAlpha(24)
: Colors.black.withAlpha(24),
),
borderRadius: widget.attachmentBorderRadiusGeometry ??
widget.borderRadiusGeometry ??
BorderRadius.zero,
);
}
List<Widget> _parseAttachments(BuildContext context) {
final images = widget.message.attachments
.where((element) => element.type == 'image')
@@ -574,18 +585,7 @@ class _MessageWidgetState extends State<MessageWidget> {
clipBehavior: Clip.hardEdge,
shape: widget.attachmentShape ??
widget.shape ??
ContinuousRectangleBorder(
side: widget.attachmentBorderSide ??
widget.borderSide ??
BorderSide(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white.withAlpha(24)
: Colors.black.withAlpha(24),
),
borderRadius: widget.attachmentBorderRadiusGeometry ??
widget.borderRadiusGeometry ??
BorderRadius.zero,
),
_getDefaultShape(context),
child: Padding(
padding: widget.attachmentPadding,
child: ClipRRect(
@@ -621,7 +621,7 @@ class _MessageWidgetState extends State<MessageWidget> {
if (widget.onMessageActions != null) {
widget.onMessageActions(context, widget.message);
} else {
_showMessageBottomSheet(context);
_showMessageModalBottomSheet(context);
}
return;
}
+1 -1
View File
@@ -24,7 +24,7 @@ class ReactionPicker extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
return Material(
color: Colors.black87,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,