feat: Added pin message functionality

This commit is contained in:
Deven Joshi
2021-05-26 16:39:48 +05:30
parent b954cc2872
commit 0e1e9a12f9
6 changed files with 118 additions and 3 deletions
@@ -27,6 +27,8 @@ class MessageActionsModal extends StatefulWidget {
this.showResendMessage = true,
this.showThreadReplyMessage = true,
this.showFlagButton = true,
this.showPinButton = true,
this.showPinHighlight = false,
this.showUserAvatar = DisplayWidget.show,
this.editMessageInputBuilder,
this.messageShape,
@@ -79,6 +81,12 @@ class MessageActionsModal extends StatefulWidget {
/// Flag for showing flag action
final bool showFlagButton;
/// Flag for showing pin action
final bool showPinButton;
/// Display Pin Highlight
final bool showPinHighlight;
/// Flag for reversing message
final bool reverse;
@@ -222,6 +230,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
showSendingIndicator: false,
shape: widget.messageShape,
attachmentShape: widget.attachmentShape,
showPinHighlight: false,
),
),
const SizedBox(height: 8),
@@ -258,6 +267,8 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
_buildCopyButton(context),
if (widget.showFlagButton)
_buildFlagButton(context),
if (widget.showPinButton)
_buildPinButton(context),
if (widget.showDeleteMessage)
_buildDeleteButton(context),
...widget.customActions
@@ -359,6 +370,21 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
}
}
void _togglePin() async {
final channel = StreamChannel.of(context).channel;
try {
if (!widget.message.pinned) {
await channel.pinMessage(widget.message);
} else {
await channel.unpinMessage(widget.message);
}
Navigator.pop(context);
} catch (e) {
_showErrorAlert();
}
}
void _showDeleteDialog() async {
setState(() {
_showActions = false;
@@ -451,6 +477,29 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
);
}
Widget _buildPinButton(BuildContext context) {
final streamChatThemeData = StreamChatTheme.of(context);
return InkWell(
onTap: _togglePin,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row(
children: [
StreamSvgIcon.pin(
color: streamChatThemeData.primaryIconTheme.color,
size: 24,
),
const SizedBox(width: 16),
Text(
'${widget.message.pinned ? 'Unpin from' : 'Pin to'} Conversation',
style: streamChatThemeData.textTheme.body,
),
],
),
),
);
}
Widget _buildDeleteButton(BuildContext context) {
final isDeleteFailed =
widget.message.status == MessageSendingStatus.failed_delete;
@@ -157,6 +157,7 @@ class MessageReactionsModal extends StatelessWidget {
),
showReactionPickerIndicator: showReactions &&
(message.status == MessageSendingStatus.sent),
showPinHighlight: false,
),
),
if (message.latestReactions?.isNotEmpty == true) ...[
@@ -83,6 +83,8 @@ class MessageWidget extends StatefulWidget {
this.showResendMessage = true,
this.showCopyMessage = true,
this.showFlagButton = true,
this.showPinButton = true,
this.showPinHighlight = true,
this.onUserAvatarTap,
this.onLinkTap,
this.onMessageActions,
@@ -367,6 +369,12 @@ class MessageWidget extends StatefulWidget {
/// Show flag action
final bool showFlagButton;
/// Show flag action
final bool showPinButton;
/// Display Pin Highlight
final bool showPinHighlight;
/// Builder for respective attachment types
final Map<String, AttachmentBuilder> attachmentBuilders;
@@ -450,7 +458,12 @@ class _MessageWidgetState extends State<MessageWidget>
widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5;
return Material(
type: MaterialType.transparency,
type: widget.message.pinned && widget.showPinHighlight
? MaterialType.card
: MaterialType.transparency,
color: widget.message.pinned && widget.showPinHighlight
? StreamChatTheme.of(context).colorTheme.highlight
: null,
child: Portal(
child: InkWell(
onTap: () {
@@ -483,6 +496,10 @@ class _MessageWidgetState extends State<MessageWidget>
: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (widget.message.pinned &&
widget.message.pinnedBy != null &&
widget.showPinHighlight)
_buildPinnedMessage(widget.message),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
@@ -918,6 +935,7 @@ class _MessageWidgetState extends State<MessageWidget>
!isFailedState &&
widget.onThreadTap != null,
showFlagButton: widget.showFlagButton,
showPinButton: widget.showPinButton,
customActions: widget.customActions,
),
));
@@ -1113,8 +1131,38 @@ class _MessageWidgetState extends State<MessageWidget>
);
}
Widget _buildPinnedMessage(Message message) {
final pinnedBy = message.pinnedBy;
final pinnedByMe = StreamChat.of(context).user!.id == pinnedBy!.id;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
StreamSvgIcon.pin(
size: 16,
),
const SizedBox(
width: 4,
),
Text(
'Pinned by ${pinnedByMe ? 'You' : pinnedBy.name}',
style: TextStyle(
color: StreamChatTheme.of(context).colorTheme.grey,
fontSize: 13,
fontWeight: FontWeight.w400,
),
)
],
),
);
}
bool get isOnlyEmoji => widget.message.text!.isOnlyEmoji;
bool get isPinned => widget.message.pinned;
Color? _getBackgroundColor() {
if (hasQuotedMessage) {
return widget.messageTheme.messageBackgroundColor;
@@ -889,6 +889,18 @@ class StreamSvgIcon extends StatelessWidget {
height: size,
);
/// [StreamSvgIcon] type
factory StreamSvgIcon.pin({
double? size,
Color? color,
}) =>
StreamSvgIcon(
assetName: 'icon_pin.svg',
color: color,
width: size,
height: size,
);
/// Name of icon asset
final String? assetName;