Skip to content

Commit 81b1b8b

Browse files
committed
action-sheet: Add "Copy message link" button
Fixes: #673
1 parent 682d1a5 commit 81b1b8b

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-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 message link",
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';
@@ -45,6 +47,7 @@ void showMessageActionSheet({required BuildContext context, required Message mes
4547
messageListContext: context,
4648
),
4749
CopyMessageTextButton(message: message, messageListContext: context),
50+
CopyMessageLinkButton(message: message, messageListContext: context),
4851
]);
4952
});
5053
}
@@ -366,3 +369,34 @@ class CopyMessageTextButton extends MessageActionSheetMenuItemButton {
366369
data: ClipboardData(text: rawContent));
367370
};
368371
}
372+
373+
class CopyMessageLinkButton extends MessageActionSheetMenuItemButton {
374+
CopyMessageLinkButton({
375+
super.key,
376+
required super.message,
377+
required super.messageListContext,
378+
});
379+
380+
@override get icon => Icons.link;
381+
382+
@override
383+
String label(ZulipLocalizations zulipLocalizations) {
384+
return zulipLocalizations.actionSheetOptionCopyMessageLink;
385+
}
386+
387+
@override get onPressed => (BuildContext context) {
388+
Navigator.of(context).pop();
389+
final zulipLocalizations = ZulipLocalizations.of(messageListContext);
390+
391+
final store = PerAccountStoreWidget.of(messageListContext);
392+
final messageLink = narrowLink(
393+
store,
394+
SendableNarrow.ofMessage(message, selfUserId: store.selfUserId),
395+
nearMessageId: message.id,
396+
);
397+
398+
copyWithPopup(context: messageListContext,
399+
successContent: Text(zulipLocalizations.successLinkCopied),
400+
data: ClipboardData(text: messageLink.toString()));
401+
};
402+
}

test/widgets/action_sheet_test.dart

Lines changed: 29 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,32 @@ 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+
514+
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
515+
final expectedLink = narrowLink(store, narrow, nearMessageId: message.id).toString();
516+
517+
await tapCopyMessageLinkButton(tester);
518+
await tester.pump(Duration.zero);
519+
check(await Clipboard.getData('text/plain')).isNotNull().text.equals(expectedLink);
520+
});
521+
});
493522
}

0 commit comments

Comments
 (0)