From 009795eb3b344d3cf9eeac68a0c46d3483a6efbc Mon Sep 17 00:00:00 2001 From: William Grant Date: Fri, 28 Jun 2024 17:24:14 +1000 Subject: [PATCH] feat: migrated lightbox to modal state --- .../conversation/SessionConversation.tsx | 20 ------------- .../media-gallery/MediaGridItem.tsx | 5 ++-- .../message-content/MessageAttachment.tsx | 23 +++++++-------- ts/components/dialog/ModalContainer.tsx | 4 +++ ts/components/lightbox/Lightbox.tsx | 8 +++--- ts/components/lightbox/LightboxGallery.tsx | 10 +++---- ts/state/ducks/conversations.ts | 11 -------- ts/state/ducks/modalDialog.tsx | 28 +++++++++++++++++++ ts/state/selectors/conversations.ts | 4 --- ts/state/selectors/modal.ts | 6 ++++ ts/state/smart/SessionConversation.ts | 2 -- 11 files changed, 59 insertions(+), 62 deletions(-) diff --git a/ts/components/conversation/SessionConversation.tsx b/ts/components/conversation/SessionConversation.tsx index a7c178ee2..1150e5916 100644 --- a/ts/components/conversation/SessionConversation.tsx +++ b/ts/components/conversation/SessionConversation.tsx @@ -34,7 +34,6 @@ import { import { updateConfirmModal } from '../../state/ducks/modalDialog'; import { addStagedAttachmentsInConversation } from '../../state/ducks/stagedAttachments'; import { MIME } from '../../types'; -import { AttachmentTypeWithPath } from '../../types/Attachment'; import { THUMBNAIL_CONTENT_TYPE, getAudioDuration, @@ -48,7 +47,6 @@ import { EmptyMessageView } from '../EmptyMessageView'; import { SplitViewContainer } from '../SplitViewContainer'; import { SessionButtonColor } from '../basic/SessionButton'; import { InConversationCallContainer } from '../calling/InConversationCallContainer'; -import { LightboxGallery, MediaItemType } from '../lightbox/LightboxGallery'; import { NoMessageInConversation } from './SubtleNotification'; import { ConversationHeaderWithDetails } from './header/ConversationHeader'; @@ -63,10 +61,6 @@ const DEFAULT_JPEG_QUALITY = 0.85; interface State { isDraggingFile: boolean; } -export interface LightBoxOptions { - media: Array; - attachment: AttachmentTypeWithPath; -} interface Props { ourDisplayNameInProfile: string; @@ -79,9 +73,6 @@ interface Props { hasOngoingCallWithFocusedConvo: boolean; htmlDirection: HTMLDirection; - // lightbox options - lightBoxOptions?: LightBoxOptions; - stagedAttachments: Array; isSelectedConvoInitialLoadingInProgress: boolean; } @@ -238,7 +229,6 @@ export class SessionConversation extends Component { messagesProps, selectedMessages, isRightPanelShowing, - lightBoxOptions, isSelectedConvoInitialLoadingInProgress, } = this.props; @@ -280,8 +270,6 @@ export class SessionConversation extends Component { onKeyDown={this.onKeyDown} role="navigation" > - {lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)} -
@@ -357,14 +345,6 @@ export class SessionConversation extends Component { } } - private renderLightBox({ media, attachment }: LightBoxOptions) { - const selectedIndex = - media.length > 1 - ? media.findIndex(mediaMessage => mediaMessage.attachment.path === attachment.path) - : 0; - return ; - } - private async onChoseAttachments(attachmentsFileList: Array) { if (!attachmentsFileList || attachmentsFileList.length === 0) { return; diff --git a/ts/components/conversation/media-gallery/MediaGridItem.tsx b/ts/components/conversation/media-gallery/MediaGridItem.tsx index a71d21163..d392b9b4c 100644 --- a/ts/components/conversation/media-gallery/MediaGridItem.tsx +++ b/ts/components/conversation/media-gallery/MediaGridItem.tsx @@ -3,10 +3,9 @@ import { useState } from 'react'; import { useDisableDrag } from '../../../hooks/useDisableDrag'; import { useEncryptedFileFetch } from '../../../hooks/useEncryptedFileFetch'; -import { showLightBox } from '../../../state/ducks/conversations'; +import { LightBoxOptions, updateLightBoxOptions } from '../../../state/ducks/modalDialog'; import { isImageTypeSupported, isVideoTypeSupported } from '../../../util/GoogleChrome'; import { MediaItemType } from '../../lightbox/LightboxGallery'; -import { LightBoxOptions } from '../SessionConversation'; type Props = { mediaItem: MediaItemType; @@ -104,7 +103,7 @@ export const MediaGridItem = (props: Props) => { attachment: props.mediaItem.attachment, }; - window.inboxStore?.dispatch(showLightBox(lightBoxOptions)); + window.inboxStore?.dispatch(updateLightBoxOptions(lightBoxOptions)); }} > diff --git a/ts/components/conversation/message/message-content/MessageAttachment.tsx b/ts/components/conversation/message/message-content/MessageAttachment.tsx index ba5161b76..6534faed2 100644 --- a/ts/components/conversation/message/message-content/MessageAttachment.tsx +++ b/ts/components/conversation/message/message-content/MessageAttachment.tsx @@ -5,11 +5,8 @@ import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; import { Data } from '../../../../data/data'; import { MessageModelType, MessageRenderingProps } from '../../../../models/messageType'; -import { - PropsForAttachment, - showLightBox, - toggleSelectedMessageId, -} from '../../../../state/ducks/conversations'; +import { PropsForAttachment, toggleSelectedMessageId } from '../../../../state/ducks/conversations'; +import { LightBoxOptions, updateLightBoxOptions } from '../../../../state/ducks/modalDialog'; import { StateType } from '../../../../state/reducer'; import { useMessageSelected } from '../../../../state/selectors'; import { @@ -28,10 +25,10 @@ import { isVideo, } from '../../../../types/Attachment'; import { saveAttachmentToDisk } from '../../../../util/attachmentsUtil'; +import { MediaItemType } from '../../../lightbox/LightboxGallery'; import { Spinner } from '../../../loading'; import { AudioPlayerWithEncryptedFile } from '../../H5AudioPlayer'; import { ImageGrid } from '../../ImageGrid'; -import { LightBoxOptions } from '../../SessionConversation'; import { ClickToTrustSender } from './ClickToTrustSender'; import { MessageHighlighter } from './MessageHighlighter'; @@ -244,7 +241,7 @@ export async function showLightboxFromAttachmentProps( const media = (msgAttachments || []).map(attachmentForMedia => { index++; const messageTimestamp = - found.get('timestamp') || found.get('serverTimestamp') || found.get('received_at'); + found.get('timestamp') || found.get('serverTimestamp') || found.get('received_at') || -1; return { index: clone(index), @@ -259,10 +256,10 @@ export async function showLightboxFromAttachmentProps( if (attachmentIsAttachmentTypeWithPath(selected)) { const lightBoxOptions: LightBoxOptions = { - media: media as any, + media, attachment: selected, }; - window.inboxStore?.dispatch(showLightBox(lightBoxOptions)); + window.inboxStore?.dispatch(updateLightBoxOptions(lightBoxOptions)); } else { window.log.warn('Attachment is not of the right type'); } @@ -281,10 +278,10 @@ const onClickAttachment = async (onClickProps: { } const msgAttachments = found.getPropsForMessage().attachments; - const media = (msgAttachments || []).map(attachmentForMedia => { + const media: Array = (msgAttachments || []).map(attachmentForMedia => { index++; const messageTimestamp = - found.get('timestamp') || found.get('serverTimestamp') || found.get('received_at'); + found.get('timestamp') || found.get('serverTimestamp') || found.get('received_at') || -1; return { index: clone(index), @@ -299,10 +296,10 @@ const onClickAttachment = async (onClickProps: { if (attachmentIsAttachmentTypeWithPath(onClickProps.attachment)) { const lightBoxOptions: LightBoxOptions = { - media: media as any, + media, attachment: onClickProps.attachment, }; - window.inboxStore?.dispatch(showLightBox(lightBoxOptions)); + window.inboxStore?.dispatch(updateLightBoxOptions(lightBoxOptions)); } else { window.log.warn('Attachment is not of the right type'); } diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index 944edeebd..a643ce2dc 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -10,6 +10,7 @@ import { getEnterPasswordModalState, getHideRecoveryPasswordModalState, getInviteContactModal, + getLightBoxOptions, getOnionPathDialog, getReactClearAllDialog, getReactListDialog, @@ -19,6 +20,7 @@ import { getUpdateGroupNameModal, getUserDetailsModal, } from '../../state/selectors/modal'; +import { LightboxGallery } from '../lightbox/LightboxGallery'; import { BanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; import { DeleteAccountModal } from './DeleteAccountModal'; import { EditProfilePictureModal } from './EditProfilePictureModal'; @@ -57,6 +59,7 @@ export const ModalContainer = () => { const reactClearAllModalState = useSelector(getReactClearAllDialog); const editProfilePictureModalState = useSelector(getEditProfilePictureModalState); const hideRecoveryPasswordModalState = useSelector(getHideRecoveryPasswordModalState); + const lightBoxOptions = useSelector(getLightBoxOptions); return ( <> @@ -84,6 +87,7 @@ export const ModalContainer = () => { {hideRecoveryPasswordModalState && ( )} + {lightBoxOptions && } ); }; diff --git a/ts/components/lightbox/Lightbox.tsx b/ts/components/lightbox/Lightbox.tsx index f7ab461b3..6d9245e24 100644 --- a/ts/components/lightbox/Lightbox.tsx +++ b/ts/components/lightbox/Lightbox.tsx @@ -6,7 +6,7 @@ import useUnmount from 'react-use/lib/useUnmount'; import styled from 'styled-components'; import { useDisableDrag } from '../../hooks/useDisableDrag'; import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch'; -import { showLightBox } from '../../state/ducks/conversations'; +import { updateLightBoxOptions } from '../../state/ducks/modalDialog'; import * as MIME from '../../types/MIME'; import { assertUnreachable } from '../../types/sqlSharedTypes'; import { GoogleChrome } from '../../util'; @@ -277,14 +277,14 @@ export const Lightbox = (props: Props) => { const onObjectClick = (event: any) => { event.stopPropagation(); - dispatch(showLightBox(undefined)); + dispatch(updateLightBoxOptions(null)); }; const onContainerClick = (event: MouseEvent) => { if (renderedRef && event.target === renderedRef.current) { return; } - dispatch(showLightBox(undefined)); + dispatch(updateLightBoxOptions(null)); }; return ( @@ -309,7 +309,7 @@ export const Lightbox = (props: Props) => { { - dispatch(showLightBox(undefined)); + dispatch(updateLightBoxOptions(null)); }} /> diff --git a/ts/components/lightbox/LightboxGallery.tsx b/ts/components/lightbox/LightboxGallery.tsx index f89e26106..12ea7ce0b 100644 --- a/ts/components/lightbox/LightboxGallery.tsx +++ b/ts/components/lightbox/LightboxGallery.tsx @@ -4,7 +4,7 @@ import useKey from 'react-use/lib/useKey'; import { Lightbox } from './Lightbox'; -import { showLightBox } from '../../state/ducks/conversations'; +import { updateLightBoxOptions } from '../../state/ducks/modalDialog'; import { useSelectedConversationKey } from '../../state/selectors/selectedConversation'; import { MIME } from '../../types'; import { AttachmentTypeWithPath } from '../../types/Attachment'; @@ -23,11 +23,11 @@ export interface MediaItemType { type Props = { media: Array; - selectedIndex: number; + selectedIndex?: number; }; export const LightboxGallery = (props: Props) => { - const { media } = props; + const { media, selectedIndex = -1 } = props; const [currentIndex, setCurrentIndex] = useState(-1); const selectedConversation = useSelectedConversationKey(); @@ -35,7 +35,7 @@ export const LightboxGallery = (props: Props) => { // just run once, when the component is mounted. It's to show the lightbox on the specified index at start. useEffect(() => { - setCurrentIndex(props.selectedIndex); + setCurrentIndex(selectedIndex); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -82,7 +82,7 @@ export const LightboxGallery = (props: Props) => { useKey( 'Escape', () => { - dispatch(showLightBox(undefined)); + dispatch(updateLightBoxOptions(null)); }, undefined, [currentIndex] diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 198b8a83a..e2af55ef2 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -3,7 +3,6 @@ import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; import { omit, toNumber } from 'lodash'; import { ReplyingToMessageProps } from '../../components/conversation/composition/CompositionBox'; import { QuotedAttachmentType } from '../../components/conversation/message/message-content/quote/Quote'; -import { LightBoxOptions } from '../../components/conversation/SessionConversation'; import { Data } from '../../data/data'; import { ConversationInteractionStatus, @@ -313,7 +312,6 @@ export type ConversationsStateType = { messageInfoId: string | undefined; showRightPanel: boolean; selectedMessageIds: Array; - lightBox?: LightBoxOptions; quotedMessage?: ReplyingToMessageProps; areMoreMessagesBeingFetched: boolean; @@ -869,7 +867,6 @@ const conversationsSlice = createSlice({ showRightPanel: false, selectedMessageIds: [], - lightBox: undefined, messageInfoId: undefined, quotedMessage: undefined, @@ -935,13 +932,6 @@ const conversationsSlice = createSlice({ state.oldBottomMessageId = null; return state; }, - showLightBox( - state: ConversationsStateType, - action: PayloadAction - ) { - state.lightBox = action.payload; - return state; - }, showScrollToBottomButton(state: ConversationsStateType, action: PayloadAction) { state.showScrollButton = action.payload; return state; @@ -1141,7 +1131,6 @@ export const { addMessageIdToSelection, resetSelectedMessageIds, toggleSelectedMessageId, - showLightBox, quoteMessage, showScrollToBottomButton, quotedMessageToAnimate, diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index cb27d97b7..5f04f0d2a 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -2,6 +2,8 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { EnterPasswordModalProps } from '../../components/dialog/EnterPasswordModal'; import { HideRecoveryPasswordDialogProps } from '../../components/dialog/HideRecoveryPasswordDialog'; import { SessionConfirmDialogProps } from '../../components/dialog/SessionConfirm'; +import { MediaItemType } from '../../components/lightbox/LightboxGallery'; +import { AttachmentTypeWithPath } from '../../types/Attachment'; import type { EditProfilePictureModalProps, PasswordAction } from '../../types/ReduxTypes'; export type BanType = 'ban' | 'unban'; @@ -40,6 +42,12 @@ export type EditProfilePictureModalState = EditProfilePictureModalProps | null; export type HideRecoveryPasswordModalState = HideRecoveryPasswordDialogProps | null; +export type LightBoxOptions = { + media: Array; + attachment: AttachmentTypeWithPath; + selectedIndex?: number; +} | null; + export type ModalState = { confirmModal: ConfirmModalState; inviteContactModal: InviteContactModalState; @@ -59,6 +67,7 @@ export type ModalState = { reactClearAllModalState: ReactModalsState; editProfilePictureModalState: EditProfilePictureModalState; hideRecoveryPasswordModalState: HideRecoveryPasswordModalState; + lightBoxOptions: LightBoxOptions; }; export const initialModalState: ModalState = { @@ -80,6 +89,7 @@ export const initialModalState: ModalState = { reactClearAllModalState: null, editProfilePictureModalState: null, hideRecoveryPasswordModalState: null, + lightBoxOptions: null, }; const ModalSlice = createSlice({ @@ -140,6 +150,23 @@ const ModalSlice = createSlice({ updateHideRecoveryPasswordModel(state, action: PayloadAction) { return { ...state, hideRecoveryPasswordModalState: action.payload }; }, + updateLightBoxOptions(state, action: PayloadAction) { + const lightBoxOptions = action.payload; + + if (lightBoxOptions) { + const { media, attachment } = lightBoxOptions; + + if (attachment && media) { + const selectedIndex = + media.length > 1 + ? media.findIndex(mediaMessage => mediaMessage.attachment.path === attachment.path) + : 0; + lightBoxOptions.selectedIndex = selectedIndex; + } + } + + return { ...state, lightBoxOptions }; + }, }, }); @@ -163,5 +190,6 @@ export const { updateReactClearAllModal, updateEditProfilePictureModel, updateHideRecoveryPasswordModel, + updateLightBoxOptions, } = actions; export const modalReducer = reducer; diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index d56abfea8..29cf2ae44 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -22,7 +22,6 @@ import { MessageContentSelectorProps } from '../../components/conversation/messa import { MessageContentWithStatusSelectorProps } from '../../components/conversation/message/message-content/MessageContentWithStatus'; import { MessageTextSelectorProps } from '../../components/conversation/message/message-content/MessageText'; import { GenericReadableMessageSelectorProps } from '../../components/conversation/message/message-item/GenericReadableMessage'; -import { LightBoxOptions } from '../../components/conversation/SessionConversation'; import { hasValidIncomingRequestValues } from '../../models/conversation'; import { CONVERSATION_PRIORITIES, isOpenOrClosedGroup } from '../../models/conversationAttributes'; import { getConversationController } from '../../session/conversations'; @@ -511,9 +510,6 @@ export const getSelectedMessageIds = (state: StateType): Array => export const getIsMessageSelectionMode = (state: StateType): boolean => Boolean(getSelectedMessageIds(state).length); -export const getLightBoxOptions = (state: StateType): LightBoxOptions | undefined => - state.conversations.lightBox; - export const getQuotedMessage = (state: StateType): ReplyingToMessageProps | undefined => state.conversations.quotedMessage; diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index 1e22a7498..71ce6b581 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -11,6 +11,7 @@ import { EnterPasswordModalState, HideRecoveryPasswordModalState, InviteContactModalState, + LightBoxOptions, ModalState, OnionPathModalState, ReactModalsState, @@ -115,3 +116,8 @@ export const getHideRecoveryPasswordModalState = createSelector( getModal, (state: ModalState): HideRecoveryPasswordModalState => state.hideRecoveryPasswordModalState ); + +export const getLightBoxOptions = createSelector( + getModal, + (state: ModalState): LightBoxOptions => state.lightBoxOptions +); diff --git a/ts/state/smart/SessionConversation.ts b/ts/state/smart/SessionConversation.ts index 9941d8137..ed7e05590 100644 --- a/ts/state/smart/SessionConversation.ts +++ b/ts/state/smart/SessionConversation.ts @@ -6,7 +6,6 @@ import { StateType } from '../reducer'; import { getHasOngoingCallWithFocusedConvo } from '../selectors/call'; import { getIsSelectedConvoInitialLoadingInProgress, - getLightBoxOptions, getSelectedConversation, getSelectedMessageIds, getSortedMessagesOfSelectedConversation, @@ -31,7 +30,6 @@ const mapStateToProps = (state: StateType, ownProps: SmartSessionConversationOwn ourNumber: getOurNumber(state), isRightPanelShowing: isRightPanelShowing(state), selectedMessages: getSelectedMessageIds(state), - lightBoxOptions: getLightBoxOptions(state), stagedAttachments: getStagedAttachmentsForCurrentConversation(state), hasOngoingCallWithFocusedConvo: getHasOngoingCallWithFocusedConvo(state), isSelectedConvoInitialLoadingInProgress: getIsSelectedConvoInitialLoadingInProgress(state),