mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-11-15 20:27:24 +01:00
feat: Enhanced timeline
This commit is contained in:
parent
c365469dc5
commit
9b8acb8b6b
@ -184,28 +184,21 @@ class ChatController extends State<Chat> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> getTimeline() async {
|
Future<bool> getTimeline({String? eventContextId}) async {
|
||||||
if (timeline == null) {
|
if (timeline == null) {
|
||||||
|
eventContextId ??= room!.fullyRead;
|
||||||
await Matrix.of(context).client.roomsLoading;
|
await Matrix.of(context).client.roomsLoading;
|
||||||
await Matrix.of(context).client.accountDataLoading;
|
await Matrix.of(context).client.accountDataLoading;
|
||||||
timeline = await room!.getTimeline(onUpdate: updateView);
|
timeline = await room!.getTimeline(
|
||||||
|
onUpdate: updateView,
|
||||||
|
eventContextId: eventContextId,
|
||||||
|
);
|
||||||
if (timeline!.events.isNotEmpty) {
|
if (timeline!.events.isNotEmpty) {
|
||||||
if (room!.markedUnread) room!.markUnread(false);
|
if (room!.markedUnread) room!.markUnread(false);
|
||||||
setReadMarker();
|
setReadMarker();
|
||||||
}
|
}
|
||||||
|
|
||||||
// when the scroll controller is attached we want to scroll to an event id, if specified
|
if (eventContextId.isNotEmpty) scrollToEventId(eventContextId);
|
||||||
// and update the scroll controller...which will trigger a request history, if the
|
|
||||||
// "load more" button is visible on the screen
|
|
||||||
SchedulerBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
if (mounted) {
|
|
||||||
final event = VRouter.of(context).queryParameters['event'];
|
|
||||||
if (event != null) {
|
|
||||||
scrollToEventId(event);
|
|
||||||
}
|
|
||||||
_updateScrollController();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
timeline!.requestKeys(onlineKeyBackupOnly: false);
|
timeline!.requestKeys(onlineKeyBackupOnly: false);
|
||||||
return true;
|
return true;
|
||||||
@ -636,59 +629,42 @@ class ChatController extends State<Chat> {
|
|||||||
inputFocus.requestFocus();
|
inputFocus.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollToEventId(String eventId) async {
|
void openTimelineAtEventId(String eventId) async {
|
||||||
var eventIndex = timeline!.events.indexWhere((e) => e.eventId == eventId);
|
setState(() {
|
||||||
if (eventIndex == -1) {
|
timeline = null;
|
||||||
// event id not found...maybe we can fetch it?
|
|
||||||
// the try...finally is here to start and close the loading dialog reliably
|
|
||||||
await showFutureLoadingDialog(
|
|
||||||
context: context,
|
|
||||||
future: () async {
|
|
||||||
// okay, we first have to fetch if the event is in the room
|
|
||||||
try {
|
|
||||||
final event = await timeline!.getEventById(eventId);
|
|
||||||
if (event == null) {
|
|
||||||
// event is null...meaning something is off
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
if (err is MatrixException && err.errcode == 'M_NOT_FOUND') {
|
|
||||||
// event wasn't found, as the server gave a 404 or something
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
// okay, we know that the event *is* in the room
|
|
||||||
while (eventIndex == -1) {
|
|
||||||
if (!canLoadMore) {
|
|
||||||
// we can't load any more events but still haven't found ours yet...better stop here
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await timeline!.requestHistory(historyCount: _loadHistoryCount);
|
|
||||||
} catch (err) {
|
|
||||||
if (err is TimeoutException) {
|
|
||||||
// loading the history timed out...so let's do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
eventIndex =
|
|
||||||
timeline!.events.indexWhere((e) => e.eventId == eventId);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
await getTimeline(eventContextId: eventId);
|
||||||
|
scrollToEventId(eventId);
|
||||||
}
|
}
|
||||||
if (!mounted) {
|
|
||||||
return;
|
/// 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
|
||||||
|
/// "load more" button is visible on the screen
|
||||||
|
void scrollToEventId(String eventId) async {
|
||||||
|
SchedulerBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
if (!mounted) return;
|
||||||
|
final eventIndex =
|
||||||
|
timeline!.events.indexWhere((e) => e.eventId == eventId);
|
||||||
|
if (eventIndex == -1) return;
|
||||||
|
if (!mounted) return;
|
||||||
await scrollController.scrollToIndex(
|
await scrollController.scrollToIndex(
|
||||||
eventIndex,
|
eventIndex,
|
||||||
preferPosition: AutoScrollPosition.middle,
|
preferPosition: AutoScrollPosition.middle,
|
||||||
);
|
);
|
||||||
_updateScrollController();
|
_updateScrollController();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollDown() => scrollController.jumpTo(0);
|
void scrollDown() {
|
||||||
|
if (timeline!.isFragmentedTimeline) {
|
||||||
|
setState(() {
|
||||||
|
timeline = null;
|
||||||
|
});
|
||||||
|
getTimeline();
|
||||||
|
} else {
|
||||||
|
scrollController.jumpTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void onEmojiSelected(_, Emoji? emoji) {
|
void onEmojiSelected(_, Emoji? emoji) {
|
||||||
switch (emojiPickerType) {
|
switch (emojiPickerType) {
|
||||||
|
|||||||
@ -55,16 +55,17 @@ class ChatEventList extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
i--;
|
||||||
|
|
||||||
// Request history button or progress indicator:
|
// Request history button or progress indicator:
|
||||||
if (i == controller.timeline!.events.length + 1) {
|
if (i == controller.timeline!.events.length) {
|
||||||
if (controller.timeline!.isRequestingHistory) {
|
if (controller.timeline!.isRequestingHistory) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (controller.canLoadMore) {
|
if (controller.canLoadMore) {
|
||||||
Center(
|
return Center(
|
||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
@ -78,7 +79,10 @@ class ChatEventList extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The message at this index:
|
// The message at this index:
|
||||||
final event = controller.timeline!.events[i - 1];
|
if (i >= controller.timeline!.events.length) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
final event = controller.timeline!.events[i];
|
||||||
|
|
||||||
return AutoScrollTag(
|
return AutoScrollTag(
|
||||||
key: ValueKey(event.eventId),
|
key: ValueKey(event.eventId),
|
||||||
|
|||||||
@ -219,9 +219,7 @@ class Message extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (scrollToEventId != null) {
|
scrollToEventId?.call(replyEvent.eventId);
|
||||||
scrollToEventId!(replyEvent.eventId);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class PinnedEvents extends StatelessWidget {
|
|||||||
))
|
))
|
||||||
.toList());
|
.toList());
|
||||||
|
|
||||||
if (eventId != null) controller.scrollToEventId(eventId);
|
if (eventId != null) controller.openTimelineAtEventId(eventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user