Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chat-NG: Message Actions #2529

Merged
merged 16 commits into from
Feb 5, 2025
Merged

Conversation

gtalha07
Copy link
Contributor

@gtalha07 gtalha07 commented Jan 28, 2025

PR Description:

  • Adds the implementation of message actions UI .i.e. reply/edit/copy/delete. The PR grew to large change-set, particularly because of how these features are aligned within chat editor and have to make adjustments across entire module to have this in effect.

  • I have pointed out explanation, by detail where a reviewer should probably look at, explaining why certain things are intended the way it is needed to work.

PREVIEW:

(Desktop):

Screen.Recording.2025-02-04.at.22.57.00.mov

(Mobile):

Screen.Recording.2025-02-04.at.23.14.34.mov

Copy link

codecov bot commented Jan 28, 2025

Codecov Report

Attention: Patch coverage is 48.40764% with 162 lines in your changes missing coverage. Please review.

Project coverage is 31.88%. Comparing base (3a5aa68) to head (804afd5).
Report is 17 commits behind head on main.

Files with missing lines Patch % Lines
...dgets/chat_editor/chat_editor_actions_preview.dart 56.52% 30 Missing ⚠️
...eatures/chat_ng/actions/redact_message_action.dart 0.00% 26 Missing ⚠️
...tures/chat_ng/widgets/chat_editor/chat_editor.dart 72.30% 18 Missing ⚠️
.../lib/features/chat_ng/dialogs/message_actions.dart 0.00% 16 Missing ⚠️
...atures/chat_ng/widgets/message_actions_widget.dart 75.92% 13 Missing ⚠️
...pp/lib/common/widgets/html_editor/html_editor.dart 20.00% 8 Missing ⚠️
.../features/chat_ng/actions/send_message_action.dart 0.00% 8 Missing ⚠️
.../features/chat_ng/actions/copy_message_action.dart 0.00% 7 Missing ⚠️
...eatures/chat_ng/actions/report_message_action.dart 0.00% 7 Missing ⚠️
...chat_ng/providers/chat_room_messages_provider.dart 33.33% 6 Missing ⚠️
... and 10 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2529      +/-   ##
==========================================
+ Coverage   31.33%   31.88%   +0.54%     
==========================================
  Files         716      724       +8     
  Lines       47369    47609     +240     
==========================================
+ Hits        14843    15180     +337     
+ Misses      32526    32429      -97     
Flag Coverage Δ
integration-test 41.70% <ø> (-0.02%) ⬇️
unittest 23.39% <48.40%> (+0.86%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -34,3 +34,12 @@ final selectedChatIdProvider =
NotifierProvider<SelectedChatIdNotifier, String?>(
() => SelectedChatIdNotifier(),
);

final chatComposerDraftProvider = FutureProvider.autoDispose
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just moved from chat module to much more common providers section because it makes sense but also to avoid import conflicts.

@@ -48,6 +48,23 @@ extension ActerEditorStateHelpers on EditorState {
String intoMarkdown({AppFlowyEditorMarkdownCodec? codec}) {
return (codec ?? defaultMarkdownCodec).encode(document);
}

/// clear the editor text with selection
void clear() async {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is utility fn added as extension to textEditorState to clear document content. Because it's usage is widely needed so having it neatly separated is so nice!!

import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

Future<void> copyMessageAction(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these message actions along with other are moved entirely to actions for legibility.

required String roomId,
}) async {
// trigger vibration haptic
await HapticFeedback.heavyImpact();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a vibration haptic which is often commonly seen on opening message actions .i.e. WhatsApp, Signal etc.

@@ -22,29 +28,36 @@ void reactionSelectionAction({
barrierColor: Colors.transparent,
transitionDuration: const Duration(milliseconds: 200),
pageBuilder: (context, animation, secondaryAnimation) {
return Stack(
return Column(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from Stack to Column layout. Because it allows better positioning for message actions + reaction selector and makes the selected message appeared centered regardless of its actual position in message list.

Positioned(
left: position.dx,
top: position.dy - 60,
child: _AnimatedReactionSelector(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is evolved to single re-usable AnimatedActionsContainer because we need similar effect for message actions :)


enum MessageAction { none, reply, edit }

class ChatEditorState {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new ChatEditorState as opposed to other chat version ChatInputState, but much more simplified and refined.

@@ -24,28 +26,29 @@ typedef RoomMsgId = ({String roomId, String uniqueId});
typedef MentionQuery = (String, MentionType);
typedef ReactionItem = (String, List<ReactionRecord>);

final chatStateProvider = StateNotifierProvider.family<ChatRoomMessagesNotifier,
ChatRoomState, String>(
final chatMessagesStateProvider = StateNotifierProvider.family<
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid conflicting namings of similar providers from other version chat.

show RoomEventItem;
import 'package:flutter_riverpod/flutter_riverpod.dart';

class ChatEditorNotifier extends AutoDisposeNotifier<ChatEditorState> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new notifier for ChatEditorState as opposed to ChatInputState. But the benefit here is this new notifier uses Notifier (newer API) from StateNotifier migration.

@@ -55,6 +60,14 @@ class _ChatEditorState extends ConsumerState<ChatEditor> {
// have it call the first time to adjust height
_updateHeight();
WidgetsBinding.instance.addPostFrameCallback((_) => _loadDraft());

ref.listenManual(chatEditorStateProvider, (prev, next) async {
if (next.isEditing &&
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only need Edit case here to update EditorState.

@@ -72,6 +85,26 @@ class _ChatEditorState extends ConsumerState<ChatEditor> {
}
}

void _handleEditing(RoomEventItem? item) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part handles editorState field update when action is Editing.

if (chatEditorState.isReplying || chatEditorState.isEditing) {
final msgItem = chatEditorState.selectedMsgItem;
previewWidget = msgItem.map(
(item) => ChatEditorActionsPreview(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actual preview widget of reply/edit actions which appears on top of ChatEditor.

final chatEditorState = ref.watch(chatEditorStateProvider);
final isPreviewOpen =
chatEditorState.isReplying || chatEditorState.isEditing;
final radiusVal = isPreviewOpen ? 2.0 : 15.0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep UI not ugly when preview widget is opened!

import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class MessageActionsWidget extends ConsumerWidget {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This widget is responsible for rendering message actions options .i.e. copy/delete/reply/edit etc.

}

void main() {
group('Chat editor reply/edit preview tests', () {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And finally some widgets tests to ensure that actions state logics are working as intended!

},
);

// testWidgets('closing edit preview resets chat editor state',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably need some help here. This test-case is fine logic wise but somehow tester can't find close icon of preview widget. Would like to have thoughtful solutions here :)

@gtalha07 gtalha07 marked this pull request as ready for review February 4, 2025 18:18
@gtalha07 gtalha07 requested a review from gnunicorn February 4, 2025 18:19
Copy link
Contributor

@kumarpalsinh25 kumarpalsinh25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good code wise.

Few minor remarks.

  1. Action Menu and Reaction positioning looks weird on Desktop:
    Screenshot 2025-02-05 at 4 29 05 PM

  2. Addition new line gets added when you do Edit Message.

Edit.Message.mov

Comment on lines +55 to +59
final transaction = this.transaction;
final selection = this.selection;
final node = transaction.document.root.children.last;
transaction.deleteNode(node);
transaction.insertNode([0], paragraphNode(text: ''));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipping review of this logic as I don't have much insight knowledge of AppFlowy Editor.

@gtalha07
Copy link
Contributor Author

gtalha07 commented Feb 5, 2025

Look good code wise.

Few minor remarks.

  1. Action Menu and Reaction positioning looks weird on Desktop:
    Screenshot 2025-02-05 at 4 29 05 PM
  2. Addition new line gets added when you do Edit Message.

Edit.Message.mov

Coming to your questions:

  1. This is the case for message bubbles which have short content and bubble doesn't occupy maximum allowed width. Which also complicates further because desktop size window is dynamic. So shrinking the window size would achieve the desired behavior but I'd not probably write that heinous calculation code (for now) because the importance here is that message actions should be visible within current frame.

  2. I sense the source is probably within Appflowy itself where it adds <br> upon text insertion operation. Or maybe the Appflowy document encoder parsers applies this when converting to document. The reason is still unknown to me so I'd like to put ticket on this for further debugging and research as to why it happens.

@kumarpalsinh25
Copy link
Contributor

@gtalha07

This is the case for message bubbles which have short content and bubble doesn't occupy maximum allowed width. Which also complicates further because desktop size window is dynamic. So shrinking the window size would achieve the desired behavior but I'd not probably write that heinous calculation code (for now) because the importance here is that message actions should be visible within current frame.

It fine to not write complicated calculation but just love to see alignment fixes which make it better UI feel. (Like MenuAction and Reaction can be in Right side for isMe message and vice a versa)

@gtalha07
Copy link
Contributor Author

gtalha07 commented Feb 5, 2025

@gtalha07

This is the case for message bubbles which have short content and bubble doesn't occupy maximum allowed width. Which also complicates further because desktop size window is dynamic. So shrinking the window size would achieve the desired behavior but I'd not probably write that heinous calculation code (for now) because the importance here is that message actions should be visible within current frame.

It fine to not write complicated calculation but just love to see alignment fixes which make it better UI feel. (Like MenuAction and Reaction can be in Right side for isMe message and vice a versa)

Hmm, I guess that's a fine suggestion to try. Will check and update if it fixes :)

@gtalha07 gtalha07 enabled auto-merge February 5, 2025 13:18
@gtalha07 gtalha07 merged commit 509e976 into acterglobal:main Feb 5, 2025
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Recently Done
Development

Successfully merging this pull request may close these issues.

2 participants