Skip to content

Commit 25cd9f4

Browse files
morethanwordsclaude
andcommitted
Chat: an unsupported message's plate keeps what a message has — its side, a post's buttons, selection, reading
The plate came in drawn on the service path, which returns before everything the chat does for a message, so it lost that piece by piece: an outgoing one could hold the unread delimiter, a report's choice and a swipe to reply passed it by, a channel post lost its share and comments buttons, its views and its reading, a forward on its way could be selected, a protected channel's post kept a share button, an ad anchored after it was dropped. - It is drawn on the regular path now, as the content of a bubble with no background of its own, the way a sticker stands (`just-media`), so all of that comes with it by construction. What it shows stays Android's plate alone: no time (`noMessageInfo`, as a call has), no name, no forward header, no quote; a saved copy keeps its button to where it was saved from. - A post's comments stand beside the plate, as beside a sticker; a broadcast post with no time to be read by is watched itself. - A rich message whose media this client cannot show keeps its rich content, as before. - The plate gives way to a column narrower than it instead of running past its edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1777d27 commit 25cd9f4

6 files changed

Lines changed: 64 additions & 44 deletions

File tree

‎src/components/chat/bubbleParts/unsupportedMessagePlate.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ const ICON_SVG = `<svg class="${CLASS_NAME}-icon" viewBox="0 0 144 144" aria-hid
77
<path class="${CLASS_NAME}-icon-plane" fill-rule="evenodd" transform="translate(33 33) scale(1.0833)" d="M6.232,35.046C22.115,28.147 32.706,23.599 38.006,21.401C53.136,15.126 56.28,14.036 58.329,14C58.78,13.992 59.788,14.104 60.441,14.632C60.992,15.078 61.143,15.68 61.216,16.103C61.289,16.526 61.379,17.489 61.307,18.241C60.487,26.831 56.939,47.675 55.134,57.295C54.371,61.366 52.867,62.731 51.411,62.865C48.247,63.155 45.844,60.78 42.78,58.777C37.985,55.643 35.276,53.692 30.621,50.634C25.242,47.1 28.729,45.157 31.795,41.983C32.597,41.152 46.537,28.51 46.807,27.363C46.841,27.22 46.872,26.685 46.554,26.403C46.235,26.12 45.765,26.217 45.426,26.294C44.945,26.402 37.284,31.451 22.444,41.438C20.27,42.927 18.3,43.652 16.536,43.614C14.591,43.572 10.849,42.518 8.067,41.616C4.655,40.51 2.448,39.938 2.684,38.06C2.807,37.082 3.99,36.077 6.232,35.046Z"/>
88
</svg>`;
99

