diff --git a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart index e70ae4a4..c25807bc 100644 --- a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart +++ b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart @@ -180,7 +180,7 @@ class TimelineOverlayState extends State { }); } - void setAttatchedToBottom(bool value) { + void setAttachedToBottom(bool value) { if (value != isAttatchedToBottom) { setState(() { isAttatchedToBottom = value; diff --git a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart index ba17f7a9..9e2501e0 100644 --- a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart +++ b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart @@ -28,6 +28,7 @@ class _RoomTimelineWidgetState extends State { key: timelineViewKey, timeline: widget.timeline, onViewScrolled: onViewScrolled, + onAttachedToBottom: onAttachedToBottom, setReplyingEvent: widget.setReplyingEvent, setEditingEvent: widget.setEditingEvent, ); @@ -50,6 +51,14 @@ class _RoomTimelineWidgetState extends State { if (offset > maxScrollExtent - loadingThreshold && loadingHistory == null) { loadMoreHistory(); } + + if (state?.attachedToBottom == true) {} + } + + void onAttachedToBottom() { + if (widget.timeline.events.isNotEmpty) { + widget.timeline.markAsRead(widget.timeline.events.first); + } } void loadMoreHistory() async { diff --git a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart index 4c963079..3c7c0727 100644 --- a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart +++ b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart @@ -18,11 +18,13 @@ class RoomTimelineWidgetView extends StatefulWidget { this.onViewScrolled, this.setEditingEvent, this.setReplyingEvent, + this.onAttachedToBottom, super.key}); final Timeline timeline; final Function(TimelineEvent event)? markAsRead; final Function(TimelineEvent? event)? setReplyingEvent; final Function(TimelineEvent? event)? setEditingEvent; + final Function()? onAttachedToBottom; final Function({required double offset, required double maxScrollExtent})? onViewScrolled; @@ -53,6 +55,8 @@ class RoomTimelineWidgetViewState extends State { late List subscriptions; + bool wasLastScrollAttachedToBottom = false; + bool get attachedToBottom => controller.hasClients ? controller.offset - controller.positions.first.minScrollExtent < 50 || animatingToBottom @@ -147,6 +151,7 @@ class RoomTimelineWidgetViewState extends State { double extent = controller.position.minScrollExtent; controller = ScrollController(initialScrollOffset: extent); controller.addListener(onScroll); + widget.onAttachedToBottom?.call(); setState(() { firstFrame = false; }); @@ -159,14 +164,21 @@ class RoomTimelineWidgetViewState extends State { maxScrollExtent: controller.position.maxScrollExtent); var overlayState = overlayKey.currentState as TimelineOverlayState?; - overlayState?.setAttatchedToBottom(attachedToBottom); + overlayState?.setAttachedToBottom(attachedToBottom); + + if (wasLastScrollAttachedToBottom == false && attachedToBottom) { + widget.onAttachedToBottom?.call(); + } + + wasLastScrollAttachedToBottom = attachedToBottom; } void animateAndSnapToBottom() { controller.position.hold(() {}); var overlayState = overlayKey.currentState as TimelineOverlayState?; - overlayState?.setAttatchedToBottom(attachedToBottom); + overlayState?.setAttachedToBottom(attachedToBottom); + widget.onAttachedToBottom?.call(); animatingToBottom = true;