refactor: Enhance logic when to mark room as read

pull/920/head
krille-chan 1 year ago
parent 03511a1e8d
commit 0cf6a1d74a
No known key found for this signature in database

@ -252,6 +252,7 @@ class ChatController extends State<ChatPageWithRoom>
setState(() => _scrolledUp = true); setState(() => _scrolledUp = true);
} else if (scrollController.position.pixels <= 0 && _scrolledUp == true) { } else if (scrollController.position.pixels <= 0 && _scrolledUp == true) {
setState(() => _scrolledUp = false); setState(() => _scrolledUp = false);
setReadMarker();
} }
if (scrollController.position.pixels == 0 || if (scrollController.position.pixels == 0 ||
@ -275,6 +276,7 @@ class ChatController extends State<ChatPageWithRoom>
_loadDraft(); _loadDraft();
super.initState(); super.initState();
sendingClient = Matrix.of(context).client; sendingClient = Matrix.of(context).client;
WidgetsBinding.instance.addObserver(this);
_tryLoadTimeline(); _tryLoadTimeline();
} }
@ -286,7 +288,6 @@ class ChatController extends State<ChatPageWithRoom>
if (fullyRead.isEmpty) return; if (fullyRead.isEmpty) return;
if (timeline!.events.any((event) => event.eventId == fullyRead)) { if (timeline!.events.any((event) => event.eventId == fullyRead)) {
Logs().v('Scroll up to visible event', fullyRead); Logs().v('Scroll up to visible event', fullyRead);
setReadMarker();
return; return;
} }
if (!mounted) return; if (!mounted) return;
@ -317,6 +318,11 @@ class ChatController extends State<ChatPageWithRoom>
int? animateInEventIndex; int? animateInEventIndex;
void onInsert(int i) { void onInsert(int i) {
if (timeline?.events[i].status == EventStatus.synced) {
final index = timeline!.events.firstIndexWhereNotError;
if (i == index) setReadMarker(eventId: timeline?.events[i].eventId);
}
// setState will be called by updateView() anyway // setState will be called by updateView() anyway
animateInEventIndex = i; animateInEventIndex = i;
} }
@ -350,6 +356,7 @@ class ChatController extends State<ChatPageWithRoom>
} }
timeline!.requestKeys(onlineKeyBackupOnly: false); timeline!.requestKeys(onlineKeyBackupOnly: false);
if (room.markedUnread) room.markUnread(false); if (room.markedUnread) room.markUnread(false);
setReadMarker();
// when the scroll controller is attached we want to scroll to an event id, if specified // when the scroll controller is attached we want to scroll to an event id, if specified
// and update the scroll controller...which will trigger a request history, if the // and update the scroll controller...which will trigger a request history, if the
@ -371,7 +378,6 @@ class ChatController extends State<ChatPageWithRoom>
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
if (state != AppLifecycleState.resumed) return; if (state != AppLifecycleState.resumed) return;
if (!_scrolledUp) return;
setReadMarker(); setReadMarker();
} }
@ -379,13 +385,19 @@ class ChatController extends State<ChatPageWithRoom>
void setReadMarker({String? eventId}) { void setReadMarker({String? eventId}) {
if (_setReadMarkerFuture != null) return; if (_setReadMarkerFuture != null) return;
if (_scrolledUp) return;
if (scrollUpBannerEventId != null) return; if (scrollUpBannerEventId != null) return;
if (eventId == null && if (eventId == null &&
!room.hasNewMessages && !room.hasNewMessages &&
room.notificationCount == 0) { room.notificationCount == 0) {
return; return;
} }
if (!Matrix.of(context).webHasFocus) return;
// Do not send read markers when app is not in foreground
if (!Matrix.of(context).webHasFocus ||
WidgetsBinding.instance.lifecycleState != AppLifecycleState.resumed) {
return;
}
final timeline = this.timeline; final timeline = this.timeline;
if (timeline == null || timeline.events.isEmpty) return; if (timeline == null || timeline.events.isEmpty) return;
@ -932,7 +944,6 @@ class ChatController extends State<ChatPageWithRoom>
); );
}); });
await loadTimelineFuture; await loadTimelineFuture;
setReadMarker();
} }
scrollController.jumpTo(0); scrollController.jumpTo(0);
} }
@ -1174,7 +1185,6 @@ class ChatController extends State<ChatPageWithRoom>
void onInputBarChanged(String text) { void onInputBarChanged(String text) {
if (_inputTextIsEmpty != text.isEmpty) { if (_inputTextIsEmpty != text.isEmpty) {
setReadMarker();
setState(() { setState(() {
_inputTextIsEmpty = text.isEmpty; _inputTextIsEmpty = text.isEmpty;
}); });
@ -1300,3 +1310,12 @@ class ChatController extends State<ChatPageWithRoom>
} }
enum EmojiPickerType { reaction, keyboard } enum EmojiPickerType { reaction, keyboard }
extension on List<Event> {
int get firstIndexWhereNotError {
if (isEmpty) return 0;
final index = indexWhere((event) => !event.status.isError);
if (index == -1) return length;
return index;
}
}

@ -150,11 +150,6 @@ class ChatView extends StatelessWidget {
controller.emojiPickerAction(); controller.emojiPickerAction();
} }
}, },
child: GestureDetector(
onTapDown: (_) => controller.setReadMarker(),
behavior: HitTestBehavior.opaque,
child: MouseRegion(
onEnter: (_) => controller.setReadMarker(),
child: StreamBuilder( child: StreamBuilder(
stream: controller.room.onUpdate.stream stream: controller.room.onUpdate.stream
.rateLimit(const Duration(seconds: 1)), .rateLimit(const Duration(seconds: 1)),
@ -220,9 +215,8 @@ class ChatView extends StatelessWidget {
TombstoneDisplay(controller), TombstoneDisplay(controller),
if (scrollUpBannerEventId != null) if (scrollUpBannerEventId != null)
Material( Material(
color: Theme.of(context) color:
.colorScheme Theme.of(context).colorScheme.surfaceVariant,
.surfaceVariant,
shape: Border( shape: Border(
bottom: BorderSide( bottom: BorderSide(
width: 1, width: 1,
@ -237,23 +231,20 @@ class ChatView extends StatelessWidget {
icon: const Icon(Icons.close), icon: const Icon(Icons.close),
tooltip: L10n.of(context)!.close, tooltip: L10n.of(context)!.close,
onPressed: () { onPressed: () {
controller controller.discardScrollUpBannerEventId();
.discardScrollUpBannerEventId();
controller.setReadMarker(); controller.setReadMarker();
}, },
), ),
title: Text( title: Text(
L10n.of(context)!.jumpToLastReadMessage, L10n.of(context)!.jumpToLastReadMessage,
), ),
contentPadding: contentPadding: const EdgeInsets.only(left: 8),
const EdgeInsets.only(left: 8),
trailing: TextButton( trailing: TextButton(
onPressed: () { onPressed: () {
controller.scrollToEventId( controller.scrollToEventId(
scrollUpBannerEventId, scrollUpBannerEventId,
); );
controller controller.discardScrollUpBannerEventId();
.discardScrollUpBannerEventId();
}, },
child: Text(L10n.of(context)!.jump), child: Text(L10n.of(context)!.jump),
), ),
@ -267,8 +258,7 @@ class ChatView extends StatelessWidget {
builder: (context) { builder: (context) {
if (controller.timeline == null) { if (controller.timeline == null) {
return const Center( return const Center(
child: CircularProgressIndicator child: CircularProgressIndicator.adaptive(
.adaptive(
strokeWidth: 2, strokeWidth: 2,
), ),
); );
@ -308,8 +298,7 @@ class ChatView extends StatelessWidget {
Brightness.light Brightness.light
? Colors.white ? Colors.white
: Colors.black, : Colors.black,
child: controller.room.isAbandonedDMRoom == child: controller.room.isAbandonedDMRoom == true
true
? Row( ? Row(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.spaceEvenly, MainAxisAlignment.spaceEvenly,
@ -319,8 +308,7 @@ class ChatView extends StatelessWidget {
padding: const EdgeInsets.all( padding: const EdgeInsets.all(
16, 16,
), ),
foregroundColor: foregroundColor: Theme.of(context)
Theme.of(context)
.colorScheme .colorScheme
.error, .error,
), ),
@ -341,8 +329,7 @@ class ChatView extends StatelessWidget {
icon: const Icon( icon: const Icon(
Icons.forum_outlined, Icons.forum_outlined,
), ),
onPressed: onPressed: controller.recreateChat,
controller.recreateChat,
label: Text( label: Text(
L10n.of(context)!.reopenChat, L10n.of(context)!.reopenChat,
), ),
@ -382,8 +369,6 @@ class ChatView extends StatelessWidget {
}, },
), ),
), ),
),
),
); );
} }
} }

Loading…
Cancel
Save