182 lines
5.3 KiB
Dart
182 lines
5.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:jiffy/jiffy.dart';
|
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
|
import 'package:stream_chat_flutter/src/extension.dart';
|
|
|
|
/// It shows the current [Message] preview.
|
|
///
|
|
/// Usually you don't use this widget as it's the default item used by
|
|
/// [MessageSearchListView].
|
|
///
|
|
/// The widget renders the ui based on the first ancestor of type
|
|
/// [StreamChatTheme].
|
|
/// Modify it to change the widget appearance.
|
|
class MessageSearchItem extends StatelessWidget {
|
|
/// Instantiate a new MessageSearchItem
|
|
const MessageSearchItem({
|
|
Key? key,
|
|
required this.getMessageResponse,
|
|
this.onTap,
|
|
this.showOnlineStatus = true,
|
|
}) : super(key: key);
|
|
|
|
/// [Message] displayed
|
|
final GetMessageResponse getMessageResponse;
|
|
|
|
/// Function called when tapping this widget
|
|
final VoidCallback? onTap;
|
|
|
|
/// If true the [MessageSearchItem] will show the current online Status
|
|
final bool showOnlineStatus;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final message = getMessageResponse.message;
|
|
final channel = getMessageResponse.channel;
|
|
final channelName = channel?.extraData['name'];
|
|
final user = message.user!;
|
|
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
|
return ListTile(
|
|
onTap: onTap,
|
|
leading: UserAvatar(
|
|
user: user,
|
|
showOnlineStatus: showOnlineStatus,
|
|
constraints: const BoxConstraints.tightFor(
|
|
height: 40,
|
|
width: 40,
|
|
),
|
|
),
|
|
title: Row(
|
|
children: [
|
|
Text(
|
|
user.id == StreamChat.of(context).currentUser?.id
|
|
? context.translations.youText
|
|
: user.name,
|
|
style: channelPreviewTheme.titleStyle,
|
|
),
|
|
if (channelName != null) ...[
|
|
Text(
|
|
' ${context.translations.inText} ',
|
|
style: channelPreviewTheme.titleStyle?.copyWith(
|
|
fontWeight: FontWeight.normal,
|
|
),
|
|
),
|
|
Text(
|
|
channelName as String,
|
|
style: channelPreviewTheme.titleStyle,
|
|
),
|
|
],
|
|
],
|
|
),
|
|
subtitle: Row(
|
|
children: [
|
|
Expanded(child: _buildSubtitle(context, message)),
|
|
const SizedBox(width: 16),
|
|
_buildDate(context, message),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDate(BuildContext context, Message message) {
|
|
final createdAt = message.createdAt;
|
|
String stringDate;
|
|
final now = DateTime.now();
|
|
|
|
if (now.year != createdAt.year ||
|
|
now.month != createdAt.month ||
|
|
now.day != createdAt.day) {
|
|
stringDate = Jiffy(createdAt.toLocal()).yMd;
|
|
} else {
|
|
stringDate = Jiffy(createdAt.toLocal()).jm;
|
|
}
|
|
|
|
return Text(
|
|
stringDate,
|
|
style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAtStyle,
|
|
);
|
|
}
|
|
|
|
Widget _buildSubtitle(BuildContext context, Message message) {
|
|
var text = message.text;
|
|
if (message.isDeleted) {
|
|
text = context.translations.messageDeletedText;
|
|
} else if (message.attachments.isNotEmpty) {
|
|
final parts = <String>[
|
|
...message.attachments.map((e) {
|
|
if (e.type == 'image') {
|
|
return '📷';
|
|
} else if (e.type == 'video') {
|
|
return '🎬';
|
|
} else if (e.type == 'giphy') {
|
|
return '[GIF]';
|
|
}
|
|
return e == message.attachments.last
|
|
? (e.title ?? 'File')
|
|
: '${e.title ?? 'File'} , ';
|
|
}),
|
|
message.text ?? '',
|
|
];
|
|
|
|
text = parts.join(' ');
|
|
}
|
|
|
|
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
|
return Text.rich(
|
|
_getDisplayText(
|
|
text!,
|
|
message.mentionedUsers,
|
|
message.attachments,
|
|
channelPreviewTheme.subtitleStyle?.copyWith(
|
|
fontStyle: (message.isSystem || message.isDeleted)
|
|
? FontStyle.italic
|
|
: FontStyle.normal,
|
|
),
|
|
channelPreviewTheme.subtitleStyle?.copyWith(
|
|
fontStyle: (message.isSystem || message.isDeleted)
|
|
? FontStyle.italic
|
|
: FontStyle.normal,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
);
|
|
}
|
|
|
|
TextSpan _getDisplayText(
|
|
String text,
|
|
List<User> mentions,
|
|
List<Attachment> attachments,
|
|
TextStyle? normalTextStyle,
|
|
TextStyle? mentionsTextStyle) {
|
|
final textList = text.split(' ');
|
|
final resList = <TextSpan>[];
|
|
for (final e in textList) {
|
|
if (mentions.isNotEmpty &&
|
|
mentions.any((element) => '@${element.name}' == e)) {
|
|
resList.add(TextSpan(
|
|
text: '$e ',
|
|
style: mentionsTextStyle,
|
|
));
|
|
} else if (attachments.isNotEmpty &&
|
|
attachments
|
|
.where((e) => e.title != null)
|
|
.any((element) => element.title == e)) {
|
|
resList.add(TextSpan(
|
|
text: '$e ',
|
|
style: normalTextStyle?.copyWith(fontStyle: FontStyle.italic),
|
|
));
|
|
} else {
|
|
resList.add(TextSpan(
|
|
text: e == textList.last ? e : '$e ',
|
|
style: normalTextStyle,
|
|
));
|
|
}
|
|
}
|
|
|
|
return TextSpan(children: resList);
|
|
}
|
|
}
|