refactor: зарефакторил пересланные сообщения

This commit is contained in:
Jganenokk
2026-08-09 01:10:03 +07:00
parent 45297e4aff
commit 05ca3a9413
10 changed files with 513 additions and 275 deletions
+258 -2
View File
@@ -2,16 +2,29 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:komet/backend/modules/messages.dart';
import 'package:komet/core/utils/text_format.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/bubble_context.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/call_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/contact_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/file_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/forwarded_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/location_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/photo_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/share_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/sticker_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/video_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/video_note_bubble.dart';
import 'package:komet/frontend/widgets/attachment/bubbles/voice_bubble.dart';
import 'package:komet/frontend/widgets/formatted_message_text.dart';
import 'package:komet/frontend/widgets/message_bubble.dart';
import 'package:komet/l10n/app_localizations.dart';
import 'package:komet/models/attachment.dart';
import 'package:material_symbols_icons/symbols.dart';
Future<void> _pumpBubble(
WidgetTester tester,
CachedMessage message, {
void Function(ForwardedMessageAttachment forwarded)? onSourceTap,
bool isMe = false,
}) async {
tester.view.physicalSize = const Size(1080, 2400);
tester.view.devicePixelRatio = 2.5;
@@ -27,7 +40,7 @@ Future<void> _pumpBubble(
alignment: Alignment.topLeft,
child: MessageBubble(
message: message,
isMe: false,
isMe: isMe,
myId: 1,
chatType: 'CHAT',
onForwardedSourceTap: onSourceTap,
@@ -242,9 +255,13 @@ void main() {
expect(formatted.ranges.single.format, TextFormat.heading);
expect(find.text('0'), findsNothing);
expect(
tester.getSize(find.byType(ForwardedPhotoBubble)).width,
tester.getSize(find.byType(ForwardedHeader)).width,
closeTo(200, 0.1),
);
expect(
tester.getSize(find.byType(ForwardedHeader)).width,
closeTo(tester.getSize(find.byType(PhotoBubble)).width, 0.1),
);
expect(
tester.getBottomLeft(find.byType(ClipRRect).first).dy,
lessThanOrEqualTo(tester.getTopLeft(find.text(caption)).dy),
@@ -255,6 +272,245 @@ void main() {
expect(tappedSource?.isChannel, isTrue);
});
testWidgets('renders a forwarded video with its original metadata', (
tester,
) async {
final attachment = ForwardedMessageAttachment.fromMap({
'link': {
'type': 'FORWARD',
'message': {
'id': 'synthetic-source-message',
'time': 9000,
'type': 'USER',
'sender': 44,
'text': 'Synthetic video caption',
'attaches': [
{
'_type': 'VIDEO',
'videoId': 7001,
'token': 'synthetic-video-token',
'videoType': 0,
'duration': 9000,
'width': 720,
'height': 1280,
},
],
},
'chatId': -50,
},
});
final video = attachment.originalAttachments!.single as VideoAttachment;
final message = CachedMessage(
id: 'synthetic-forward-message',
accountId: 1,
chatId: 2,
senderId: 43,
time: 10000,
attachments: [attachment],
);
expect(video.videoId, 7001);
expect(video.videoToken, 'synthetic-video-token');
expect(video.videoType, 0);
await _pumpBubble(tester, message);
expect(find.byType(ForwardedHeader), findsOneWidget);
expect(find.byType(VideoBubble), findsOneWidget);
expect(find.text('Synthetic video caption'), findsOneWidget);
expect(find.text('0:09'), findsOneWidget);
final forwardedWidth = tester.getSize(find.byType(ForwardedHeader)).width;
final videoWidth = tester.getSize(find.byType(VideoBubble)).width;
expect(forwardedWidth, closeTo(BubbleContext.photoMaxSize, 0.1));
expect(forwardedWidth, closeTo(videoWidth, 0.1));
final preview = find.descendant(
of: find.byType(VideoBubble),
matching: find.byType(ClipRRect),
);
expect(
tester.getBottomLeft(preview.first).dy,
lessThanOrEqualTo(
tester.getTopLeft(find.text('Synthetic video caption')).dy,
),
);
final bubble = tester.widget<VideoBubble>(find.byType(VideoBubble));
expect(bubble.ctx.sourceMessageId, 'synthetic-source-message');
expect(bubble.ctx.sourceChatId, -50);
final forwardedVideoSize = tester.getSize(find.byType(VideoBubble));
final forwardedPreviewSize = tester.getSize(preview.first);
final regularMessage = CachedMessage(
id: 'synthetic-regular-message',
accountId: 1,
chatId: 2,
senderId: 43,
time: 10000,
text: 'Synthetic video caption',
attachments: [video],
);
await _pumpBubble(tester, regularMessage);
final regularPreview = find.descendant(
of: find.byType(VideoBubble),
matching: find.byType(ClipRRect),
);
expect(tester.getSize(find.byType(VideoBubble)), forwardedVideoSize);
expect(tester.getSize(regularPreview.first), forwardedPreviewSize);
expect(find.byType(ForwardedHeader), findsNothing);
});
final nativeAttachmentCases =
<({String name, MessageAttachment attachment, Type bubbleType})>[
(
name: 'file',
attachment: const FileAttachment(
fileId: 7101,
name: 'synthetic.txt',
size: 128,
),
bubbleType: FileBubble,
),
(
name: 'sticker',
attachment: const StickerAttachment(
stickerId: 'synthetic-sticker',
width: 128,
height: 128,
),
bubbleType: StickerBubble,
),
(
name: 'location',
attachment: const LocationAttachment(
latitude: 1,
longitude: 2,
title: 'Synthetic location',
),
bubbleType: LocationBubble,
),
(
name: 'call',
attachment: const CallAttachment(isVideo: false, durationMs: 1000),
bubbleType: CallBubble,
),
(
name: 'share',
attachment: const ShareAttachment(
shareId: 7102,
title: 'Synthetic preview',
url: 'https://example.test/synthetic',
),
bubbleType: ShareBubble,
),
(
name: 'audio',
attachment: const AudioAttachment(
audioId: 7103,
duration: 1000,
baseUrl: 'https://example.test/synthetic.ogg',
),
bubbleType: VoiceMessageBubble,
),
(
name: 'video note',
attachment: const VideoAttachment(
videoId: 7104,
videoToken: 'synthetic-note-token',
videoType: 1,
duration: 1000,
width: 480,
height: 480,
),
bubbleType: VideoNoteBubble,
),
];
for (final item in nativeAttachmentCases) {
testWidgets('decorates forwarded ${item.name} native bubble', (
tester,
) async {
final forwarded = ForwardedMessageAttachment(
originalSenderId: 71,
originalMessageId: 'synthetic-source-${item.name}',
originalChatId: 72,
originalText: item.name == 'share'
? 'Synthetic forwarded caption'
: null,
originalAttachments: [item.attachment],
);
final message = CachedMessage(
id: 'synthetic-forward-${item.name}',
accountId: 1,
chatId: 2,
senderId: 70,
time: 11000,
text: 'Synthetic outer text',
attachments: [forwarded],
);
await _pumpBubble(tester, message, isMe: item.name == 'audio');
expect(find.byType(ForwardedHeader), findsOneWidget);
expect(find.byType(item.bubbleType), findsOneWidget);
final usesFloatingHeader =
item.name == 'sticker' || item.name == 'video note';
if (usesFloatingHeader) {
expect(find.byType(ForwardedHeaderFloating), findsOneWidget);
expect(
tester.getRect(find.byType(ForwardedHeaderFloating)).bottom,
lessThanOrEqualTo(tester.getRect(find.byType(item.bubbleType)).top),
);
} else {
expect(find.byType(ForwardedHeaderFloating), findsNothing);
}
if (item.name == 'audio') {
final headerRect = tester.getRect(find.byType(ForwardedHeader));
final voiceRect = tester.getRect(find.byType(VoiceMessageBubble));
expect(voiceRect.left - headerRect.left, closeTo(14, 0.1));
expect(headerRect.right - voiceRect.right, closeTo(14, 0.1));
expect(
find.descendant(
of: find.byType(VoiceMessageBubble),
matching: find.byIcon(Symbols.check),
),
findsOneWidget,
);
}
if (item.name == 'share') {
expect(find.text('Synthetic forwarded caption'), findsOneWidget);
expect(find.text('Synthetic outer text'), findsNothing);
}
});
}
testWidgets('decorates the native forwarded contact bubble', (
tester,
) async {
const forwarded = ForwardedMessageAttachment(
originalSenderId: 73,
originalMessageId: 'synthetic-contact-source',
originalChatId: 74,
originalContact: ContactAttachment(
firstName: 'Synthetic',
lastName: 'Contact',
phoneNumber: '+10000000000',
),
);
const message = CachedMessage(
id: 'synthetic-contact-forward',
accountId: 1,
chatId: 2,
senderId: 70,
time: 12000,
attachments: [forwarded],
);
await _pumpBubble(tester, message);
expect(find.byType(ForwardedHeader), findsOneWidget);
expect(find.byType(ContactBubble), findsOneWidget);
});
testWidgets('makes the forwarded user name clickable', (tester) async {
const attachment = ForwardedMessageAttachment(
originalSenderId: 42,