From b42aa1f88a0cce3a53a3587eb074889cb46f1848 Mon Sep 17 00:00:00 2001 From: Yurin Andrey Date: Fri, 24 Oct 2025 16:35:19 +0300 Subject: [PATCH 1/5] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BC=D0=B5=D0=BD=D1=8E=D1=88=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/main_page/chat/widgets/message.dart | 102 +++-------------- .../main_page/feed/widgets/comments_page.dart | 32 +++--- .../main_page/feed/widgets/feed_comment.dart | 72 +++++++----- .../main_page/feed/widgets/feed_post.dart | 13 +++ .../context_menu/context_menu_action.dart | 78 +++++++++++++ .../context_menu/context_menu_factory.dart | 103 ++++++++++++++++++ .../context_menu/context_menu_helper.dart | 76 +++++++++++++ 7 files changed, 339 insertions(+), 137 deletions(-) create mode 100644 lib/ui/widgets/context_menu/context_menu_action.dart create mode 100644 lib/ui/widgets/context_menu/context_menu_factory.dart create mode 100644 lib/ui/widgets/context_menu/context_menu_helper.dart diff --git a/lib/ui/views/main_page/chat/widgets/message.dart b/lib/ui/views/main_page/chat/widgets/message.dart index 4894760f..fceee48c 100644 --- a/lib/ui/views/main_page/chat/widgets/message.dart +++ b/lib/ui/views/main_page/chat/widgets/message.dart @@ -2,7 +2,6 @@ // Copyright 2025 BitCodersNN import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_bbcode/flutter_bbcode.dart'; import 'package:unn_mobile/core/constants/date_pattern.dart'; import 'package:unn_mobile/core/misc/custom_bb_tags.dart'; @@ -22,6 +21,8 @@ import 'package:unn_mobile/core/viewmodels/main_page/feed/attached_file_view_mod import 'package:unn_mobile/ui/views/base_view.dart'; import 'package:unn_mobile/ui/views/main_page/feed/widgets/attached_file.dart'; import 'package:unn_mobile/ui/views/main_page/feed/widgets/reaction_bubble.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_factory.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_helper.dart'; const systemMessageSeparator = '------------------------------------------------------\n'; @@ -231,7 +232,17 @@ class _MessageWidgetState extends State { return BaseView( model: MessageReactionViewModel.cached(widget.message.messageId), builder: (context, model, _) => GestureDetector( - onLongPress: () => _showContextMenu(model), + onLongPress: () => ContextMenuHelper.showContextMenu( + context: context, + model: model, + actionsBuilder: () => createMessageActions( + context: context, + model: model, + widget: widget, + ), + onOpen: () => setState(() => _isHighlighted = true), + onClose: () => setState(() => _isHighlighted = false), + ), child: _buildMessageContent(context, model, theme), ), onModelReady: (model) => model.init( @@ -241,93 +252,6 @@ class _MessageWidgetState extends State { ); } - void _showContextMenu(MessageReactionViewModel model) { - setState(() => _isHighlighted = true); - triggerHaptic(HapticIntensity.medium); - - final renderBox = context.findRenderObject()! as RenderBox; - final offset = renderBox.localToGlobal(Offset.zero); - - showMenu( - context: context, - position: RelativeRect.fromLTRB( - offset.dx, - offset.dy + renderBox.size.height, - offset.dx + renderBox.size.width, - offset.dy + renderBox.size.height + 1, - ), - items: _buildMenuItems(model), - ).then((value) { - setState(() => _isHighlighted = false); - _handleMenuSelection(value); - }); - } - - List> _buildMenuItems( - MessageReactionViewModel model, - ) => - [ - PopupMenuItem( - enabled: false, - child: Scrollbar( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: ReactionType.values - .map( - (reaction) => GestureDetector( - onTap: () => _handleReactionTap(reaction, model), - child: Padding( - padding: const EdgeInsets.all(4.0), - child: CircleAvatar( - radius: 16, - backgroundImage: AssetImage(reaction.assetName), - ), - ), - ), - ) - .toList(), - ), - ), - ), - ), - const PopupMenuItem( - value: 'copy', - child: Text('Скопировать текст'), - ), - const PopupMenuItem( - value: 'reply', - child: Text('Ответить'), - ), - ]; - - void _handleReactionTap( - ReactionType reaction, - MessageReactionViewModel model, - ) { - triggerHaptic(HapticIntensity.selection); - if (model.currentReaction != reaction) { - model.toggleReaction(reaction); - } - Navigator.pop(context); - } - - void _handleMenuSelection(String? value) async { - if (value == null) { - return; - } - - switch (value) { - case 'copy': - await Clipboard.setData(ClipboardData(text: widget.message.text)); - break; - case 'reply': - widget.chatModel.replyMessage = widget.message; - break; - } - } - Widget _buildMessageContent( BuildContext context, MessageReactionViewModel model, diff --git a/lib/ui/views/main_page/feed/widgets/comments_page.dart b/lib/ui/views/main_page/feed/widgets/comments_page.dart index ea088a48..86739c5a 100644 --- a/lib/ui/views/main_page/feed/widgets/comments_page.dart +++ b/lib/ui/views/main_page/feed/widgets/comments_page.dart @@ -51,25 +51,19 @@ class CommentsPage extends StatelessWidget { ), ), ), - for (final comment in model.comments) - Column( - children: [ - const Padding( - padding: EdgeInsets.only( - left: 18, - bottom: 10, - right: 18, - ), - child: Divider( - thickness: 0.3, - color: Color(0xFF989EA9), - ), - ), - FeedCommentView( - viewModel: comment, - ), - ], - ), + Column( + children: [ + const Divider( + height: 1, + thickness: 0.3, + color: Color(0xFF989EA9), + indent: 18, + endIndent: 18, + ), + for (final comment in model.comments) + FeedCommentView(viewModel: comment), + ], + ), ], ), ), diff --git a/lib/ui/views/main_page/feed/widgets/feed_comment.dart b/lib/ui/views/main_page/feed/widgets/feed_comment.dart index 07af561d..22d2102e 100644 --- a/lib/ui/views/main_page/feed/widgets/feed_comment.dart +++ b/lib/ui/views/main_page/feed/widgets/feed_comment.dart @@ -13,6 +13,8 @@ import 'package:unn_mobile/ui/views/main_page/feed/widgets/attached_file.dart'; import 'package:unn_mobile/ui/views/main_page/feed/widgets/packed_post_images.dart'; import 'package:unn_mobile/ui/views/main_page/feed/widgets/post_html_widget.dart'; import 'package:unn_mobile/ui/views/main_page/feed/widgets/reaction_bubble.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_factory.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_helper.dart'; import 'package:unn_mobile/ui/widgets/shimmer.dart'; import 'package:unn_mobile/ui/widgets/shimmer_loading.dart'; @@ -26,38 +28,50 @@ class FeedCommentView extends StatelessWidget { @override Widget build(BuildContext context) => BaseView( model: viewModel, - builder: (context, model, child) => Shimmer( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _CommentHeader( - dateTime: model.comment.dateTime, - viewModel: model.profileViewModel, - hide: model.isBusy, - ), - Padding( - padding: const EdgeInsets.only( - left: 16, - bottom: 10, - right: 10, - top: 8, + builder: (context, model, child) => GestureDetector( + onLongPress: () => ContextMenuHelper.showContextMenu( + context: context, + model: model, + actionsBuilder: () => createCommentActions( + context: context, + model: model, + ), + ), + child: Shimmer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _CommentHeader( + dateTime: model.comment.dateTime, + viewModel: model.profileViewModel, + hide: model.isBusy, + ), + Padding( + padding: const EdgeInsets.only( + left: 16, + bottom: 10, + right: 10, + top: 8, + ), + child: model.renderMessage + ? PostHtmlWidget(text: model.message) + : const SizedBox(), ), - child: model.renderMessage - ? PostHtmlWidget(text: model.message) - : const SizedBox(), - ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20.0, vertical: 8.0), - child: PackedPostImages(attachedImages: model.attachedImages), - ), - for (final file in model.attachedFileViewModels) Padding( - padding: const EdgeInsets.only(left: 16), - child: AttachedFile(viewModel: file), + padding: const EdgeInsets.symmetric( + horizontal: 20.0, + vertical: 0.0, + ), + child: PackedPostImages(attachedImages: model.attachedImages), ), - _ReactionView(model: model.reactionViewModel, context: context), - ], + for (final file in model.attachedFileViewModels) + Padding( + padding: const EdgeInsets.only(left: 16), + child: AttachedFile(viewModel: file), + ), + _ReactionView(model: model.reactionViewModel, context: context), + ], + ), ), ), ); diff --git a/lib/ui/views/main_page/feed/widgets/feed_post.dart b/lib/ui/views/main_page/feed/widgets/feed_post.dart index 9871a6a0..a3d997fe 100644 --- a/lib/ui/views/main_page/feed/widgets/feed_post.dart +++ b/lib/ui/views/main_page/feed/widgets/feed_post.dart @@ -26,6 +26,8 @@ import 'package:unn_mobile/ui/views/main_page/feed/widgets/attached_file.dart'; import 'package:unn_mobile/ui/views/main_page/feed/widgets/packed_post_images.dart'; import 'package:unn_mobile/ui/views/main_page/feed/widgets/post_html_widget.dart'; import 'package:unn_mobile/ui/views/main_page/main_page_routing.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_factory.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_helper.dart'; import 'package:unn_mobile/ui/widgets/height_limiter.dart'; import 'package:unn_mobile/ui/widgets/shimmer.dart'; import 'package:unn_mobile/ui/widgets/shimmer_loading.dart'; @@ -71,6 +73,17 @@ class _FeedPostState extends State { .putInCache(model.blogData.id, model); _openPostCommentsPage(context, model); }, + onLongPress: () => ContextMenuHelper.showContextMenu( + context: context, + model: model, + actionsBuilder: () => createPostActions( + context: context, + model: model, + onShare: _sharePost, + ), + onOpen: () => setState(() {}), + onClose: () => setState(() {}), + ), child: Shimmer( child: AnimatedContainer( duration: const Duration(milliseconds: 100), diff --git a/lib/ui/widgets/context_menu/context_menu_action.dart b/lib/ui/widgets/context_menu/context_menu_action.dart new file mode 100644 index 00000000..801a964a --- /dev/null +++ b/lib/ui/widgets/context_menu/context_menu_action.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:unn_mobile/core/misc/haptic_utils.dart'; +import 'package:unn_mobile/core/models/feed/rating_list.dart'; +import 'package:unn_mobile/core/viewmodels/main_page/common/reaction_view_model_base.dart'; + +class ContextMenuAction { + final PopupMenuEntry entry; + final VoidCallback? onTap; + + const ContextMenuAction({ + required this.entry, + this.onTap, + }); + + factory ContextMenuAction.text({ + required String label, + VoidCallback? onTap, + }) => + ContextMenuAction( + entry: PopupMenuItem( + child: Text(label), + ), + onTap: onTap, + ); + + factory ContextMenuAction.reaction({ + required BuildContext context, + required ReactionViewModelBase reactionViewModel, + }) => + ContextMenuAction( + entry: PopupMenuItem( + enabled: false, + child: SizedBox( + width: 280, + child: Scrollbar( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + for (final reaction in ReactionType.values) + GestureDetector( + onTap: () { + triggerHaptic(HapticIntensity.selection); + if (reactionViewModel.currentReaction != reaction) { + reactionViewModel.toggleReaction(reaction); + } + Navigator.pop(context); + }, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: CircleAvatar( + radius: 16, + backgroundImage: AssetImage(reaction.assetName), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ); + + factory ContextMenuAction.custom({ + required Widget child, + VoidCallback? onTap, + }) => + ContextMenuAction( + entry: PopupMenuItem( + enabled: false, + child: child, + ), + onTap: onTap, + ); +} diff --git a/lib/ui/widgets/context_menu/context_menu_factory.dart b/lib/ui/widgets/context_menu/context_menu_factory.dart new file mode 100644 index 00000000..6187edc5 --- /dev/null +++ b/lib/ui/widgets/context_menu/context_menu_factory.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:unn_mobile/core/viewmodels/main_page/chat/message_reaction_view_model.dart'; +import 'package:unn_mobile/core/viewmodels/main_page/common/reaction_view_model_base.dart'; +import 'package:unn_mobile/core/viewmodels/main_page/feed/feed_comment_view_model.dart'; +import 'package:unn_mobile/core/viewmodels/main_page/feed/feed_post_view_model.dart'; +import 'package:unn_mobile/ui/views/main_page/chat/widgets/message.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_action.dart'; + +List createMessageActions({ + required BuildContext context, + required MessageReactionViewModel model, + required MessageWidget widget, +}) => + _createActions( + context: context, + reactionViewModel: model, + textToCopy: widget.message.text, + onReply: () => widget.chatModel.replyMessage = widget.message, + ); + +List createPostActions({ + required BuildContext context, + required FeedPostViewModel model, + required Function(FeedPostViewModel) onShare, +}) => + _createActions( + context: context, + reactionViewModel: model.reactionViewModel, + textToCopy: model.postText, + onTogglePin: model.togglePin, + isPinned: model.isPinned, + onShare: () => onShare(model), + ); + +List createCommentActions({ + required BuildContext context, + required FeedCommentViewModel model, +}) => + _createActions( + context: context, + reactionViewModel: model.reactionViewModel, + textToCopy: model.message, + ); + +List _createActions({ + required BuildContext context, + ReactionViewModelBase? reactionViewModel, + String? textToCopy, + VoidCallback? onReply, + VoidCallback? onTogglePin, + bool? isPinned, + VoidCallback? onShare, +}) { + final actions = []; + + if (reactionViewModel != null) { + actions.add( + ContextMenuAction.reaction( + context: context, + reactionViewModel: reactionViewModel, + ), + ); + } + + if (textToCopy != null) { + actions.add( + ContextMenuAction.text( + label: 'Скопировать текст', + onTap: () => Clipboard.setData(ClipboardData(text: textToCopy)), + ), + ); + } + + if (onReply != null) { + actions.add( + ContextMenuAction.text( + label: 'Ответить', + onTap: onReply, + ), + ); + } + + if (onTogglePin != null && isPinned != null) { + actions.add( + ContextMenuAction.text( + label: isPinned ? 'Открепить' : 'Закрепить', + onTap: onTogglePin, + ), + ); + } + + if (onShare != null) { + actions.add( + ContextMenuAction.text( + label: 'Поделиться', + onTap: onShare, + ), + ); + } + + return actions; +} diff --git a/lib/ui/widgets/context_menu/context_menu_helper.dart b/lib/ui/widgets/context_menu/context_menu_helper.dart new file mode 100644 index 00000000..e9056604 --- /dev/null +++ b/lib/ui/widgets/context_menu/context_menu_helper.dart @@ -0,0 +1,76 @@ +// context_menu_action.dart + +import 'package:flutter/material.dart'; +import 'package:unn_mobile/core/misc/haptic_utils.dart'; +import 'package:unn_mobile/ui/widgets/context_menu/context_menu_action.dart'; + +class ContextMenuHelper { + static void showContextMenu({ + required BuildContext context, + required dynamic model, + required List Function() actionsBuilder, + VoidCallback? onOpen, + VoidCallback? onClose, + }) { + triggerHaptic(HapticIntensity.medium); + final renderBox = context.findRenderObject()! as RenderBox; + + final actions = actionsBuilder(); + + ContextMenuHelper.show( + context: context, + renderBox: renderBox, + actions: actions, + onOpen: onOpen, + onClose: onClose, + ); + } + + static Future show({ + required BuildContext context, + required RenderBox renderBox, + required List actions, + VoidCallback? onOpen, + VoidCallback? onClose, + }) async { + triggerHaptic(HapticIntensity.medium); + onOpen?.call(); + + final wrappedEntries = >[ + for (final action in actions) _wrapAction(context, action), + ]; + + final offset = renderBox.localToGlobal(Offset.zero); + final position = RelativeRect.fromLTRB( + offset.dx, + offset.dy + renderBox.size.height, + offset.dx + renderBox.size.width, + offset.dy + renderBox.size.height + 1, + ); + + await showMenu( + context: context, + position: position, + items: wrappedEntries, + ); + + onClose?.call(); + } + + static PopupMenuEntry _wrapAction( + BuildContext context, + ContextMenuAction action, + ) { + final entry = action.entry; + + if (entry is PopupMenuItem && entry.enabled) { + return PopupMenuItem( + child: entry.child, + onTap: () { + action.onTap?.call(); + }, + ); + } + return entry; + } +} From 08805e2bcfd107c484e341f4350441bdd423fb05 Mon Sep 17 00:00:00 2001 From: UNN MOBILE runner Date: Fri, 24 Oct 2025 13:41:08 +0000 Subject: [PATCH 2/5] Change version in pubspec --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 210af5a3..ff17972c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: unn_mobile description: A mobile application for UNN Portal website publish_to: 'none' -version: 0.6.0+363 +version: 0.6.0+364 environment: sdk: '>=3.1.2 <4.0.0' From 91a0be506f452e6f6acb1018ead7e0c7e9c3dacf Mon Sep 17 00:00:00 2001 From: UNN MOBILE runner Date: Fri, 24 Oct 2025 13:41:28 +0000 Subject: [PATCH 3/5] Add license headers to files --- lib/ui/widgets/context_menu/context_menu_action.dart | 3 +++ lib/ui/widgets/context_menu/context_menu_factory.dart | 3 +++ lib/ui/widgets/context_menu/context_menu_helper.dart | 3 +++ 3 files changed, 9 insertions(+) diff --git a/lib/ui/widgets/context_menu/context_menu_action.dart b/lib/ui/widgets/context_menu/context_menu_action.dart index 801a964a..d60b183f 100644 --- a/lib/ui/widgets/context_menu/context_menu_action.dart +++ b/lib/ui/widgets/context_menu/context_menu_action.dart @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 BitCodersNN + import 'package:flutter/material.dart'; import 'package:unn_mobile/core/misc/haptic_utils.dart'; import 'package:unn_mobile/core/models/feed/rating_list.dart'; diff --git a/lib/ui/widgets/context_menu/context_menu_factory.dart b/lib/ui/widgets/context_menu/context_menu_factory.dart index 6187edc5..ecab64fc 100644 --- a/lib/ui/widgets/context_menu/context_menu_factory.dart +++ b/lib/ui/widgets/context_menu/context_menu_factory.dart @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 BitCodersNN + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:unn_mobile/core/viewmodels/main_page/chat/message_reaction_view_model.dart'; diff --git a/lib/ui/widgets/context_menu/context_menu_helper.dart b/lib/ui/widgets/context_menu/context_menu_helper.dart index e9056604..577751e7 100644 --- a/lib/ui/widgets/context_menu/context_menu_helper.dart +++ b/lib/ui/widgets/context_menu/context_menu_helper.dart @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 BitCodersNN + // context_menu_action.dart import 'package:flutter/material.dart'; From f6e265b654b850a8bc4a58e6a024bc16cc16fd20 Mon Sep 17 00:00:00 2001 From: Yurin Andrey Date: Fri, 24 Oct 2025 16:51:24 +0300 Subject: [PATCH 4/5] =?UTF-8?q?=D0=9F=D0=BE=D1=87=D0=B8=D0=BD=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=BE=D1=82=D1=81=D1=82=D1=83=D0=BF=D1=8B=20=D0=B2=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D1=8F?= =?UTF-8?q?=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main_page/feed/widgets/comments_page.dart | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/ui/views/main_page/feed/widgets/comments_page.dart b/lib/ui/views/main_page/feed/widgets/comments_page.dart index 86739c5a..8ae1660f 100644 --- a/lib/ui/views/main_page/feed/widgets/comments_page.dart +++ b/lib/ui/views/main_page/feed/widgets/comments_page.dart @@ -53,12 +53,16 @@ class CommentsPage extends StatelessWidget { ), Column( children: [ - const Divider( - height: 1, - thickness: 0.3, - color: Color(0xFF989EA9), - indent: 18, - endIndent: 18, + const Padding( + padding: EdgeInsets.symmetric( + horizontal: 18, + vertical: 10, + ), + child: Divider( + height: 1, + thickness: 0.3, + color: Color(0xFF989EA9), + ), ), for (final comment in model.comments) FeedCommentView(viewModel: comment), From 0335901631988724b9b319c5928f2e7a63f3fd1d Mon Sep 17 00:00:00 2001 From: Yurin Andrey Date: Wed, 29 Oct 2025 14:53:47 +0300 Subject: [PATCH 5/5] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ui/widgets/context_menu/context_menu_action.dart | 12 +++++++++++- .../widgets/context_menu/context_menu_factory.dart | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/ui/widgets/context_menu/context_menu_action.dart b/lib/ui/widgets/context_menu/context_menu_action.dart index d60b183f..adb0cc69 100644 --- a/lib/ui/widgets/context_menu/context_menu_action.dart +++ b/lib/ui/widgets/context_menu/context_menu_action.dart @@ -18,10 +18,20 @@ class ContextMenuAction { factory ContextMenuAction.text({ required String label, VoidCallback? onTap, + Widget? leadingIcon, }) => ContextMenuAction( entry: PopupMenuItem( - child: Text(label), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (leadingIcon != null) ...[ + leadingIcon, + const SizedBox(width: 12), + ], + Text(label), + ], + ), ), onTap: onTap, ); diff --git a/lib/ui/widgets/context_menu/context_menu_factory.dart b/lib/ui/widgets/context_menu/context_menu_factory.dart index ecab64fc..77e3a2e4 100644 --- a/lib/ui/widgets/context_menu/context_menu_factory.dart +++ b/lib/ui/widgets/context_menu/context_menu_factory.dart @@ -71,6 +71,7 @@ List _createActions({ ContextMenuAction.text( label: 'Скопировать текст', onTap: () => Clipboard.setData(ClipboardData(text: textToCopy)), + leadingIcon: const Icon(Icons.content_copy, size: 18), ), ); } @@ -80,6 +81,7 @@ List _createActions({ ContextMenuAction.text( label: 'Ответить', onTap: onReply, + leadingIcon: const Icon(Icons.reply, size: 18), ), ); } @@ -89,6 +91,10 @@ List _createActions({ ContextMenuAction.text( label: isPinned ? 'Открепить' : 'Закрепить', onTap: onTogglePin, + leadingIcon: Icon( + isPinned ? Icons.push_pin : Icons.push_pin_outlined, + size: 18, + ), ), ); } @@ -98,6 +104,7 @@ List _createActions({ ContextMenuAction.text( label: 'Поделиться', onTap: onShare, + leadingIcon: const Icon(Icons.share, size: 18), ), ); }