feat: еще стикеры..

This commit is contained in:
Jganenokk
2026-07-03 12:32:30 +07:00
parent a0f4acf4b5
commit 03cfa21c75
11 changed files with 869 additions and 87 deletions
+96 -28
View File
@@ -26,6 +26,7 @@ import '../../core/utils/webview_support.dart';
import '../../core/config/app_link_preview.dart';
import 'custom_notification.dart';
import 'link_text.dart';
import 'sticker_image.dart';
import '../../models/attachment.dart';
import 'poll_view.dart';
import 'photo_viewer.dart';
@@ -181,6 +182,12 @@ class MessageBubble extends StatelessWidget {
return first is VideoAttachment && first.isNote;
}
bool get _isSticker {
final a = message.attachments;
if (a == null || a.isEmpty) return false;
return a.first is StickerAttachment;
}
MessageType get _contentType {
if (_hasShareAttachment) return _computeContentType();
return _contentTypeCache[message] ??= _computeContentType();
@@ -450,7 +457,8 @@ class MessageBubble extends StatelessWidget {
final maxBubbleWidth = MediaQuery.sizeOf(context).width * 0.75;
final keyboard = _inlineKeyboard;
final isVideoNote = _isVideoNote;
final bubbleColor = isVideoNote
final noBubbleBackground = isVideoNote || _isSticker;
final bubbleColor = noBubbleBackground
? Colors.transparent
: (isMe ? cs.primaryContainer : cs.surfaceContainerHighest);
@@ -538,7 +546,7 @@ class MessageBubble extends StatelessWidget {
constraints: BoxConstraints(maxWidth: maxBubbleWidth),
decoration: BoxDecoration(
color: bubbleColor,
borderRadius: isVideoNote
borderRadius: noBubbleBackground
? null
: _borderRadiusFor(
AppBubbleShape.current.value,
@@ -2335,39 +2343,99 @@ class MessageBubble extends StatelessWidget {
Widget _buildStickerAttachment(_BubbleCtx ctx, MessageAttachment sticker) {
final url = sticker.baseUrl ?? '';
final preview = sticker.previewData ?? '';
final imageUrl = url.isNotEmpty ? url : preview;
final staticUrl = url.isNotEmpty ? url : preview;
final lottieUrl = sticker is StickerAttachment ? sticker.lottieUrl : null;
final Widget image = ClipRRect(
borderRadius: BorderRadius.circular(photoBorderRadius),
child: Stack(
children: [
if (imageUrl.isNotEmpty)
CachedNetworkImage(
imageUrl: imageUrl,
width: 150,
height: 150,
fit: BoxFit.contain,
memCacheWidth: 300,
memCacheHeight: 300,
fadeInDuration: const Duration(milliseconds: 120),
errorWidget: (_, _, _) =>
_buildPhotoPlaceholder(ctx.cs, 150, 150),
)
else
_buildPhotoPlaceholder(ctx.cs, 150, 150),
],
),
Widget content = Stack(
children: [
SizedBox(
width: 150,
height: 150,
child: StickerImage(
url: staticUrl,
lottieUrl: lottieUrl,
size: 150,
memCacheWidth: 300,
),
),
Positioned(
bottom: compactTimePadding,
right: compactTimePadding,
child: _buildStickerMeta(ctx),
),
],
);
final onTap = onStickerTap;
if (onTap == null || sticker is! StickerAttachment) return image;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => onTap(sticker),
child: image,
if (onTap != null && sticker is StickerAttachment) {
content = GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => onTap(sticker),
child: content,
);
}
return content;
}
Widget _buildStickerMeta(_BubbleCtx ctx) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.35),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
_clockText,
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.w500,
),
),
if (isMe) ...[const SizedBox(width: 3), _buildStickerStatusIcon()],
if (message.deleted) ...[
const SizedBox(width: 3),
const Icon(Symbols.delete, size: 12, color: Colors.white),
],
],
),
);
}
Widget _buildStickerStatusIcon() {
final status = overrideStatus ?? message.status;
IconData icon;
Color color;
switch (status) {
case 'sending':
case 'pending':
icon = Symbols.schedule;
color = Colors.white;
case null:
case 'sent':
icon = Symbols.check;
color = Colors.white;
case 'delivered':
icon = Symbols.done_all;
color = Colors.white;
case 'read':
icon = Symbols.done_all;
color = const Color(0xFF4FC3F7);
case 'error':
icon = Symbols.error;
color = Colors.redAccent;
default:
icon = Symbols.check;
color = Colors.white;
}
return Icon(icon, size: 13, color: color);
}
Widget _buildContactAttachment(_BubbleCtx ctx, MessageAttachment contact) {
final contactData = contact as ContactAttachment;