jump to bottom

This commit is contained in:
Michael Peters 2022-02-08 22:43:56 -06:00
parent 515738ae41
commit 33f880f4b1
3 changed files with 43 additions and 13 deletions

View File

@ -1,5 +1,5 @@
{ {
"printWidth": 240, "printWidth": 120,
"tabWidth": 4, "tabWidth": 4,
"useTabs": true, "useTabs": true,
"semi": true, "semi": true,

View File

@ -1,10 +1,11 @@
import React, { ReactNode } from 'react'; import React, { MutableRefObject, ReactNode, RefObject, useCallback, useRef } from 'react';
import { LoadableValueScrolling } from '../require/loadables'; import { LoadableValueScrolling } from '../require/loadables';
import { useScrollableCallables } from '../require/react-helper'; import { useScrollableCallables } from '../require/react-helper';
import Retry from './retry'; import Retry from './retry';
export interface InfiniteScrollRecoilProps<T, E> { export interface InfiniteScrollRecoilProps<T, E> {
infiniteScrollRef: MutableRefObject<HTMLDivElement | null>;
scrollable: LoadableValueScrolling<T, E>; scrollable: LoadableValueScrolling<T, E>;
initialErrorMessage: string; // for if there was a problem loading the initial messages initialErrorMessage: string; // for if there was a problem loading the initial messages
aboveErrorMessage: string; // for if there was a problem loading messages above the list aboveErrorMessage: string; // for if there was a problem loading messages above the list
@ -12,12 +13,13 @@ export interface InfiniteScrollRecoilProps<T, E> {
children: ReactNode; children: ReactNode;
} }
function InfiniteScrollRecoil<T>(props: InfiniteScrollRecoilProps<T[], T>) { function InfiniteScrollRecoil<T>(props: InfiniteScrollRecoilProps<T[], T>) {
const { scrollable, initialErrorMessage, aboveErrorMessage, belowErrorMessage, children } = props; const { infiniteScrollRef, scrollable, initialErrorMessage, aboveErrorMessage, belowErrorMessage, children } =
props;
const { fetchAboveCallable, fetchBelowCallable, onScrollCallable } = useScrollableCallables(scrollable, 600); // activate fetch above/below when 600 client px from the top/bottom const { fetchAboveCallable, fetchBelowCallable, onScrollCallable } = useScrollableCallables(scrollable, 600); // activate fetch above/below when 600 client px from the top/bottom
return ( return (
<div className="infinite-scroll-scroll-base" onScroll={onScrollCallable}> <div ref={infiniteScrollRef} className="infinite-scroll-scroll-base" onScroll={onScrollCallable}>
<div className="infinite-scroll-elements"> <div className="infinite-scroll-elements">
<Retry error={scrollable?.above?.error} text={aboveErrorMessage} retryFunc={fetchAboveCallable} /> <Retry error={scrollable?.above?.error} text={aboveErrorMessage} retryFunc={fetchAboveCallable} />
{children} {children}

View File

@ -3,22 +3,20 @@ const electronConsole = electronRemote.getGlobal('console') as Console;
import Logger from '../../../../logger/logger'; import Logger from '../../../../logger/logger';
const LOG = Logger.create(__filename, electronConsole); const LOG = Logger.create(__filename, electronConsole);
import React, { FC, useEffect, useMemo } from 'react'; import React, { FC, useEffect, useMemo, useRef } from 'react';
import { Message } from '../../data-types'; import { Message } from '../../data-types';
import MessageElement from './components/message-element'; import MessageElement from './components/message-element';
import { currGuildActiveChannelMessagesState, currGuildState } from '../require/atoms'; import { currGuildActiveChannelMessagesState, currGuildSelfMemberState, currGuildState } from '../require/atoms';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { isFailed, isLoaded, isPended, isUnload } from '../require/loadables'; import { isFailed, isLoaded, isPended, isUnload } from '../require/loadables';
import InfiniteScrollRecoil from '../components/infinite-scroll'; import InfiniteScrollRecoil from '../components/infinite-scroll';
const MessageList: FC = () => { const MessageList: FC = () => {
// const scrollToBottomFunc = useCallback(() => { const infiniteScrollElementRef = useRef<HTMLDivElement>(null);
// if (!infiniteScrollElementRef.current) return;
// infiniteScrollElementRef.current.scrollTop = 0; // Keep in mind that this is reversed since we are in flex-flow: column-reverse
// }, []);
const guild = useRecoilValue(currGuildState); const guild = useRecoilValue(currGuildState);
const messages = useRecoilValue(currGuildActiveChannelMessagesState); const messages = useRecoilValue(currGuildActiveChannelMessagesState);
const selfMember = useRecoilValue(currGuildSelfMemberState);
// TODO: Show loading indicators if above/below are pending // TODO: Show loading indicators if above/below are pending
// TODO: Show nicer retry buttons (and test the retry buttons) // TODO: Show nicer retry buttons (and test the retry buttons)
@ -34,9 +32,26 @@ const MessageList: FC = () => {
} else if (isFailed(messages)) { } else if (isFailed(messages)) {
LOG.debug('recoilMessages failed'); LOG.debug('recoilMessages failed');
} }
// lOG.debug('recoilMessages update', { recoilMessagesLength: recoilMessages.value?.length ?? 'unloaded' });
}, [messages]); }, [messages]);
useEffect(() => {
if (guild === null) return;
const onMessages = (messages: Message[]) => {
if (!infiniteScrollElementRef.current) return;
if (!isLoaded(selfMember)) return;
for (const message of messages) {
if (message.member.id === selfMember.value.id) {
// keep in mind that this is reversed since we are in flex-flow: column-reverse
infiniteScrollElementRef.current.scrollTop = 0;
}
}
};
guild.on('new-messages', onMessages);
return () => {
guild.off('new-messages', onMessages);
};
}, [guild, selfMember]);
const messageElements = useMemo(() => { const messageElements = useMemo(() => {
if (guild === null) return []; if (guild === null) return [];
if (!isLoaded(messages)) return []; if (!isLoaded(messages)) return [];
@ -44,14 +59,27 @@ const MessageList: FC = () => {
for (let i = 0; i < messages.value.length; ++i) { for (let i = 0; i < messages.value.length; ++i) {
const prevMessage = messages.value[i - 1] ?? null; const prevMessage = messages.value[i - 1] ?? null;
const message = messages.value[i] as Message; const message = messages.value[i] as Message;
result.push(<MessageElement key={guild.id + 'm#' + message.id} guild={guild} message={message} prevMessage={prevMessage} />); result.push(
<MessageElement
key={guild.id + 'm#' + message.id}
guild={guild}
message={message}
prevMessage={prevMessage}
/>,
);
} }
return result; return result;
}, [guild, messages]); }, [guild, messages]);
return ( return (
<div className="message-list"> <div className="message-list">
<InfiniteScrollRecoil scrollable={messages} initialErrorMessage="Unable to retrieve recent messages" aboveErrorMessage="Unable to retrieve messages above" belowErrorMessage="Unable to retrieve messages below"> <InfiniteScrollRecoil
infiniteScrollRef={infiniteScrollElementRef}
scrollable={messages}
initialErrorMessage="Unable to retrieve recent messages"
aboveErrorMessage="Unable to retrieve messages above"
belowErrorMessage="Unable to retrieve messages below"
>
{messageElements} {messageElements}
</InfiniteScrollRecoil> </InfiniteScrollRecoil>
</div> </div>