я умер пока фиксил фронт
This commit is contained in:
@@ -21,9 +21,6 @@ class MessageBubble extends StatelessWidget {
|
||||
return false;
|
||||
final hasPhoto = message.attachments!.any((a) => a is PhotoAttachment);
|
||||
final hasCaption = message.text != null && message.text!.isNotEmpty;
|
||||
debugPrint(
|
||||
'DEBUG _hasPhotoWithCaption: hasPhoto=$hasPhoto, hasCaption=$hasCaption, text="${message.text}", shape=$shape',
|
||||
);
|
||||
return hasPhoto && hasCaption;
|
||||
}
|
||||
|
||||
@@ -81,6 +78,7 @@ class MessageBubble extends StatelessWidget {
|
||||
MessageType get contentType {
|
||||
if (message.attachments != null && message.attachments!.isNotEmpty) {
|
||||
final first = message.attachments!.first;
|
||||
if (first is UnknownAttachment) return MessageType.text;
|
||||
if (first.type == AttachmentType.audio) return MessageType.voice;
|
||||
return MessageType.attachment;
|
||||
}
|
||||
@@ -251,16 +249,7 @@ class MessageBubble extends StatelessWidget {
|
||||
return const EdgeInsets.symmetric(horizontal: 14, vertical: 10);
|
||||
}
|
||||
case MessageType.attachment:
|
||||
switch (shape) {
|
||||
case BubbleShape.groupedMiddle:
|
||||
return const EdgeInsets.all(0);
|
||||
case BubbleShape.singleTop:
|
||||
return const EdgeInsets.all(0);
|
||||
case BubbleShape.singleBottom:
|
||||
return const EdgeInsets.all(0);
|
||||
case BubbleShape.singleMiddle:
|
||||
return const EdgeInsets.all(0);
|
||||
}
|
||||
return const EdgeInsets.all(0);
|
||||
case MessageType.voice:
|
||||
switch (shape) {
|
||||
case BubbleShape.groupedMiddle:
|
||||
@@ -395,7 +384,12 @@ class MessageBubble extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
return IntrinsicWidth(
|
||||
final photo = photos[0];
|
||||
final pw = photo.width?.toDouble() ?? 200;
|
||||
final photoWidth = pw.clamp(photoMinSize, photoMaxSize);
|
||||
|
||||
return SizedBox(
|
||||
width: photoWidth,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -410,7 +404,7 @@ class MessageBubble extends StatelessWidget {
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Expanded(child: _buildCaption(ctx)),
|
||||
Flexible(child: _buildCaption(ctx)),
|
||||
_buildMeta(ctx),
|
||||
],
|
||||
),
|
||||
@@ -744,68 +738,82 @@ class MessageBubble extends StatelessWidget {
|
||||
? Colors.white
|
||||
: (isDark ? cs.onSurface : const Color(0xFF1C1C1E));
|
||||
final subtitleColor = isMe
|
||||
? Colors.white.withValues(alpha: 0.7)
|
||||
? Colors.white.withValues(alpha: 0.65)
|
||||
: (isDark ? cs.onSurfaceVariant : const Color(0xFF8E8E93));
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
width: 220,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: isMe
|
||||
? Colors.white.withValues(alpha: 0.15)
|
||||
: (isDark ? cs.surface : const Color(0xFFFFFFFF)),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 38,
|
||||
height: 38,
|
||||
decoration: BoxDecoration(
|
||||
color: isMe
|
||||
? Colors.white.withValues(alpha: 0.2)
|
||||
: cs.primaryContainer,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(
|
||||
Symbols.description,
|
||||
color: isMe ? Colors.white : cs.primary,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: isMe
|
||||
? Colors.white.withValues(alpha: 0.2)
|
||||
: cs.primaryContainer,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.2,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
child: Icon(
|
||||
Symbols.file_download,
|
||||
color: isMe ? Colors.white : cs.primary,
|
||||
size: 22,
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
sizeStr,
|
||||
style: TextStyle(
|
||||
color: subtitleColor,
|
||||
fontSize: 12,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
'Скачать • $sizeStr',
|
||||
style: TextStyle(color: subtitleColor, fontSize: 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildMeta(ctx),
|
||||
],
|
||||
const SizedBox(width: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
decoration: BoxDecoration(
|
||||
color: isMe
|
||||
? Colors.white.withValues(alpha: 0.15)
|
||||
: (isDark
|
||||
? cs.surfaceContainerHighest
|
||||
: const Color(0xFFE5E5EA)),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Symbols.download,
|
||||
color: isMe ? Colors.white : cs.primary,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@ abstract class MessageAttachment {
|
||||
return LocationAttachment.fromMap(map);
|
||||
case 'CONTROL':
|
||||
return ControlAttachment.fromMap(map);
|
||||
case 'SHARE':
|
||||
return FileAttachment.fromMap(map);
|
||||
case 'INLINE_KEYBOARD':
|
||||
return UnknownAttachment(map);
|
||||
default:
|
||||
return UnknownAttachment(map);
|
||||
}
|
||||
@@ -125,8 +129,19 @@ class VideoAttachment extends MessageAttachment {
|
||||
}) : super(type: AttachmentType.video);
|
||||
|
||||
factory VideoAttachment.fromMap(Map<String, dynamic> map) {
|
||||
String? previewStr;
|
||||
final previewRaw = map['previewData'];
|
||||
if (previewRaw is String) {
|
||||
previewStr = previewRaw;
|
||||
} else if (previewRaw is List) {
|
||||
try {
|
||||
final bytes = List<int>.from(previewRaw);
|
||||
previewStr = String.fromCharCodes(bytes);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return VideoAttachment(
|
||||
previewData: map['previewData'] as String?,
|
||||
previewData: previewStr,
|
||||
baseUrl: map['baseUrl'] as String?,
|
||||
videoId: map['videoId'] as int?,
|
||||
videoToken: map['videoToken'] as String?,
|
||||
@@ -170,8 +185,19 @@ class AudioAttachment extends MessageAttachment {
|
||||
}) : super(type: AttachmentType.audio);
|
||||
|
||||
factory AudioAttachment.fromMap(Map<String, dynamic> map) {
|
||||
String? previewStr;
|
||||
final previewRaw = map['previewData'];
|
||||
if (previewRaw is String) {
|
||||
previewStr = previewRaw;
|
||||
} else if (previewRaw is List) {
|
||||
try {
|
||||
final bytes = List<int>.from(previewRaw);
|
||||
previewStr = String.fromCharCodes(bytes);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return AudioAttachment(
|
||||
previewData: map['previewData'] as String?,
|
||||
previewData: previewStr,
|
||||
baseUrl: map['baseUrl'] as String?,
|
||||
audioId: map['audioId'] as int?,
|
||||
audioToken: map['audioToken'] as String?,
|
||||
@@ -211,8 +237,19 @@ class FileAttachment extends MessageAttachment {
|
||||
}) : super(type: AttachmentType.file);
|
||||
|
||||
factory FileAttachment.fromMap(Map<String, dynamic> map) {
|
||||
String? previewStr;
|
||||
final previewRaw = map['previewData'];
|
||||
if (previewRaw is String) {
|
||||
previewStr = previewRaw;
|
||||
} else if (previewRaw is List) {
|
||||
try {
|
||||
final bytes = List<int>.from(previewRaw);
|
||||
previewStr = String.fromCharCodes(bytes);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return FileAttachment(
|
||||
previewData: map['previewData'] as String?,
|
||||
previewData: previewStr,
|
||||
baseUrl: map['baseUrl'] as String?,
|
||||
fileId: map['fileId'] as int?,
|
||||
fileToken: map['fileToken'] as String?,
|
||||
@@ -250,8 +287,19 @@ class StickerAttachment extends MessageAttachment {
|
||||
}) : super(type: AttachmentType.sticker);
|
||||
|
||||
factory StickerAttachment.fromMap(Map<String, dynamic> map) {
|
||||
String? previewStr;
|
||||
final previewRaw = map['previewData'];
|
||||
if (previewRaw is String) {
|
||||
previewStr = previewRaw;
|
||||
} else if (previewRaw is List) {
|
||||
try {
|
||||
final bytes = List<int>.from(previewRaw);
|
||||
previewStr = String.fromCharCodes(bytes);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return StickerAttachment(
|
||||
previewData: map['previewData'] as String?,
|
||||
previewData: previewStr,
|
||||
baseUrl: map['baseUrl'] as String?,
|
||||
stickerId: map['stickerId'] as String?,
|
||||
stickerPackId: map['stickerPackId'] as String?,
|
||||
|
||||
Reference in New Issue
Block a user