Merge branch 'feature/FullStack' of https://github.com/KometTeam/Komet into feature/FullStack
This commit is contained in:
@@ -210,6 +210,7 @@ class _ChatScreenState extends State<ChatScreen>
|
|||||||
originalText: a.originalText,
|
originalText: a.originalText,
|
||||||
originalChatId: a.originalChatId,
|
originalChatId: a.originalChatId,
|
||||||
originalAttachments: a.originalAttachments,
|
originalAttachments: a.originalAttachments,
|
||||||
|
originalContact: a.originalContact,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:komet/backend/modules/chats.dart';
|
import 'package:komet/backend/modules/chats.dart';
|
||||||
import 'package:komet/backend/modules/contacts.dart';
|
import 'package:komet/backend/modules/contacts.dart';
|
||||||
import 'package:komet/main.dart';
|
import 'package:komet/main.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import '../../backend/modules/messages.dart';
|
import '../../backend/modules/messages.dart';
|
||||||
import '../../models/attachment.dart';
|
import '../../models/attachment.dart';
|
||||||
@@ -85,11 +86,17 @@ class MessageBubble extends StatelessWidget {
|
|||||||
final first = message.attachments!.first;
|
final first = message.attachments!.first;
|
||||||
if (first is ForwardedMessageAttachment) {
|
if (first is ForwardedMessageAttachment) {
|
||||||
final fwd = first;
|
final fwd = first;
|
||||||
|
final hasContact = fwd.originalContact != null;
|
||||||
final hasPhoto =
|
final hasPhoto =
|
||||||
fwd.originalAttachments != null &&
|
fwd.originalAttachments != null &&
|
||||||
fwd.originalAttachments!.any((a) => a is PhotoAttachment);
|
fwd.originalAttachments!.any((a) => a is PhotoAttachment);
|
||||||
return hasPhoto ? MessageType.attachment : MessageType.text;
|
final hasOther =
|
||||||
|
fwd.originalAttachments != null &&
|
||||||
|
fwd.originalAttachments!.isNotEmpty;
|
||||||
|
if (hasContact || hasPhoto || hasOther) return MessageType.attachment;
|
||||||
|
return MessageType.text;
|
||||||
}
|
}
|
||||||
|
if (first is ContactAttachment) return MessageType.attachment;
|
||||||
if (first is UnknownAttachment) return MessageType.text;
|
if (first is UnknownAttachment) return MessageType.text;
|
||||||
if (first.type == AttachmentType.audio) return MessageType.voice;
|
if (first.type == AttachmentType.audio) return MessageType.voice;
|
||||||
return MessageType.attachment;
|
return MessageType.attachment;
|
||||||
@@ -364,8 +371,16 @@ class MessageBubble extends StatelessWidget {
|
|||||||
? Colors.white
|
? Colors.white
|
||||||
: (isDark ? cs.onSurface : const Color(0xFF1C1C1E));
|
: (isDark ? cs.onSurface : const Color(0xFF1C1C1E));
|
||||||
|
|
||||||
|
final attachments = message.attachments;
|
||||||
|
final isForwardedContact =
|
||||||
|
attachments != null &&
|
||||||
|
attachments.isNotEmpty &&
|
||||||
|
attachments.first is ForwardedMessageAttachment &&
|
||||||
|
(attachments.first as ForwardedMessageAttachment).originalContact !=
|
||||||
|
null;
|
||||||
|
|
||||||
final forwarded = _getForwardedAttachment();
|
final forwarded = _getForwardedAttachment();
|
||||||
final isForwarded = forwarded != null;
|
final isForwarded = forwarded != null && !isForwardedContact;
|
||||||
|
|
||||||
// TODO: Нормальное кеширование контактов
|
// TODO: Нормальное кеширование контактов
|
||||||
final ss = messagesModule.searchContactById(message.senderId);
|
final ss = messagesModule.searchContactById(message.senderId);
|
||||||
@@ -554,15 +569,27 @@ class MessageBubble extends StatelessWidget {
|
|||||||
final first = attachments.first;
|
final first = attachments.first;
|
||||||
if (first is ForwardedMessageAttachment) {
|
if (first is ForwardedMessageAttachment) {
|
||||||
final fwd = first;
|
final fwd = first;
|
||||||
|
if (fwd.originalContact != null) {
|
||||||
|
return _buildForwardedContactContent(context, fwd);
|
||||||
|
}
|
||||||
final photos = fwd.originalAttachments
|
final photos = fwd.originalAttachments
|
||||||
?.whereType<PhotoAttachment>()
|
?.whereType<PhotoAttachment>()
|
||||||
.toList();
|
.toList();
|
||||||
if (photos != null && photos.isNotEmpty) {
|
if (photos != null && photos.isNotEmpty) {
|
||||||
return _buildForwardedPhotoContent(context, fwd, photos);
|
return _buildForwardedPhotoContent(context, fwd, photos);
|
||||||
}
|
}
|
||||||
|
final files = fwd.originalAttachments;
|
||||||
|
if (files != null && files.isNotEmpty) {
|
||||||
|
return _buildForwardedGenericContent(context, fwd, files);
|
||||||
|
}
|
||||||
return _buildTextContent(context);
|
return _buildTextContent(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final contacts = attachments.whereType<ContactAttachment>().toList();
|
||||||
|
if (contacts.isNotEmpty) {
|
||||||
|
return _buildContactAttachment(context, contacts.first);
|
||||||
|
}
|
||||||
|
|
||||||
final photos = attachments.whereType<PhotoAttachment>().toList();
|
final photos = attachments.whereType<PhotoAttachment>().toList();
|
||||||
if (photos.isEmpty) {
|
if (photos.isEmpty) {
|
||||||
return _buildGenericAttachment(context, attachments.first);
|
return _buildGenericAttachment(context, attachments.first);
|
||||||
@@ -725,6 +752,136 @@ class MessageBubble extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildForwardedFileContent(
|
||||||
|
BuildContext context,
|
||||||
|
ForwardedMessageAttachment forwarded,
|
||||||
|
List<FileAttachment> files,
|
||||||
|
) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
|
final headerColor = isMe
|
||||||
|
? Colors.white.withValues(alpha: 0.7)
|
||||||
|
: cs.onSurfaceVariant;
|
||||||
|
final displaySender =
|
||||||
|
forwarded.originalSenderName ?? forwarded.originalSenderId.toString();
|
||||||
|
final senderAvatar = forwarded.originalSenderAvatar;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(Symbols.forward, size: 14, color: headerColor),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
if (senderAvatar != null && senderAvatar.isNotEmpty)
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 10,
|
||||||
|
backgroundImage: NetworkImage(senderAvatar),
|
||||||
|
backgroundColor: cs.primaryContainer,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 10,
|
||||||
|
backgroundColor: cs.primaryContainer,
|
||||||
|
child: Text(
|
||||||
|
displaySender.isNotEmpty
|
||||||
|
? displaySender[0].toUpperCase()
|
||||||
|
: '?',
|
||||||
|
style: TextStyle(fontSize: 9, color: cs.onPrimaryContainer),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
displaySender,
|
||||||
|
style: TextStyle(
|
||||||
|
color: headerColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
...files.map((file) => _buildFileAttachment(context, file)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildForwardedGenericContent(
|
||||||
|
BuildContext context,
|
||||||
|
ForwardedMessageAttachment forwarded,
|
||||||
|
List<MessageAttachment> attachments,
|
||||||
|
) {
|
||||||
|
debugPrint('DEBUG: _buildForwardedGenericContent called');
|
||||||
|
debugPrint('DEBUG: attachments count: ${attachments.length}');
|
||||||
|
for (var i = 0; i < attachments.length; i++) {
|
||||||
|
debugPrint('DEBUG: attachment[$i] type: ${attachments[i].runtimeType}');
|
||||||
|
debugPrint('DEBUG: attachment[$i] type field: ${attachments[i].type}');
|
||||||
|
}
|
||||||
|
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
|
final headerColor = isMe
|
||||||
|
? Colors.white.withValues(alpha: 0.7)
|
||||||
|
: cs.onSurfaceVariant;
|
||||||
|
final displaySender =
|
||||||
|
forwarded.originalSenderName ?? forwarded.originalSenderId.toString();
|
||||||
|
final senderAvatar = forwarded.originalSenderAvatar;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(Symbols.forward, size: 14, color: headerColor),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
if (senderAvatar != null && senderAvatar.isNotEmpty)
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 10,
|
||||||
|
backgroundImage: NetworkImage(senderAvatar),
|
||||||
|
backgroundColor: cs.primaryContainer,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 10,
|
||||||
|
backgroundColor: cs.primaryContainer,
|
||||||
|
child: Text(
|
||||||
|
displaySender.isNotEmpty
|
||||||
|
? displaySender[0].toUpperCase()
|
||||||
|
: '?',
|
||||||
|
style: TextStyle(fontSize: 9, color: cs.onPrimaryContainer),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
displaySender,
|
||||||
|
style: TextStyle(
|
||||||
|
color: headerColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
...attachments.map((a) {
|
||||||
|
if (a is FileAttachment) {
|
||||||
|
return _buildFileAttachment(context, a);
|
||||||
|
}
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildSinglePhoto(BuildContext ctx, PhotoAttachment photo) {
|
Widget _buildSinglePhoto(BuildContext ctx, PhotoAttachment photo) {
|
||||||
final imageUrl = photo.baseUrl ?? '';
|
final imageUrl = photo.baseUrl ?? '';
|
||||||
final width = photo.width?.toDouble() ?? 200;
|
final width = photo.width?.toDouble() ?? 200;
|
||||||
@@ -1134,6 +1291,247 @@ class MessageBubble extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildContactAttachment(BuildContext ctx, MessageAttachment contact) {
|
||||||
|
final cs = Theme.of(ctx).colorScheme;
|
||||||
|
final isDark = cs.brightness == Brightness.dark;
|
||||||
|
final contactData = contact as ContactAttachment;
|
||||||
|
|
||||||
|
final firstName = contactData.firstName ?? '';
|
||||||
|
final lastName = contactData.lastName ?? '';
|
||||||
|
final hasFirstName = firstName.isNotEmpty;
|
||||||
|
final hasLastName = lastName.isNotEmpty;
|
||||||
|
|
||||||
|
final name = (hasFirstName || hasLastName)
|
||||||
|
? '${hasFirstName ? firstName : ''}${hasLastName ? ' $lastName' : ''}'
|
||||||
|
.trim()
|
||||||
|
: (contactData.name ?? 'Contact');
|
||||||
|
final photoUrl = contactData.photoUrl ?? contactData.baseUrl;
|
||||||
|
|
||||||
|
final textColor = isMe
|
||||||
|
? Colors.white
|
||||||
|
: (isDark ? cs.onSurface : const Color(0xFF1C1C1E));
|
||||||
|
final subtitleColor = isMe
|
||||||
|
? Colors.white.withValues(alpha: 0.65)
|
||||||
|
: (isDark ? cs.onSurfaceVariant : const Color(0xFF8E8E93));
|
||||||
|
final bgColor = isMe
|
||||||
|
? Colors.white.withValues(alpha: 0.2)
|
||||||
|
: (isDark ? cs.surfaceContainerHighest : const Color(0xFFE5E5EA));
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: bgColor,
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
|
),
|
||||||
|
child: photoUrl != null && photoUrl.isNotEmpty
|
||||||
|
? ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
|
child: Image.network(
|
||||||
|
photoUrl,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) => Icon(
|
||||||
|
Symbols.person,
|
||||||
|
color: isMe ? Colors.white : cs.primary,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Icon(
|
||||||
|
Symbols.person,
|
||||||
|
color: isMe ? Colors.white : cs.primary,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Flexible(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
name.isNotEmpty ? name : 'Contact',
|
||||||
|
style: TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
height: 1.2,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
if (contactData.phoneNumber != null) ...[
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
contactData.phoneNumber!,
|
||||||
|
style: TextStyle(
|
||||||
|
color: subtitleColor,
|
||||||
|
fontSize: 12,
|
||||||
|
height: 1.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildForwardedContactContent(
|
||||||
|
BuildContext context,
|
||||||
|
ForwardedMessageAttachment forwarded,
|
||||||
|
) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
|
final isDark = cs.brightness == Brightness.dark;
|
||||||
|
final contact = forwarded.originalContact!;
|
||||||
|
|
||||||
|
final firstName = contact.firstName ?? '';
|
||||||
|
final lastName = contact.lastName ?? '';
|
||||||
|
final hasFirstName = firstName.isNotEmpty;
|
||||||
|
final hasLastName = lastName.isNotEmpty;
|
||||||
|
|
||||||
|
final name = (hasFirstName || hasLastName)
|
||||||
|
? '${hasFirstName ? firstName : ''}${hasLastName ? ' $lastName' : ''}'
|
||||||
|
.trim()
|
||||||
|
: (contact.name ?? 'Contact');
|
||||||
|
final photoUrl = contact.photoUrl ?? contact.baseUrl;
|
||||||
|
|
||||||
|
final textColor = isMe
|
||||||
|
? Colors.white
|
||||||
|
: (isDark ? cs.onSurface : const Color(0xFF1C1C1E));
|
||||||
|
final subtitleColor = isMe
|
||||||
|
? Colors.white.withValues(alpha: 0.65)
|
||||||
|
: (isDark ? cs.onSurfaceVariant : const Color(0xFF8E8E93));
|
||||||
|
final bgColor = isMe
|
||||||
|
? Colors.white.withValues(alpha: 0.2)
|
||||||
|
: (isDark ? cs.surfaceContainerHighest : const Color(0xFFE5E5EA));
|
||||||
|
final headerColor = isMe
|
||||||
|
? Colors.white.withValues(alpha: 0.7)
|
||||||
|
: cs.onSurfaceVariant;
|
||||||
|
|
||||||
|
final displaySender =
|
||||||
|
forwarded.originalSenderName ?? forwarded.originalSenderId.toString();
|
||||||
|
final senderAvatar = forwarded.originalSenderAvatar;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(Symbols.forward, size: 14, color: headerColor),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
if (senderAvatar != null && senderAvatar.isNotEmpty)
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 10,
|
||||||
|
backgroundImage: NetworkImage(senderAvatar),
|
||||||
|
backgroundColor: cs.primaryContainer,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 10,
|
||||||
|
backgroundColor: cs.primaryContainer,
|
||||||
|
child: Text(
|
||||||
|
displaySender.isNotEmpty
|
||||||
|
? displaySender[0].toUpperCase()
|
||||||
|
: '?',
|
||||||
|
style: TextStyle(fontSize: 9, color: cs.onPrimaryContainer),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
displaySender,
|
||||||
|
style: TextStyle(
|
||||||
|
color: headerColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: bgColor,
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
|
),
|
||||||
|
child: photoUrl != null && photoUrl.isNotEmpty
|
||||||
|
? ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
|
child: Image.network(
|
||||||
|
photoUrl,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) => Icon(
|
||||||
|
Symbols.person,
|
||||||
|
color: isMe ? Colors.white : cs.primary,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Icon(
|
||||||
|
Symbols.person,
|
||||||
|
color: isMe ? Colors.white : cs.primary,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Flexible(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
name.isNotEmpty ? name : 'Contact',
|
||||||
|
style: TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
height: 1.2,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
if (contact.phoneNumber != null) ...[
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
contact.phoneNumber!,
|
||||||
|
style: TextStyle(
|
||||||
|
color: subtitleColor,
|
||||||
|
fontSize: 12,
|
||||||
|
height: 1.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _openPhotoViewer(BuildContext ctx, PhotoAttachment photo) {
|
void _openPhotoViewer(BuildContext ctx, PhotoAttachment photo) {
|
||||||
// TODO: Open photo viewer
|
// TODO: Open photo viewer
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,6 +325,9 @@ class ContactAttachment extends MessageAttachment {
|
|||||||
final String? firstName;
|
final String? firstName;
|
||||||
final String? lastName;
|
final String? lastName;
|
||||||
final String? phoneNumber;
|
final String? phoneNumber;
|
||||||
|
final String? photoUrl;
|
||||||
|
final int? contactId;
|
||||||
|
final String? name;
|
||||||
|
|
||||||
const ContactAttachment({
|
const ContactAttachment({
|
||||||
super.previewData,
|
super.previewData,
|
||||||
@@ -334,6 +337,9 @@ class ContactAttachment extends MessageAttachment {
|
|||||||
this.firstName,
|
this.firstName,
|
||||||
this.lastName,
|
this.lastName,
|
||||||
this.phoneNumber,
|
this.phoneNumber,
|
||||||
|
this.photoUrl,
|
||||||
|
this.contactId,
|
||||||
|
this.name,
|
||||||
}) : super(type: AttachmentType.contact);
|
}) : super(type: AttachmentType.contact);
|
||||||
|
|
||||||
factory ContactAttachment.fromMap(Map<String, dynamic> map) {
|
factory ContactAttachment.fromMap(Map<String, dynamic> map) {
|
||||||
@@ -344,6 +350,9 @@ class ContactAttachment extends MessageAttachment {
|
|||||||
firstName: map['firstName'] as String?,
|
firstName: map['firstName'] as String?,
|
||||||
lastName: map['lastName'] as String?,
|
lastName: map['lastName'] as String?,
|
||||||
phoneNumber: map['phoneNumber'] as String?,
|
phoneNumber: map['phoneNumber'] as String?,
|
||||||
|
photoUrl: map['photoUrl'] as String?,
|
||||||
|
contactId: map['contactId'] as int?,
|
||||||
|
name: map['name'] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +365,9 @@ class ContactAttachment extends MessageAttachment {
|
|||||||
'firstName': firstName,
|
'firstName': firstName,
|
||||||
'lastName': lastName,
|
'lastName': lastName,
|
||||||
'phoneNumber': phoneNumber,
|
'phoneNumber': phoneNumber,
|
||||||
|
'photoUrl': photoUrl,
|
||||||
|
'contactId': contactId,
|
||||||
|
'name': name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,6 +454,7 @@ class ForwardedMessageAttachment extends MessageAttachment {
|
|||||||
final String? originalText;
|
final String? originalText;
|
||||||
final int? originalChatId;
|
final int? originalChatId;
|
||||||
final List<MessageAttachment>? originalAttachments;
|
final List<MessageAttachment>? originalAttachments;
|
||||||
|
final ContactAttachment? originalContact;
|
||||||
|
|
||||||
const ForwardedMessageAttachment({
|
const ForwardedMessageAttachment({
|
||||||
required this.originalSenderId,
|
required this.originalSenderId,
|
||||||
@@ -452,6 +465,7 @@ class ForwardedMessageAttachment extends MessageAttachment {
|
|||||||
this.originalText,
|
this.originalText,
|
||||||
this.originalChatId,
|
this.originalChatId,
|
||||||
this.originalAttachments,
|
this.originalAttachments,
|
||||||
|
this.originalContact,
|
||||||
}) : super(type: AttachmentType.photo);
|
}) : super(type: AttachmentType.photo);
|
||||||
|
|
||||||
factory ForwardedMessageAttachment.fromMap(Map<String, dynamic> map) {
|
factory ForwardedMessageAttachment.fromMap(Map<String, dynamic> map) {
|
||||||
@@ -470,11 +484,25 @@ class ForwardedMessageAttachment extends MessageAttachment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<MessageAttachment>? originalAttaches;
|
List<MessageAttachment>? originalAttaches;
|
||||||
|
ContactAttachment? originalContact;
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
final attaches = message['attaches'] as List?;
|
final attaches = message['attaches'] as List?;
|
||||||
if (attaches != null) {
|
if (attaches != null) {
|
||||||
|
final contactAttaches = attaches
|
||||||
|
.whereType<Map>()
|
||||||
|
.where((a) => (a['_type'] as String?)?.toUpperCase() == 'CONTACT')
|
||||||
|
.toList();
|
||||||
|
if (contactAttaches.isNotEmpty) {
|
||||||
|
originalContact = ContactAttachment.fromMap(
|
||||||
|
Map<String, dynamic>.from(contactAttaches.first),
|
||||||
|
);
|
||||||
|
}
|
||||||
originalAttaches = attaches
|
originalAttaches = attaches
|
||||||
.whereType<Map>()
|
.whereType<Map>()
|
||||||
|
.where((a) {
|
||||||
|
final type = (a['_type'] as String?)?.toUpperCase();
|
||||||
|
return type != 'CONTACT';
|
||||||
|
})
|
||||||
.map((a) => MessageAttachment.fromMap(Map<String, dynamic>.from(a)))
|
.map((a) => MessageAttachment.fromMap(Map<String, dynamic>.from(a)))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
@@ -487,6 +515,7 @@ class ForwardedMessageAttachment extends MessageAttachment {
|
|||||||
originalText: message?['text'] as String?,
|
originalText: message?['text'] as String?,
|
||||||
originalChatId: link?['chatId'] as int?,
|
originalChatId: link?['chatId'] as int?,
|
||||||
originalAttachments: originalAttaches,
|
originalAttachments: originalAttaches,
|
||||||
|
originalContact: originalContact,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user