Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
@@ -7,65 +7,115 @@ import initMatrix from '../../../client/initMatrix';
|
||||
import cons from '../../../client/state/cons';
|
||||
|
||||
import Text from '../../atoms/text/Text';
|
||||
import Button from '../../atoms/button/Button';
|
||||
import IconButton from '../../atoms/button/IconButton';
|
||||
|
||||
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
|
||||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
||||
|
||||
import { getUsersActionJsx } from './common';
|
||||
|
||||
function RoomViewFloating({
|
||||
roomId, roomTimeline, viewEvent,
|
||||
}) {
|
||||
const [reachedBottom, setReachedBottom] = useState(true);
|
||||
function useJumpToEvent(roomTimeline) {
|
||||
const [eventId, setEventId] = useState(null);
|
||||
|
||||
const jumpToEvent = () => {
|
||||
roomTimeline.loadEventTimeline(eventId);
|
||||
setEventId(null);
|
||||
};
|
||||
|
||||
const cancelJumpToEvent = () => {
|
||||
setEventId(null);
|
||||
roomTimeline.markAsRead();
|
||||
};
|
||||
|
||||
// TODO: if user reaches the unread messages with other ways
|
||||
// like by paginating, or loading timeline for that event by other ways ex: clicking on reply.
|
||||
// then setEventId(null);
|
||||
|
||||
useEffect(() => {
|
||||
const readEventId = roomTimeline.getReadUpToEventId();
|
||||
// we only show "Jump to unread" btn only if the event is not in live timeline.
|
||||
// if event is in live timeline
|
||||
// we will automatically open the timeline from that event
|
||||
if (!roomTimeline.hasEventInLiveTimeline(readEventId)) {
|
||||
setEventId(readEventId);
|
||||
}
|
||||
|
||||
return () => {
|
||||
setEventId(null);
|
||||
};
|
||||
}, [roomTimeline]);
|
||||
|
||||
return [!!eventId, jumpToEvent, cancelJumpToEvent];
|
||||
}
|
||||
|
||||
function useTypingMembers(roomTimeline) {
|
||||
const [typingMembers, setTypingMembers] = useState(new Set());
|
||||
const mx = initMatrix.matrixClient;
|
||||
|
||||
function isSomeoneTyping(members) {
|
||||
const m = members;
|
||||
m.delete(mx.getUserId());
|
||||
if (m.size === 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTypingMessage(members) {
|
||||
const userIds = members;
|
||||
userIds.delete(mx.getUserId());
|
||||
return getUsersActionJsx(roomId, [...userIds], 'typing...');
|
||||
}
|
||||
|
||||
function updateTyping(members) {
|
||||
const updateTyping = (members) => {
|
||||
const mx = initMatrix.matrixClient;
|
||||
members.delete(mx.getUserId());
|
||||
setTypingMembers(members);
|
||||
}
|
||||
const handleTimelineScroll = (position) => {
|
||||
setReachedBottom(position === 'BOTTOM');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setReachedBottom(true);
|
||||
setTypingMembers(new Set());
|
||||
viewEvent.on('timeline-scroll', handleTimelineScroll);
|
||||
return () => viewEvent.removeListener('timeline-scroll', handleTimelineScroll);
|
||||
}, [roomId]);
|
||||
|
||||
useEffect(() => {
|
||||
roomTimeline.on(cons.events.roomTimeline.TYPING_MEMBERS_UPDATED, updateTyping);
|
||||
return () => {
|
||||
roomTimeline?.removeListener(cons.events.roomTimeline.TYPING_MEMBERS_UPDATED, updateTyping);
|
||||
};
|
||||
}, [roomTimeline]);
|
||||
|
||||
return [typingMembers];
|
||||
}
|
||||
|
||||
function useScrollToBottom(roomId, viewEvent) {
|
||||
const [isAtBottom, setIsAtBottom] = useState(true);
|
||||
const handleAtBottom = (atBottom) => setIsAtBottom(atBottom);
|
||||
|
||||
useEffect(() => {
|
||||
setIsAtBottom(true);
|
||||
viewEvent.on('at-bottom', handleAtBottom);
|
||||
return () => viewEvent.removeListener('at-bottom', handleAtBottom);
|
||||
}, [roomId]);
|
||||
|
||||
return [isAtBottom, setIsAtBottom];
|
||||
}
|
||||
|
||||
function RoomViewFloating({
|
||||
roomId, roomTimeline, viewEvent,
|
||||
}) {
|
||||
const [isJumpToEvent, jumpToEvent, cancelJumpToEvent] = useJumpToEvent(roomTimeline, viewEvent);
|
||||
const [typingMembers] = useTypingMembers(roomTimeline);
|
||||
const [isAtBottom, setIsAtBottom] = useScrollToBottom(roomId, viewEvent);
|
||||
|
||||
const handleScrollToBottom = () => {
|
||||
viewEvent.emit('scroll-to-live');
|
||||
setIsAtBottom(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`room-view__typing${isSomeoneTyping(typingMembers) ? ' room-view__typing--open' : ''}`}>
|
||||
<div className="bouncing-loader"><div /></div>
|
||||
<Text variant="b2">{getTypingMessage(typingMembers)}</Text>
|
||||
</div>
|
||||
<div className={`room-view__STB${reachedBottom ? '' : ' room-view__STB--open'}`}>
|
||||
<div className={`room-view__unread ${isJumpToEvent ? 'room-view__unread--open' : ''}`}>
|
||||
<Button onClick={jumpToEvent} variant="primary">
|
||||
<Text variant="b2">Jump to unread</Text>
|
||||
</Button>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
viewEvent.emit('scroll-to-live');
|
||||
setReachedBottom(true);
|
||||
}}
|
||||
onClick={cancelJumpToEvent}
|
||||
variant="primary"
|
||||
size="extra-small"
|
||||
src={CrossIC}
|
||||
tooltipPlacement="bottom"
|
||||
tooltip="Cancel"
|
||||
/>
|
||||
</div>
|
||||
<div className={`room-view__typing${typingMembers.size > 0 ? ' room-view__typing--open' : ''}`}>
|
||||
<div className="bouncing-loader"><div /></div>
|
||||
<Text variant="b2">{getUsersActionJsx(roomId, [...typingMembers], 'typing...')}</Text>
|
||||
</div>
|
||||
<div className={`room-view__STB${isAtBottom ? '' : ' room-view__STB--open'}`}>
|
||||
<IconButton
|
||||
onClick={handleScrollToBottom}
|
||||
src={ChevronBottomIC}
|
||||
tooltip="Scroll to Bottom"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user