merge fetching more messages for top and bottom in the same flag

pull/2142/head
Audric Ackermann 3 years ago
parent 9000c649f8
commit 949c36a42f
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -11,9 +11,8 @@ import {
showScrollToBottomButton, showScrollToBottomButton,
} from '../../../../state/ducks/conversations'; } from '../../../../state/ducks/conversations';
import { import {
areMoreBottomMessagesBeingFetched, areMoreMessagesBeingFetched,
areMoreTopMessagesBeingFetched, getConversationHasUnread,
getFirstUnreadMessageId,
getLoadedMessagesLength, getLoadedMessagesLength,
getMostRecentMessageId, getMostRecentMessageId,
getOldestMessageId, getOldestMessageId,
@ -68,9 +67,8 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
const mostRecentMessageId = useSelector(getMostRecentMessageId); const mostRecentMessageId = useSelector(getMostRecentMessageId);
const oldestMessageId = useSelector(getOldestMessageId); const oldestMessageId = useSelector(getOldestMessageId);
const youngestMessageId = useSelector(getYoungestMessageId); const youngestMessageId = useSelector(getYoungestMessageId);
const fetchingTopMore = useSelector(areMoreTopMessagesBeingFetched); const fetchingMoreInProgress = useSelector(areMoreMessagesBeingFetched);
const fetchingBottomMore = useSelector(areMoreBottomMessagesBeingFetched); const conversationHasUnread = useSelector(getConversationHasUnread);
const conversationHasUnread = Boolean(useSelector(getFirstUnreadMessageId));
const shouldMarkReadWhenVisible = isUnread; const shouldMarkReadWhenVisible = isUnread;
const [didScroll, setDidScroll] = useState(false); const [didScroll, setDidScroll] = useState(false);
@ -118,7 +116,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
inView === true && inView === true &&
isAppFocused && isAppFocused &&
oldestMessageId === messageId && oldestMessageId === messageId &&
!fetchingTopMore && !fetchingMoreInProgress &&
selectedConversationKey selectedConversationKey
) { ) {
debouncedTriggerLoadMoreTop(selectedConversationKey, oldestMessageId); debouncedTriggerLoadMoreTop(selectedConversationKey, oldestMessageId);
@ -128,7 +126,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
inView === true && inView === true &&
isAppFocused && isAppFocused &&
youngestMessageId === messageId && youngestMessageId === messageId &&
!fetchingBottomMore && !fetchingMoreInProgress &&
selectedConversationKey selectedConversationKey
) { ) {
debouncedTriggerLoadMoreBottom(selectedConversationKey, youngestMessageId); debouncedTriggerLoadMoreBottom(selectedConversationKey, youngestMessageId);
@ -155,8 +153,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
selectedConversationKey, selectedConversationKey,
mostRecentMessageId, mostRecentMessageId,
oldestMessageId, oldestMessageId,
fetchingTopMore, fetchingMoreInProgress,
fetchingBottomMore,
isAppFocused, isAppFocused,
loadedMessagesLength, loadedMessagesLength,
receivedAt, receivedAt,

@ -800,6 +800,11 @@ export async function getLastMessagesByConversation(
return new MessageCollection(messages); return new MessageCollection(messages);
} }
export async function getLastMessageIdInConversation(conversationId: string) {
const collection = await getLastMessagesByConversation(conversationId, 1, true);
return collection.models.length ? collection.models[0].id : null;
}
export async function getLastMessageInConversation(conversationId: string) { export async function getLastMessageInConversation(conversationId: string) {
const messages = await channels.getLastMessagesByConversation(conversationId, 1); const messages = await channels.getLastMessagesByConversation(conversationId, 1);
for (const message of messages) { for (const message of messages) {

@ -349,8 +349,8 @@ export async function handleMessageJob(
); );
} }
// save the message model to the db and it save the messageId generated to our copy
const id = await messageModel.commit(); const id = await messageModel.commit();
messageModel.set({ id }); messageModel.set({ id });
// Note that this can save the message again, if jobs were queued. We need to // Note that this can save the message again, if jobs were queued. We need to

@ -2,6 +2,7 @@ import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { getConversationController } from '../../session/conversations'; import { getConversationController } from '../../session/conversations';
import { import {
getFirstUnreadMessageIdInConversation, getFirstUnreadMessageIdInConversation,
getLastMessageIdInConversation,
getLastMessageInConversation, getLastMessageInConversation,
getMessagesByConversation, getMessagesByConversation,
getOldestMessageInConversation, getOldestMessageInConversation,
@ -277,8 +278,7 @@ export type ConversationsStateType = {
selectedMessageIds: Array<string>; selectedMessageIds: Array<string>;
lightBox?: LightBoxOptions; lightBox?: LightBoxOptions;
quotedMessage?: ReplyingToMessageProps; quotedMessage?: ReplyingToMessageProps;
areMoreTopMessagesBeingFetched: boolean; areMoreMessagesBeingFetched: boolean;
areMoreBottomMessagesBeingFetched: boolean;
/** /**
* oldTopMessageId should only be set when, as the user scroll up we trigger a load of more top messages. * oldTopMessageId should only be set when, as the user scroll up we trigger a load of more top messages.
@ -298,6 +298,12 @@ export type ConversationsStateType = {
*/ */
oldBottomMessageId: string | null; oldBottomMessageId: string | null;
/**
* Contains the most recent message id for this conversation.
* This is the one at the bottom, if the most recent page of the conversation was loaded
*/
mostRecentMessageId: string | null;
showScrollButton: boolean; showScrollButton: boolean;
animateQuotedMessageId?: string; animateQuotedMessageId?: string;
shouldHighlightMessage: boolean; shouldHighlightMessage: boolean;
@ -424,14 +430,14 @@ export function getEmptyConversationState(): ConversationsStateType {
messageDetailProps: undefined, messageDetailProps: undefined,
showRightPanel: false, showRightPanel: false,
selectedMessageIds: [], selectedMessageIds: [],
areMoreTopMessagesBeingFetched: false, areMoreMessagesBeingFetched: false, // top or bottom
areMoreBottomMessagesBeingFetched: false,
showScrollButton: false, showScrollButton: false,
mentionMembers: [], mentionMembers: [],
firstUnreadMessageId: undefined, firstUnreadMessageId: undefined,
oldTopMessageId: null, oldTopMessageId: null,
oldBottomMessageId: null, oldBottomMessageId: null,
shouldHighlightMessage: false, shouldHighlightMessage: false,
mostRecentMessageId: null,
}; };
} }
@ -739,6 +745,7 @@ const conversationsSlice = createSlice({
action: PayloadAction<{ action: PayloadAction<{
conversationKey: string; conversationKey: string;
firstUnreadIdOnOpen: string | undefined; firstUnreadIdOnOpen: string | undefined;
mostRecentMessageIdOnOpen: string | null;
initialMessages: Array<MessageModelPropsWithoutConvoProps>; initialMessages: Array<MessageModelPropsWithoutConvoProps>;
}> }>
) { ) {
@ -748,25 +755,26 @@ const conversationsSlice = createSlice({
return { return {
conversationLookup: state.conversationLookup, conversationLookup: state.conversationLookup,
mostRecentMessageId: action.payload.mostRecentMessageIdOnOpen,
selectedConversation: action.payload.conversationKey, selectedConversation: action.payload.conversationKey,
areMoreTopMessagesBeingFetched: false, firstUnreadMessageId: action.payload.firstUnreadIdOnOpen,
areMoreBottomMessagesBeingFetched: false,
messages: action.payload.initialMessages, messages: action.payload.initialMessages,
areMoreMessagesBeingFetched: false,
showRightPanel: false, showRightPanel: false,
selectedMessageIds: [], selectedMessageIds: [],
lightBox: undefined, lightBox: undefined,
messageDetailProps: undefined, messageDetailProps: undefined,
quotedMessage: undefined, quotedMessage: undefined,
nextMessageToPlay: undefined, nextMessageToPlay: undefined,
showScrollButton: false, showScrollButton: Boolean(action.payload.firstUnreadIdOnOpen),
animateQuotedMessageId: undefined, animateQuotedMessageId: undefined,
shouldHighlightMessage: false, shouldHighlightMessage: false,
oldTopMessageId: null, oldTopMessageId: null,
oldBottomMessageId: null, oldBottomMessageId: null,
mentionMembers: [], mentionMembers: [],
firstUnreadMessageId: action.payload.firstUnreadIdOnOpen,
}; };
}, },
openConversationToSpecificMessage( openConversationToSpecificMessage(
@ -775,14 +783,16 @@ const conversationsSlice = createSlice({
conversationKey: string; conversationKey: string;
messageIdToNavigateTo: string; messageIdToNavigateTo: string;
shouldHighlightMessage: boolean; shouldHighlightMessage: boolean;
mostRecentMessageIdOnOpen: string | null;
initialMessages: Array<MessageModelPropsWithoutConvoProps>; initialMessages: Array<MessageModelPropsWithoutConvoProps>;
}> }>
) { ) {
return { return {
...state, ...state,
selectedConversation: action.payload.conversationKey, selectedConversation: action.payload.conversationKey,
areMoreTopMessagesBeingFetched: false, mostRecentMessageIdOnOpen: action.payload.mostRecentMessageIdOnOpen,
areMoreBottomMessagesBeingFetched: false, areMoreMessagesBeingFetched: false,
messages: action.payload.initialMessages, messages: action.payload.initialMessages,
showScrollButton: true, showScrollButton: true,
animateQuotedMessageId: action.payload.messageIdToNavigateTo, animateQuotedMessageId: action.payload.messageIdToNavigateTo,
@ -845,9 +855,12 @@ const conversationsSlice = createSlice({
// Add reducers for additional action types here, and handle loading state as needed // Add reducers for additional action types here, and handle loading state as needed
builder.addCase( builder.addCase(
fetchTopMessagesForConversation.fulfilled, fetchTopMessagesForConversation.fulfilled,
(state: ConversationsStateType, action: PayloadAction<FetchedTopMessageResults>) => { (
state: ConversationsStateType,
action: PayloadAction<FetchedTopMessageResults>
): ConversationsStateType => {
if (!action.payload) { if (!action.payload) {
return state; return { ...state, areMoreMessagesBeingFetched: false };
} }
// this is called once the messages are loaded from the db for the currently selected conversation // this is called once the messages are loaded from the db for the currently selected conversation
const { messagesProps, conversationKey, oldTopMessageId } = action.payload; const { messagesProps, conversationKey, oldTopMessageId } = action.payload;
@ -857,23 +870,34 @@ const conversationsSlice = createSlice({
...state, ...state,
oldTopMessageId, oldTopMessageId,
messages: messagesProps, messages: messagesProps,
areMoreTopMessagesBeingFetched: false, areMoreMessagesBeingFetched: false,
}; };
} }
return state; return state;
} }
); );
builder.addCase(fetchTopMessagesForConversation.pending, (state: ConversationsStateType) => { builder.addCase(
state.areMoreTopMessagesBeingFetched = true; fetchTopMessagesForConversation.pending,
}); (state: ConversationsStateType): ConversationsStateType => {
builder.addCase(fetchTopMessagesForConversation.rejected, (state: ConversationsStateType) => { state.areMoreMessagesBeingFetched = true;
state.areMoreTopMessagesBeingFetched = false; return state;
}); }
);
builder.addCase(
fetchTopMessagesForConversation.rejected,
(state: ConversationsStateType): ConversationsStateType => {
state.areMoreMessagesBeingFetched = false;
return state;
}
);
builder.addCase( builder.addCase(
fetchBottomMessagesForConversation.fulfilled, fetchBottomMessagesForConversation.fulfilled,
(state: ConversationsStateType, action: PayloadAction<FetchedBottomMessageResults>) => { (
state: ConversationsStateType,
action: PayloadAction<FetchedBottomMessageResults>
): ConversationsStateType => {
if (!action.payload) { if (!action.payload) {
return state; return { ...state, areMoreMessagesBeingFetched: false };
} }
// this is called once the messages are loaded from the db for the currently selected conversation // this is called once the messages are loaded from the db for the currently selected conversation
const { messagesProps, conversationKey, oldBottomMessageId } = action.payload; const { messagesProps, conversationKey, oldBottomMessageId } = action.payload;
@ -883,19 +907,24 @@ const conversationsSlice = createSlice({
...state, ...state,
oldBottomMessageId, oldBottomMessageId,
messages: messagesProps, messages: messagesProps,
areMoreBottomMessagesBeingFetched: false, areMoreMessagesBeingFetched: false,
}; };
} }
return state; return state;
} }
); );
builder.addCase(fetchBottomMessagesForConversation.pending, (state: ConversationsStateType) => { builder.addCase(
state.areMoreBottomMessagesBeingFetched = true; fetchBottomMessagesForConversation.pending,
}); (state: ConversationsStateType): ConversationsStateType => {
state.areMoreMessagesBeingFetched = true;
return state;
}
);
builder.addCase( builder.addCase(
fetchBottomMessagesForConversation.rejected, fetchBottomMessagesForConversation.rejected,
(state: ConversationsStateType) => { (state: ConversationsStateType): ConversationsStateType => {
state.areMoreBottomMessagesBeingFetched = false; state.areMoreMessagesBeingFetched = false;
return state;
} }
); );
}, },
@ -963,6 +992,7 @@ export async function openConversationWithMessages(args: {
}) { }) {
const { conversationKey, messageId } = args; const { conversationKey, messageId } = args;
const firstUnreadIdOnOpen = await getFirstUnreadMessageIdInConversation(conversationKey); const firstUnreadIdOnOpen = await getFirstUnreadMessageIdInConversation(conversationKey);
const mostRecentMessageIdOnOpen = await getLastMessageIdInConversation(conversationKey);
const initialMessages = await getMessages({ const initialMessages = await getMessages({
conversationKey, conversationKey,
@ -973,6 +1003,7 @@ export async function openConversationWithMessages(args: {
actions.openConversationExternal({ actions.openConversationExternal({
conversationKey, conversationKey,
firstUnreadIdOnOpen, firstUnreadIdOnOpen,
mostRecentMessageIdOnOpen,
initialMessages, initialMessages,
}) })
); );
@ -990,10 +1021,14 @@ export async function openConversationToSpecificMessage(args: {
messageId: messageIdToNavigateTo, messageId: messageIdToNavigateTo,
}); });
const mostRecentMessageIdOnOpen = await getLastMessageIdInConversation(conversationKey);
// we do not care about the firstunread message id when opening to a specific message
window.inboxStore?.dispatch( window.inboxStore?.dispatch(
actions.openConversationToSpecificMessage({ actions.openConversationToSpecificMessage({
conversationKey, conversationKey,
messageIdToNavigateTo, messageIdToNavigateTo,
mostRecentMessageIdOnOpen,
shouldHighlightMessage, shouldHighlightMessage,
initialMessages: messagesAroundThisMessage, initialMessages: messagesAroundThisMessage,
}) })

@ -160,12 +160,15 @@ export const getSortedMessagesOfSelectedConversation = createSelector(
} }
); );
export const getFirstUnreadMessageId = createSelector( const getFirstUnreadMessageId = createSelector(getConversations, (state: ConversationsStateType):
getConversations, | string
(state: ConversationsStateType): string | undefined => { | undefined => {
return state.firstUnreadMessageId; return state.firstUnreadMessageId;
} });
);
export const getConversationHasUnread = createSelector(getFirstUnreadMessageId, unreadId => {
return Boolean(unreadId);
});
export type MessagePropsType = export type MessagePropsType =
| 'group-notification' | 'group-notification'
@ -592,14 +595,9 @@ export const getQuotedMessage = createSelector(
(state: ConversationsStateType): ReplyingToMessageProps | undefined => state.quotedMessage (state: ConversationsStateType): ReplyingToMessageProps | undefined => state.quotedMessage
); );
export const areMoreTopMessagesBeingFetched = createSelector( export const areMoreMessagesBeingFetched = createSelector(
getConversations, getConversations,
(state: ConversationsStateType): boolean => state.areMoreTopMessagesBeingFetched || false (state: ConversationsStateType): boolean => state.areMoreMessagesBeingFetched || false
);
export const areMoreBottomMessagesBeingFetched = createSelector(
getConversations,
(state: ConversationsStateType): boolean => state.areMoreBottomMessagesBeingFetched || false
); );
export const getShowScrollButton = createSelector( export const getShowScrollButton = createSelector(
@ -685,10 +683,14 @@ function sortMessages(
return messagesSorted; return messagesSorted;
} }
/**
* This returns the most recent message id in the database. This is not the most recent message shown,
* but the most recent one, which could still not be loaded.
*/
export const getMostRecentMessageId = createSelector( export const getMostRecentMessageId = createSelector(
getSortedMessagesOfSelectedConversation, getConversations,
(messages: Array<MessageModelPropsWithoutConvoProps>): string | undefined => { (state: ConversationsStateType): string | null => {
return messages.length ? messages[0].propsForMessage.id : undefined; return state.mostRecentMessageId;
} }
); );

Loading…
Cancel
Save