From 1c5a632d2a6b87d6462edb5d3c6b26f61d935e8c Mon Sep 17 00:00:00 2001 From: OfficialDakari Date: Sun, 26 Oct 2025 20:58:25 +0500 Subject: [PATCH] update thread card --- .../reports/problems/problems-report.html | 2 +- lib/pages/chat/chat.dart | 97 ++++++++++++------- lib/pages/chat/chat_event_list.dart | 5 +- lib/pages/chat/events/poll_content.dart | 43 +++++--- 4 files changed, 96 insertions(+), 51 deletions(-) diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html index 2e4e670..f85479d 100644 --- a/android/build/reports/problems/problems-report.html +++ b/android/build/reports/problems/problems-report.html @@ -650,7 +650,7 @@ code + .copy-button { diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 96d7fc3..b6eef99 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -380,14 +380,32 @@ class ChatController extends State scrollUpBannerEventId = eventId; }); - void updateView() { + Future updateView() async { if (!mounted) return; setReadMarker(); + await updateThreads(); setState(() {}); } + Future updateThreads() async { + if (timeline?.events == null) return; + final lastEvent = timeline?.events[timeline!.events.length - 1]; + + if (lastEvent == null) return; + if (lastEvent.relationshipType == RelationshipTypes.thread && + lastEvent.relationshipEventId != null) { + final thread = await room.client.database + .getThread(room.id, lastEvent.relationshipEventId!, room.client); + if (thread != null) { + setState(() { + threads?[lastEvent.eventId] = thread; + }); + } + } + } + Future? loadTimelineFuture; - Map? threads; + Map? threads = {}; int? animateInEventIndex; @@ -437,9 +455,10 @@ class ChatController extends State Logs().v("Thread timeline loaded"); } catch (e, s) { Logs().w( - 'Unable to load timeline on event ID $eventContextId (in thread)', - e, - s); + 'Unable to load timeline on event ID $eventContextId (in thread)', + e, + s, + ); if (!mounted) return; timeline = await thread!.getTimeline( onUpdate: updateView, @@ -595,13 +614,15 @@ class ChatController extends State } // ignore: unawaited_futures - room.sendTextEvent(sendController.text, - inReplyTo: replyEvent, - editEventId: editEvent?.eventId, - parseCommands: parseCommands, - threadRootEventId: thread?.rootEvent.eventId, - threadLastEventId: - thread?.lastEvent?.eventId ?? thread?.rootEvent.eventId); + room.sendTextEvent( + sendController.text, + inReplyTo: replyEvent, + editEventId: editEvent?.eventId, + parseCommands: parseCommands, + threadRootEventId: thread?.rootEvent.eventId, + threadLastEventId: + thread?.lastEvent?.eventId ?? thread?.rootEvent.eventId, + ); sendController.value = TextEditingValue( text: pendingText, selection: const TextSelection.collapsed(offset: 0), @@ -821,7 +842,8 @@ class ChatController extends State final reports = await mx.client.getEventReports(); final report = reports.firstWhere( - (rep) => rep['room_id'] == roomId && rep['event_id'] == event.eventId); + (rep) => rep['room_id'] == roomId && rep['event_id'] == event.eventId, + ); final recoveredEvent = await mx.client.getReportedEvent(report['id']); if (recoveredEvent == null) { @@ -831,15 +853,17 @@ class ChatController extends State return; } - Navigator.of(context).push(MaterialPageRoute( - builder: (BuildContext ctx) { - return RecoveredEventDialog( - event: recoveredEvent, - timeline: timeline!, - ); - }, - fullscreenDialog: true, - )); + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext ctx) { + return RecoveredEventDialog( + event: recoveredEvent, + timeline: timeline!, + ); + }, + fullscreenDialog: true, + ), + ); } void translateEventAction() async { @@ -854,7 +878,9 @@ class ChatController extends State final content = {...event.content}; try { text = await Translator.translate( - text, PlatformDispatcher.instance.locale.languageCode); + text, + PlatformDispatcher.instance.locale.languageCode, + ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(L10n.of(context).errorTranslatingMessage)), @@ -867,19 +893,24 @@ class ChatController extends State content['body'] = text; } content['xyz.extera.translated'] = true; - Navigator.of(context).push(new MaterialPageRoute( + Navigator.of(context).push( + new MaterialPageRoute( builder: (BuildContext ctx) { return TranslatedEventDialog( - event: new Event( - content: content, - type: 'm.room.message', - eventId: event.eventId, - senderId: event.senderId, - originServerTs: event.originServerTs, - room: room), - timeline: timeline!); + event: new Event( + content: content, + type: 'm.room.message', + eventId: event.eventId, + senderId: event.senderId, + originServerTs: event.originServerTs, + room: room, + ), + timeline: timeline!, + ); }, - fullscreenDialog: true)); + fullscreenDialog: true, + ), + ); } void reportEventAction() async { diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index 178dc72..f807fd4 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -39,6 +39,7 @@ class ChatEventList extends StatelessWidget { final events = timeline.events.filterByVisibleInGui().filterByThreaded(controller.thread != null); final animateInEventIndex = controller.animateInEventIndex; + final threads = controller.room.threads; // create a map of eventId --> index to greatly improve performance of // ListView's findChildIndexCallback @@ -121,8 +122,8 @@ class ChatEventList extends StatelessWidget { timeline.events.length > animateInEventIndex && event == timeline.events[animateInEventIndex]; - final thread = (controller.threads?.containsKey(event.eventId) ?? false) - ? controller.threads![event.eventId] + final thread = threads.containsKey(event.eventId) + ? threads[event.eventId] : null; return AutoScrollTag( diff --git a/lib/pages/chat/events/poll_content.dart b/lib/pages/chat/events/poll_content.dart index 579f63e..33fb26b 100644 --- a/lib/pages/chat/events/poll_content.dart +++ b/lib/pages/chat/events/poll_content.dart @@ -58,8 +58,12 @@ class PollWidgetState extends State { final rel = await Matrix.of(context) .client - .getRelatingEventsWithRelTypeAndEventType(room.id, widget.event.eventId, - "m.reference", "org.matrix.msc3381.poll.response"); + .getRelatingEventsWithRelTypeAndEventType( + room.id, + widget.event.eventId, + "m.reference", + "org.matrix.msc3381.poll.response", + ); // Get all poll response events for this poll final responses = rel.chunk; @@ -90,8 +94,12 @@ class PollWidgetState extends State { final rel = await Matrix.of(context) .client - .getRelatingEventsWithRelTypeAndEventType(room.id, pollEventId, - "m.reference", "org.matrix.msc3381.poll.response"); + .getRelatingEventsWithRelTypeAndEventType( + room.id, + pollEventId, + "m.reference", + "org.matrix.msc3381.poll.response", + ); // Get all poll response events for this poll final responses = rel.chunk; @@ -124,15 +132,18 @@ class PollWidgetState extends State { final room = widget.event.room; // Send poll response event - await room.sendEvent({ - 'm.relates_to': { - 'rel_type': 'm.reference', - 'event_id': widget.event.eventId, + await room.sendEvent( + { + 'm.relates_to': { + 'rel_type': 'm.reference', + 'event_id': widget.event.eventId, + }, + 'org.matrix.msc3381.poll.response': { + 'answers': answers, + }, }, - 'org.matrix.msc3381.poll.response': { - 'answers': answers, - }, - }, type: 'org.matrix.msc3381.poll.response'); + type: 'org.matrix.msc3381.poll.response', + ); setState(() { selectedAnswers = answers; @@ -369,9 +380,11 @@ class PollWidgetState extends State { height: 16, child: CircularProgressIndicator(strokeWidth: 2), ) - : Text(hasVoted - ? L10n.of(context).changeVote - : L10n.of(context).vote), + : Text( + hasVoted + ? L10n.of(context).changeVote + : L10n.of(context).vote, + ), ), const Spacer(),