diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 9a429f9f..864bc3ab 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2527,5 +2527,6 @@ "path": {} } }, - "jumpToLastReadMessage": "Jump to last read message" + "jumpToLastReadMessage": "Jump to last read message", + "readUpToHere": "Read up to here" } diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 4ef1fb57..e6f77f40 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -53,6 +53,8 @@ class ChatController extends State { MatrixState? matrix; + String? readMarkerEventId; + String? get roomId => context.vRouter.pathParameters['roomid']; final AutoScrollController scrollController = AutoScrollController(); diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index 0d5e7796..71e5dfd2 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -123,6 +123,8 @@ class ChatEventList extends StatelessWidget { selected: controller.selectedEvents .any((e) => e.eventId == event.eventId), timeline: controller.timeline!, + displayReadMarker: + controller.readMarkerEventId == event.eventId, nextEvent: i < controller.timeline!.events.length ? controller.timeline!.events[i] : null, diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index db0fb9b1..ad3f3f0b 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -143,6 +143,7 @@ class ChatView extends StatelessWidget { final client = controller.matrix!.client; controller.sendingClient ??= client; controller.room = controller.sendingClient!.getRoomById(controller.roomId!); + controller.readMarkerEventId ??= controller.room!.fullyRead; if (controller.room == null) { return Scaffold( appBar: AppBar( diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index 1b6c1510..836e70a2 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; import 'package:swipe_to_action/swipe_to_action.dart'; @@ -18,6 +19,7 @@ import 'verification_request_content.dart'; class Message extends StatelessWidget { final Event event; final Event? nextEvent; + final bool displayReadMarker; final void Function(Event)? onSelect; final void Function(Event)? onAvatarTab; final void Function(Event)? onInfoTab; @@ -30,6 +32,7 @@ class Message extends StatelessWidget { const Message( this.event, { this.nextEvent, + this.displayReadMarker = false, this.longPressSelect = false, this.onSelect, this.onInfoTab, @@ -303,7 +306,8 @@ class Message extends StatelessWidget { Widget container; if (event.hasAggregatedEvents(timeline, RelationshipTypes.reaction) || displayTime || - selected) { + selected || + displayReadMarker) { container = Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: @@ -347,6 +351,17 @@ class Message extends StatelessWidget { ), child: MessageReactions(event, timeline), ), + if (displayReadMarker) + Row( + children: [ + const Expanded(child: Divider()), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text(L10n.of(context)!.readUpToHere), + ), + const Expanded(child: Divider()), + ], + ), ], ); } else { diff --git a/lib/pages/chat/input_bar.dart b/lib/pages/chat/input_bar.dart index fa17c7aa..ecd00c2c 100644 --- a/lib/pages/chat/input_bar.dart +++ b/lib/pages/chat/input_bar.dart @@ -458,11 +458,12 @@ class InputBar extends StatelessWidget { buildSuggestion(c, s, Matrix.of(context).client), onSuggestionSelected: (Map suggestion) => insertSuggestion(context, suggestion), - errorBuilder: (BuildContext context, Object? error) => const SizedBox.shrink(), + errorBuilder: (BuildContext context, Object? error) => + const SizedBox.shrink(), loadingBuilder: (BuildContext context) => const SizedBox.shrink(), // fix loading briefly flickering a dark box - noItemsFoundBuilder: (BuildContext context) => - const SizedBox.shrink(), // fix loading briefly showing no suggestions + noItemsFoundBuilder: (BuildContext context) => const SizedBox + .shrink(), // fix loading briefly showing no suggestions ), ), ); diff --git a/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart b/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart index 6897cc85..1e254065 100644 --- a/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart +++ b/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart @@ -35,7 +35,8 @@ class MultipleEmotesSettingsView extends StatelessWidget { final keys = packs.keys.toList(); keys.sort(); return ListView.separated( - separatorBuilder: (BuildContext context, int i) => const SizedBox.shrink(), + separatorBuilder: (BuildContext context, int i) => + const SizedBox.shrink(), itemCount: keys.length, itemBuilder: (BuildContext context, int i) { final event = packs[keys[i]];