mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-08 00:00:28 +03:00
scroll to bottom in unfocused window but stop sending read receipt (#2214)
* scroll to bottom in unfocused window but stop sending read receipt * send read-receipt when new message are in view after regaining focus
This commit is contained in:
parent
59e8d66255
commit
b63868bbb5
2 changed files with 82 additions and 37 deletions
|
|
@ -586,15 +586,19 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
// so timeline can be updated with evt like: edits, reactions etc
|
||||
if (atBottomRef.current) {
|
||||
if (document.hasFocus() && (!unreadInfo || mEvt.getSender() === mx.getUserId())) {
|
||||
// Check if the document is in focus (user is actively viewing the app),
|
||||
// and either there are no unread messages or the latest message is from the current user.
|
||||
// If either condition is met, trigger the markAsRead function to send a read receipt.
|
||||
requestAnimationFrame(() => markAsRead(mx, mEvt.getRoomId()!));
|
||||
}
|
||||
|
||||
if (document.hasFocus()) {
|
||||
scrollToBottomRef.current.count += 1;
|
||||
scrollToBottomRef.current.smooth = true;
|
||||
} else if (!unreadInfo) {
|
||||
if (!document.hasFocus() && !unreadInfo) {
|
||||
setUnreadInfo(getRoomUnreadInfo(room));
|
||||
}
|
||||
|
||||
scrollToBottomRef.current.count += 1;
|
||||
scrollToBottomRef.current.smooth = true;
|
||||
|
||||
setTimeline((ct) => ({
|
||||
...ct,
|
||||
range: {
|
||||
|
|
@ -613,6 +617,36 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
)
|
||||
);
|
||||
|
||||
const handleOpenEvent = useCallback(
|
||||
async (
|
||||
evtId: string,
|
||||
highlight = true,
|
||||
onScroll: ((scrolled: boolean) => void) | undefined = undefined
|
||||
) => {
|
||||
const evtTimeline = getEventTimeline(room, evtId);
|
||||
const absoluteIndex =
|
||||
evtTimeline && getEventIdAbsoluteIndex(timeline.linkedTimelines, evtTimeline, evtId);
|
||||
|
||||
if (typeof absoluteIndex === 'number') {
|
||||
const scrolled = scrollToItem(absoluteIndex, {
|
||||
behavior: 'smooth',
|
||||
align: 'center',
|
||||
stopInView: true,
|
||||
});
|
||||
if (onScroll) onScroll(scrolled);
|
||||
setFocusItem({
|
||||
index: absoluteIndex,
|
||||
scrollTo: false,
|
||||
highlight,
|
||||
});
|
||||
} else {
|
||||
setTimeline(getEmptyTimeline());
|
||||
loadEventTimeline(evtId);
|
||||
}
|
||||
},
|
||||
[room, timeline, scrollToItem, loadEventTimeline]
|
||||
);
|
||||
|
||||
useLiveTimelineRefresh(
|
||||
room,
|
||||
useCallback(() => {
|
||||
|
|
@ -646,16 +680,17 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
);
|
||||
|
||||
const tryAutoMarkAsRead = useCallback(() => {
|
||||
if (!unreadInfo) {
|
||||
const readUptoEventId = readUptoEventIdRef.current;
|
||||
if (!readUptoEventId) {
|
||||
requestAnimationFrame(() => markAsRead(mx, room.roomId));
|
||||
return;
|
||||
}
|
||||
const evtTimeline = getEventTimeline(room, unreadInfo.readUptoEventId);
|
||||
const evtTimeline = getEventTimeline(room, readUptoEventId);
|
||||
const latestTimeline = evtTimeline && getFirstLinkedTimeline(evtTimeline, Direction.Forward);
|
||||
if (latestTimeline === room.getLiveTimeline()) {
|
||||
requestAnimationFrame(() => markAsRead(mx, room.roomId));
|
||||
}
|
||||
}, [mx, room, unreadInfo]);
|
||||
}, [mx, room]);
|
||||
|
||||
const debounceSetAtBottom = useDebounce(
|
||||
useCallback((entry: IntersectionObserverEntry) => {
|
||||
|
|
@ -672,7 +707,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
if (targetEntry) debounceSetAtBottom(targetEntry);
|
||||
if (targetEntry?.isIntersecting && atLiveEndRef.current) {
|
||||
setAtBottom(true);
|
||||
tryAutoMarkAsRead();
|
||||
if (document.hasFocus()) {
|
||||
tryAutoMarkAsRead();
|
||||
}
|
||||
}
|
||||
},
|
||||
[debounceSetAtBottom, tryAutoMarkAsRead]
|
||||
|
|
@ -691,10 +728,20 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
useCallback(
|
||||
(inFocus) => {
|
||||
if (inFocus && atBottomRef.current) {
|
||||
if (unreadInfo?.inLiveTimeline) {
|
||||
handleOpenEvent(unreadInfo.readUptoEventId, false, (scrolled) => {
|
||||
// the unread event is already in view
|
||||
// so, try mark as read;
|
||||
if (!scrolled) {
|
||||
tryAutoMarkAsRead();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
tryAutoMarkAsRead();
|
||||
}
|
||||
},
|
||||
[tryAutoMarkAsRead]
|
||||
[tryAutoMarkAsRead, unreadInfo, handleOpenEvent]
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -832,27 +879,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||
async (evt) => {
|
||||
const targetId = evt.currentTarget.getAttribute('data-event-id');
|
||||
if (!targetId) return;
|
||||
const replyTimeline = getEventTimeline(room, targetId);
|
||||
const absoluteIndex =
|
||||
replyTimeline && getEventIdAbsoluteIndex(timeline.linkedTimelines, replyTimeline, targetId);
|
||||
|
||||
if (typeof absoluteIndex === 'number') {
|
||||
scrollToItem(absoluteIndex, {
|
||||
behavior: 'smooth',
|
||||
align: 'center',
|
||||
stopInView: true,
|
||||
});
|
||||
setFocusItem({
|
||||
index: absoluteIndex,
|
||||
scrollTo: false,
|
||||
highlight: true,
|
||||
});
|
||||
} else {
|
||||
setTimeline(getEmptyTimeline());
|
||||
loadEventTimeline(targetId);
|
||||
}
|
||||
handleOpenEvent(targetId);
|
||||
},
|
||||
[room, timeline, scrollToItem, loadEventTimeline]
|
||||
[handleOpenEvent]
|
||||
);
|
||||
|
||||
const handleUserClick: MouseEventHandler<HTMLButtonElement> = useCallback(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue