add first step to enable back MessageDetails.

Still not much the react way to do it for now
pull/1381/head
Audric Ackermann 5 years ago
parent 71e1f1e143
commit 5c55a9411f
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -55,6 +55,9 @@ export interface MessageModel extends Backbone.Model<MessageAttributes> {
sendSyncMessageOnly: (message: any) => void; sendSyncMessageOnly: (message: any) => void;
isUnread: () => boolean; isUnread: () => boolean;
commit: () => Promise<number>; commit: () => Promise<number>;
getPropsForMessageDetail: (
onSendAnyway: any /*, onShowSafetyNumber: any*/
) => any; // FIXME enable this back. Be sure to handle case where it comes from a medium group
propsForMessage?: any; propsForMessage?: any;
propsForTimerNotification?: any; propsForTimerNotification?: any;

@ -617,7 +617,6 @@
onCopyPubKey: () => this.copyPubKey(), onCopyPubKey: () => this.copyPubKey(),
onBanUser: () => this.banUser(), onBanUser: () => this.banUser(),
onRetrySend: () => this.retrySend(), onRetrySend: () => this.retrySend(),
onShowDetail: () => this.trigger('show-message-detail', this),
markRead: readAt => this.markRead(readAt), markRead: readAt => this.markRead(readAt),
onShowUserDetails: pubkey => onShowUserDetails: pubkey =>
@ -804,7 +803,7 @@
return Boolean(lookup[contactId]); return Boolean(lookup[contactId]);
}, },
async getPropsForMessageDetail() { async getPropsForMessageDetail(onSendAnyway, onShowSafetyNumber) {
const newIdentity = i18n('newIdentity'); const newIdentity = i18n('newIdentity');
const OUTGOING_KEY_ERROR = 'OutgoingIdentityKeyError'; const OUTGOING_KEY_ERROR = 'OutgoingIdentityKeyError';
@ -867,13 +866,15 @@
isUnidentifiedDelivery, isUnidentifiedDelivery,
isPrimaryDevice, isPrimaryDevice,
profileName, profileName,
onSendAnyway: () => onSendAnyway: () => {
this.trigger('force-send', { onSendAnyway({
contact: this.findContact(id), contact: this.findContact(id),
message: this, message: this,
}), });
onShowSafetyNumber: () => },
this.trigger('show-identity', this.findContact(id)), onShowSafetyNumber: () => {
onShowSafetyNumber(this.findContact(id));
},
}; };
}) })
); );
@ -890,7 +891,7 @@
sentAt: this.get('sent_at'), sentAt: this.get('sent_at'),
receivedAt: this.get('received_at'), receivedAt: this.get('received_at'),
message: { message: {
...this.getPropsForMessage({ noClick: true }), ...this.propsForMessage,
disableMenu: true, disableMenu: true,
// To ensure that group avatar doesn't show up // To ensure that group avatar doesn't show up
conversationType: 'direct', conversationType: 'direct',

@ -2,6 +2,7 @@
height: calc(100% - 48px); height: calc(100% - 48px);
width: 100%; width: 100%;
overflow-y: auto; overflow-y: auto;
z-index: 2;
} }
.message-container { .message-container {

@ -1203,6 +1203,7 @@
.module-message-detail__contact__text { .module-message-detail__contact__text {
margin-inline-start: 10px; margin-inline-start: 10px;
flex-grow: 1; flex-grow: 1;
min-width: 0;
} }
.module-message-detail__contact__error { .module-message-detail__contact__error {

@ -145,54 +145,56 @@ export class MessageDetail extends React.Component<Props> {
const { errors, message, receivedAt, sentAt } = this.props; const { errors, message, receivedAt, sentAt } = this.props;
return ( return (
<div className="module-message-detail"> <div className="message-detail-wrapper">
<div className="module-message-detail__message-container"> <div className="module-message-detail">
<Message {...message} /> <div className="module-message-detail__message-container">
</div> <Message {...message} />
<table className="module-message-detail__info"> </div>
<tbody> <table className="module-message-detail__info">
{(errors || []).map((error, index) => ( <tbody>
<tr key={index}> {(errors || []).map((error, index) => (
<td className="module-message-detail__label"> <tr key={index}>
{i18n('error')} <td className="module-message-detail__label">
</td> {i18n('error')}
</td>
<td>
{' '}
<span className="error-message">{error.message}</span>{' '}
</td>
</tr>
))}
<tr>
<td className="module-message-detail__label">{i18n('sent')}</td>
<td> <td>
{' '} {moment(sentAt).format('LLLL')}{' '}
<span className="error-message">{error.message}</span>{' '} <span className="module-message-detail__unix-timestamp">
({sentAt})
</span>
</td> </td>
</tr> </tr>
))} {receivedAt ? (
<tr> <tr>
<td className="module-message-detail__label">{i18n('sent')}</td> <td className="module-message-detail__label">
<td> {i18n('received')}
{moment(sentAt).format('LLLL')}{' '} </td>
<span className="module-message-detail__unix-timestamp"> <td>
({sentAt}) {moment(receivedAt).format('LLLL')}{' '}
</span> <span className="module-message-detail__unix-timestamp">
</td> ({receivedAt})
</tr> </span>
{receivedAt ? ( </td>
</tr>
) : null}
<tr> <tr>
<td className="module-message-detail__label"> <td className="module-message-detail__label">
{i18n('received')} {message.direction === 'incoming' ? i18n('from') : i18n('to')}
</td>
<td>
{moment(receivedAt).format('LLLL')}{' '}
<span className="module-message-detail__unix-timestamp">
({receivedAt})
</span>
</td> </td>
</tr> </tr>
) : null} </tbody>
<tr> </table>
<td className="module-message-detail__label"> {this.renderContacts()}
{message.direction === 'incoming' ? i18n('from') : i18n('to')} {this.renderDeleteButton()}
</td> </div>
</tr>
</tbody>
</table>
{this.renderContacts()}
{this.renderDeleteButton()}
</div> </div>
); );
} }

@ -30,6 +30,7 @@ import { ConversationType } from '../../../state/ducks/conversations';
import { MessageView } from '../../MainViewController'; import { MessageView } from '../../MainViewController';
import { getMessageById, removeMessage } from '../../../../js/modules/data'; import { getMessageById, removeMessage } from '../../../../js/modules/data';
import { pushUnblockToSend } from '../../../session/utils/Toast'; import { pushUnblockToSend } from '../../../session/utils/Toast';
import { MessageDetail } from '../../conversation/MessageDetail';
interface State { interface State {
// Message sending progress // Message sending progress
@ -50,8 +51,11 @@ interface State {
showRecordingView: boolean; showRecordingView: boolean;
showOptionsPane: boolean; showOptionsPane: boolean;
// For displaying `More Info` on messages, and `Safety Number`, etc. // For displaying `Safety Number`, etc.
infoViewState?: 'safetyNumber' | 'messageDetails'; infoViewState?: 'safetyNumber';
// if set, the `More Info` of a message screen is shown on top of the conversation.
messageDetailShowProps?: any; // FIXME set the type for this
stagedAttachments: Array<StagedAttachmentType>; stagedAttachments: Array<StagedAttachmentType>;
isDraggingFile: boolean; isDraggingFile: boolean;
@ -127,6 +131,7 @@ export class SessionConversation extends React.Component<Props, State> {
this.deleteSelectedMessages = this.deleteSelectedMessages.bind(this); this.deleteSelectedMessages = this.deleteSelectedMessages.bind(this);
this.replyToMessage = this.replyToMessage.bind(this); this.replyToMessage = this.replyToMessage.bind(this);
this.showMessageDetails = this.showMessageDetails.bind(this);
this.deleteMessage = this.deleteMessage.bind(this); this.deleteMessage = this.deleteMessage.bind(this);
this.onClickAttachment = this.onClickAttachment.bind(this); this.onClickAttachment = this.onClickAttachment.bind(this);
this.downloadAttachment = this.downloadAttachment.bind(this); this.downloadAttachment = this.downloadAttachment.bind(this);
@ -210,6 +215,7 @@ export class SessionConversation extends React.Component<Props, State> {
infoViewState: undefined, infoViewState: undefined,
stagedAttachments: [], stagedAttachments: [],
isDraggingFile: false, isDraggingFile: false,
messageDetailShowProps: undefined,
}); });
} }
} }
@ -239,6 +245,8 @@ export class SessionConversation extends React.Component<Props, State> {
selectedMessages, selectedMessages,
isDraggingFile, isDraggingFile,
stagedAttachments, stagedAttachments,
infoViewState,
messageDetailShowProps,
} = this.state; } = this.state;
const selectionMode = !!selectedMessages.length; const selectionMode = !!selectedMessages.length;
@ -273,7 +281,7 @@ export class SessionConversation extends React.Component<Props, State> {
); );
if (this.messageContainerRef.current) { if (this.messageContainerRef.current) {
// force scrolling to bottom on message sent // force scrolling to bottom on message sent
// this will mark all messages as read // this will mark all messages as read, and reset the conversation unreadCount
(this.messageContainerRef (this.messageContainerRef
.current as any).scrollTop = this.messageContainerRef.current?.scrollHeight; .current as any).scrollTop = this.messageContainerRef.current?.scrollHeight;
} }
@ -281,8 +289,8 @@ export class SessionConversation extends React.Component<Props, State> {
const shouldRenderRightPanel = !conversationModel.isRss(); const shouldRenderRightPanel = !conversationModel.isRss();
const showSafetyNumber = this.state.infoViewState === 'safetyNumber'; const showSafetyNumber = infoViewState === 'safetyNumber';
const showMessageDetails = this.state.infoViewState === 'messageDetails'; const showMessageDetails = !!messageDetailShowProps;
return ( return (
<SessionTheme theme={this.props.theme}> <SessionTheme theme={this.props.theme}>
@ -308,13 +316,15 @@ export class SessionConversation extends React.Component<Props, State> {
<div <div
className={classNames( className={classNames(
'conversation-info-panel', 'conversation-info-panel',
this.state.infoViewState && 'show' (infoViewState || showMessageDetails) && 'show'
)} )}
> >
{showSafetyNumber && ( {showSafetyNumber && (
<SessionKeyVerification conversation={conversationModel} /> <SessionKeyVerification conversation={conversationModel} />
)} )}
{showMessageDetails && <>&nbsp</>} {showMessageDetails && (
<MessageDetail {...messageDetailShowProps} />
)}
</div> </div>
{lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)} {lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)}
@ -400,7 +410,11 @@ export class SessionConversation extends React.Component<Props, State> {
public getHeaderProps() { public getHeaderProps() {
const { conversationKey } = this.props; const { conversationKey } = this.props;
const { selectedMessages, infoViewState } = this.state; const {
selectedMessages,
infoViewState,
messageDetailShowProps,
} = this.state;
const conversation = window.ConversationController.getOrThrow( const conversation = window.ConversationController.getOrThrow(
conversationKey conversationKey
); );
@ -433,7 +447,7 @@ export class SessionConversation extends React.Component<Props, State> {
subscriberCount: conversation.get('subscriberCount'), subscriberCount: conversation.get('subscriberCount'),
isKickedFromGroup: conversation.get('isKickedFromGroup'), isKickedFromGroup: conversation.get('isKickedFromGroup'),
expirationSettingName, expirationSettingName,
showBackButton: Boolean(infoViewState), showBackButton: Boolean(infoViewState || messageDetailShowProps),
timerOptions: window.Whisper.ExpirationTimerOptions.map((item: any) => ({ timerOptions: window.Whisper.ExpirationTimerOptions.map((item: any) => ({
name: item.getName(), name: item.getName(),
value: item.get('seconds'), value: item.get('seconds'),
@ -458,7 +472,10 @@ export class SessionConversation extends React.Component<Props, State> {
}, },
onGoBack: () => { onGoBack: () => {
this.setState({ infoViewState: undefined }); this.setState({
infoViewState: undefined,
messageDetailShowProps: undefined,
});
}, },
onUpdateGroupName: () => { onUpdateGroupName: () => {
@ -514,6 +531,7 @@ export class SessionConversation extends React.Component<Props, State> {
deleteMessage: this.deleteMessage, deleteMessage: this.deleteMessage,
fetchMessagesForConversation: actions.fetchMessagesForConversation, fetchMessagesForConversation: actions.fetchMessagesForConversation,
replyToMessage: this.replyToMessage, replyToMessage: this.replyToMessage,
showMessageDetails: this.showMessageDetails,
onClickAttachment: this.onClickAttachment, onClickAttachment: this.onClickAttachment,
onDownloadAttachment: this.downloadAttachment, onDownloadAttachment: this.downloadAttachment,
messageContainerRef: this.messageContainerRef, messageContainerRef: this.messageContainerRef,
@ -812,6 +830,13 @@ export class SessionConversation extends React.Component<Props, State> {
} }
} }
private async showMessageDetails(messageProps: any) {
messageProps.onDeleteMessage = (id: string) => {
this.deleteMessage(id);
};
this.setState({ messageDetailShowProps: messageProps });
}
private onClickAttachment(attachment: any, message: any) { private onClickAttachment(attachment: any, message: any) {
const lightBoxOptions = { const lightBoxOptions = {
media: [ media: [

@ -37,6 +37,7 @@ interface Props {
count: number; count: number;
}) => void; }) => void;
replyToMessage: (messageId: number) => Promise<void>; replyToMessage: (messageId: number) => Promise<void>;
showMessageDetails: (messageProps: any) => Promise<void>;
onClickAttachment: (attachment: any, message: any) => void; onClickAttachment: (attachment: any, message: any) => void;
onDownloadAttachment: ({ attachment }: { attachment: any }) => void; onDownloadAttachment: ({ attachment }: { attachment: any }) => void;
onDeleteSelectedMessages: () => Promise<void>; onDeleteSelectedMessages: () => Promise<void>;
@ -61,6 +62,8 @@ export class SessionMessagesList extends React.Component<Props, State> {
this.getScrollOffsetBottomPx = this.getScrollOffsetBottomPx.bind(this); this.getScrollOffsetBottomPx = this.getScrollOffsetBottomPx.bind(this);
this.displayUnreadBannerIndex = this.displayUnreadBannerIndex.bind(this); this.displayUnreadBannerIndex = this.displayUnreadBannerIndex.bind(this);
this.onSendAnyway = this.onSendAnyway.bind(this);
this.messageContainerRef = this.props.messageContainerRef; this.messageContainerRef = this.props.messageContainerRef;
this.ignoreScrollEvents = true; this.ignoreScrollEvents = true;
} }
@ -272,7 +275,8 @@ export class SessionMessagesList extends React.Component<Props, State> {
{this.renderMessage( {this.renderMessage(
messageProps, messageProps,
message.firstMessageOfSeries, message.firstMessageOfSeries,
multiSelectMode multiSelectMode,
message
)} )}
{unreadIndicator} {unreadIndicator}
</> </>
@ -285,7 +289,8 @@ export class SessionMessagesList extends React.Component<Props, State> {
private renderMessage( private renderMessage(
messageProps: any, messageProps: any,
firstMessageOfSeries: boolean, firstMessageOfSeries: boolean,
multiSelectMode: boolean multiSelectMode: boolean,
message: MessageModel
) { ) {
const selected = const selected =
!!messageProps?.id && !!messageProps?.id &&
@ -298,6 +303,13 @@ export class SessionMessagesList extends React.Component<Props, State> {
messageProps.onSelectMessage = this.props.selectMessage; messageProps.onSelectMessage = this.props.selectMessage;
messageProps.onDeleteMessage = this.props.deleteMessage; messageProps.onDeleteMessage = this.props.deleteMessage;
messageProps.onReply = this.props.replyToMessage; messageProps.onReply = this.props.replyToMessage;
messageProps.onShowDetail = async () => {
void this.props.showMessageDetails(
await message.getPropsForMessageDetail(
this.onSendAnyway /*, this.props.onShowSafetyNumber*/
)
);
};
messageProps.onClickAttachment = (attachment: any) => { messageProps.onClickAttachment = (attachment: any) => {
this.props.onClickAttachment(attachment, messageProps); this.props.onClickAttachment(attachment, messageProps);
@ -534,4 +546,30 @@ export class SessionMessagesList extends React.Component<Props, State> {
const clientHeight = messageContainer.clientHeight; const clientHeight = messageContainer.clientHeight;
return scrollHeight - scrollTop - clientHeight; return scrollHeight - scrollTop - clientHeight;
} }
private async onSendAnyway({ contact, message }: any) {
const { i18n } = window;
window.confirmationDialog({
message: i18n('identityKeyErrorOnSend', [
contact.getTitle(),
contact.getTitle(),
]),
messageSub: i18n('youMayWishToVerifyContact'),
okText: i18n('sendAnyway'),
resolve: async () => {
await contact.updateVerified();
if (contact.isUnverified()) {
await contact.setVerifiedDefault();
}
const untrusted = await contact.isUntrusted();
if (untrusted) {
await contact.setApproved();
}
message.resend(contact.id);
},
});
}
} }

@ -33,7 +33,7 @@ export type MessageType = {
isSelected?: boolean; isSelected?: boolean;
}; };
export type MessageTypeInConvo = { type MessageTypeInConvo = {
id: string; id: string;
conversationId: string; conversationId: string;
attributes: any; attributes: any;
@ -46,6 +46,7 @@ export type MessageTypeInConvo = {
propsForGroupNotification: Object; propsForGroupNotification: Object;
firstMessageOfSeries: boolean; firstMessageOfSeries: boolean;
receivedAt: number; receivedAt: number;
getPropsForMessageDetail(): Promise<any>;
}; };
export type ConversationType = { export type ConversationType = {
@ -397,6 +398,15 @@ const toPickFromMessageModel = [
'propsForVerificationNotification', 'propsForVerificationNotification',
'propsForResetSessionNotification', 'propsForResetSessionNotification',
'propsForGroupNotification', 'propsForGroupNotification',
// FIXME below are what is needed to fetch on the fly messageDetails. This is not the react way
'getPropsForMessageDetail',
'get',
'getConversation',
'isIncoming',
'findAndFormatContact',
'findContact',
'isUnidentifiedDelivery',
'getStatus',
]; ];
function getEmptyState(): ConversationsStateType { function getEmptyState(): ConversationsStateType {

Loading…
Cancel
Save