From 1d45aa6f459818a492a89334d4c52e90b0d4651d Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 8 Sep 2022 16:26:43 +1000 Subject: [PATCH] fix: show loading spinner while sogs is fetching initial messages --- ts/components/basic/YourSessionIDPill.tsx | 1 - .../conversation/SessionConversation.tsx | 107 +++++++++++------- .../leftpane/overlay/OverlayCommunity.tsx | 14 ++- .../opengroupV2/JoinOpenGroupV2.ts | 16 --- .../opengroupV2/OpenGroupServerPoller.ts | 40 +++++-- ts/session/utils/GlobalEvents.ts | 3 - ts/state/ducks/conversations.ts | 22 +++- ts/state/selectors/conversations.ts | 5 + ts/state/smart/SessionConversation.ts | 2 + ts/window.d.ts | 1 + 10 files changed, 136 insertions(+), 75 deletions(-) delete mode 100644 ts/session/utils/GlobalEvents.ts diff --git a/ts/components/basic/YourSessionIDPill.tsx b/ts/components/basic/YourSessionIDPill.tsx index 7bf8eecb8..f949b9313 100644 --- a/ts/components/basic/YourSessionIDPill.tsx +++ b/ts/components/basic/YourSessionIDPill.tsx @@ -38,7 +38,6 @@ const StyledYourSessionIDSelectable = styled.p` user-select: none; text-align: center; word-break: break-all; - padding: 0px var(--margins-lg); font-weight: 300; color: var(--color-text); font-size: var(--font-size-sm); diff --git a/ts/components/conversation/SessionConversation.tsx b/ts/components/conversation/SessionConversation.tsx index a7a836565..65bc21e4b 100644 --- a/ts/components/conversation/SessionConversation.tsx +++ b/ts/components/conversation/SessionConversation.tsx @@ -54,6 +54,8 @@ import { ConversationMessageRequestButtons } from './ConversationRequestButtons' import { ConversationRequestinfo } from './ConversationRequestInfo'; import { getCurrentRecoveryPhrase } from '../../util/storage'; import loadImage from 'blueimp-load-image'; +import { SessionSpinner } from '../basic/SessionSpinner'; +import styled from 'styled-components'; // tslint:disable: jsx-curly-spacing interface State { @@ -78,8 +80,25 @@ interface Props { lightBoxOptions?: LightBoxOptions; stagedAttachments: Array; + isSelectedConvoInitialLoadingInProgress: boolean; } +const StyledSpinnerContainer = styled.div` + display: flex; + justify-content: center; + width: 100%; + height: 100%; + align-items: center; +`; + +const ConvoLoadingSpinner = () => { + return ( + + + + ); +}; + export class SessionConversation extends React.Component { private readonly messageContainerRef: React.RefObject; private dragCounter: number; @@ -219,6 +238,7 @@ export class SessionConversation extends React.Component { selectedMessages, isRightPanelShowing, lightBoxOptions, + isSelectedConvoInitialLoadingInProgress, } = this.props; if (!selectedConversation || !messagesProps) { @@ -233,46 +253,55 @@ export class SessionConversation extends React.Component {
-
-
- -
- {lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)} - -
- - } - bottom={ - + ) : ( + <> +
+
+ +
+ {lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)} + +
+ + } + bottom={ + + } + disableTop={!this.props.hasOngoingCallWithFocusedConvo} /> - } - disableTop={!this.props.hasOngoingCallWithFocusedConvo} - /> - - {isDraggingFile && } -
- - - -
-
- -
+ + {isDraggingFile && } +
+ + + +
+
+ +
+ + )} ); } diff --git a/ts/components/leftpane/overlay/OverlayCommunity.tsx b/ts/components/leftpane/overlay/OverlayCommunity.tsx index 23cad11c3..4a8d3b665 100644 --- a/ts/components/leftpane/overlay/OverlayCommunity.tsx +++ b/ts/components/leftpane/overlay/OverlayCommunity.tsx @@ -17,7 +17,10 @@ import { openGroupV2CompleteURLRegex } from '../../../session/apis/open_group_ap import { ToastUtils } from '../../../session/utils'; import useKey from 'react-use/lib/useKey'; import { getOverlayMode } from '../../../state/selectors/section'; -import { openConversationWithMessages } from '../../../state/ducks/conversations'; +import { + markConversationInitialLoadingInProgress, + openConversationWithMessages, +} from '../../../state/ducks/conversations'; async function joinOpenGroup( serverUrl: string, @@ -60,7 +63,14 @@ export const OverlayCommunity = () => { function joinSogsUICallback(args: JoinSogsRoomUICallbackArgs) { setLoading(args.loadingState === 'started'); - + if (args.conversationKey) { + dispatch( + markConversationInitialLoadingInProgress({ + conversationKey: args.conversationKey, + isInitialFetchingInProgress: true, + }) + ); + } if (args.loadingState === 'finished' && overlayModeIsCommunity && args.conversationKey) { closeOverlay(); void openConversationWithMessages({ conversationKey: args.conversationKey, messageId: null }); // open to last unread for a session run sogs diff --git a/ts/session/apis/open_group_api/opengroupV2/JoinOpenGroupV2.ts b/ts/session/apis/open_group_api/opengroupV2/JoinOpenGroupV2.ts index 9dba3a83d..54382a9c8 100644 --- a/ts/session/apis/open_group_api/opengroupV2/JoinOpenGroupV2.ts +++ b/ts/session/apis/open_group_api/opengroupV2/JoinOpenGroupV2.ts @@ -2,8 +2,6 @@ import _ from 'lodash'; import { OpenGroupV2Room } from '../../../../data/opengroups'; import { getConversationController } from '../../../conversations'; import { PromiseUtils, ToastUtils } from '../../../utils'; -import { getEventSogsFirstPoll } from '../../../utils/GlobalEvents'; -import { sleepFor, waitForTask } from '../../../utils/Promise'; import { forceSyncConfigurationNowIfNeeded } from '../../../utils/syncUtils'; import { @@ -154,20 +152,6 @@ export async function joinOpenGroupV2WithUIEvents( await joinOpenGroupV2(parsedRoom, fromConfigMessage); - if (!fromConfigMessage && showToasts) { - // this is very hacky but is made so we wait for the poller to receive the first messages related to that room. - // once the poller added all the messages to the queue of jobs to be run, we still wait a bit for them to be processed. - // This won't age well, but I am not too sure how we can design better. - await waitForTask(done => { - const eventToWait = getEventSogsFirstPoll(parsedRoom.serverPublicKey, parsedRoom.roomId); - window.Whisper.events.on(eventToWait, async () => { - window.Whisper.events.off(eventToWait); - await sleepFor(5000); - done(0); - }); - }, 25000); - } - const isConvoCreated = getConversationController().get(conversationID); if (isConvoCreated) { if (showToasts) { diff --git a/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts b/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts index 1e8592173..99e925faa 100644 --- a/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts +++ b/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts @@ -20,7 +20,10 @@ import { roomHasBlindEnabled, } from '../sogsv3/sogsV3Capabilities'; import { OpenGroupReaction } from '../../../../types/Reaction'; -import { getEventSogsFirstPoll } from '../../../utils/GlobalEvents'; +import { + markConversationInitialLoadingInProgress, + openConversationWithMessages, +} from '../../../../state/ducks/conversations'; export type OpenGroupMessageV4 = { /** AFAIK: indicates the number of the message in the group. e.g. 2nd message will be 1 or 2 */ @@ -319,14 +322,33 @@ export class OpenGroupServerPoller { // ==> At this point all those results need to trigger conversation updates, so update what we have to update await handleBatchPollResults(this.serverUrl, batchPollResults, subrequestOptions); - const roomsInDb = OpenGroupData.getV2OpenGroupRoomsByServerUrl(this.serverUrl); - if (roomsInDb?.[0]?.serverPublicKey) { - for (const room of subrequestOptions) { - if (room.type === 'messages' && !room.messages?.sinceSeqNo && room.messages?.roomId) { - window.Whisper.events.trigger( - getEventSogsFirstPoll(roomsInDb[0].serverPublicKey, room.messages.roomId) - ); - } + for (const room of subrequestOptions) { + if (room.type === 'messages' && !room.messages?.sinceSeqNo && room.messages?.roomId) { + const conversationKey = getOpenGroupV2ConversationId( + this.serverUrl, + room.messages.roomId + ); + + global.setTimeout(() => { + const stateConversations = window.inboxStore?.getState().conversations; + if ( + stateConversations.conversationLookup?.[conversationKey]?.isInitialFetchingInProgress + ) { + if ( + stateConversations.selectedConversation && + conversationKey === stateConversations.selectedConversation + ) { + void openConversationWithMessages({ conversationKey, messageId: null }).then(() => { + window.inboxStore?.dispatch( + markConversationInitialLoadingInProgress({ + conversationKey, + isInitialFetchingInProgress: false, + }) + ); + }); + } + } + }, 5000); } } } catch (e) { diff --git a/ts/session/utils/GlobalEvents.ts b/ts/session/utils/GlobalEvents.ts deleted file mode 100644 index 52d16b8cb..000000000 --- a/ts/session/utils/GlobalEvents.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function getEventSogsFirstPoll(serverpubkey: string, roomId: string) { - return `first-poll-sogs:${roomId}-${serverpubkey}`; -} diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 178fe8618..0ff54b94d 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -264,6 +264,7 @@ export interface ReduxConversationType { currentNotificationSetting?: ConversationNotificationSettingType; isPinned?: boolean; + isInitialFetchingInProgress?: boolean; isApproved?: boolean; didApproveMe?: boolean; @@ -717,10 +718,6 @@ const conversationsSlice = createSlice({ initialMessages: Array; }> ) { - if (state.selectedConversation === action.payload.conversationKey) { - return state; - } - // this is quite hacky, but we don't want to show the showScrollButton if we have only a small amount of messages, // or if the first unread message is not far from the most recent one. // this is because when a new message get added, we do not add it to redux depending on the showScrollButton state. @@ -835,6 +832,20 @@ const conversationsSlice = createSlice({ state.mentionMembers = action.payload; return state; }, + markConversationInitialLoadingInProgress( + state: ConversationsStateType, + action: PayloadAction<{ conversationKey: string; isInitialFetchingInProgress: boolean }> + ) { + window?.log?.info( + `mark conversation initialLoading ${action.payload.conversationKey}: ${action.payload.isInitialFetchingInProgress}` + ); + if (state.conversationLookup[action.payload.conversationKey]) { + state.conversationLookup[action.payload.conversationKey].isInitialFetchingInProgress = + action.payload.isInitialFetchingInProgress; + } + + return state; + }, }, extraReducers: (builder: any) => { // Add reducers for additional action types here, and handle loading state as needed @@ -945,7 +956,7 @@ function applyConversationChanged( selectedConversation, conversationLookup: { ...conversationLookup, - [id]: data, + [id]: { ...data, isInitialFetchingInProgress: existing.isInitialFetchingInProgress }, }, }; } @@ -981,6 +992,7 @@ export const { setNextMessageToPlayId, updateMentionsMembers, resetConversationExternal, + markConversationInitialLoadingInProgress, } = actions; export async function openConversationWithMessages(args: { diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index 247380d89..f3b1c0b3c 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -1172,3 +1172,8 @@ export const getOldBottomMessageId = createSelector( getConversations, (state: ConversationsStateType): string | null => state.oldBottomMessageId || null ); + +export const getIsSelectedConvoInitialLoadingInProgress = createSelector( + getSelectedConversation, + (convo: ReduxConversationType | undefined): boolean => Boolean(convo?.isInitialFetchingInProgress) +); diff --git a/ts/state/smart/SessionConversation.ts b/ts/state/smart/SessionConversation.ts index f38cf803b..ca9692a6c 100644 --- a/ts/state/smart/SessionConversation.ts +++ b/ts/state/smart/SessionConversation.ts @@ -3,6 +3,7 @@ import { mapDispatchToProps } from '../actions'; import { StateType } from '../reducer'; import { getTheme } from '../selectors/theme'; import { + getIsSelectedConvoInitialLoadingInProgress, getLightBoxOptions, getSelectedConversation, getSelectedConversationKey, @@ -29,6 +30,7 @@ const mapStateToProps = (state: StateType) => { lightBoxOptions: getLightBoxOptions(state), stagedAttachments: getStagedAttachmentsForCurrentConversation(state), hasOngoingCallWithFocusedConvo: getHasOngoingCallWithFocusedConvo(state), + isSelectedConvoInitialLoadingInProgress: getIsSelectedConvoInitialLoadingInProgress(state), }; }; diff --git a/ts/window.d.ts b/ts/window.d.ts index aabfae723..6e55cbb27 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -6,6 +6,7 @@ import { Store } from 'redux'; import { ConversationCollection, ConversationModel } from './models/conversation'; import { ConversationType } from './state/ducks/conversations'; +import { StateType } from './state/reducer'; export interface LibTextsecure { messaging: boolean;