From 1f6bf33b0ee0475d47753264f25a7b1d58281bde Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 6 Jan 2025 23:15:18 +0800 Subject: [PATCH] :wheelchair: Chat message action on system text selection area --- lib/screens/notification.dart | 9 ++-- lib/widgets/attachment/attachment_zoom.dart | 2 +- lib/widgets/chat/chat_message.dart | 58 ++++++++++++++++++--- lib/widgets/context_menu.dart | 1 - lib/widgets/markdown_content.dart | 18 ++----- lib/widgets/post/post_item.dart | 8 ++- 6 files changed, 68 insertions(+), 28 deletions(-) diff --git a/lib/screens/notification.dart b/lib/screens/notification.dart index 1e9ec8f..e265ffb 100644 --- a/lib/screens/notification.dart +++ b/lib/screens/notification.dart @@ -206,10 +206,11 @@ class _NotificationScreenState extends State { style: Theme.of(context).textTheme.titleSmall, ), if (nty.subtitle != null) const Gap(4), - MarkdownTextContent( - content: nty.body, - isAutoWarp: true, - isSelectable: true, + SelectionArea( + child: MarkdownTextContent( + content: nty.body, + isAutoWarp: true, + ), ), if ([ 'interactive.feedback', diff --git a/lib/widgets/attachment/attachment_zoom.dart b/lib/widgets/attachment/attachment_zoom.dart index 5a16045..3bbe9bf 100644 --- a/lib/widgets/attachment/attachment_zoom.dart +++ b/lib/widgets/attachment/attachment_zoom.dart @@ -329,7 +329,7 @@ class _AttachmentZoomViewState extends State { ) else Text( - '${item.size} Bytes', + item.size.formatBytes(), style: metaTextStyle, ), if (item.metadata['width'] != null && item.metadata['height'] != null) diff --git a/lib/widgets/chat/chat_message.dart b/lib/widgets/chat/chat_message.dart index 242572f..4c99e54 100644 --- a/lib/widgets/chat/chat_message.dart +++ b/lib/widgets/chat/chat_message.dart @@ -150,7 +150,12 @@ class ChatMessage extends StatelessWidget { ), )).padding(bottom: 4, top: 4), switch (data.type) { - 'messages.new' => _ChatMessageText(data: data), + 'messages.new' => _ChatMessageText( + data: data, + onReply: onReply, + onEdit: onEdit, + onDelete: onDelete, + ), _ => _ChatMessageSystemNotify(data: data), }, ], @@ -181,8 +186,11 @@ class ChatMessage extends StatelessWidget { class _ChatMessageText extends StatelessWidget { final SnChatMessage data; + final Function(SnChatMessage)? onReply; + final Function(SnChatMessage)? onEdit; + final Function(SnChatMessage)? onDelete; - const _ChatMessageText({required this.data}); + const _ChatMessageText({required this.data, this.onReply, this.onEdit, this.onDelete}); @override Widget build(BuildContext context) { @@ -190,10 +198,48 @@ class _ChatMessageText extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - MarkdownTextContent( - content: data.body['text'], - isSelectable: true, - isAutoWarp: true, + SelectionArea( + contextMenuBuilder: (context, editableTextState) { + final List items = editableTextState.contextMenuButtonItems; + items.insert( + 0, + ContextMenuButtonItem( + label: 'reply'.tr(), + onPressed: () { + ContextMenuController.removeAny(); + onReply?.call(data); + }, + ), + ); + items.insert( + 1, + ContextMenuButtonItem( + label: 'edit'.tr(), + onPressed: () { + ContextMenuController.removeAny(); + onEdit?.call(data); + }, + ), + ); + items.insert( + 2, + ContextMenuButtonItem( + label: 'delete'.tr(), + onPressed: () { + ContextMenuController.removeAny(); + onDelete?.call(data); + }, + ), + ); + return AdaptiveTextSelectionToolbar.buttonItems( + anchors: editableTextState.contextMenuAnchors, + buttonItems: items, + ); + }, + child: MarkdownTextContent( + content: data.body['text'], + isAutoWarp: true, + ), ), if (data.updatedAt != data.createdAt) Text( diff --git a/lib/widgets/context_menu.dart b/lib/widgets/context_menu.dart index 86c5819..0206b1f 100644 --- a/lib/widgets/context_menu.dart +++ b/lib/widgets/context_menu.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_context_menu/flutter_context_menu.dart'; import 'package:provider/provider.dart'; -import 'package:responsive_framework/responsive_framework.dart'; import 'package:surface/providers/config.dart'; class ContextMenuArea extends StatelessWidget { diff --git a/lib/widgets/markdown_content.dart b/lib/widgets/markdown_content.dart index db22f20..edf9f2a 100644 --- a/lib/widgets/markdown_content.dart +++ b/lib/widgets/markdown_content.dart @@ -17,7 +17,6 @@ import 'attachment/attachment_zoom.dart'; class MarkdownTextContent extends StatelessWidget { final String content; - final bool isSelectable; final bool isAutoWarp; final bool isEnlargeSticker; final TextScaler? textScaler; @@ -26,14 +25,14 @@ class MarkdownTextContent extends StatelessWidget { const MarkdownTextContent({ super.key, required this.content, - this.isSelectable = false, this.isAutoWarp = false, this.isEnlargeSticker = false, this.textScaler, this.attachments, }); - Widget _buildContent(BuildContext context) { + @override + Widget build(BuildContext context) { return Markdown( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -68,8 +67,7 @@ class MarkdownTextContent extends StatelessWidget { ), code: GoogleFonts.robotoMono(height: 1), ), - builders: { - }, + builders: {}, softLineBreak: true, extensionSet: markdown.ExtensionSet( [ @@ -144,7 +142,7 @@ class MarkdownTextContent extends StatelessWidget { ); case 'attachments': final attachment = attachments?.firstWhere( - (ele) => ele?.rid == segments[1], + (ele) => ele?.rid == segments[1], orElse: () => null, ); if (attachment != null) { @@ -202,14 +200,6 @@ class MarkdownTextContent extends StatelessWidget { }, ); } - - @override - Widget build(BuildContext context) { - if (isSelectable) { - return SelectionArea(child: _buildContent(context)); - } - return _buildContent(context); - } } class _UserNameCardInlineSyntax extends markdown.InlineSyntax { diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index a748fef..60f42b0 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -879,13 +879,17 @@ class _PostContentBody extends StatelessWidget { @override Widget build(BuildContext context) { if (data.body['content'] == null) return const SizedBox.shrink(); - return MarkdownTextContent( - isSelectable: isSelectable, + final content = MarkdownTextContent( isEnlargeSticker: true, textScaler: isEnlarge ? TextScaler.linear(1.1) : null, content: data.body['content'], attachments: data.preload?.attachments, ); + + if (isSelectable) { + return SelectionArea(child: content); + } + return content; } }