forked from Henry-Hiles/nexus
progress
This commit is contained in:
parent
541933a939
commit
63a9d2d169
15 changed files with 388 additions and 299 deletions
|
|
@ -1,13 +1,14 @@
|
|||
import "dart:io";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||
import "package:flutter_chat_ui/flutter_chat_ui.dart";
|
||||
import "package:flutter_hooks/flutter_hooks.dart";
|
||||
import "package:fluttertagger/fluttertagger.dart";
|
||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||
import "package:matrix/matrix.dart";
|
||||
import "package:nexus/helpers/extensions/get_headers.dart";
|
||||
import "package:nexus/widgets/form_text_input.dart";
|
||||
import "package:nexus/controllers/room_chat_controller.dart";
|
||||
|
||||
class ChatBox extends HookWidget {
|
||||
class ChatBox extends HookConsumerWidget {
|
||||
final Message? replyToMessage;
|
||||
final VoidCallback onDismiss;
|
||||
final Room room;
|
||||
|
|
@ -19,83 +20,142 @@ class ChatBox extends HookWidget {
|
|||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = Theme.of(context);
|
||||
final controller = useRef(FlutterTaggerController());
|
||||
final trigger = useState<String?>(null);
|
||||
|
||||
Future<void> send() => ref
|
||||
.watch(RoomChatController.provider(room).notifier)
|
||||
.send(controller.value.text);
|
||||
|
||||
final node = useFocusNode(
|
||||
onKeyEvent: (_, event) {
|
||||
if (event is KeyDownEvent &&
|
||||
event.logicalKey == LogicalKeyboardKey.enter &&
|
||||
!(Platform.isAndroid || Platform.isIOS) ^
|
||||
HardwareKeyboard.instance.isShiftPressed) {
|
||||
send();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
},
|
||||
);
|
||||
|
||||
final style = TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
FlutterTagger(
|
||||
overlay: SizedBox(),
|
||||
controller: controller.value,
|
||||
onSearch: (query, triggerCharacter) {
|
||||
triggerCharacter == "#";
|
||||
if (controller.value.tags.isEmpty)
|
||||
controller.value.addTag(id: "id", name: "name");
|
||||
},
|
||||
triggerCharacterAndStyles: {"@": style, "#": style},
|
||||
builder: (context, key) => TextFormField(controller: controller.value, key: key,autofocus: true,onFieldSubmitted: (_) {
|
||||
|
||||
},)
|
||||
// Composer(
|
||||
// textEditingController: controller.value,
|
||||
// key: key,
|
||||
// sigmaY: 0,
|
||||
// sendIconColor: theme.colorScheme.primary,
|
||||
// sendOnEnter: true,
|
||||
// topWidget: replyToMessage == null
|
||||
// ? null
|
||||
// : ColoredBox(
|
||||
// color: theme.colorScheme.surfaceContainer,
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.symmetric(
|
||||
// horizontal: 16,
|
||||
// vertical: 4,
|
||||
// ),
|
||||
// child: Row(
|
||||
// spacing: 8,
|
||||
// children: [
|
||||
// Avatar(
|
||||
// userId: replyToMessage!.authorId,
|
||||
// headers: room.client.headers,
|
||||
// size: 16,
|
||||
// ),
|
||||
// Text(
|
||||
// replyToMessage!.metadata?["displayName"] ??
|
||||
// replyToMessage!.authorId,
|
||||
// style: theme.textTheme.labelMedium?.copyWith(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// Expanded(
|
||||
// child: (replyToMessage is TextMessage)
|
||||
// ? Text(
|
||||
// (replyToMessage as TextMessage).text,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// style: theme.textTheme.labelMedium,
|
||||
// maxLines: 1,
|
||||
// )
|
||||
// : SizedBox(),
|
||||
// ),
|
||||
// IconButton(
|
||||
// onPressed: onDismiss,
|
||||
// icon: Icon(Icons.close),
|
||||
// iconSize: 20,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// autofocus: true,
|
||||
// ),
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Padding(
|
||||
padding: EdgeInsetsGeometry.all(12),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
child: Container(
|
||||
color: theme.colorScheme.surfaceContainerHighest,
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: // TODO: This doesn't work?
|
||||
room.canSendDefaultMessages
|
||||
? Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) => [],
|
||||
icon: Icon(Icons.add),
|
||||
),
|
||||
Expanded(
|
||||
child: FlutterTagger(
|
||||
overlay: SizedBox(),
|
||||
controller: controller.value,
|
||||
onSearch: (query, triggerCharacter) {
|
||||
triggerCharacter == "#";
|
||||
if (controller.value.tags.isEmpty) {
|
||||
controller.value.addTag(
|
||||
id: "id",
|
||||
name: "name",
|
||||
); // TODO: RM
|
||||
}
|
||||
},
|
||||
triggerCharacterAndStyles: {
|
||||
"@": style,
|
||||
"#": style,
|
||||
":": style,
|
||||
},
|
||||
builder: (context, key) => TextFormField(
|
||||
maxLines: 12,
|
||||
minLines: 1,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Your message here...",
|
||||
border: InputBorder.none,
|
||||
),
|
||||
controller: controller.value,
|
||||
key: key,
|
||||
autofocus: true,
|
||||
focusNode: node,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(onPressed: send, icon: Icon(Icons.send)),
|
||||
],
|
||||
)
|
||||
: Text("You don't have permission to send messages here..."),
|
||||
// Composer(
|
||||
// textEditingController: controller.value,
|
||||
// key: key,
|
||||
// sigmaY: 0,
|
||||
// sendIconColor: theme.colorScheme.primary,
|
||||
// sendOnEnter: true,
|
||||
// topWidget: replyToMessage == null
|
||||
// ? null
|
||||
// : ColoredBox(
|
||||
// color: theme.colorScheme.surfaceContainer,
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.symmetric(
|
||||
// horizontal: 16,
|
||||
// vertical: 4,
|
||||
// ),
|
||||
// child: Row(
|
||||
// spacing: 8,
|
||||
// children: [
|
||||
// Avatar(
|
||||
// userId: replyToMessage!.authorId,
|
||||
// headers: room.client.headers,
|
||||
// size: 16,
|
||||
// ),
|
||||
// Text(
|
||||
// replyToMessage!.metadata?["displayName"] ??
|
||||
// replyToMessage!.authorId,
|
||||
// style: theme.textTheme.labelMedium?.copyWith(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// Expanded(
|
||||
// child: (replyToMessage is TextMessage)
|
||||
// ? Text(
|
||||
// (replyToMessage as TextMessage).text,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// style: theme.textTheme.labelMedium,
|
||||
// maxLines: 1,
|
||||
// )
|
||||
// : SizedBox(),
|
||||
// ),
|
||||
// IconButton(
|
||||
// onPressed: onDismiss,
|
||||
// icon: Icon(Icons.close),
|
||||
// iconSize: 20,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// autofocus: true,
|
||||
// ),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_hooks/flutter_hooks.dart";
|
||||
import "package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart";
|
||||
|
||||
class SpoilerText extends HookWidget {
|
||||
final String text;
|
||||
|
|
@ -10,18 +11,20 @@ class SpoilerText extends HookWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final revealed = useState(false);
|
||||
|
||||
return InkWell(
|
||||
onTap: () => revealed.value = !revealed.value,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: revealed.value ? Colors.transparent : Colors.blueGrey,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(color: revealed.value ? null : Colors.transparent),
|
||||
return InlineCustomWidget(
|
||||
child: InkWell(
|
||||
onTap: () => revealed.value = !revealed.value,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: revealed.value ? Colors.transparent : Colors.blueGrey,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(color: revealed.value ? null : Colors.transparent),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -135,177 +135,197 @@ class RoomChat extends HookConsumerWidget {
|
|||
body: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ref
|
||||
.watch(controllerProvider)
|
||||
.betterWhen(
|
||||
data: (controller) => Chat(
|
||||
currentUserId: room.roomData.client.userID!,
|
||||
theme: ChatTheme.fromThemeData(theme).copyWith(
|
||||
colors: ChatColors.fromThemeData(theme).copyWith(
|
||||
primary: theme.colorScheme.primaryContainer,
|
||||
onPrimary: theme.colorScheme.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
onMessageSecondaryTap:
|
||||
(
|
||||
context,
|
||||
message, {
|
||||
required details,
|
||||
required index,
|
||||
}) => context.showContextMenu(
|
||||
globalPosition: details.globalPosition,
|
||||
children: getMessageOptions(message),
|
||||
),
|
||||
onMessageLongPress:
|
||||
(
|
||||
context,
|
||||
message, {
|
||||
required details,
|
||||
required index,
|
||||
}) => context.showContextMenu(
|
||||
globalPosition: details.globalPosition,
|
||||
children: getMessageOptions(message),
|
||||
),
|
||||
builders: Builders(
|
||||
loadMoreBuilder: (_) => Loading(),
|
||||
chatAnimatedListBuilder: (_, itemBuilder) =>
|
||||
ChatAnimatedList(
|
||||
itemBuilder: itemBuilder,
|
||||
onEndReached: notifier.loadOlder,
|
||||
onStartReached: notifier.markRead,
|
||||
),
|
||||
composerBuilder: (_) => ChatBox(
|
||||
replyToMessage: replyToMessage.value,
|
||||
onDismiss: () => replyToMessage.value = null,
|
||||
room: room.roomData,
|
||||
),
|
||||
textMessageBuilder:
|
||||
(
|
||||
context,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => FlyerChatTextMessage(
|
||||
customWidget: Html(
|
||||
message.metadata?["formatted"]
|
||||
.replaceAllMapped(
|
||||
RegExp(
|
||||
regexLink,
|
||||
caseSensitive: false,
|
||||
),
|
||||
(m) =>
|
||||
"<a href=\"${m.group(0)!}\">${m.group(0)!}</a>",
|
||||
) +
|
||||
((message.editedAt != null)
|
||||
? "<sub edited>(edited)</sub>"
|
||||
: ""),
|
||||
client: room.roomData.client,
|
||||
),
|
||||
topWidget: TopWidget(
|
||||
message,
|
||||
headers: room.roomData.client.headers,
|
||||
groupStatus: groupStatus,
|
||||
),
|
||||
message: message,
|
||||
showTime: true,
|
||||
index: index,
|
||||
),
|
||||
linkPreviewBuilder: (_, message, isSentByMe) =>
|
||||
LinkPreview(
|
||||
text: message.text,
|
||||
backgroundColor: isSentByMe
|
||||
? theme.colorScheme.inversePrimary
|
||||
: theme.colorScheme.surfaceContainerLow,
|
||||
insidePadding: EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
horizontal: 16,
|
||||
),
|
||||
linkPreviewData: message.linkPreviewData,
|
||||
onLinkPreviewDataFetched:
|
||||
(linkPreviewData) =>
|
||||
notifier.updateMessage(
|
||||
message,
|
||||
message.copyWith(
|
||||
linkPreviewData:
|
||||
linkPreviewData,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ref
|
||||
.watch(controllerProvider)
|
||||
.betterWhen(
|
||||
data: (controller) => Chat(
|
||||
currentUserId: room.roomData.client.userID!,
|
||||
theme: ChatTheme.fromThemeData(theme)
|
||||
.copyWith(
|
||||
colors: ChatColors.fromThemeData(theme)
|
||||
.copyWith(
|
||||
primary: theme
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
onPrimary: theme
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
imageMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => FlyerChatImageMessage(
|
||||
topWidget: TopWidget(
|
||||
message,
|
||||
headers: room.roomData.client.headers,
|
||||
groupStatus: groupStatus,
|
||||
alwaysShow: true,
|
||||
),
|
||||
message: message,
|
||||
index: index,
|
||||
headers: room.roomData.client.headers,
|
||||
),
|
||||
fileMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => InkWell(
|
||||
onTap: () => showAboutDialog(
|
||||
context: context,
|
||||
), // TODO: Download
|
||||
child: FlyerChatFileMessage(
|
||||
topWidget: TopWidget(
|
||||
message,
|
||||
headers: room.roomData.client.headers,
|
||||
groupStatus: groupStatus,
|
||||
),
|
||||
message: message,
|
||||
index: index,
|
||||
onMessageSecondaryTap:
|
||||
(
|
||||
context,
|
||||
message, {
|
||||
required details,
|
||||
required index,
|
||||
}) => context.showContextMenu(
|
||||
globalPosition: details.globalPosition,
|
||||
children: getMessageOptions(message),
|
||||
),
|
||||
onMessageLongPress:
|
||||
(
|
||||
context,
|
||||
message, {
|
||||
required details,
|
||||
required index,
|
||||
}) => context.showContextMenu(
|
||||
globalPosition: details.globalPosition,
|
||||
children: getMessageOptions(message),
|
||||
),
|
||||
builders: Builders(
|
||||
loadMoreBuilder: (_) => Loading(),
|
||||
chatAnimatedListBuilder: (_, itemBuilder) =>
|
||||
ChatAnimatedList(
|
||||
itemBuilder: itemBuilder,
|
||||
onEndReached: notifier.loadOlder,
|
||||
onStartReached: notifier.markRead,
|
||||
bottomPadding: 72,
|
||||
),
|
||||
composerBuilder: (_) => ChatBox(
|
||||
replyToMessage: replyToMessage.value,
|
||||
onDismiss: () =>
|
||||
replyToMessage.value = null,
|
||||
room: room.roomData,
|
||||
),
|
||||
textMessageBuilder:
|
||||
(
|
||||
context,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => FlyerChatTextMessage(
|
||||
customWidget: Html(
|
||||
message.metadata?["formatted"]
|
||||
.replaceAllMapped(
|
||||
RegExp(
|
||||
regexLink,
|
||||
caseSensitive: false,
|
||||
),
|
||||
(m) =>
|
||||
"<a href=\"${m.group(0)!}\">${m.group(0)!}</a>",
|
||||
) +
|
||||
((message.editedAt != null)
|
||||
? "<sub edited>(edited)</sub>"
|
||||
: ""),
|
||||
client: room.roomData.client,
|
||||
),
|
||||
topWidget: TopWidget(
|
||||
message,
|
||||
headers:
|
||||
room.roomData.client.headers,
|
||||
groupStatus: groupStatus,
|
||||
),
|
||||
message: message,
|
||||
showTime: true,
|
||||
index: index,
|
||||
),
|
||||
linkPreviewBuilder:
|
||||
(_, message, isSentByMe) => LinkPreview(
|
||||
text: message.text,
|
||||
backgroundColor: isSentByMe
|
||||
? theme.colorScheme.inversePrimary
|
||||
: theme
|
||||
.colorScheme
|
||||
.surfaceContainerLow,
|
||||
insidePadding: EdgeInsets.symmetric(
|
||||
vertical: 8,
|
||||
horizontal: 16,
|
||||
),
|
||||
linkPreviewData:
|
||||
message.linkPreviewData,
|
||||
onLinkPreviewDataFetched:
|
||||
(linkPreviewData) =>
|
||||
notifier.updateMessage(
|
||||
message,
|
||||
message.copyWith(
|
||||
linkPreviewData:
|
||||
linkPreviewData,
|
||||
),
|
||||
),
|
||||
),
|
||||
imageMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => FlyerChatImageMessage(
|
||||
topWidget: TopWidget(
|
||||
message,
|
||||
headers:
|
||||
room.roomData.client.headers,
|
||||
groupStatus: groupStatus,
|
||||
alwaysShow: true,
|
||||
),
|
||||
message: message,
|
||||
index: index,
|
||||
headers: room.roomData.client.headers,
|
||||
),
|
||||
fileMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => InkWell(
|
||||
onTap: () => showAboutDialog(
|
||||
context: context,
|
||||
), // TODO: Download
|
||||
child: FlyerChatFileMessage(
|
||||
topWidget: TopWidget(
|
||||
message,
|
||||
headers:
|
||||
room.roomData.client.headers,
|
||||
groupStatus: groupStatus,
|
||||
),
|
||||
message: message,
|
||||
index: index,
|
||||
),
|
||||
),
|
||||
systemMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => FlyerChatSystemMessage(
|
||||
message: message,
|
||||
index: index,
|
||||
),
|
||||
unsupportedMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => Text(
|
||||
"${message.authorId} sent ${message.metadata?["eventType"]}",
|
||||
style: theme.textTheme.labelSmall
|
||||
?.copyWith(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
systemMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => FlyerChatSystemMessage(
|
||||
message: message,
|
||||
index: index,
|
||||
),
|
||||
unsupportedMessageBuilder:
|
||||
(
|
||||
_,
|
||||
message,
|
||||
index, {
|
||||
required bool isSentByMe,
|
||||
MessageGroupStatus? groupStatus,
|
||||
}) => Text(
|
||||
"${message.authorId} sent ${message.metadata?["eventType"]}",
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
resolveUser: notifier.resolveUser,
|
||||
chatController: controller,
|
||||
),
|
||||
resolveUser: notifier.resolveUser,
|
||||
chatController: controller,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
if (memberListOpened.value == true && showMembersByDefault)
|
||||
MemberList(room.roomData),
|
||||
],
|
||||
),
|
||||
|
||||
endDrawer: showMembersByDefault
|
||||
? null
|
||||
: MemberList(room.roomData),
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@ class Sidebar extends HookConsumerWidget {
|
|||
(space) => NavigationRailDestination(
|
||||
icon: AvatarOrHash(
|
||||
space.avatar,
|
||||
fallback: space.icon,
|
||||
fallback: space.icon == null
|
||||
? null
|
||||
: Icon(space.icon),
|
||||
space.title,
|
||||
headers: space.client.headers,
|
||||
hasBadge:
|
||||
|
|
@ -126,7 +128,9 @@ class Sidebar extends HookConsumerWidget {
|
|||
appBar: AppBar(
|
||||
leading: AvatarOrHash(
|
||||
space.avatar,
|
||||
fallback: space.icon,
|
||||
fallback: space.icon == null
|
||||
? null
|
||||
: Icon(space.icon),
|
||||
space.title,
|
||||
headers: space.client.headers,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ import "package:flutter/material.dart";
|
|||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||
import "package:flutter_chat_ui/flutter_chat_ui.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:nexus/controllers/avatar_controller.dart";
|
||||
import "package:nexus/controllers/message_controller.dart";
|
||||
import "package:nexus/helpers/extensions/better_when.dart";
|
||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||
import "package:nexus/widgets/chat_page/quoted.dart";
|
||||
|
||||
class TopWidget extends ConsumerWidget {
|
||||
|
|
@ -62,11 +64,18 @@ class TopWidget extends ConsumerWidget {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 8,
|
||||
children: [
|
||||
Avatar(
|
||||
userId: replyMessage.authorId,
|
||||
headers: headers,
|
||||
size: 16,
|
||||
),
|
||||
ref
|
||||
.watch(
|
||||
AvatarController.provider(replyMessage.authorId),
|
||||
)
|
||||
.betterWhen(
|
||||
data: (avatar) => AvatarOrHash(
|
||||
avatar,
|
||||
replyMessage.metadata?["displayName"] ??
|
||||
replyMessage.authorId,
|
||||
headers: headers,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
replyMessage.metadata?["displayName"] ??
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue