forked from Henry-Hiles/nexus
continue layout changes
This commit is contained in:
parent
163754870a
commit
dd7b88c994
4 changed files with 265 additions and 293 deletions
|
|
@ -46,6 +46,12 @@ class MessageController extends AsyncNotifier<Message?> {
|
||||||
final content = (event.decrypted ?? event.content);
|
final content = (event.decrypted ?? event.content);
|
||||||
final type = (config.event.decryptedType ?? config.event.type);
|
final type = (config.event.decryptedType ?? config.event.type);
|
||||||
final newContent = content["m.new_content"] as Map?;
|
final newContent = content["m.new_content"] as Map?;
|
||||||
|
|
||||||
|
final homeserver = ref.read(ClientStateController.provider)?.homeserverUrl;
|
||||||
|
final source = homeserver == null || content["url"] == null
|
||||||
|
? "null"
|
||||||
|
: Uri.parse(content["url"]).mxcToHttps(homeserver).toString();
|
||||||
|
|
||||||
final metadata = {
|
final metadata = {
|
||||||
"body": config.event.redactedBy == null
|
"body": config.event.redactedBy == null
|
||||||
? (newContent?["body"] ?? content["body"] ?? "")
|
? (newContent?["body"] ?? content["body"] ?? "")
|
||||||
|
|
@ -72,6 +78,16 @@ class MessageController extends AsyncNotifier<Message?> {
|
||||||
? author?.content["displayname"]
|
? author?.content["displayname"]
|
||||||
: event.authorId.substring(1).split(":")[0],
|
: event.authorId.substring(1).split(":")[0],
|
||||||
"txnId": config.event.transactionId,
|
"txnId": config.event.transactionId,
|
||||||
|
"image": content["msgtype"] == "m.image"
|
||||||
|
? Message.image(
|
||||||
|
id: "${config.event.eventId}-image",
|
||||||
|
authorId: event.authorId,
|
||||||
|
source: source,
|
||||||
|
replyToMessageId: replyId,
|
||||||
|
deliveredAt: config.event.timestamp,
|
||||||
|
blurhash: (content["info"] as Map?)?["xyz.amorgan.blurhash"],
|
||||||
|
)
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!ref.mounted) return null;
|
if (!ref.mounted) return null;
|
||||||
|
|
@ -106,11 +122,6 @@ class MessageController extends AsyncNotifier<Message?> {
|
||||||
)
|
)
|
||||||
as TextMessage;
|
as TextMessage;
|
||||||
|
|
||||||
final homeserver = ref.read(ClientStateController.provider)?.homeserverUrl;
|
|
||||||
final source = homeserver == null || content["url"] == null
|
|
||||||
? "null"
|
|
||||||
: Uri.parse(content["url"]).mxcToHttps(homeserver).toString();
|
|
||||||
|
|
||||||
return switch (type) {
|
return switch (type) {
|
||||||
"m.room.encrypted" => asText.copyWith(
|
"m.room.encrypted" => asText.copyWith(
|
||||||
text: "Unable to decrypt message.",
|
text: "Unable to decrypt message.",
|
||||||
|
|
@ -127,20 +138,6 @@ class MessageController extends AsyncNotifier<Message?> {
|
||||||
// authorId: senderId,
|
// authorId: senderId,
|
||||||
// ),
|
// ),
|
||||||
("m.sticker" || "m.room.message") => switch (content["msgtype"]) {
|
("m.sticker" || "m.room.message") => switch (content["msgtype"]) {
|
||||||
(null || "m.image") => Message.image(
|
|
||||||
id: config.event.eventId,
|
|
||||||
metadata: metadata,
|
|
||||||
authorId: event.authorId,
|
|
||||||
text:
|
|
||||||
newContent?["formatted_body"] ??
|
|
||||||
newContent?["body"] ??
|
|
||||||
content["formatted_body"] ??
|
|
||||||
content["body"],
|
|
||||||
source: source,
|
|
||||||
replyToMessageId: replyId,
|
|
||||||
deliveredAt: config.event.timestamp,
|
|
||||||
blurhash: (content["info"] as Map?)?["xyz.amorgan.blurhash"],
|
|
||||||
),
|
|
||||||
"m.audio" || "m.file" => Message.file(
|
"m.audio" || "m.file" => Message.file(
|
||||||
name: content["filename"].toString(),
|
name: content["filename"].toString(),
|
||||||
size: content["info"]["size"],
|
size: content["info"]["size"],
|
||||||
|
|
|
||||||
39
lib/widgets/chat_page/message_wrapper.dart
Normal file
39
lib/widgets/chat_page/message_wrapper.dart
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
|
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||||
|
|
||||||
|
class MessageWrapper extends StatelessWidget {
|
||||||
|
final Message message;
|
||||||
|
final Widget child;
|
||||||
|
final MessageGroupStatus? groupStatus;
|
||||||
|
const MessageWrapper(this.message, this.child, this.groupStatus, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Row(
|
||||||
|
spacing: 8,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
groupStatus?.isFirst != false
|
||||||
|
? AvatarOrHash(
|
||||||
|
Uri.parse(message.metadata?["avatarUrl"] ?? ""),
|
||||||
|
height: 40,
|
||||||
|
message.metadata?["displayName"] ?? "",
|
||||||
|
)
|
||||||
|
: SizedBox(width: 40),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (groupStatus?.isFirst != false)
|
||||||
|
Text(
|
||||||
|
message.metadata?["displayName"] ?? message.authorId,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
child,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import "dart:math";
|
import "dart:math";
|
||||||
|
|
||||||
import "package:cross_cache/cross_cache.dart";
|
import "package:cross_cache/cross_cache.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||||
|
|
@ -21,10 +20,10 @@ import "package:nexus/helpers/extensions/get_headers.dart";
|
||||||
import "package:nexus/helpers/extensions/show_context_menu.dart";
|
import "package:nexus/helpers/extensions/show_context_menu.dart";
|
||||||
import "package:nexus/models/relation_type.dart";
|
import "package:nexus/models/relation_type.dart";
|
||||||
import "package:nexus/models/requests/report_request.dart";
|
import "package:nexus/models/requests/report_request.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
|
||||||
import "package:nexus/widgets/chat_page/chat_box.dart";
|
import "package:nexus/widgets/chat_page/chat_box.dart";
|
||||||
import "package:nexus/widgets/chat_page/html/html.dart";
|
import "package:nexus/widgets/chat_page/html/html.dart";
|
||||||
import "package:nexus/widgets/chat_page/member_list.dart";
|
import "package:nexus/widgets/chat_page/member_list.dart";
|
||||||
|
import "package:nexus/widgets/chat_page/message_wrapper.dart";
|
||||||
import "package:nexus/widgets/chat_page/room_appbar.dart";
|
import "package:nexus/widgets/chat_page/room_appbar.dart";
|
||||||
import "package:nexus/widgets/chat_page/top_widget.dart";
|
import "package:nexus/widgets/chat_page/top_widget.dart";
|
||||||
import "package:nexus/widgets/form_text_input.dart";
|
import "package:nexus/widgets/form_text_input.dart";
|
||||||
|
|
@ -52,37 +51,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final danger = theme.colorScheme.error;
|
final danger = theme.colorScheme.error;
|
||||||
|
|
||||||
Widget getTextWidget(TextMessage message) => Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Html(
|
|
||||||
textStyle: message.metadata?["big"] == true
|
|
||||||
? TextStyle(fontSize: 32)
|
|
||||||
: null,
|
|
||||||
message.text
|
|
||||||
.replaceAllMapped(
|
|
||||||
RegExp(
|
|
||||||
"(<a\\b[^>]*>.*?<\\/a>)|(\\bhttps?:\\/\\/[^\\s<]+)",
|
|
||||||
caseSensitive: false,
|
|
||||||
),
|
|
||||||
(m) {
|
|
||||||
// If it's already an <a> tag, leave it unchanged
|
|
||||||
if (m.group(1) != null) {
|
|
||||||
return m.group(1)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, wrap the bare URL
|
|
||||||
final url = m.group(2)!;
|
|
||||||
return "<a href=\"$url\">$url</a>";
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.replaceAll("\n", "<br class=\"fake-break\"/>"),
|
|
||||||
),
|
|
||||||
if (message.editedAt != null)
|
|
||||||
Text("(edited)", style: theme.textTheme.labelSmall),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (room == null || userId == null || room.metadata?.id == null) {
|
if (room == null || userId == null || room.metadata?.id == null) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
@ -268,47 +236,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
globalPosition: details.globalPosition,
|
globalPosition: details.globalPosition,
|
||||||
children: getMessageOptions(message),
|
children: getMessageOptions(message),
|
||||||
),
|
),
|
||||||
onMessageTap:
|
|
||||||
(
|
|
||||||
context,
|
|
||||||
message, {
|
|
||||||
required details,
|
|
||||||
required index,
|
|
||||||
}) {
|
|
||||||
if (message is ImageMessage) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => LayoutBuilder(
|
|
||||||
builder: (context, constraints) => Dialog(
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
insetPadding: EdgeInsets.all(
|
|
||||||
constraints.maxWidth / 100,
|
|
||||||
),
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minWidth: min(
|
|
||||||
constraints.maxWidth,
|
|
||||||
1000,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: InteractiveViewer(
|
|
||||||
child: Image(
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
image: CachedNetworkImage(
|
|
||||||
message.source,
|
|
||||||
ref.watch(
|
|
||||||
CrossCacheController.provider,
|
|
||||||
),
|
|
||||||
headers: ref.headers,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
builders: Builders(
|
builders: Builders(
|
||||||
loadMoreBuilder: (_) => Loading(),
|
loadMoreBuilder: (_) => Loading(),
|
||||||
chatAnimatedListBuilder: (_, itemBuilder) =>
|
chatAnimatedListBuilder: (_, itemBuilder) =>
|
||||||
|
|
@ -432,48 +359,161 @@ class RoomChat extends HookConsumerWidget {
|
||||||
index, {
|
index, {
|
||||||
required bool isSentByMe,
|
required bool isSentByMe,
|
||||||
MessageGroupStatus? groupStatus,
|
MessageGroupStatus? groupStatus,
|
||||||
}) => Row(
|
}) {
|
||||||
spacing: 8,
|
final image =
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
message.metadata?["image"]
|
||||||
|
as ImageMessage?;
|
||||||
|
return MessageWrapper(
|
||||||
|
message,
|
||||||
|
Column(
|
||||||
|
spacing: 4,
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
FlyerChatTextMessage(
|
||||||
|
showTime: true,
|
||||||
|
showStatus: false,
|
||||||
|
customWidget: Column(
|
||||||
|
spacing: 4,
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
groupStatus?.isFirst != false
|
|
||||||
? AvatarOrHash(
|
|
||||||
Uri.parse(
|
|
||||||
message.metadata?["avatarUrl"] ??
|
|
||||||
"",
|
|
||||||
),
|
|
||||||
height: 40,
|
|
||||||
message.metadata?["displayName"] ??
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
: SizedBox(width: 40),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (groupStatus?.isFirst != false)
|
Html(
|
||||||
|
textStyle:
|
||||||
|
message.metadata?["big"] ==
|
||||||
|
true
|
||||||
|
? TextStyle(
|
||||||
|
fontSize: 32,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
message.text
|
||||||
|
.replaceAllMapped(
|
||||||
|
RegExp(
|
||||||
|
"(<a\\b[^>]*>.*?<\\/a>)|(\\bhttps?:\\/\\/[^\\s<]+)",
|
||||||
|
caseSensitive:
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
(m) {
|
||||||
|
// If it's already an <a> tag, leave it unchanged
|
||||||
|
if (m.group(1) !=
|
||||||
|
null) {
|
||||||
|
return m.group(
|
||||||
|
1,
|
||||||
|
)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, wrap the bare URL
|
||||||
|
final url = m.group(
|
||||||
|
2,
|
||||||
|
)!;
|
||||||
|
return "<a href=\"$url\">$url</a>";
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.replaceAll(
|
||||||
|
"\n",
|
||||||
|
"<br class=\"fake-break\"/>",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (message.editedAt != null)
|
||||||
Text(
|
Text(
|
||||||
message.metadata?["displayName"] ??
|
"(edited)",
|
||||||
message.authorId,
|
style: theme
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
.textTheme
|
||||||
.titleMedium
|
.labelSmall,
|
||||||
?.copyWith(
|
),
|
||||||
fontWeight: FontWeight.bold,
|
],
|
||||||
|
),
|
||||||
|
if (image != null)
|
||||||
|
InkWell(
|
||||||
|
onTap: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => LayoutBuilder(
|
||||||
|
builder: (context, constraints) => Dialog(
|
||||||
|
backgroundColor:
|
||||||
|
Colors.transparent,
|
||||||
|
insetPadding:
|
||||||
|
EdgeInsets.all(
|
||||||
|
constraints
|
||||||
|
.maxWidth /
|
||||||
|
100,
|
||||||
|
),
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints:
|
||||||
|
BoxConstraints(
|
||||||
|
minWidth: min(
|
||||||
|
constraints
|
||||||
|
.maxWidth,
|
||||||
|
1000,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
FlyerChatTextMessage(
|
child: InteractiveViewer(
|
||||||
showStatus: false,
|
child: Image(
|
||||||
customWidget: getTextWidget(message),
|
fit: BoxFit
|
||||||
|
.contain,
|
||||||
|
image: CachedNetworkImage(
|
||||||
|
image.source,
|
||||||
|
ref.watch(
|
||||||
|
CrossCacheController
|
||||||
|
.provider,
|
||||||
|
),
|
||||||
|
headers:
|
||||||
|
ref.headers,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: FlyerChatImageMessage(
|
||||||
|
customImageProvider:
|
||||||
|
CachedNetworkImage(
|
||||||
|
image.source,
|
||||||
|
ref.watch(
|
||||||
|
CrossCacheController
|
||||||
|
.provider,
|
||||||
|
),
|
||||||
|
headers: ref.headers,
|
||||||
|
),
|
||||||
|
errorBuilder:
|
||||||
|
(
|
||||||
|
context,
|
||||||
|
error,
|
||||||
|
stackTrace,
|
||||||
|
) => Center(
|
||||||
|
child: Text(
|
||||||
|
"Image Failed to Load",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.error,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
message: image,
|
||||||
|
index: index,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
topWidget: TopWidget(
|
||||||
|
message,
|
||||||
|
groupStatus: groupStatus,
|
||||||
|
onTapReply:
|
||||||
|
notifier.scrollToMessage,
|
||||||
|
),
|
||||||
message: message,
|
message: message,
|
||||||
showTime: true,
|
|
||||||
index: index,
|
index: index,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
groupStatus,
|
||||||
),
|
);
|
||||||
|
},
|
||||||
linkPreviewBuilder: (_, message, isSentByMe) =>
|
linkPreviewBuilder: (_, message, isSentByMe) =>
|
||||||
LinkPreview(
|
LinkPreview(
|
||||||
text: message.text,
|
text: message.text,
|
||||||
|
|
@ -493,80 +533,6 @@ class RoomChat extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
imageMessageBuilder:
|
|
||||||
(
|
|
||||||
_,
|
|
||||||
message,
|
|
||||||
index, {
|
|
||||||
required bool isSentByMe,
|
|
||||||
MessageGroupStatus? groupStatus,
|
|
||||||
}) {
|
|
||||||
final textMessage =
|
|
||||||
message.text?.isNotEmpty == true
|
|
||||||
? TextMessage(
|
|
||||||
id: "${message.id}-text",
|
|
||||||
authorId: message.authorId,
|
|
||||||
text: message.text!,
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
return Column(
|
|
||||||
spacing: 4,
|
|
||||||
crossAxisAlignment: isSentByMe
|
|
||||||
? CrossAxisAlignment.end
|
|
||||||
: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 12),
|
|
||||||
if (textMessage != null)
|
|
||||||
FlyerChatTextMessage(
|
|
||||||
customWidget: getTextWidget(
|
|
||||||
textMessage,
|
|
||||||
),
|
|
||||||
topWidget: TopWidget(
|
|
||||||
message,
|
|
||||||
groupStatus: groupStatus,
|
|
||||||
onTapReply:
|
|
||||||
notifier.scrollToMessage,
|
|
||||||
alwaysShow: true,
|
|
||||||
),
|
|
||||||
message: textMessage,
|
|
||||||
index: index,
|
|
||||||
),
|
|
||||||
FlyerChatImageMessage(
|
|
||||||
topWidget:
|
|
||||||
message.text?.isNotEmpty == true
|
|
||||||
? null
|
|
||||||
: TopWidget(
|
|
||||||
message,
|
|
||||||
groupStatus: groupStatus,
|
|
||||||
onTapReply:
|
|
||||||
notifier.scrollToMessage,
|
|
||||||
alwaysShow: true,
|
|
||||||
),
|
|
||||||
customImageProvider: CachedNetworkImage(
|
|
||||||
message.source,
|
|
||||||
ref.watch(
|
|
||||||
CrossCacheController.provider,
|
|
||||||
),
|
|
||||||
headers: ref.headers,
|
|
||||||
),
|
|
||||||
errorBuilder:
|
|
||||||
(context, error, stackTrace) =>
|
|
||||||
Center(
|
|
||||||
child: Text(
|
|
||||||
"Image Failed to Load",
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(
|
|
||||||
context,
|
|
||||||
).colorScheme.error,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
message: message,
|
|
||||||
index: index,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
fileMessageBuilder:
|
fileMessageBuilder:
|
||||||
(
|
(
|
||||||
_,
|
_,
|
||||||
|
|
@ -574,11 +540,15 @@ class RoomChat extends HookConsumerWidget {
|
||||||
index, {
|
index, {
|
||||||
required bool isSentByMe,
|
required bool isSentByMe,
|
||||||
MessageGroupStatus? groupStatus,
|
MessageGroupStatus? groupStatus,
|
||||||
}) => InkWell(
|
}) => MessageWrapper(
|
||||||
|
message,
|
||||||
|
InkWell(
|
||||||
onTap: () => showDialog(
|
onTap: () => showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => Dialog(
|
builder: (_) => Dialog(
|
||||||
child: Text("TODO: Download Attachments"),
|
child: Text(
|
||||||
|
"TODO: Download Attachments",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: FlyerChatFileMessage(
|
child: FlyerChatFileMessage(
|
||||||
|
|
@ -591,6 +561,8 @@ class RoomChat extends HookConsumerWidget {
|
||||||
index: index,
|
index: index,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
groupStatus,
|
||||||
|
),
|
||||||
systemMessageBuilder:
|
systemMessageBuilder:
|
||||||
(
|
(
|
||||||
_,
|
_,
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,7 @@ class TopWidget extends ConsumerWidget {
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) => Column(
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Builder(
|
|
||||||
builder: (_) {
|
|
||||||
final replyMessage = message.metadata?["reply"] as Message?;
|
final replyMessage = message.metadata?["reply"] as Message?;
|
||||||
|
|
||||||
if (replyMessage == null) return SizedBox.shrink();
|
if (replyMessage == null) return SizedBox.shrink();
|
||||||
|
|
@ -36,8 +32,7 @@ class TopWidget extends ConsumerWidget {
|
||||||
max(
|
max(
|
||||||
max(
|
max(
|
||||||
(message as TextMessage).text.length -
|
(message as TextMessage).text.length -
|
||||||
(replyMessage.metadata?["displayName"] as String)
|
(replyMessage.metadata?["displayName"] as String).length -
|
||||||
.length -
|
|
||||||
5,
|
5,
|
||||||
message.metadata?["displayName"].length,
|
message.metadata?["displayName"].length,
|
||||||
),
|
),
|
||||||
|
|
@ -71,8 +66,9 @@ class TopWidget extends ConsumerWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
replyMessage.metadata?["displayName"] ??
|
replyMessage.metadata?["displayName"] ??
|
||||||
replyMessage.authorId,
|
replyMessage.authorId,
|
||||||
style: Theme.of(context).textTheme.labelMedium
|
style: Theme.of(context).textTheme.labelMedium?.copyWith(
|
||||||
?.copyWith(fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -89,37 +85,5 @@ class TopWidget extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
),
|
|
||||||
if (alwaysShow ||
|
|
||||||
groupStatus?.isFirst != false ||
|
|
||||||
message.metadata?["reply"] != null)
|
|
||||||
InkWell(
|
|
||||||
onTap: () => showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) =>
|
|
||||||
Dialog(child: Text("TODO: Show user profile")), // TODO
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
spacing: 8,
|
|
||||||
children: [
|
|
||||||
AvatarOrHash(
|
|
||||||
Uri.parse(message.metadata?["avatarUrl"] ?? ""),
|
|
||||||
message.metadata?["displayName"] ?? "",
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
message.metadata?["displayName"] ?? message.authorId,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue