Skip to content

Commit f87b14e

Browse files
committed
action-sheet: Add "Copy message link" button
Fixes: #673
1 parent b5e0a5f commit f87b14e

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

assets/l10n/app_en.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
"@actionSheetOptionCopyMessageText": {
4848
"description": "Label for copy message text button on action sheet."
4949
},
50+
"actionSheetOptionCopyMessageLink": "Copy link to message",
51+
"@actionSheetOptionCopyMessageLink": {
52+
"description": "Label for copy message link button on action sheet."
53+
},
5054
"actionSheetOptionShare": "Share",
5155
"@actionSheetOptionShare": {
5256
"description": "Label for share button on action sheet."

lib/widgets/action_sheet.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import 'package:share_plus/share_plus.dart';
66
import '../api/exception.dart';
77
import '../api/model/model.dart';
88
import '../api/route/messages.dart';
9+
import '../model/internal_link.dart';
10+
import '../model/narrow.dart';
911
import 'clipboard.dart';
1012
import 'compose_box.dart';
1113
import 'dialog.dart';
@@ -44,6 +46,7 @@ void showMessageActionSheet({required BuildContext context, required Message mes
4446
messageListContext: context,
4547
),
4648
CopyMessageTextButton(message: message, messageListContext: context),
49+
CopyMessageLinkButton(message: message, messageListContext: context),
4750
ShareButton(message: message, messageListContext: context),
4851
]);
4952
});
@@ -310,6 +313,37 @@ class CopyMessageTextButton extends MessageActionSheetMenuItemButton {
310313
}
311314
}
312315

316+
class CopyMessageLinkButton extends MessageActionSheetMenuItemButton {
317+
CopyMessageLinkButton({
318+
super.key,
319+
required super.message,
320+
required super.messageListContext,
321+
});
322+
323+
@override IconData get icon => Icons.link;
324+
325+
@override
326+
String label(ZulipLocalizations zulipLocalizations) {
327+
return zulipLocalizations.actionSheetOptionCopyMessageLink;
328+
}
329+
330+
@override void onPressed(BuildContext context) {
331+
Navigator.of(context).pop();
332+
final zulipLocalizations = ZulipLocalizations.of(messageListContext);
333+
334+
final store = PerAccountStoreWidget.of(messageListContext);
335+
final messageLink = narrowLink(
336+
store,
337+
SendableNarrow.ofMessage(message, selfUserId: store.selfUserId),
338+
nearMessageId: message.id,
339+
);
340+
341+
copyWithPopup(context: messageListContext,
342+
successContent: Text(zulipLocalizations.successLinkCopied),
343+
data: ClipboardData(text: messageLink.toString()));
344+
}
345+
}
346+
313347
class ShareButton extends MessageActionSheetMenuItemButton {
314348
ShareButton({
315349
super.key,

test/widgets/action_sheet_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:http/http.dart' as http;
99
import 'package:zulip/api/model/model.dart';
1010
import 'package:zulip/api/route/messages.dart';
1111
import 'package:zulip/model/compose.dart';
12+
import 'package:zulip/model/internal_link.dart';
1213
import 'package:zulip/model/localizations.dart';
1314
import 'package:zulip/model/narrow.dart';
1415
import 'package:zulip/model/store.dart';
@@ -490,4 +491,31 @@ void main() {
490491
check(await Clipboard.getData('text/plain')).isNull();
491492
});
492493
});
494+
495+
group('CopyMessageLinkButton', () {
496+
setUp(() async {
497+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
498+
SystemChannels.platform,
499+
MockClipboard().handleMethodCall,
500+
);
501+
});
502+
503+
Future<void> tapCopyMessageLinkButton(WidgetTester tester) async {
504+
await tester.ensureVisible(find.byIcon(Icons.link, skipOffstage: false));
505+
await tester.tap(find.byIcon(Icons.link));
506+
await tester.pump(); // [MenuItemButton.onPressed] called in a post-frame callback: flutter/flutter@e4a39fa2e
507+
}
508+
509+
testWidgets('copies message link to clipboard', (tester) async {
510+
final message = eg.streamMessage();
511+
final narrow = TopicNarrow.ofMessage(message);
512+
await setupToMessageActionSheet(tester, message: message, narrow: narrow);
513+
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
514+
515+
final expectedLink = narrowLink(store, narrow, nearMessageId: message.id).toString();
516+
await tapCopyMessageLinkButton(tester);
517+
await tester.pump(Duration.zero);
518+
check(await Clipboard.getData('text/plain')).isNotNull().text.equals(expectedLink);
519+
});
520+
});
493521
}

0 commit comments

Comments
 (0)