feat: Jump to last read event

This commit is contained in:
Krille 2023-03-22 13:16:00 +01:00
parent c00a6e3d00
commit 5c70dd39bc
3 changed files with 62 additions and 16 deletions

View file

@ -2526,5 +2526,6 @@
"placeholders": {
"path": {}
}
}
},
"jumpToLastReadMessage": "Jump to last read message"
}

View file

@ -132,6 +132,11 @@ class ChatController extends State<Chat> {
bool showEmojiPicker = false;
bool get lastReadEventVisible =>
timeline == null ||
room!.fullyRead.isEmpty ||
timeline!.events.any((event) => event.eventId == room!.fullyRead);
void recreateChat() async {
final room = this.room;
final userId = room?.directChatMatrixID;
@ -190,9 +195,13 @@ class ChatController extends State<Chat> {
}
void requestFuture() async {
if (!timeline!.canRequestFuture) return;
final timeline = this.timeline;
if (timeline == null) return;
if (!timeline.canRequestFuture) return;
try {
await timeline!.requestFuture(historyCount: _loadHistoryCount);
final mostRecentEventId = timeline.events.first.eventId;
await timeline.requestFuture(historyCount: _loadHistoryCount);
setReadMarker(eventId: mostRecentEventId);
} catch (err) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@ -280,19 +289,29 @@ class ChatController extends State<Chat> {
Future<void>? _setReadMarkerFuture;
void setReadMarker([_]) {
if (_setReadMarkerFuture == null &&
(room!.hasNewMessages || room!.notificationCount > 0) &&
timeline != null &&
timeline!.events.isNotEmpty &&
Matrix.of(context).webHasFocus) {
Logs().v('Set read marker...');
// ignore: unawaited_futures
_setReadMarkerFuture = timeline!.setReadMarker().then((_) {
_setReadMarkerFuture = null;
});
room!.client.updateIosBadge();
void setReadMarker({String? eventId}) {
if (_setReadMarkerFuture != null) return;
if (lastReadEventVisible &&
!room!.hasNewMessages &&
room!.notificationCount == 0) {
return;
}
if (!Matrix.of(context).webHasFocus) return;
final timeline = this.timeline;
if (timeline == null || timeline.events.isEmpty) return;
if (eventId == null && !lastReadEventVisible) {
return;
}
eventId ??= timeline.events.first.eventId;
Logs().v('Set read marker...', eventId);
// ignore: unawaited_futures
_setReadMarkerFuture = timeline.setReadMarker(eventId).then((_) {
_setReadMarkerFuture = null;
});
room!.client.updateIosBadge();
}
@override
@ -759,6 +778,7 @@ class ChatController extends State<Chat> {
timeline = null;
});
await getTimeline();
setReadMarker(eventId: timeline!.events.first.eventId);
}
scrollController.jumpTo(0);
}

View file

@ -174,7 +174,7 @@ class ChatView extends StatelessWidget {
}
},
child: GestureDetector(
onTapDown: controller.setReadMarker,
onTapDown: (_) => controller.setReadMarker(),
behavior: HitTestBehavior.opaque,
child: StreamBuilder(
stream: controller.room!.onUpdate.stream
@ -351,6 +351,31 @@ class ChatView extends StatelessWidget {
],
),
),
if (!controller.lastReadEventVisible)
Positioned(
top: 16,
left: 0,
right: 0,
child: Center(
child: FloatingActionButton.extended(
icon: const Icon(Icons.arrow_upward_outlined),
onPressed: () => controller
.scrollToEventId(controller.room!.fullyRead),
label: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(L10n.of(context)!.jumpToLastReadMessage),
IconButton(
onPressed: () => controller.setReadMarker(
eventId: controller.room!.fullyRead,
),
icon: const Icon(Icons.close),
),
],
),
),
),
),
if (controller.dragging)
Container(
color: Theme.of(context)