|
|
|
@ -102,7 +102,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|
|
|
|
|
|
|
|
|
Timeline? timeline;
|
|
|
|
|
|
|
|
|
|
String? readMarkerEventId;
|
|
|
|
|
late final String readMarkerEventId;
|
|
|
|
|
|
|
|
|
|
String get roomId => widget.room.id;
|
|
|
|
|
|
|
|
|
@ -270,6 +270,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
sendingClient = Matrix.of(context).client;
|
|
|
|
|
readMarkerEventId = room.hasNewMessages ? room.fullyRead : '';
|
|
|
|
|
WidgetsBinding.instance.addObserver(this);
|
|
|
|
|
_tryLoadTimeline();
|
|
|
|
|
if (kIsWeb) {
|
|
|
|
@ -284,19 +285,22 @@ class ChatController extends State<ChatPageWithRoom>
|
|
|
|
|
await loadTimelineFuture;
|
|
|
|
|
if (initialEventId != null) scrollToEventId(initialEventId);
|
|
|
|
|
|
|
|
|
|
final fullyRead = room.fullyRead;
|
|
|
|
|
if (fullyRead.isEmpty) {
|
|
|
|
|
setReadMarker();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (timeline?.events.any((event) => event.eventId == fullyRead) ??
|
|
|
|
|
false) {
|
|
|
|
|
Logs().v('Scroll up to visible event', fullyRead);
|
|
|
|
|
scrollToEventId(fullyRead, highlightEvent: false);
|
|
|
|
|
final readMarkerEventIndex = readMarkerEventId.isEmpty
|
|
|
|
|
? -1
|
|
|
|
|
: timeline!.events
|
|
|
|
|
.where((e) => e.isVisibleInGui)
|
|
|
|
|
.toList()
|
|
|
|
|
.indexWhere((e) => e.eventId == readMarkerEventId);
|
|
|
|
|
|
|
|
|
|
if (readMarkerEventIndex > 1) {
|
|
|
|
|
Logs().v('Scroll up to visible event', readMarkerEventId);
|
|
|
|
|
scrollToEventId(readMarkerEventId, highlightEvent: false);
|
|
|
|
|
return;
|
|
|
|
|
} else if (readMarkerEventId.isNotEmpty && readMarkerEventIndex == -1) {
|
|
|
|
|
_showScrollUpMaterialBanner(readMarkerEventId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!mounted) return;
|
|
|
|
|
_showScrollUpMaterialBanner(fullyRead);
|
|
|
|
|
} catch (e, s) {
|
|
|
|
|
ErrorReporter(context, 'Unable to load timeline').onErrorCallback(e, s);
|
|
|
|
|
rethrow;
|
|
|
|
@ -323,13 +327,16 @@ class ChatController extends State<ChatPageWithRoom>
|
|
|
|
|
int? animateInEventIndex;
|
|
|
|
|
|
|
|
|
|
void onInsert(int i) {
|
|
|
|
|
onChange(i);
|
|
|
|
|
// setState will be called by updateView() anyway
|
|
|
|
|
animateInEventIndex = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onChange(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
|
|
|
|
|
animateInEventIndex = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _getTimeline({
|
|
|
|
@ -347,6 +354,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|
|
|
|
onUpdate: updateView,
|
|
|
|
|
eventContextId: eventContextId,
|
|
|
|
|
onInsert: onInsert,
|
|
|
|
|
onChange: onChange,
|
|
|
|
|
);
|
|
|
|
|
} catch (e, s) {
|
|
|
|
|
Logs().w('Unable to load timeline on event ID $eventContextId', e, s);
|
|
|
|
@ -354,6 +362,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|
|
|
|
timeline = await room.getTimeline(
|
|
|
|
|
onUpdate: updateView,
|
|
|
|
|
onInsert: onInsert,
|
|
|
|
|
onChange: onChange,
|
|
|
|
|
);
|
|
|
|
|
if (!mounted) return;
|
|
|
|
|
if (e is TimeoutException || e is IOException) {
|
|
|
|
@ -380,6 +389,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|
|
|
|
if (_setReadMarkerFuture != null) return;
|
|
|
|
|
if (_scrolledUp) return;
|
|
|
|
|
if (scrollUpBannerEventId != null) return;
|
|
|
|
|
|
|
|
|
|
if (eventId == null &&
|
|
|
|
|
!room.hasNewMessages &&
|
|
|
|
|
room.notificationCount == 0) {
|
|
|
|
|