import React, { useEffect, useState } from 'react'; import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon'; import { Avatar, AvatarSize } from '../../Avatar'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton'; import { SessionDropdown } from '../SessionDropdown'; import { MediaGallery } from '../../conversation/media-gallery/MediaGallery'; import _, { noop } from 'lodash'; import { TimerOption } from '../../conversation/ConversationHeader'; import { Constants } from '../../../session'; import { ConversationAvatar, usingClosedConversationDetails, } from '../usingClosedConversationDetails'; import { AttachmentTypeWithPath, save } from '../../../types/Attachment'; import { DefaultTheme, useTheme, withTheme } from 'styled-components'; import { getMessagesWithFileAttachments, getMessagesWithVisualMediaAttachments, } from '../../../data/data'; import { getDecryptedMediaUrl } from '../../../session/crypto/DecryptedAttachmentsManager'; import { LightBoxOptions } from './SessionConversation'; import { UserUtils } from '../../../session/utils'; import { sendDataExtractionNotification } from '../../../session/messages/outgoing/controlMessage/DataExtractionNotificationMessage'; import { SpacerLG } from '../../basic/Text'; import { deleteMessagesByConvoIdWithConfirmation, setDisappearingMessagesByConvoId, showAddModeratorsByConvoId, showInviteContactByConvoId, showLeaveGroupByConvoId, showRemoveModeratorsByConvoId, showUpdateGroupMembersByConvoId, showUpdateGroupNameByConvoId, } from '../../../interactions/conversationInteractions'; import { ItemClickEvent } from '../../conversation/media-gallery/types/ItemClickEvent'; import { MediaItemType } from '../../LightboxGallery'; // tslint:disable-next-line: no-submodule-imports import useInterval from 'react-use/lib/useInterval'; import { useSelector } from 'react-redux'; import { getTimerOptions } from '../../../state/selectors/timerOptions'; type Props = { id: string; name?: string; profileName?: string; phoneNumber: string; memberCount: number; avatarPath: string | null; isPublic: boolean; isAdmin: boolean; isKickedFromGroup: boolean; left: boolean; isBlocked: boolean; isShowing: boolean; isGroup: boolean; memberAvatars?: Array; // this is added by usingClosedConversationDetails onGoBack: () => void; onShowLightBox: (lightboxOptions?: LightBoxOptions) => void; }; async function getMediaGalleryProps( conversationId: string, medias: Array, onShowLightBox: (lightboxOptions?: LightBoxOptions) => void ): Promise<{ documents: Array; media: Array; onItemClick: any; }> { // We fetch more documents than media as they don’t require to be loaded // into memory right away. Revisit this once we have infinite scrolling: const rawMedia = await getMessagesWithVisualMediaAttachments(conversationId, { limit: Constants.CONVERSATION.DEFAULT_MEDIA_FETCH_COUNT, }); const rawDocuments = await getMessagesWithFileAttachments(conversationId, { limit: Constants.CONVERSATION.DEFAULT_DOCUMENTS_FETCH_COUNT, }); const media = _.flatten( rawMedia.map(attributes => { const { attachments, source, id, timestamp, serverTimestamp, received_at } = attributes; return (attachments || []) .filter( (attachment: AttachmentTypeWithPath) => attachment.thumbnail && !attachment.pending && !attachment.error ) .map((attachment: AttachmentTypeWithPath, index: number) => { const { thumbnail } = attachment; const mediaItem: MediaItemType = { objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath(attachment.path), thumbnailObjectUrl: thumbnail ? window.Signal.Migrations.getAbsoluteAttachmentPath(thumbnail.path) : null, contentType: attachment.contentType || '', index, messageTimestamp: timestamp || serverTimestamp || received_at || 0, messageSender: source, messageId: id, attachment, }; return mediaItem; }); }) ); // Unlike visual media, only one non-image attachment is supported const documents = rawDocuments.map(attributes => { // this is to not fail if the attachment is invalid (could be a Long Attachment type which is not supported) if (!attributes.attachments?.length) { // window?.log?.info( // 'Got a message with an empty list of attachment. Skipping...' // ); return null; } const attachment = attributes.attachments[0]; const { source, id, timestamp, serverTimestamp, received_at } = attributes; return { contentType: attachment.contentType, index: 0, attachment, messageTimestamp: timestamp || serverTimestamp || received_at || 0, messageSender: source, messageId: id, }; }); const saveAttachment = async ({ attachment, messageTimestamp, messageSender, }: { attachment: AttachmentTypeWithPath; messageTimestamp: number; messageSender: string; }) => { const timestamp = messageTimestamp; attachment.url = await getDecryptedMediaUrl(attachment.url, attachment.contentType); save({ attachment, document, getAbsolutePath: window.Signal.Migrations.getAbsoluteAttachmentPath, timestamp, }); await sendDataExtractionNotification(conversationId, messageSender, timestamp); }; const onItemClick = (event: ItemClickEvent) => { if (!event) { console.warn('no event'); return; } const { mediaItem, type } = event; switch (type) { case 'documents': { void saveAttachment({ messageSender: mediaItem.messageSender, messageTimestamp: mediaItem.messageTimestamp, attachment: mediaItem.attachment, }); break; } case 'media': { const lightBoxOptions: LightBoxOptions = { media: medias, attachment: mediaItem.attachment, }; onShowLightBox(lightBoxOptions); break; } default: throw new TypeError(`Unknown attachment type: '${type}'`); } }; return { media, documents: _.compact(documents), // remove null onItemClick, }; } // tslint:disable: cyclomatic-complexity // tslint:disable: max-func-body-length export const SessionRightPanelWithDetails = (props: Props) => { const [documents, setDocuments] = useState>([]); const [media, setMedia] = useState>([]); const [onItemClick, setOnItemClick] = useState(undefined); const theme = useTheme(); console.warn('props', props); useEffect(() => { let isRunning = true; if (props.isShowing) { void getMediaGalleryProps(props.id, media, props.onShowLightBox).then(results => { console.warn('results2', results); if (isRunning) { setDocuments(results.documents); setMedia(results.media); setOnItemClick(results.onItemClick); } }); } return () => { isRunning = false; return; }; }, [props.isShowing, props.id]); useInterval(async () => { if (props.isShowing) { const results = await getMediaGalleryProps(props.id, media, props.onShowLightBox); console.warn('results', results); if (results.documents.length !== documents.length || results.media.length !== media.length) { setDocuments(results.documents); setMedia(results.media); setOnItemClick(results.onItemClick); } } }, 10000); function renderHeader() { const { memberAvatars, onGoBack, avatarPath, profileName, phoneNumber } = props; const showInviteContacts = (isPublic || isAdmin) && !isKickedFromGroup && !isBlocked && !left; const userName = name || profileName || phoneNumber; return (
{showInviteContacts && ( { showInviteContactByConvoId(props.id); }} theme={theme} /> )}
); } const { id, memberCount, name, isKickedFromGroup, left, isPublic, isAdmin, isBlocked, isGroup, } = props; const showMemberCount = !!(memberCount && memberCount > 0); const commonNoShow = isKickedFromGroup || left || isBlocked; console.warn('AUDRIC: render right panel'); const hasDisappearingMessages = !isPublic && !commonNoShow; const leaveGroupString = isPublic ? window.i18n('leaveGroup') : isKickedFromGroup ? window.i18n('youGotKickedFromGroup') : left ? window.i18n('youLeftTheGroup') : window.i18n('leaveGroup'); const timerOptions = useSelector(getTimerOptions).timerOptions; const disappearingMessagesOptions = timerOptions.map(option => { return { content: option.name, onClick: async () => { await setDisappearingMessagesByConvoId(id, option.value); }, }; }); const showUpdateGroupNameButton = isAdmin && !commonNoShow; const showAddRemoveModeratorsButton = isAdmin && !commonNoShow && isPublic; const showUpdateGroupMembersButton = !isPublic && isGroup && !commonNoShow; const deleteConvoAction = isPublic ? () => { deleteMessagesByConvoIdWithConfirmation(id); } : () => { showLeaveGroupByConvoId(id); }; console.warn('onItemClick', onItemClick); return (
{renderHeader()}

{name}

{showMemberCount && ( <>
{window.i18n('members', memberCount)}
)} {showUpdateGroupNameButton && (
{ await showUpdateGroupNameByConvoId(id); }} > {isPublic ? window.i18n('editGroup') : window.i18n('editGroupName')}
)} {showAddRemoveModeratorsButton && ( <>
{ showAddModeratorsByConvoId(id); }} > {window.i18n('addModerators')}
{ showRemoveModeratorsByConvoId(id); }} > {window.i18n('removeModerators')}
)} {showUpdateGroupMembersButton && (
{ await showUpdateGroupMembersByConvoId(id); }} > {window.i18n('groupMembers')}
)} {hasDisappearingMessages && ( )} {isGroup && ( // tslint:disable-next-line: use-simple-attributes )}
); };