10-
export default function wrapUnsupportedMessagePlate(container: HTMLElement) {
11-
container.classList.add(`${CLASS_NAME}-wrapper`);
10+
/** The plate a message this client cannot show is drawn as, the way Android draws it (`UnsupportedBlockDrawable`) */
11+
export default function wrapUnsupportedMessagePlate() {
12+
const container = document.createElement('div');
13+
container.classList.add(CLASS_NAME);
1214
container.insertAdjacentHTML('beforeend', ICON_SVG);
1315

1416
const text = document.createElement('div');
@@ -23,4 +25,5 @@ export default function wrapUnsupportedMessagePlate(container: HTMLElement) {
2325
text.append(title, subtitle);
2426

2527
container.append(text);
28+
return container;
2629
}

‎src/components/chat/bubbles.ts‎

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ import {modifyAckedPromise} from '@helpers/modifyAckedResult';
148148
import callbackify from '@helpers/callbackify';
149149
import {avatarNew, findUpAvatar} from '@components/avatarNew';
150150
import Icon from '@components/icon';
151-
import wrapUnsupportedMessagePlate from '@components/chat/bubbleParts/unsupportedMessagePlate';
152151
import SendingStatusIcon, {SendingStatusIconState, setSendingStatusIconState} from '@components/sendingStatusIcon';
153152
import wrapCallBubble from '@components/wrappers/callBubble';
153+
import wrapUnsupportedMessagePlate from '@components/chat/bubbleParts/unsupportedMessagePlate';
154154
import {FullMid, makeFullMid, splitFullMid} from '@appManagers/utils/messages/fullMid';
155155
import apiManagerProxy from '@lib/apiManagerProxy';
156156
import setBlankToAnchor from '@lib/richTextProcessor/setBlankToAnchor';
@@ -348,21 +348,20 @@ if(IS_GROUP_CALL_SUPPORTED) {
348348

349349
const isStoryMentionMessage = (message: Message.message) => !!(message.media as MessageMedia.messageMediaStory)?.pFlags?.via_mention;
350350
const isSelfDestructingMediaMessage = (message: Message.message) => !!(message.media as MessageMedia.messageMediaPhoto)?.ttl_seconds;
351-
const isUnsupportedMessage = (message: Message.message) => message.media?._ === 'messageMediaUnsupported';
351+
// * a rich message keeps its content when its media is one this client cannot show
352+
const isUnsupportedMessage = (message: Message.message) => message.media?._ === 'messageMediaUnsupported' && !message.rich_message;
352353

353354
/**
354355
* Whether a message is drawn as a service line, neither incoming nor outgoing: a service message but a call, a
355-
* story mention, self-destructing media that cannot be seen, a message this client cannot show
356+
* story mention, self-destructing media that cannot be seen
356357
*/
357358
function isDrawnAsService(message: Message.message | Message.messageService) {
358359
if(message._ !== 'message') {
359360
const action = (message as Message.messageService).action;
360361
return !action || !SERVICE_AS_REGULAR.has(action._);
361362
}
362363

363-
return isStoryMentionMessage(message) ||
364-
(isSelfDestructingMediaMessage(message) && !canSeeMessageMedia(message)) ||
365-
isUnsupportedMessage(message);
364+
return isStoryMentionMessage(message) || (isSelfDestructingMediaMessage(message) && !canSeeMessageMedia(message));
366365
}
367366

368367
// Service actions whose inline photo (suggested profile photo, or a group/channel
@@ -9092,7 +9091,6 @@ export default class ChatBubbles {
90929091

90939092
const isStoryMention = isMessage && isStoryMentionMessage(message);
90949093
const isSelfDestructingMedia = isMessage && isSelfDestructingMediaMessage(message);
9095-
const isUnsupported = isMessage && isUnsupportedMessage(message);
90969094
let returnService: boolean;
90979095

90989096
if(
@@ -9708,9 +9706,6 @@ export default class ChatBubbles {
97089706

97099707
s.append(avatarContainer, text, button);
97109708
}
9711-
} else if(isUnsupported) {
9712-
bubble.classList.add('is-unsupported', this.chat.isOutMessage(message) ? 'is-unsupported-out' : 'is-unsupported-in');
9713-
wrapUnsupportedMessagePlate(s);
97149709
} else if(isSelfDestructingMedia) {
97159710
const promise = wrapMessageForReply({
97169711
message,
@@ -10145,9 +10140,13 @@ export default class ChatBubbles {
1014510140
// message-info block at all, rather than one parked in a corner.
1014610141
// A welcome template is sent whenever someone joins, so its own date means nothing (Android
1014710142
// draws no time there either).
10143+
// A message this client cannot show is a plate and nothing else, as Android draws it: no time,
10144+
// no name, no forward header, no quote.
10145+
const isUnsupported = isMessage && isUnsupportedMessage(message);
1014810146
const noMessageInfo = isSponsored ||
1014910147
context.messageMedia?._ === 'messageMediaCall' ||
10150-
this.chat.type === ChatType.Welcome;
10148+
this.chat.type === ChatType.Welcome ||
10149+
isUnsupported;
1015110150

1015210151
let timeSpan: HTMLElement, _clearfix: HTMLElement;
1015310152
if(!noMessageInfo) {
@@ -10174,6 +10173,9 @@ export default class ChatBubbles {
1017410173
}
1017510174
} else if(isSponsored) {
1017610175
bubble.classList.add('is-sponsored');
10176+
} else if(isBroadcast) {
10177+
// * a post with no time to be read by is read by itself
10178+
setUnreadObserver?.();
1017710179
}
1017810180

1017910181
bubbleContainer.prepend(messageDiv);
@@ -11722,8 +11724,19 @@ export default class ChatBubbles {
1172211724
}
1172311725

1172411726
context.attachmentDiv = undefined;
11725-
context.mediaRequiresMessageDiv = true;
1172611727
noAttachmentDivNeeded = true;
11728+
11729+
// * a plate on the message's side with no bubble around it, as a sticker stands, and with all a message has
11730+
// * the way a sticker has it: the buttons beside a post, its side, a selection, a swipe to reply
11731+
if(isUnsupported) {
11732+
bubble.classList.add('is-unsupported');
11733+
context.isStandaloneMedia = true;
11734+
context.canHaveTail = false;
11735+
messageDiv.before(wrapUnsupportedMessagePlate());
11736+
break;
11737+
}
11738+
11739+
context.mediaRequiresMessageDiv = true;
1172711740
messageDiv.replaceChildren(i18n(UNSUPPORTED_LANG_PACK_KEY));
1172811741
bubble.timeAppenders[0].callback();
1172911742
this.log.warn('unrecognized media type:', context.messageMedia._, message);
@@ -11827,7 +11840,11 @@ export default class ChatBubbles {
1182711840
(showNameForVerificationCodes && !replyTo);
1182811841

1182911842
let nameDiv: HTMLElement;
11830-
if(needName || fwdFrom || replyTo) { // chat
11843+
if(isUnsupported) {
11844+
bubble.classList.add('hide-name');
11845+
// * the plate is all it shows, but a saved copy still leads to where it was saved from
11846+
savedFrom = (message as Message.message).savedFrom || savedFrom;
11847+
} else if(needName || fwdFrom || replyTo) { // chat
1183111848
let title: HTMLElement;
1183211849
let titleVia: typeof title;
1183311850
let noColor: boolean;
@@ -12419,7 +12436,13 @@ export default class ChatBubbles {
1241912436
});
1242012437
reactionsElement.render(changedResults, waitPromise);
1242112438

12422-
if(bubble.classList.contains('has-floating-time') || bubble.classList.contains('service')) {
12439+
// * a bubble with no text to hold them (its time floats over its media, or it is the plate of a message this client
12440+
// * cannot show, which has no time at all) and a service line take them under their content
12441+
if(
12442+
bubble.classList.contains('has-floating-time') ||
12443+
bubble.classList.contains('service') ||
12444+
bubble.classList.contains('is-unsupported')
12445+
) {
1242312446
bubble.querySelector('.bubble-content-wrapper').append(reactionsElement);
1242412447
} else {
1242512448
const timeSpan = bubble.timeSpan;

‎src/components/chat/messageRender.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,8 @@ export namespace MessageRender {
435435
}) => {
436436
const isFooter = !bubble.classList.contains('sticker') &&
437437
!bubble.classList.contains('emoji-big') &&
438-
!bubble.classList.contains('round');
438+
!bubble.classList.contains('round') &&
439+
!bubble.classList.contains('is-unsupported');
439440
const repliesFooter = RepliesElement.create();
440441
repliesFooter.message = message;
441442
repliesFooter.type = isFooter ? 'footer' : 'beside';

‎src/scripts/out/langPack.strings‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,8 @@
477477
"Message.Context.Selection.SendNow" = "Send selected now";
478478
"Message.Unsupported.Desktop" = "__This message is currently not supported on Telegram Web. Try [getdesktop.telegram.org](https://getdesktop.telegram.org/)__";
479479
"Message.Unsupported.Mobile" = "__This message is currently not supported on Telegram Web. Try [telegram.org/dl](https://telegram.org/dl/)__";
480+
"UnsupportedMessageTitle" = "Unsupported Message";
481+
"UnsupportedMessageMessage" = "Update Telegram to view this message";
480482
"RichMessage.Error.TooLong" = "This rich text message is too long (%1$d of %2$d characters).";
481483
"RichMessage.Error.TooManyBlocks" = "This rich text message has too many blocks (%1$d of %2$d).";
482484
"RichMessage.Error.TooDeep" = "This rich text message is nested too deeply (%1$d of %2$d levels).";

‎src/scss/partials/_chat.scss‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,8 +1499,7 @@
14991499

15001500
&.is-chat,
15011501
&.with-message-avatars {
1502-
.is-in .bubble-content-wrapper,
1503-
.bubble.is-unsupported-in .bubble-content-wrapper {
1502+
.is-in .bubble-content-wrapper {
15041503
margin-inline-start: 2.875rem;
15051504
}
15061505
}

‎src/scss/partials/_chatBubble.scss‎

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2518,17 +2518,19 @@
25182518
}
25192519
}
25202520

2521+
// * the plate of a message this client cannot show, drawn as Android draws it (`UnsupportedBlockDrawable`): on the
2522+
// * wallpaper in the service lines' colours, in a bubble with no background of its own (`.just-media`)
25212523
&-unsupported {
2522-
&-wrapper {
2523-
display: flex !important;
2524-
align-items: center;
2525-
gap: .5rem;
2526-
width: 25rem;
2527-
max-width: 100%;
2528-
padding: .4375rem .6875rem .4375rem .375rem !important;
2529-
border-radius: 1.125rem !important;
2530-
text-align: start;
2531-
}
2524+
display: flex;
2525+
align-items: center;
2526+
gap: .5rem;
2527+
width: 25rem;
2528+
max-width: 100%;
2529+
padding: .4375rem .6875rem .4375rem .375rem;
2530+
border-radius: 1.125rem;
2531+
background-color: var(--message-highlighting-color);
2532+
color: #fff;
2533+
user-select: none;
25322534

25332535
&-icon {
25342536
flex: 0 0 auto;
@@ -2550,7 +2552,6 @@
25502552
display: flex;
25512553
flex-direction: column;
25522554
gap: .125rem;
2553-
text-align: start;
25542555
}
25552556

25562557
&-title {
@@ -2567,6 +2568,11 @@
25672568
}
25682569
}
25692570

2571+
// * its width gives way to a column narrower than it, with an avatars' margin beside it too, as text would wrap
2572+
&.is-unsupported .bubble-content-wrapper {
2573+
min-width: 0;
2574+
}
2575+
25702576
// Generic "media + caption + button" service bubble (e.g. suggested profile
25712577
// photo). Centered round media, modeled on the story-mention bubble above.
25722578
&-service-media {
@@ -3468,20 +3474,6 @@
34683474
padding: 0 2rem;
34693475
}
34703476
}
3471-
3472-
&.is-unsupported {
3473-
.bubble-content-wrapper {
3474-
padding: 0;
3475-
}
3476-
3477-
&-in {
3478-
justify-content: flex-start;
3479-
}
3480-
3481-
&-out {
3482-
justify-content: flex-end;
3483-
}
3484-
}
34853477
}
34863478

34873479
.bubble.service, .bubble.has-fake-service {

0 commit comments

Comments
 (0)