Skip to content

fix(mobile): keep token labels visible in authored Markdown links - #7545

Open
masfour7 wants to merge 1 commit into
block:mainfrom
Infinitix-LLC:fix/mobile-link-label-scopes
Open

fix(mobile): keep token labels visible in authored Markdown links#7545
masfour7 wants to merge 1 commit into
block:mainfrom
Infinitix-LLC:fix/mobile-link-label-scopes

Conversation

@masfour7

@masfour7 masfour7 commented Sep 9, 2026

Copy link
Copy Markdown

Summary

On iOS, an authored Markdown link renders as blank when its label is recognized as a Buzz channel, mention, or custom emoji. For example:

[#2959](https://example.com/)

The surrounding text remains visible, but the link has no visible label or tap target.

Buzz's _ChannelLinkMd, _MentionMd, and CustomEmojiMd components return WidgetSpans. gpt_markdown also renders an authored link through a WidgetSpan and reparses its label through the registered components. Because the Buzz components were allowed to run inside link labels, the result was a placeholder nested inside another placeholder, which does not paint on iOS.

This PR adds the same scope restriction used by gpt_markdown's built-in link component:

@override
Set<MarkdownScope> get scopes =>
    MarkdownComponent.allScopesExceptLinkLabel;

The override is applied to all three widget-based components. Authored labels such as [#2959](url), [@Alice](url), and [:wave:](url) therefore remain ordinary link text, while the same tokens outside links continue rendering as Buzz pills and custom emoji.

The PR also updates the shared test helpers to find RichText subclasses. Since the upgrade to gpt_markdown 1.2.1, body paragraphs can render through BidiRichText; find.byType(RichText) does not match that subclass and could allow an absence assertion to pass without inspecting the message text.

The handling of unknown bare #tokens is deliberately unchanged. Whether those should remain non-interactive pills or become plain text is a separate product decision.

Related issue

Fixes #6124.

This supersedes #6135. That PR solves the same issue by maintaining a custom fork of gpt_markdown's link component; this PR instead uses the scoped-component API already available in gpt_markdown 1.2.1.

Testing

Focused suites:

flutter test \
  test/features/channels/message_content_test.dart \
  test/features/channels/message_content_custom_emoji_test.dart

Result: 95 tests passed, 0 failed.

Additional checks:

  • just mobile-check — passed; analyzer reported no issues.
  • just mobile-fmt — passed; 549 files formatted with 0 changes.
  • Six new regression tests cover channel, mention, emoji, plain-link control, and outside-link behavior.
  • Removing the _ChannelLinkMd override causes two regression tests to fail; removing _MentionMd or CustomEmojiMd causes one test to fail in each case.
  • Three tests in message_content_test.dart directly assert that the nested-placeholder structure is absent. The custom-emoji tests separately verify literal text and the absence or presence of CustomEmojiImage, depending on whether the shortcode is inside or outside a link.

The complete local mobile suite reports 15 failures that reproduce identically on a clean checkout of main at 44316ff7. In CI for that same commit, Clients / Mobile, Mobile, and Mobile Swift Domain / Mobile Swift all passed.

No native-device screenshot is included. The nested-placeholder fix was verified through the rendered widget structure, but an iOS simulator build was blocked by the existing MLImage.framework arm64-simulator incompatibility.

@masfour7
masfour7 requested a review from a team as a code owner September 9, 2026 22:06
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is ad9591c43bdb7e221ee93964b09d5dadf820497f...1ec6c4ddc1ba056cecc46feb9091262dba3f9828.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 1ec6c4ddc1ba056cecc46feb9091262dba3f9828 to authorize a new review.
Any previous review applies only to its recorded range.

gpt_markdown renders a link's label by recursing with
`MarkdownScope.linkLabel`. `_ChannelLinkMd`, `_MentionMd` and
`CustomEmojiMd` inherited the default `scopes => allScopes`, so they claimed
labels such as `block#2959`, `@Alice` and `:wave:` and returned a `WidgetSpan`.
That span landed inside the link's own `WidgetSpan`, and a placeholder nested
in a placeholder does not paint on iOS — the label, underline and tap target
all disappeared.

Opt all three components out of the link-label scope. Tokens outside a link
label keep their pills.

Also widen four `message_content_test.dart` helpers from
`find.byType(RichText)` to a subclass-aware predicate. Body paragraphs render
through `BidiRichText` since gpt_markdown 1.2.1, so those helpers no longer
saw them and a regression test built on top of them would not have bound to
the rendered output.

Fixes block#6124

Co-authored-by: Samin Yeasar Sohag <sssohag172@gmail.com>
Signed-off-by: Samin Yeasar Sohag <sssohag172@gmail.com>
Signed-off-by: Mohammad Asfour <mya26@cornell.edu>
@masfour7
masfour7 force-pushed the fix/mobile-link-label-scopes branch from 73bcafb to 1ec6c4d Compare September 9, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mobile: Markdown links with a #-prefixed label render as nothing (desktop renders them fine)

2 participants