Skip to content

"Copy link to topic" in topic action sheet #1762

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

Merged
merged 2 commits into from
Jul 30, 2025

Conversation

sm-sayedi
Copy link
Collaborator

@sm-sayedi sm-sayedi commented Jul 28, 2025

Screenshots

Topic action sheet Copied link pasted
Copy link to topic Topic link pasted

Screen recording

Screen.Recording.2025-07-29.at.1.10.16.AM.mov

Fixes: #792

@sm-sayedi sm-sayedi added the maintainer review PR ready for review by Zulip maintainers label Jul 28, 2025
@sm-sayedi sm-sayedi requested a review from chrisbobbe July 28, 2025 20:47
Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

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

Thanks! This looks good; one small comment on the icon in the action sheet.

For the tests, let's include a test for the pre-271 behavior of omitting "/with/" (see resolveApiNarrowForServer).


final TopicNarrow narrow;

@override IconData get icon => Icons.link;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I notice that this is Icons.link instead of ZulipIcons.link. Do we have a custom icon we can use here?

…Ah I think we do. Here's the SVG: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=544-22131&p=f&m=dev

I see it being used for "Copy link to channel" in Figma: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=6326-96513&m=dev

Would you add a prep commit that adds that new custom icon, and another commit that changes the one existing Icons.link (in "Copy link to message") to use the new icon?

@alya
Copy link
Collaborator

alya commented Jul 29, 2025

Would it be a follow-up to do the equivalent of zulip/zulip#29136?

@sm-sayedi
Copy link
Collaborator Author

Thanks @chrisbobbe for the review! New revision pushed, with tests included. Also added the new "link" icon, with screenshots updated. PTAL.

@sm-sayedi sm-sayedi requested a review from chrisbobbe July 29, 2025 08:06
@sm-sayedi
Copy link
Collaborator Author

Would it be a follow-up to do the equivalent of zulip/zulip#29136?

Yeah, I think doing that as a follow-up would be the better option and will make it easy to get this PR merged sooner.

@sm-sayedi
Copy link
Collaborator Author

@chrisbobbe Pushed a new revision with the small changes you suggested in today's call.

Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

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

Thanks, this looks great! Just small comments below, and I see you've already updated the lastOrNull commit as discussed on our call today.

Comment on lines -361 to -400
if (optionButtons.isEmpty) {
// TODO(a11y): This case makes a no-op gesture handler; as a consequence,
// we're presenting some UI (to people who use screen-reader software) as
// though it offers a gesture interaction that it doesn't meaningfully
// offer, which is confusing. The solution here is probably to remove this
// is-empty case by having at least one button that's always present,
// such as "copy link to topic".
return;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

🎉

}
optionButtons.add(CopyTopicLinkButton(
narrow: TopicNarrow(channelId, topic,
// TODO(#1499): use the/a max message id of the topic
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there still a TODO here? A previous commit started using lastOrNull of a list of message IDs.

Copy link
Collaborator Author

@sm-sayedi sm-sayedi Jul 29, 2025

Choose a reason for hiding this comment

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

Yeah, I think we will still need that TODO as the previous commit partially addressed the "max message id" case and did it only for when the topic action sheet is opened through the app bar title (it's still partial becuase the last message of topic list view is still not gauranteed to be the most recent message of topic). Then for other places where the sheet is opened from, like through the recipient header or in inbox view (which currently don't pass the max message id), the best option will be to get the most recent message id from a central place.

Copy link
Member

Choose a reason for hiding this comment

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

I think no further change is actually needed in this direction.

  • The recipient header uses the message ID of the message directly under it. When that's how the user got to the topic action sheet, having the /with/ operand point to that message seems fine and good — it means the link will continue to link to the conversation that that message belongs to, if things get split up.
  • The inbox uses the latest unread message ID in the conversation, right? When there are any unreads, the latest unread will almost always be the latest message. In the unusual situations where it isn't, and if the latest (but not unread) message later gets split to a different conversation from the latest unread, I'm not sure which one would be better for the link to point to.

}

group('copies topic link to clipboard', () {
testWidgets('FL >= 271 -> link contains "with" operator', (tester) async {
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: When there's a pair of tests for "legacy" vs. "current" behavior, I like to consider the "current" behavior as boring/default/unmarked, so for example naming the test like

testWidgets('copies message link to clipboard', (tester) async {

, and consider the "legacy" one as interesting/unusual/marked:

testWidgets('FL < 271 -> link doesn\'t contain "with" operator', (tester) async {

In the future, when we stop supporting servers with the legacy behavior, "message link" will always include "with" in its meaning, and when we clear out the backwards-compatibility code and its corresponding test, the remaining test won't need any changes to make it look natural.

Comment on lines 890 to 892
final expectedLink = narrowLink(store,
TopicNarrow(someChannel.streamId, TopicName(someTopic), with_: message.id)
).toString();
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about a quick check(expectedLink.toString().contains('with')).isTrue(), and isFalse in the "FL < 271" test? Just to satisfy a reader that narrowLink handles the feature-level condition correctly and they don't need to check that detail in its implementation or tests.

(No need for a TODO to remove that check in the default/current test when clearing out backwards-compatibility code; it won't be as necessary in that future, but it's just one line so the cost is pretty minimal.)

@sm-sayedi
Copy link
Collaborator Author

Thanks @chrisbobbe for the review. New changes pushed.

@sm-sayedi sm-sayedi requested a review from chrisbobbe July 29, 2025 20:08
Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

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

Thanks, LGTM! Marking for Greg's review.

@chrisbobbe chrisbobbe requested a review from gnprice July 29, 2025 20:20
@chrisbobbe chrisbobbe assigned gnprice and unassigned chrisbobbe Jul 29, 2025
@chrisbobbe chrisbobbe added integration review Added by maintainers when PR may be ready for integration and removed maintainer review PR ready for review by Zulip maintainers labels Jul 29, 2025
In the next commit(s), when creating topic permalinks, we try to use
max message id of the topic, if possible. If we cannot find the max
message id, then I think better to use a message id near to max message id.

Related CZO discussions:
  https://chat.zulip.org/#narrow/channel/101-design/topic/redirects.20from.20near.20links/near/1460694
  https://chat.zulip.org/#narrow/channel/101-design/topic/redirects.20from.20near.20links/near/1774403
Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Thanks @sm-sayedi for taking care of this, and @chrisbobbe for the previous reviews! Just small comments below.

).toString();
check(expectedLink.toString().contains('/with/')).isTrue();
Copy link
Member

Choose a reason for hiding this comment

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

nit: redundant toString

I'd probably remove the first one, and let expectedLink be a Uri object.

Comment on lines 925 to 927
await prepare(channel: someChannel, topic: someTopic,
zulipFeatureLevel: 270);
await showFromRecipientHeader(tester, message: message);
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason this test uses showFromRecipientHeader while its counterpart above uses showFromAppBar?

Because these two are meant to demonstrate a contrast in the behavior depending on the feature level, it's best if their setup is all the same except for the feature level.

}
optionButtons.add(CopyTopicLinkButton(
narrow: TopicNarrow(channelId, topic,
// TODO(#1499): use the/a max message id of the topic
Copy link
Member

Choose a reason for hiding this comment

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

I think no further change is actually needed in this direction.

  • The recipient header uses the message ID of the message directly under it. When that's how the user got to the topic action sheet, having the /with/ operand point to that message seems fine and good — it means the link will continue to link to the conversation that that message belongs to, if things get split up.
  • The inbox uses the latest unread message ID in the conversation, right? When there are any unreads, the latest unread will almost always be the latest message. In the unusual situations where it isn't, and if the latest (but not unread) message later gets split to a different conversation from the latest unread, I'm not sure which one would be better for the link to point to.

@sm-sayedi
Copy link
Collaborator Author

Thanks @gnprice for the review. New revision pushed. PTAL.

@sm-sayedi sm-sayedi requested a review from gnprice July 29, 2025 21:58
@gnprice gnprice merged commit 8792876 into zulip:main Jul 30, 2025
1 check passed
@gnprice
Copy link
Member

gnprice commented Jul 30, 2025

Thanks! Looks good; merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration review Added by maintainers when PR may be ready for integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Offer "Copy link to topic"
4 participants