fix newlines, wip edits
This commit is contained in:
parent
4424e27276
commit
9663995114
6 changed files with 79 additions and 33 deletions
|
|
@ -8,6 +8,7 @@ import "package:nexus/controllers/events_controller.dart";
|
|||
import "package:nexus/helpers/extensions/event_to_message.dart";
|
||||
import "package:nexus/helpers/extensions/list_to_messages.dart";
|
||||
import "package:fluttertagger/fluttertagger.dart" as tagger;
|
||||
import "package:nexus/models/relation_type.dart";
|
||||
|
||||
class RoomChatController extends AsyncNotifier<ChatController> {
|
||||
final Room room;
|
||||
|
|
@ -37,7 +38,10 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
|||
(element) => element.id == event.relationshipEventId,
|
||||
);
|
||||
if (oldMessage == null || message == null) return;
|
||||
return await updateMessage(oldMessage, message);
|
||||
return await updateMessage(
|
||||
oldMessage,
|
||||
message.copyWith(id: oldMessage.id),
|
||||
);
|
||||
}
|
||||
if (message != null) {
|
||||
return await insertMessage(message);
|
||||
|
|
@ -97,7 +101,8 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
|||
Future<void> send(
|
||||
String message, {
|
||||
required Iterable<tagger.Tag> tags,
|
||||
Message? replyTo,
|
||||
required RelationType relationType,
|
||||
Message? relation,
|
||||
}) async {
|
||||
var taggedMessage = message;
|
||||
|
||||
|
|
@ -113,7 +118,10 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
|||
|
||||
await room.sendTextEvent(
|
||||
taggedMessage,
|
||||
inReplyTo: replyTo == null ? null : await room.getEventById(replyTo.id),
|
||||
editEventId: relationType == RelationType.edit ? relation?.id : null,
|
||||
inReplyTo: (relationType == RelationType.reply && relation != null)
|
||||
? await room.getEventById(relation.id)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ extension EventToMessage on Event {
|
|||
newContent?["formatted_body"] ??
|
||||
newContent?["body"] ??
|
||||
event.content["formatted_body"] ??
|
||||
event.content["body"],
|
||||
event.content["body"] ??
|
||||
"",
|
||||
"reply": await replyEvent?.toMessage(mustBeText: true),
|
||||
"body": newContent?["body"] ?? event.content["body"],
|
||||
"eventType": event.type,
|
||||
"avatarUrl": sender.avatarUrl.toString(),
|
||||
"displayName": sender.displayName ?? sender.id,
|
||||
|
|
@ -69,7 +71,7 @@ extension EventToMessage on Event {
|
|||
return switch (type) {
|
||||
EventTypes.Encrypted => asText.copyWith(
|
||||
text: "Unable to decrypt message.",
|
||||
metadata: {"formatted": "Unable to decrypt message.", ...metadata},
|
||||
metadata: {...metadata, "formatted": "Unable to decrypt message."},
|
||||
),
|
||||
(EventTypes.Sticker || EventTypes.Message) => switch (messageType) {
|
||||
(MessageTypes.Sticker || MessageTypes.Image) => Message.image(
|
||||
|
|
|
|||
1
lib/models/relation_type.dart
Normal file
1
lib/models/relation_type.dart
Normal file
|
|
@ -0,0 +1 @@
|
|||
enum RelationType { edit, reply }
|
||||
|
|
@ -7,15 +7,18 @@ import "package:fluttertagger/fluttertagger.dart";
|
|||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||
import "package:matrix/matrix.dart";
|
||||
import "package:nexus/controllers/room_chat_controller.dart";
|
||||
import "package:nexus/models/relation_type.dart";
|
||||
import "package:nexus/widgets/chat_page/mention_overlay.dart";
|
||||
import "package:nexus/widgets/chat_page/reply_preview.dart";
|
||||
import "package:nexus/widgets/chat_page/relation_preview.dart";
|
||||
|
||||
class ChatBox extends HookConsumerWidget {
|
||||
final Message? replyToMessage;
|
||||
final Message? relatedMessage;
|
||||
final RelationType relationType;
|
||||
final VoidCallback onDismiss;
|
||||
final Room room;
|
||||
const ChatBox({
|
||||
required this.replyToMessage,
|
||||
required this.relatedMessage,
|
||||
required this.relationType,
|
||||
required this.onDismiss,
|
||||
required this.room,
|
||||
super.key,
|
||||
|
|
@ -28,14 +31,25 @@ class ChatBox extends HookConsumerWidget {
|
|||
final triggerCharacter = useState("");
|
||||
final query = useState("");
|
||||
|
||||
if (relationType == RelationType.edit &&
|
||||
relatedMessage is TextMessage &&
|
||||
controller.value.text.isEmpty) {
|
||||
final text = (relatedMessage as TextMessage).text;
|
||||
controller.value.text = relatedMessage?.replyToMessageId == null
|
||||
? text
|
||||
: text.split("\n\n").sublist(1).join("\n\n");
|
||||
}
|
||||
|
||||
void send() {
|
||||
ref
|
||||
.watch(RoomChatController.provider(room).notifier)
|
||||
.send(
|
||||
controller.value.formattedText,
|
||||
replyTo: replyToMessage,
|
||||
relation: relatedMessage,
|
||||
relationType: relationType,
|
||||
tags: controller.value.tags,
|
||||
);
|
||||
onDismiss();
|
||||
controller.value.text = "";
|
||||
}
|
||||
|
||||
|
|
@ -71,8 +85,9 @@ class ChatBox extends HookConsumerWidget {
|
|||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
child: Column(
|
||||
children: [
|
||||
ReplyPreview(
|
||||
replyToMessage: replyToMessage,
|
||||
RelationPreview(
|
||||
relatedMessage: relatedMessage,
|
||||
relationType: relationType,
|
||||
onDismiss: onDismiss,
|
||||
room: room,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -4,14 +4,17 @@ import "package:hooks_riverpod/hooks_riverpod.dart";
|
|||
import "package:matrix/matrix.dart";
|
||||
import "package:nexus/controllers/avatar_controller.dart";
|
||||
import "package:nexus/helpers/extensions/get_headers.dart";
|
||||
import "package:nexus/models/relation_type.dart";
|
||||
import "package:nexus/widgets/avatar_or_hash.dart";
|
||||
|
||||
class ReplyPreview extends ConsumerWidget {
|
||||
final Message? replyToMessage;
|
||||
class RelationPreview extends ConsumerWidget {
|
||||
final Message? relatedMessage;
|
||||
final RelationType relationType;
|
||||
final VoidCallback onDismiss;
|
||||
final Room room;
|
||||
const ReplyPreview({
|
||||
required this.replyToMessage,
|
||||
const RelationPreview({
|
||||
required this.relatedMessage,
|
||||
required this.relationType,
|
||||
required this.onDismiss,
|
||||
required this.room,
|
||||
super.key,
|
||||
|
|
@ -19,9 +22,9 @@ class ReplyPreview extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
if (relatedMessage == null) return SizedBox.shrink();
|
||||
final theme = Theme.of(context);
|
||||
|
||||
if (replyToMessage == null) return SizedBox.shrink();
|
||||
return Container(
|
||||
color: theme.colorScheme.surfaceContainerHigh,
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
|
|
@ -29,34 +32,40 @@ class ReplyPreview extends ConsumerWidget {
|
|||
spacing: 8,
|
||||
children: [
|
||||
SizedBox(width: 4),
|
||||
if (relationType == RelationType.edit)
|
||||
Text(
|
||||
"Editing message:",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
AvatarOrHash(
|
||||
ref
|
||||
.watch(
|
||||
AvatarController.provider(
|
||||
replyToMessage!.metadata!["avatarUrl"],
|
||||
relatedMessage!.metadata!["avatarUrl"],
|
||||
),
|
||||
)
|
||||
.whenOrNull(data: (data) => data),
|
||||
replyToMessage!.metadata!["displayName"].toString(),
|
||||
relatedMessage!.metadata!["displayName"].toString(),
|
||||
headers: room.client.headers,
|
||||
height: 16,
|
||||
),
|
||||
Text(
|
||||
replyToMessage!.metadata?["displayName"] ??
|
||||
replyToMessage!.authorId,
|
||||
relatedMessage!.metadata?["displayName"] ??
|
||||
relatedMessage!.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(),
|
||||
child: Text(
|
||||
(relatedMessage is TextMessage)
|
||||
? (relatedMessage as TextMessage).text
|
||||
: relatedMessage?.metadata?["body"] ??
|
||||
relatedMessage?.metadata?["eventType"],
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.labelMedium,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: onDismiss,
|
||||
|
|
@ -13,6 +13,7 @@ import "package:nexus/controllers/room_chat_controller.dart";
|
|||
import "package:nexus/helpers/extensions/better_when.dart";
|
||||
import "package:nexus/helpers/extensions/get_headers.dart";
|
||||
import "package:nexus/helpers/extensions/show_context_menu.dart";
|
||||
import "package:nexus/models/relation_type.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/member_list.dart";
|
||||
|
|
@ -34,6 +35,7 @@ class RoomChat extends HookConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final replyToMessage = useState<Message?>(null);
|
||||
final memberListOpened = useState<bool>(showMembersByDefault);
|
||||
final relationType = useState(RelationType.reply);
|
||||
final theme = Theme.of(context);
|
||||
final danger = theme.colorScheme.error;
|
||||
|
||||
|
|
@ -56,7 +58,10 @@ class RoomChat extends HookConsumerWidget {
|
|||
|
||||
List<PopupMenuEntry> getMessageOptions(Message message) => [
|
||||
PopupMenuItem(
|
||||
onTap: () => replyToMessage.value = message,
|
||||
onTap: () {
|
||||
replyToMessage.value = message;
|
||||
relationType.value = RelationType.reply;
|
||||
},
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.reply),
|
||||
title: Text("Reply"),
|
||||
|
|
@ -64,7 +69,10 @@ class RoomChat extends HookConsumerWidget {
|
|||
),
|
||||
if (message.authorId == room.roomData.client.userID)
|
||||
PopupMenuItem(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
replyToMessage.value = message;
|
||||
relationType.value = RelationType.edit;
|
||||
},
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.edit),
|
||||
title: Text("Edit"),
|
||||
|
|
@ -217,7 +225,8 @@ class RoomChat extends HookConsumerWidget {
|
|||
bottomPadding: 72,
|
||||
),
|
||||
composerBuilder: (_) => ChatBox(
|
||||
replyToMessage: replyToMessage.value,
|
||||
relationType: relationType.value,
|
||||
relatedMessage: replyToMessage.value,
|
||||
onDismiss: () =>
|
||||
replyToMessage.value = null,
|
||||
room: room.roomData,
|
||||
|
|
@ -231,7 +240,8 @@ class RoomChat extends HookConsumerWidget {
|
|||
MessageGroupStatus? groupStatus,
|
||||
}) => FlyerChatTextMessage(
|
||||
customWidget: Html(
|
||||
message.metadata?["formatted"]
|
||||
(message.metadata?["formatted"]
|
||||
as String)
|
||||
.replaceAllMapped(
|
||||
RegExp(
|
||||
regexLink,
|
||||
|
|
@ -239,7 +249,8 @@ class RoomChat extends HookConsumerWidget {
|
|||
),
|
||||
(m) =>
|
||||
"<a href=\"${m.group(0)!}\">${m.group(0)!}</a>",
|
||||
) +
|
||||
)
|
||||
.replaceAll("\n", "<br/>") +
|
||||
((message.editedAt != null)
|
||||
? "<sub edited>(edited)</sub>"
|
||||
: ""),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue