working reply rendering
This commit is contained in:
parent
7761ca73fd
commit
a72d696f49
3 changed files with 81 additions and 35 deletions
|
|
@ -31,6 +31,7 @@ abstract class Event with _$Event {
|
||||||
String? redactedBy,
|
String? redactedBy,
|
||||||
String? relatesTo,
|
String? relatesTo,
|
||||||
String? relationType,
|
String? relationType,
|
||||||
|
String? replyTo,
|
||||||
String? decryptionError,
|
String? decryptionError,
|
||||||
String? sendError,
|
String? sendError,
|
||||||
@Default(IMap.empty()) IMap<String, int> reactions,
|
@Default(IMap.empty()) IMap<String, int> reactions,
|
||||||
|
|
@ -43,6 +44,10 @@ abstract class Event with _$Event {
|
||||||
|
|
||||||
factory Event.fromJson(Map<String, dynamic> json) =>
|
factory Event.fromJson(Map<String, dynamic> json) =>
|
||||||
_$EventFromJson(json).copyWith(
|
_$EventFromJson(json).copyWith(
|
||||||
|
replyTo:
|
||||||
|
((json["decrypted"] ?? json["content"])["m.new_content"] ??
|
||||||
|
json["decrypted"] ??
|
||||||
|
json["content"])?["m.relates_to"]?["m.in_reply_to"]?["event_id"],
|
||||||
content: Content.fromEventJson(
|
content: Content.fromEventJson(
|
||||||
(json["decrypted"] ?? json["content"])["m.new_content"] ??
|
(json["decrypted"] ?? json["content"])["m.new_content"] ??
|
||||||
json["decrypted"] ??
|
json["decrypted"] ??
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import "package:nexus/models/event.dart";
|
||||||
import "package:nexus/models/requests/get_event_request.dart";
|
import "package:nexus/models/requests/get_event_request.dart";
|
||||||
import "package:nexus/widgets/expandable_image.dart";
|
import "package:nexus/widgets/expandable_image.dart";
|
||||||
import "package:nexus/widgets/html/html.dart";
|
import "package:nexus/widgets/html/html.dart";
|
||||||
import "package:nexus/widgets/html/quoted.dart";
|
|
||||||
import "package:nexus/widgets/lazy_loading/message_avatar.dart";
|
import "package:nexus/widgets/lazy_loading/message_avatar.dart";
|
||||||
import "package:nexus/widgets/lazy_loading/message_displayname.dart";
|
import "package:nexus/widgets/lazy_loading/message_displayname.dart";
|
||||||
import "package:nexus/widgets/link_preview.dart";
|
import "package:nexus/widgets/link_preview.dart";
|
||||||
|
|
@ -110,50 +109,76 @@ class EventRenderer extends ConsumerWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Card(
|
Card(
|
||||||
color:
|
color: textOnly
|
||||||
ref.watch(
|
? Colors.transparent
|
||||||
ClientStateController.provider.select(
|
: ref.watch(
|
||||||
(value) => value?.userId,
|
ClientStateController.provider.select(
|
||||||
),
|
(value) => value?.userId,
|
||||||
) ==
|
),
|
||||||
event.sender
|
) ==
|
||||||
|
event.sender
|
||||||
? (event.eventId.startsWith("~")
|
? (event.eventId.startsWith("~")
|
||||||
? colorScheme.onPrimary
|
? colorScheme.onPrimary
|
||||||
: colorScheme.primaryContainer)
|
: colorScheme.primaryContainer)
|
||||||
: colorScheme.surfaceContainer,
|
: colorScheme.surfaceContainer,
|
||||||
|
elevation: textOnly ? 0 : null,
|
||||||
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(12),
|
padding: textOnly
|
||||||
|
? EdgeInsets.zero
|
||||||
|
: EdgeInsets.all(12),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (event.relationType == "m.in_reply_to" &&
|
if (event.replyTo != null)
|
||||||
event.relatesTo != null)
|
Card(
|
||||||
Quoted(
|
margin: EdgeInsets.only(bottom: 8),
|
||||||
ref
|
color: theme.colorScheme.surfaceContainer,
|
||||||
.watch(
|
child: InkWell(
|
||||||
|
onTap: onTapReply,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsGeometry.symmetric(
|
||||||
|
vertical: 8,
|
||||||
|
horizontal: 12,
|
||||||
|
),
|
||||||
|
child: switch (ref.watch(
|
||||||
EventController.provider(
|
EventController.provider(
|
||||||
GetEventRequest(
|
GetEventRequest(
|
||||||
roomId: event.roomId,
|
roomId: event.roomId,
|
||||||
eventId: event.relatesTo!,
|
eventId: event.replyTo!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)) {
|
||||||
.when(
|
AsyncData(:final value?) ||
|
||||||
data: (replyEvent) => replyEvent == null
|
AsyncLoading(:final value?) => Row(
|
||||||
? SizedBox.shrink()
|
spacing: 8,
|
||||||
: EventRenderer(
|
children: [
|
||||||
replyEvent,
|
MessageAvatar(event, height: 24),
|
||||||
|
MessageDisplayname(
|
||||||
|
event,
|
||||||
|
style: TextStyle(
|
||||||
|
color:
|
||||||
|
theme.colorScheme.primary,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: EventRenderer(
|
||||||
|
value,
|
||||||
textOnly: true,
|
textOnly: true,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
error: (_, _) => Text(
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
AsyncError _ => Text(
|
||||||
"An error occurred while fetching the reply",
|
"An error occurred while fetching the reply",
|
||||||
style: errorStyle,
|
style: errorStyle,
|
||||||
),
|
),
|
||||||
loading: () =>
|
_ => Text("Fetching event..."),
|
||||||
Text("Fetching event..."),
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
switch (event.content) {
|
switch (event.content) {
|
||||||
EncryptedContent() => Text(
|
EncryptedContent() => Text(
|
||||||
|
|
@ -408,6 +433,8 @@ class EventRenderer extends ConsumerWidget {
|
||||||
? textOnly
|
? textOnly
|
||||||
? Text("Unknown event type", style: errorStyle)
|
? Text("Unknown event type", style: errorStyle)
|
||||||
: SizedBox.shrink()
|
: SizedBox.shrink()
|
||||||
|
: textOnly
|
||||||
|
? child
|
||||||
: GestureDetector(
|
: GestureDetector(
|
||||||
onSecondaryTapUp: contextMenuCallback,
|
onSecondaryTapUp: contextMenuCallback,
|
||||||
onLongPressStart: contextMenuCallback,
|
onLongPressStart: contextMenuCallback,
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class RoomChat extends HookConsumerWidget {
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final relatedEvent = useState<Event?>(null);
|
final relatedEvent = useState<Event?>(null);
|
||||||
final relationType = useState(RelationType.reply);
|
final relationType = useState(RelationType.reply);
|
||||||
|
final flashingEvent = useState<String?>(null);
|
||||||
|
|
||||||
final memberListOpened = useState<bool>(showMembersByDefault);
|
final memberListOpened = useState<bool>(showMembersByDefault);
|
||||||
|
|
||||||
|
|
@ -329,21 +330,34 @@ class RoomChat extends HookConsumerWidget {
|
||||||
value[index],
|
value[index],
|
||||||
EventRenderer(
|
EventRenderer(
|
||||||
value[index],
|
value[index],
|
||||||
onTapReply: () =>
|
onTapReply: () async {
|
||||||
listController.value.animateToItem(
|
final replyId = value[index].replyTo;
|
||||||
index: index,
|
listController.value.animateToItem(
|
||||||
scrollController: scrollController,
|
index: value.indexWhere(
|
||||||
alignment: 0.5,
|
(element) => element.eventId == replyId,
|
||||||
duration: (_) =>
|
|
||||||
Duration(milliseconds: 250),
|
|
||||||
curve: (_) => Curves.easeInOut,
|
|
||||||
),
|
),
|
||||||
|
scrollController: scrollController,
|
||||||
|
alignment: 0.5,
|
||||||
|
duration: (_) =>
|
||||||
|
Duration(milliseconds: 250),
|
||||||
|
curve: (_) => Curves.easeInOut,
|
||||||
|
);
|
||||||
|
flashingEvent.value = replyId;
|
||||||
|
await Future.delayed(
|
||||||
|
Duration(seconds: 1),
|
||||||
|
() {
|
||||||
|
if (flashingEvent.value == replyId) {
|
||||||
|
flashingEvent.value = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
getEventOptions: getEventOptions,
|
getEventOptions: getEventOptions,
|
||||||
// TODO: Reimplement grouping
|
// TODO: Reimplement grouping
|
||||||
isGrouped: false,
|
isGrouped: false,
|
||||||
),
|
),
|
||||||
// TODO: Reimplement flashing
|
isFlashing:
|
||||||
isFlashing: false,
|
flashingEvent.value == value[index].eventId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue