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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changes/2529-chat_ng-message-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[Labs] Chat-NG:

- [Feature] Now you can do message actions on message .i.e. edit/reply/copy/delete/report.
9 changes: 9 additions & 0 deletions app/lib/common/providers/chat_providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,12 @@
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.

.family<ComposeDraft?, String>((ref, roomId) async {
final chat = await ref.watch(chatProvider(roomId).future);

Check warning on line 40 in app/lib/common/providers/chat_providers.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/common/providers/chat_providers.dart#L40

Added line #L40 was not covered by tests
if (chat == null) {
return null;
}
return (await chat.msgDraft().then((val) => val.draft()));

Check warning on line 44 in app/lib/common/providers/chat_providers.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/common/providers/chat_providers.dart#L44

Added line #L44 was not covered by tests
});
21 changes: 20 additions & 1 deletion app/lib/common/widgets/html_editor/html_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@
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!!

if (!document.isEmpty) {
gtalha07 marked this conversation as resolved.
Show resolved Hide resolved
final transaction = this.transaction;
final selection = this.selection;
final node = transaction.document.root.children.last;
transaction.deleteNode(node);
transaction.insertNode([0], paragraphNode(text: ''));

Check warning on line 59 in app/lib/common/widgets/html_editor/html_editor.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/common/widgets/html_editor/html_editor.dart#L55-L59

Added lines #L55 - L59 were not covered by tests
Comment on lines +55 to +59
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.


updateSelectionWithReason(

Check warning on line 61 in app/lib/common/widgets/html_editor/html_editor.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/common/widgets/html_editor/html_editor.dart#L61

Added line #L61 was not covered by tests
selection,
reason: SelectionUpdateReason.transaction,
);
apply(transaction);

Check warning on line 65 in app/lib/common/widgets/html_editor/html_editor.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/common/widgets/html_editor/html_editor.dart#L65

Added line #L65 was not covered by tests
}
}
}

extension ActerDocumentHelpers on Document {
Expand Down Expand Up @@ -80,7 +97,7 @@
}) {
if (htmlContent != null) {
final document = ActerDocumentHelpers._fromHtml(htmlContent);
if (document != null) {
if (document != null && !document.isEmpty) {

Check warning on line 100 in app/lib/common/widgets/html_editor/html_editor.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/common/widgets/html_editor/html_editor.dart#L100

Added line #L100 was not covered by tests
return document;
}
}
Expand Down Expand Up @@ -206,6 +223,7 @@
void _triggerExport(ExportCallback exportFn) {
final plain = editorState.intoMarkdown();
final htmlBody = editorState.intoHtml();

exportFn(plain, htmlBody != plain ? htmlBody : null);
}

Expand Down Expand Up @@ -378,6 +396,7 @@
...standardCharacterShortcutEvents,
if (roomId != null) ...mentionShortcuts(context, roomId),
],
disableAutoScroll: true,
),
),
),
Expand Down
9 changes: 0 additions & 9 deletions app/lib/features/chat/providers/chat_providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,6 @@ final chatStateProvider =
(ref, roomId) => ChatRoomNotifier(ref: ref, roomId: roomId),
);

final chatComposerDraftProvider = FutureProvider.autoDispose
.family<ComposeDraft?, String>((ref, roomId) async {
final chat = await ref.watch(chatProvider(roomId).future);
if (chat == null) {
return null;
}
return (await chat.msgDraft().then((val) => val.draft()));
});

final chatTopic =
FutureProvider.autoDispose.family<String?, String>((ref, roomId) async {
final c = await ref.watch(chatProvider(roomId).future);
Expand Down
18 changes: 18 additions & 0 deletions app/lib/features/chat_ng/actions/copy_message_action.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

Future<void> copyMessageAction(

Check warning on line 6 in app/lib/features/chat_ng/actions/copy_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/copy_message_action.dart#L6

Added line #L6 was not covered by 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.

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

BuildContext context,
String body,
) async {
String msg = body.trim();
await Clipboard.setData(
ClipboardData(text: msg),

Check warning on line 12 in app/lib/features/chat_ng/actions/copy_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/copy_message_action.dart#L10-L12

Added lines #L10 - L12 were not covered by tests
);
if (context.mounted) {
EasyLoading.showToast(L10n.of(context).messageCopiedToClipboard);
Navigator.pop(context);

Check warning on line 16 in app/lib/features/chat_ng/actions/copy_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/copy_message_action.dart#L14-L16

Added lines #L14 - L16 were not covered by tests
}
}
65 changes: 65 additions & 0 deletions app/lib/features/chat_ng/actions/redact_message_action.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'package:acter/common/providers/chat_providers.dart';
import 'package:acter/common/toolkit/buttons/primary_action_button.dart';
import 'package:acter/common/widgets/default_dialog.dart';
import 'package:acter/features/chat_ng/providers/chat_room_messages_provider.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart'
show RoomEventItem;
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:logging/logging.dart';

final _log = Logger('a3::chat::message_actions_redact');

Check warning on line 13 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L13

Added line #L13 was not covered by tests

Future<void> redactMessageAction(

Check warning on line 15 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L15

Added line #L15 was not covered by tests
BuildContext context,
WidgetRef ref,
RoomEventItem item,
String messageId,
String roomId,
) async {
final chatEditorNotifier = ref.watch(chatEditorStateProvider.notifier);
final lang = L10n.of(context);
final senderId = item.sender();

Check warning on line 24 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L22-L24

Added lines #L22 - L24 were not covered by tests
// pop message action options
Navigator.pop(context);
await showAdaptiveDialog(

Check warning on line 27 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L26-L27

Added lines #L26 - L27 were not covered by tests
context: context,
builder: (context) => DefaultDialog(
title: Text(lang.areYouSureYouWantToDeleteThisMessage),
actions: <Widget>[
OutlinedButton(
onPressed: () => Navigator.pop(context),
child: Text(lang.no),

Check warning on line 34 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L29-L34

Added lines #L29 - L34 were not covered by tests
),
ActerPrimaryActionButton(
onPressed: () async {

Check warning on line 37 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L36-L37

Added lines #L36 - L37 were not covered by tests
try {
final convo = await ref.read(chatProvider(roomId).future);
await convo?.redactMessage(

Check warning on line 40 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L39-L40

Added lines #L39 - L40 were not covered by tests
messageId,
senderId,
null,
null,
);
chatEditorNotifier.unsetActions();
if (context.mounted) {
Navigator.pop(context);

Check warning on line 48 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L46-L48

Added lines #L46 - L48 were not covered by tests
}
} catch (e, s) {
_log.severe('Redacting message failed', e, s);
if (!context.mounted) return;
EasyLoading.showError(
lang.redactionFailed(e),

Check warning on line 54 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L51-L54

Added lines #L51 - L54 were not covered by tests
duration: const Duration(seconds: 3),
);
Navigator.pop(context);

Check warning on line 57 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L57

Added line #L57 was not covered by tests
}
},
child: Text(lang.yes),

Check warning on line 60 in app/lib/features/chat_ng/actions/redact_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/redact_message_action.dart#L60

Added line #L60 was not covered by tests
),
],
),
);
}
25 changes: 25 additions & 0 deletions app/lib/features/chat_ng/actions/report_message_action.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:acter/common/actions/report_content.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart'
show RoomEventItem;
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

Future<void> reportMessageAction(

Check warning on line 7 in app/lib/features/chat_ng/actions/report_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/report_message_action.dart#L7

Added line #L7 was not covered by tests
BuildContext context,
RoomEventItem item,
String messageId,
String roomId,
) async {
final lang = L10n.of(context);
final senderId = item.sender();

Check warning on line 14 in app/lib/features/chat_ng/actions/report_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/report_message_action.dart#L13-L14

Added lines #L13 - L14 were not covered by tests
// pop message action options
Navigator.pop(context);
await openReportContentDialog(

Check warning on line 17 in app/lib/features/chat_ng/actions/report_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/report_message_action.dart#L16-L17

Added lines #L16 - L17 were not covered by tests
context,
title: lang.reportThisMessage,
description: lang.reportMessageContent,

Check warning on line 20 in app/lib/features/chat_ng/actions/report_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/report_message_action.dart#L19-L20

Added lines #L19 - L20 were not covered by tests
senderId: senderId,
roomId: roomId,
eventId: messageId,
);
}
25 changes: 9 additions & 16 deletions app/lib/features/chat_ng/actions/send_message_action.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:acter/common/providers/chat_providers.dart';
import 'package:acter/common/widgets/html_editor/html_editor.dart';
import 'package:acter/features/chat/models/chat_input_state/chat_input_state.dart';
import 'package:acter/features/chat/providers/chat_providers.dart';
import 'package:acter/features/chat_ng/providers/chat_room_messages_provider.dart';
import 'package:acter/features/home/providers/client_providers.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart' show MsgDraft;
import 'package:appflowy_editor/appflowy_editor.dart';
Expand Down Expand Up @@ -40,35 +40,28 @@
}

// actually send it out
final inputState = ref.read(chatInputProvider);
final chatEditorState = ref.read(chatEditorStateProvider);

Check warning on line 43 in app/lib/features/chat_ng/actions/send_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/send_message_action.dart#L43

Added line #L43 was not covered by tests
final stream = await ref.read(timelineStreamProvider(roomId).future);

if (inputState.selectedMessageState == SelectedMessageState.replyTo) {
final remoteId = inputState.selectedMessage?.remoteId;
if (chatEditorState.isReplying) {
final remoteId = chatEditorState.selectedMsgItem?.eventId();

Check warning on line 47 in app/lib/features/chat_ng/actions/send_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/send_message_action.dart#L46-L47

Added lines #L46 - L47 were not covered by tests
if (remoteId == null) throw 'remote id of sel msg not available';
await stream.replyMessage(remoteId, draft);
} else if (inputState.selectedMessageState == SelectedMessageState.edit) {
final remoteId = inputState.selectedMessage?.remoteId;
} else if (chatEditorState.isEditing) {
final remoteId = chatEditorState.selectedMsgItem?.eventId();

Check warning on line 51 in app/lib/features/chat_ng/actions/send_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/send_message_action.dart#L50-L51

Added lines #L50 - L51 were not covered by tests
if (remoteId == null) throw 'remote id of sel msg not available';
await stream.editMessage(remoteId, draft);
} else {
await stream.sendMessage(draft);
}

ref.read(chatInputProvider.notifier).messageSent();
final transaction = textEditorState.transaction;
final nodes = transaction.document.root.children;
// delete all nodes of document (reset)
transaction.document.delete([0], nodes.length);
final delta = Delta()..insert('');
// insert empty text node
transaction.document.insert([0], [paragraphNode(delta: delta)]);
await textEditorState.apply(transaction, withUpdateSelection: false);
// FIXME: works for single line text, but doesn't get focus on multi-line (iOS)
textEditorState.moveCursorForward(SelectionMoveRange.line);
textEditorState.clear();

Check warning on line 59 in app/lib/features/chat_ng/actions/send_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/send_message_action.dart#L59

Added line #L59 was not covered by tests

// also clear composed state
final convo = await ref.read(chatProvider(roomId).future);
final notifier = ref.read(chatEditorStateProvider.notifier);
notifier.unsetActions();

Check warning on line 64 in app/lib/features/chat_ng/actions/send_message_action.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/actions/send_message_action.dart#L63-L64

Added lines #L63 - L64 were not covered by tests
if (convo != null) {
await convo.saveMsgDraft(
textEditorState.intoMarkdown(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import 'dart:ui';

import 'package:acter/features/chat_ng/widgets/message_actions_widget.dart';
import 'package:acter/features/chat_ng/widgets/reactions/reaction_selector.dart';
import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart'
show RoomEventItem;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

// reaction selector action on chat message
void reactionSelectionAction({
// message actions on chat message
void messageActions({

Check warning on line 11 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L11

Added line #L11 was not covered by tests
required BuildContext context,
required Widget messageWidget,
required bool isMe,
required String roomId,
required bool canRedact,
required RoomEventItem item,
required String messageId,
}) {
final RenderBox box = context.findRenderObject() as RenderBox;
final Offset position = box.localToGlobal(Offset.zero);
final messageSize = box.size;
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.

if (!context.mounted) return;

Check warning on line 22 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L21-L22

Added lines #L21 - L22 were not covered by tests

showGeneralDialog(
context: context,
Expand All @@ -22,26 +28,38 @@
barrierColor: Colors.transparent,
transitionDuration: const Duration(milliseconds: 200),
pageBuilder: (context, animation, secondaryAnimation) {
return Stack(
return Column(

Check warning on line 31 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L31

Added line #L31 was not covered by 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.

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.

mainAxisAlignment: MainAxisAlignment.center,
children: [
_ReactionOverlay(
_BlurOverlay(

Check warning on line 34 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L34

Added line #L34 was not covered by tests
animation: animation,
child: const SizedBox.expand(),
),
Positioned(
left: position.dx,
top: position.dy,
width: messageSize.width,
child: messageWidget,
child: const SizedBox.shrink(),
),
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 :)

// Reaction Row
Align(

Check warning on line 39 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L39

Added line #L39 was not covered by tests
alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
child: _AnimatedActionsContainer(

Check warning on line 41 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L41

Added line #L41 was not covered by tests
animation: animation,
messageId: messageId,
tagId: messageId,
child: ReactionSelector(
isMe: isMe,
messageId: '$messageId-reactions',

Check warning on line 46 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L46

Added line #L46 was not covered by tests
roomId: roomId,
),
),
),
// Message
Center(child: messageWidget),

Check warning on line 52 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L52

Added line #L52 was not covered by tests
// Message actions
Align(

Check warning on line 54 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L54

Added line #L54 was not covered by tests
alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
child: _AnimatedActionsContainer(

Check warning on line 56 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L56

Added line #L56 was not covered by tests
animation: animation,
tagId: '$messageId-actions',
child: MessageActionsWidget(

Check warning on line 59 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L58-L59

Added lines #L58 - L59 were not covered by tests
isMe: isMe,
canRedact: canRedact,
item: item,
messageId: messageId,
roomId: roomId,
),
Expand All @@ -53,11 +71,11 @@
);
}

class _ReactionOverlay extends StatelessWidget {
class _BlurOverlay extends StatelessWidget {
final Animation<double> animation;
final Widget child;

const _ReactionOverlay({
const _BlurOverlay({

Check warning on line 78 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L78

Added line #L78 was not covered by tests
required this.animation,
required this.child,
});
Expand Down Expand Up @@ -86,21 +104,21 @@
}
}

class _AnimatedReactionSelector extends StatelessWidget {
class _AnimatedActionsContainer extends StatelessWidget {
final Animation<double> animation;
final Widget child;
final String messageId;
final String tagId;

const _AnimatedReactionSelector({
const _AnimatedActionsContainer({

Check warning on line 112 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L112

Added line #L112 was not covered by tests
required this.animation,
required this.child,
required this.messageId,
required this.tagId,
});

@override
Widget build(BuildContext context) {
return Hero(
tag: messageId,
tag: tagId,

Check warning on line 121 in app/lib/features/chat_ng/dialogs/message_actions.dart

View check run for this annotation

Codecov / codecov/patch

app/lib/features/chat_ng/dialogs/message_actions.dart#L121

Added line #L121 was not covered by tests
child: Material(
color: Colors.transparent,
child: AnimatedBuilder(
Expand Down
Loading
Loading