From 1f6bf33b0ee0475d47753264f25a7b1d58281bde Mon Sep 17 00:00:00 2001
From: LittleSheep <littlesheep.code@hotmail.com>
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<NotificationScreen> {
                                 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<AttachmentZoomView> {
                               )
                             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<ContextMenuButtonItem> 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(
         <markdown.BlockSyntax>[
@@ -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;
   }
 }