mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 14:28:40 +00:00
add time to messages
This commit is contained in:
parent
b03bcfe6e1
commit
edf4209448
11 changed files with 260 additions and 54 deletions
|
|
@ -175,6 +175,11 @@
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"ok": "Ok",
|
"ok": "Ok",
|
||||||
|
"now": "Jetzt",
|
||||||
|
"you": "Du",
|
||||||
|
"minutesShort": "Min.",
|
||||||
|
"image": "Bild",
|
||||||
|
"video": "Video",
|
||||||
"react": "Reagieren",
|
"react": "Reagieren",
|
||||||
"reply": "Antworten",
|
"reply": "Antworten",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,11 @@
|
||||||
"disable": "Disable",
|
"disable": "Disable",
|
||||||
"enable": "Enable",
|
"enable": "Enable",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
"now": "Now",
|
||||||
|
"you": "You",
|
||||||
|
"minutesShort": "min.",
|
||||||
|
"image": "Image",
|
||||||
|
"video": "Video",
|
||||||
"react": "React",
|
"react": "React",
|
||||||
"reply": "Reply",
|
"reply": "Reply",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
|
|
|
||||||
|
|
@ -1058,6 +1058,36 @@ abstract class AppLocalizations {
|
||||||
/// **'Cancel'**
|
/// **'Cancel'**
|
||||||
String get cancel;
|
String get cancel;
|
||||||
|
|
||||||
|
/// No description provided for @now.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Now'**
|
||||||
|
String get now;
|
||||||
|
|
||||||
|
/// No description provided for @you.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'You'**
|
||||||
|
String get you;
|
||||||
|
|
||||||
|
/// No description provided for @minutesShort.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'min.'**
|
||||||
|
String get minutesShort;
|
||||||
|
|
||||||
|
/// No description provided for @image.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Image'**
|
||||||
|
String get image;
|
||||||
|
|
||||||
|
/// No description provided for @video.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Video'**
|
||||||
|
String get video;
|
||||||
|
|
||||||
/// No description provided for @react.
|
/// No description provided for @react.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,21 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get cancel => 'Abbrechen';
|
String get cancel => 'Abbrechen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get now => 'Jetzt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get you => 'Du';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get minutesShort => 'Min.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get image => 'Bild';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get video => 'Video';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get react => 'Reagieren';
|
String get react => 'Reagieren';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -531,6 +531,21 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
@override
|
@override
|
||||||
String get cancel => 'Cancel';
|
String get cancel => 'Cancel';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get now => 'Now';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get you => 'You';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get minutesShort => 'min.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get image => 'Image';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get video => 'Video';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get react => 'React';
|
String get react => 'React';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,22 +28,17 @@ Color getMessageColor(Message message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatItem {
|
class ChatItem {
|
||||||
const ChatItem._({this.message, this.date, this.time});
|
const ChatItem._({this.message, this.date});
|
||||||
factory ChatItem.date(DateTime date) {
|
factory ChatItem.date(DateTime date) {
|
||||||
return ChatItem._(date: date);
|
return ChatItem._(date: date);
|
||||||
}
|
}
|
||||||
factory ChatItem.time(DateTime time) {
|
|
||||||
return ChatItem._(time: time);
|
|
||||||
}
|
|
||||||
factory ChatItem.message(Message message) {
|
factory ChatItem.message(Message message) {
|
||||||
return ChatItem._(message: message);
|
return ChatItem._(message: message);
|
||||||
}
|
}
|
||||||
final Message? message;
|
final Message? message;
|
||||||
final DateTime? date;
|
final DateTime? date;
|
||||||
final DateTime? time;
|
|
||||||
bool get isMessage => message != null;
|
bool get isMessage => message != null;
|
||||||
bool get isDate => date != null;
|
bool get isDate => date != null;
|
||||||
bool get isTime => time != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Displays detailed information about a SampleItem.
|
/// Displays detailed information about a SampleItem.
|
||||||
|
|
@ -143,9 +138,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
msg.createdAt.year != lastDate.year) {
|
msg.createdAt.year != lastDate.year) {
|
||||||
chatItems.add(ChatItem.date(msg.createdAt));
|
chatItems.add(ChatItem.date(msg.createdAt));
|
||||||
lastDate = msg.createdAt;
|
lastDate = msg.createdAt;
|
||||||
} else if (msg.createdAt.difference(lastDate).inMinutes >= 20) {
|
|
||||||
chatItems.add(ChatItem.time(msg.createdAt));
|
|
||||||
lastDate = msg.createdAt;
|
|
||||||
}
|
}
|
||||||
chatItems.add(ChatItem.message(msg));
|
chatItems.add(ChatItem.message(msg));
|
||||||
}
|
}
|
||||||
|
|
@ -276,7 +268,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
padding: EdgeInsetsGeometry.only(top: 10),
|
padding: EdgeInsetsGeometry.only(top: 10),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (messages[i].isDate || messages[i].isTime) {
|
if (messages[i].isDate) {
|
||||||
return ChatDateChip(
|
return ChatDateChip(
|
||||||
item: messages[i],
|
item: messages[i],
|
||||||
);
|
);
|
||||||
|
|
@ -295,10 +287,14 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
scale: (focusedScrollItem == i) ? 1.05 : 1,
|
scale: (focusedScrollItem == i) ? 1.05 : 1,
|
||||||
child: ChatListEntry(
|
child: ChatListEntry(
|
||||||
key: Key(chatMessage.messageId),
|
key: Key(chatMessage.messageId),
|
||||||
chatMessage,
|
message: messages[i].message!,
|
||||||
group,
|
nextMessage:
|
||||||
galleryItems,
|
(i > 0) ? messages[i - 1].message : null,
|
||||||
isLastMessageFromSameUser(messages, i),
|
prevMessage: ((i + 1) < messages.length)
|
||||||
|
? messages[i + 1].message
|
||||||
|
: null,
|
||||||
|
group: group,
|
||||||
|
galleryItems: galleryItems,
|
||||||
scrollToMessage: scrollToMessage,
|
scrollToMessage: scrollToMessage,
|
||||||
onResponseTriggered: () {
|
onResponseTriggered: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -403,22 +399,3 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLastMessageFromSameUser(List<ChatItem> messages, int index) {
|
|
||||||
if (index <= 0) {
|
|
||||||
return true; // If there is no previous message, return true
|
|
||||||
}
|
|
||||||
return (messages[index - 1].message?.senderId ==
|
|
||||||
messages[index].message?.senderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
double calculateNumberOfLines(String text, double width, double fontSize) {
|
|
||||||
final textPainter = TextPainter(
|
|
||||||
text: TextSpan(
|
|
||||||
text: text,
|
|
||||||
style: TextStyle(fontSize: fontSize),
|
|
||||||
),
|
|
||||||
textDirection: TextDirection.ltr,
|
|
||||||
)..layout(maxWidth: width - 32);
|
|
||||||
return textPainter.computeLineMetrics().length.toDouble();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,8 @@ class ChatDateChip extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final formattedDate = item.isTime
|
final formattedDate =
|
||||||
? DateFormat.Hm(Localizations.localeOf(context).toLanguageTag())
|
'${DateFormat.Hm(Localizations.localeOf(context).toLanguageTag()).format(item.date!)}\n${DateFormat.yMd(Localizations.localeOf(context).toLanguageTag()).format(item.date!)}';
|
||||||
.format(item.time!)
|
|
||||||
: '${DateFormat.Hm(Localizations.localeOf(context).toLanguageTag()).format(item.date!)}\n${DateFormat.yMd(Localizations.localeOf(context).toLanguageTag()).format(item.date!)}';
|
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|
@ -23,6 +21,7 @@ class ChatDateChip extends StatelessWidget {
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
||||||
|
margin: const EdgeInsets.only(bottom: 20),
|
||||||
child: Text(
|
child: Text(
|
||||||
formattedDate,
|
formattedDate,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,20 @@ import 'package:twonly/src/views/chats/chat_messages_components/message_context_
|
||||||
import 'package:twonly/src/views/chats/chat_messages_components/response_container.dart';
|
import 'package:twonly/src/views/chats/chat_messages_components/response_container.dart';
|
||||||
|
|
||||||
class ChatListEntry extends StatefulWidget {
|
class ChatListEntry extends StatefulWidget {
|
||||||
const ChatListEntry(
|
const ChatListEntry({
|
||||||
this.message,
|
required this.group,
|
||||||
this.group,
|
required this.galleryItems,
|
||||||
this.galleryItems,
|
required this.prevMessage,
|
||||||
this.lastMessageFromSameUser, {
|
required this.message,
|
||||||
|
required this.nextMessage,
|
||||||
required this.onResponseTriggered,
|
required this.onResponseTriggered,
|
||||||
required this.scrollToMessage,
|
required this.scrollToMessage,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
final Message? prevMessage;
|
||||||
|
final Message? nextMessage;
|
||||||
final Message message;
|
final Message message;
|
||||||
final Group group;
|
final Group group;
|
||||||
final bool lastMessageFromSameUser;
|
|
||||||
final List<MemoryItem> galleryItems;
|
final List<MemoryItem> galleryItems;
|
||||||
final void Function(String) scrollToMessage;
|
final void Function(String) scrollToMessage;
|
||||||
final void Function() onResponseTriggered;
|
final void Function() onResponseTriggered;
|
||||||
|
|
@ -70,12 +72,16 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final right = widget.message.senderId == null;
|
final right = widget.message.senderId == null;
|
||||||
|
|
||||||
|
final (padding, borderRadius) = getMessageLayout(
|
||||||
|
widget.message,
|
||||||
|
widget.prevMessage,
|
||||||
|
widget.nextMessage,
|
||||||
|
);
|
||||||
|
|
||||||
return Align(
|
return Align(
|
||||||
alignment: right ? Alignment.centerRight : Alignment.centerLeft,
|
alignment: right ? Alignment.centerRight : Alignment.centerLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: widget.lastMessageFromSameUser
|
padding: padding,
|
||||||
? const EdgeInsets.only(top: 5, right: 10, left: 10)
|
|
||||||
: const EdgeInsets.only(top: 5, bottom: 20, right: 10, left: 10),
|
|
||||||
child: MessageContextMenu(
|
child: MessageContextMenu(
|
||||||
message: widget.message,
|
message: widget.message,
|
||||||
onResponseTriggered: widget.onResponseTriggered,
|
onResponseTriggered: widget.onResponseTriggered,
|
||||||
|
|
@ -96,10 +102,13 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
||||||
msg: widget.message,
|
msg: widget.message,
|
||||||
group: widget.group,
|
group: widget.group,
|
||||||
mediaService: mediaService,
|
mediaService: mediaService,
|
||||||
|
borderRadius: borderRadius,
|
||||||
scrollToMessage: widget.scrollToMessage,
|
scrollToMessage: widget.scrollToMessage,
|
||||||
child: (widget.message.type == MessageType.text)
|
child: (widget.message.type == MessageType.text)
|
||||||
? ChatTextEntry(
|
? ChatTextEntry(
|
||||||
message: widget.message,
|
message: widget.message,
|
||||||
|
nextMessage: widget.nextMessage,
|
||||||
|
borderRadius: borderRadius,
|
||||||
)
|
)
|
||||||
: (mediaService == null)
|
: (mediaService == null)
|
||||||
? null
|
? null
|
||||||
|
|
@ -128,3 +137,57 @@ class _ChatListEntryState extends State<ChatListEntry> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(EdgeInsetsGeometry, BorderRadius) getMessageLayout(
|
||||||
|
Message message,
|
||||||
|
Message? prevMessage,
|
||||||
|
Message? nextMessage,
|
||||||
|
) {
|
||||||
|
var bottom = 30.0;
|
||||||
|
var top = 0.0;
|
||||||
|
|
||||||
|
var topLeft = 12.0;
|
||||||
|
var topRight = 12.0;
|
||||||
|
var bottomRight = 12.0;
|
||||||
|
var bottomLeft = 12.0;
|
||||||
|
|
||||||
|
if (nextMessage != null) {
|
||||||
|
if (message.senderId == nextMessage.senderId) {
|
||||||
|
bottom = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevMessage != null) {
|
||||||
|
final combinesWidthNext = combineTextMessageWithNext(prevMessage, message);
|
||||||
|
if (combinesWidthNext) {
|
||||||
|
top = 1;
|
||||||
|
topLeft = 5.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final combinesWidthNext = combineTextMessageWithNext(message, nextMessage);
|
||||||
|
if (combinesWidthNext) {
|
||||||
|
bottom = 1;
|
||||||
|
bottomLeft = 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.senderId == null) {
|
||||||
|
final tmp = topLeft;
|
||||||
|
topLeft = topRight;
|
||||||
|
topRight = tmp;
|
||||||
|
|
||||||
|
final tmp2 = bottomLeft;
|
||||||
|
bottomLeft = bottomRight;
|
||||||
|
bottomRight = tmp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
EdgeInsets.only(top: top, bottom: bottom, right: 10, left: 10),
|
||||||
|
BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(topLeft),
|
||||||
|
topRight: Radius.circular(topRight),
|
||||||
|
bottomRight: Radius.circular(bottomRight),
|
||||||
|
bottomLeft: Radius.circular(bottomLeft),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart' hide TextDirection;
|
||||||
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/views/chats/chat_messages.view.dart';
|
import 'package:twonly/src/views/chats/chat_messages.view.dart';
|
||||||
import 'package:twonly/src/views/components/animate_icon.dart';
|
import 'package:twonly/src/views/components/animate_icon.dart';
|
||||||
import 'package:twonly/src/views/components/better_text.dart';
|
import 'package:twonly/src/views/components/better_text.dart';
|
||||||
|
|
@ -7,10 +10,14 @@ import 'package:twonly/src/views/components/better_text.dart';
|
||||||
class ChatTextEntry extends StatelessWidget {
|
class ChatTextEntry extends StatelessWidget {
|
||||||
const ChatTextEntry({
|
const ChatTextEntry({
|
||||||
required this.message,
|
required this.message,
|
||||||
|
required this.nextMessage,
|
||||||
|
required this.borderRadius,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Message message;
|
final Message message;
|
||||||
|
final Message? nextMessage;
|
||||||
|
final BorderRadius borderRadius;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -27,17 +34,98 @@ class ChatTextEntry extends StatelessWidget {
|
||||||
child: EmojiAnimation(emoji: text),
|
child: EmojiAnimation(emoji: text),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final displayTime = !combineTextMessageWithNext(message, nextMessage);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxWidth: MediaQuery.of(context).size.width * 0.8,
|
maxWidth: MediaQuery.of(context).size.width * 0.8,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.only(left: 10, top: 4, bottom: 4),
|
padding: const EdgeInsets.only(left: 10, top: 6, bottom: 6, right: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color:
|
||||||
message.quotesMessageId == null ? getMessageColor(message) : null,
|
message.quotesMessageId == null ? getMessageColor(message) : null,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: borderRadius,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
if (measureTextWidth(text) > 270)
|
||||||
|
Expanded(
|
||||||
|
child: BetterText(text: text),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
BetterText(text: text),
|
||||||
|
if (displayTime)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 6),
|
||||||
|
child: Text(
|
||||||
|
friendlyTime(context, message.createdAt),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
color: Colors.white.withAlpha(150),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
child: BetterText(text: text),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double measureTextWidth(
|
||||||
|
String text,
|
||||||
|
) {
|
||||||
|
final tp = TextPainter(
|
||||||
|
text: TextSpan(text: text, style: const TextStyle(fontSize: 17)),
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
maxLines: 1,
|
||||||
|
)..layout();
|
||||||
|
return tp.size.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool combineTextMessageWithNext(Message message, Message? nextMessage) {
|
||||||
|
if (nextMessage != null && nextMessage.content != null) {
|
||||||
|
if (nextMessage.senderId == message.senderId) {
|
||||||
|
if (nextMessage.type == MessageType.text &&
|
||||||
|
message.type == MessageType.text) {
|
||||||
|
if (!EmojiAnimation.supported(nextMessage.content!)) {
|
||||||
|
final diff =
|
||||||
|
nextMessage.createdAt.difference(message.createdAt).inMinutes;
|
||||||
|
if (diff <= 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String friendlyTime(BuildContext context, DateTime dt) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final diff = now.difference(dt);
|
||||||
|
|
||||||
|
if (diff.inMinutes >= 0 && diff.inMinutes < 60) {
|
||||||
|
final minutes = diff.inMinutes == 0 ? 1 : diff.inMinutes;
|
||||||
|
if (minutes <= 1) {
|
||||||
|
return context.lang.now;
|
||||||
|
}
|
||||||
|
return '$minutes ${context.lang.minutesShort}';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine 24h vs 12h from system/local settings
|
||||||
|
final use24Hour = MediaQuery.of(context).alwaysUse24HourFormat;
|
||||||
|
|
||||||
|
if (!use24Hour) {
|
||||||
|
// 12-hour format with locale-aware AM/PM
|
||||||
|
final format = DateFormat.jm(Localizations.localeOf(context).toString());
|
||||||
|
return format.format(dt);
|
||||||
|
} else {
|
||||||
|
// 24-hour HH:mm, locale-aware
|
||||||
|
final format = DateFormat.Hm(Localizations.localeOf(context).toString());
|
||||||
|
return format.format(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class ResponseContainer extends StatefulWidget {
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.scrollToMessage,
|
required this.scrollToMessage,
|
||||||
required this.mediaService,
|
required this.mediaService,
|
||||||
|
required this.borderRadius,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -21,6 +22,7 @@ class ResponseContainer extends StatefulWidget {
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
final Group group;
|
final Group group;
|
||||||
final MediaFileService? mediaService;
|
final MediaFileService? mediaService;
|
||||||
|
final BorderRadius borderRadius;
|
||||||
final void Function(String) scrollToMessage;
|
final void Function(String) scrollToMessage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -69,7 +71,7 @@ class _ResponseContainerState extends State<ResponseContainer> {
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: getMessageColor(widget.msg),
|
color: getMessageColor(widget.msg),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: widget.borderRadius,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|
@ -157,11 +159,12 @@ class _ResponsePreviewState extends State<ResponsePreview> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (message!.type == MessageType.media && mediaService != null) {
|
if (message!.type == MessageType.media && mediaService != null) {
|
||||||
subtitle =
|
subtitle = mediaService!.mediaFile.type == MediaType.video
|
||||||
mediaService!.mediaFile.type == MediaType.video ? 'Video' : 'Image';
|
? context.lang.video
|
||||||
|
: context.lang.image;
|
||||||
}
|
}
|
||||||
|
|
||||||
var username = 'You';
|
var username = context.lang.you;
|
||||||
if (message!.senderId != null) {
|
if (message!.senderId != null) {
|
||||||
username = message!.senderId.toString();
|
username = message!.senderId.toString();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,19 @@ class BetterText extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastMatchEnd < text.length) {
|
if (lastMatchEnd < text.length) {
|
||||||
spans.add(TextSpan(text: text.substring(lastMatchEnd)));
|
spans.add(
|
||||||
|
TextSpan(
|
||||||
|
text: text.substring(lastMatchEnd),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Text.rich(
|
return Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: spans,
|
children: spans,
|
||||||
),
|
),
|
||||||
|
softWrap: true,
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 17,
|
fontSize: 17,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue