session-desktop/ts/components/session/SessionConversation.tsx

368 lines
12 KiB
TypeScript
Raw Normal View History

2020-02-25 01:29:44 +01:00
import React, { useEffect, useRef } from 'react';
2020-02-17 01:02:35 +01:00
import { ConversationHeader } from '../conversation/ConversationHeader';
2020-02-19 02:05:48 +01:00
import { SessionCompositionBox } from './SessionCompositionBox';
import { SessionProgress } from './SessionProgress'
import { Message } from '../conversation/Message';
2020-02-25 07:26:45 +01:00
import { FriendRequest } from '../conversation/FriendRequest';
2020-02-25 05:20:34 +01:00
import { TimerNotification } from '../conversation/TimerNotification';
2020-02-25 07:26:45 +01:00
2020-02-19 03:54:59 +01:00
import { SessionSpinner } from './SessionSpinner';
2020-02-25 01:29:44 +01:00
import { SessionScrollButton } from './SessionScrollButton';
2020-02-21 00:17:04 +01:00
// interface Props {
// getHeaderProps: any;
// conversationKey: any;
// }
2020-02-25 05:20:34 +01:00
interface State {
sendingProgess: number;
prevSendingProgess: number;
conversationKey: string;
2020-02-26 00:33:32 +01:00
unreadCount: number;
messages: Array<any>;
2020-02-25 01:29:44 +01:00
// Scroll position as percentage of message-list
scrollPositionPc: number;
// Scroll position in pixels
scrollPositionPx: number;
doneInitialScroll: boolean;
2020-02-26 00:33:32 +01:00
messageFetchTimestamp: number;
}
2020-02-21 00:17:04 +01:00
export class SessionConversation extends React.Component<any, State> {
2020-02-25 01:29:44 +01:00
private messagesEndRef: React.RefObject<HTMLDivElement>;
2020-02-19 02:05:48 +01:00
constructor(props: any) {
super(props);
2020-02-26 00:33:32 +01:00
2020-02-24 04:11:54 +01:00
const conversationKey = this.props.conversations.selectedConversation;
2020-02-26 00:33:32 +01:00
const conversation = this.props.conversations.conversationLookup[conversationKey];
const unreadCount = conversation.unreadCount;
console.log(`[vince][info] Conversation: `, conversation);
this.state = {
sendingProgess: 0,
prevSendingProgess: 0,
conversationKey,
2020-02-26 00:33:32 +01:00
unreadCount,
2020-02-25 05:20:34 +01:00
messages: [],
2020-02-25 01:29:44 +01:00
doneInitialScroll: false,
scrollPositionPc: 0,
scrollPositionPx: 0,
2020-02-26 00:33:32 +01:00
messageFetchTimestamp: 0,
};
2020-02-24 04:11:54 +01:00
2020-02-25 01:29:44 +01:00
this.scrollToUnread = this.scrollToUnread.bind(this);
this.scrollToBottom = this.scrollToBottom.bind(this);
2020-02-25 05:20:34 +01:00
this.renderMessage = this.renderMessage.bind(this);
this.renderTimerNotification = this.renderTimerNotification.bind(this);
2020-02-25 07:26:45 +01:00
this.renderFriendRequest = this.renderFriendRequest.bind(this);
2020-02-25 05:20:34 +01:00
2020-02-25 01:29:44 +01:00
this.messagesEndRef = React.createRef();
2020-02-24 04:11:54 +01:00
}
2020-02-25 05:20:34 +01:00
public async componentWillMount() {
const { conversationKey } = this.state;
await this.getMessages(conversationKey);
2020-02-26 00:33:32 +01:00
// Inside a setTimeout to simultate onready()
2020-02-25 01:29:44 +01:00
setTimeout(() => {
this.scrollToBottom(true);
2020-02-25 05:20:34 +01:00
}, 0);
setTimeout(() => {
this.setState({
doneInitialScroll: true,
});
}, 100);
2020-02-25 01:29:44 +01:00
2020-02-19 02:05:48 +01:00
}
2020-02-25 05:20:34 +01:00
public async componentWillReceiveProps() {
const { conversationKey } = this.state;
2020-02-26 00:33:32 +01:00
const timestamp = this.getTimestamp();
// If we have pulled messages in the last second, don't bother rescanning
// This avoids getting messages on every re-render.
if (timestamp > this.state.messageFetchTimestamp) {
await this.getMessages(conversationKey);
} else{
console.log(`[vince][info] Messages recieved in last second, stream`);
}
}
2020-02-19 02:05:48 +01:00
render() {
2020-02-24 04:11:54 +01:00
console.log('[vince] SessionConversation was just rerendered!');
console.log(`[vince] These are SessionConversation props: `, this.props);
// const headerProps = this.props.getHeaderProps;
2020-02-25 01:29:44 +01:00
const { messages, conversationKey, doneInitialScroll } = this.state;
2020-02-25 05:20:34 +01:00
const loading = !doneInitialScroll || messages.length === 0;
2020-02-25 01:29:44 +01:00
console.log(`[vince] Loading: `, loading);
2020-02-24 04:11:54 +01:00
console.log(`[vince] My conversation key is: `, conversationKey);
2020-02-25 05:20:34 +01:00
2020-02-24 04:11:54 +01:00
// TMEPORARY SOLUTION TO GETTING CONVERSATION UNTIL
// SessionConversationStack is created
// Get conversation by Key (NOT cid)
2020-02-24 04:11:54 +01:00
const conversation = this.props.conversations.conversationLookup[conversationKey]
return (
2020-02-25 01:29:44 +01:00
<div className="conversation-item">
<div className="conversation-header">
{this.renderHeader(conversation)}
</div>
<SessionProgress
visible={true}
value={this.state.sendingProgess}
prevValue={this.state.prevSendingProgess}
/>
2020-02-25 01:29:44 +01:00
<div className="messages-wrapper">
{ loading && (
<div className="messages-container__loading">
2020-02-25 05:20:34 +01:00
{/* <SessionSpinner/> */}
</div>
)}
2020-02-25 01:29:44 +01:00
<div className="messages-container">
2020-02-26 00:33:32 +01:00
{this.renderMessages()}
2020-02-25 01:29:44 +01:00
<div ref={this.messagesEndRef} />
</div>
2020-02-26 00:33:32 +01:00
<SessionScrollButton display={true} onClick={this.scrollToUnread}/>
2020-02-25 01:29:44 +01:00
</div>
2020-02-19 02:05:48 +01:00
<SessionCompositionBox
onSendMessage={() => null}
/>
</div>
);
}
2020-02-25 05:20:34 +01:00
public renderMessages() {
const { messages } = this.state;
2020-02-25 07:26:45 +01:00
return (
<>{
messages.map((message: any) => {
2020-02-25 05:20:34 +01:00
const messageProps = message.propsForMessage;
const timerProps = message.propsForTimerNotification;
2020-02-25 07:26:45 +01:00
const friendRequestProps = message.propsForFriendRequest;
2020-02-25 05:20:34 +01:00
const attachmentProps = message.propsForAttachment;
2020-02-25 07:26:45 +01:00
const groupNotificationProps = message.propsForGroupNotification;
2020-02-25 05:20:34 +01:00
const quoteProps = message.propsForQuote;
let item;
2020-02-25 07:26:45 +01:00
// firstMessageOfSeries tells us to render the avatar only for the first message
// in a series of messages from the same user
item = messageProps ? this.renderMessage(messageProps, message.firstMessageOfSeries) : item;
2020-02-25 05:20:34 +01:00
item = timerProps ? this.renderTimerNotification(timerProps) : item;
2020-02-25 07:26:45 +01:00
item = quoteProps ? this.renderMessage(timerProps, message.firstMessageOfSeries, quoteProps) : item;
item = friendRequestProps
? this.renderFriendRequest(friendRequestProps): item;
// item = attachmentProps ? this.renderMessage(timerProps) : item;
2020-02-25 05:20:34 +01:00
return item;
})
}</>
);
}
public renderHeader(conversation: any) {
2020-02-19 02:05:48 +01:00
return (
<ConversationHeader
id={conversation.cid}
phoneNumber={conversation.id}
isVerified={true}
isMe={false}
isFriend={true}
i18n={window.i18n}
isGroup={false}
isArchived={false}
isPublic={false}
isRss={false}
amMod={false}
members={[]}
showBackButton={false}
timerOptions={[]}
isBlocked={false}
hasNickname={false}
isFriendRequestPending={false}
isOnline={true}
selectedMessages={null}
onSetDisappearingMessages={() => null}
onDeleteMessages={() => null}
onDeleteContact={() => null}
onResetSession={() => null}
onCloseOverlay={() => null}
onDeleteSelectedMessages={() => null}
onArchive={() => null}
onMoveToInbox={() => null}
onShowSafetyNumber={() => null}
onShowAllMedia={() => null}
onShowGroupMembers={() => null}
onGoBack={() => null}
onBlockUser={() => null}
onUnblockUser={() => null}
onClearNickname={() => null}
onChangeNickname={() => null}
onCopyPublicKey={() => null}
onLeaveGroup={() => null}
onAddModerators={() => null}
onRemoveModerators={() => null}
onInviteFriends={() => null}
/>
);
}
2020-02-25 05:20:34 +01:00
2020-02-26 00:33:32 +01:00
public async getMessages(conversationKey: string){
const msgCount = window.CONSTANTS.DEFAULT_MESSAGE_FETCH_COUNT + this.state.unreadCount;
2020-02-25 05:20:34 +01:00
const messageSet = await window.Signal.Data.getMessagesByConversation(
conversationKey,
2020-02-26 00:33:32 +01:00
{ msgCount, MessageCollection: window.Whisper.MessageCollection },
2020-02-25 05:20:34 +01:00
);
2020-02-25 07:26:45 +01:00
// Set first member of series here.
const messageModels = messageSet.models;
let messages = [];
let previousSender;
for (let i = 0; i < messageModels.length; i++){
2020-02-26 00:33:32 +01:00
// Handle firstMessageOfSeries for conditional avatar rendering
2020-02-25 07:26:45 +01:00
let firstMessageOfSeries = true;
if (i > 0 && previousSender === messageModels[i].authorPhoneNumber){
firstMessageOfSeries = false;
}
2020-02-26 00:33:32 +01:00
2020-02-25 07:26:45 +01:00
messages.push({...messageModels[i], firstMessageOfSeries});
previousSender = messageModels[i].authorPhoneNumber;
}
2020-02-26 00:33:32 +01:00
const messageFetchTimestamp = this.getTimestamp();
console.log(`[vince][messages] Messages Set`, messageModels);
this.setState({ messages, messageFetchTimestamp });
2020-02-25 05:20:34 +01:00
}
2020-02-25 07:26:45 +01:00
public renderMessage(messageProps: any, firstMessageOfSeries: boolean, quoteProps?: any) {
2020-02-25 05:20:34 +01:00
return (
<Message
i18n = {window.i18n}
2020-02-25 07:26:45 +01:00
text = {messageProps?.text}
direction = {messageProps?.direction}
timestamp = {messageProps?.timestamp}
attachments = {messageProps?.attachments}
authorAvatarPath = {messageProps?.authorAvatarPath}
authorColor = {messageProps?.authorColor}
authorName = {messageProps?.authorName}
authorPhoneNumber = {messageProps?.authorPhoneNumber}
firstMessageOfSeries = {firstMessageOfSeries}
authorProfileName = {messageProps?.authorProfileName}
contact = {messageProps?.contact}
conversationType = {messageProps?.conversationType}
convoId = {messageProps?.convoId}
expirationLength = {messageProps?.expirationLength}
expirationTimestamp = {messageProps?.expirationTimestamp}
id = {messageProps?.id}
isDeletable = {messageProps?.isDeletable}
isExpired = {messageProps?.isExpired}
isModerator = {messageProps?.isModerator}
isPublic = {messageProps?.isPublic}
isRss = {messageProps?.isRss}
multiSelectMode = {messageProps?.multiSelectMode}
onBanUser = {messageProps?.onBanUser}
onClickAttachment = {messageProps?.onClickAttachment}
onClickLinkPreview = {messageProps?.onClickLinkPreview}
onCopyPubKey = {messageProps?.onCopyPubKey}
onCopyText = {messageProps?.onCopyText}
onDelete = {messageProps?.onDelete}
onDownload = {messageProps?.onDownload}
onReply = {messageProps?.onReply}
onRetrySend = {messageProps?.onRetrySend}
onSelectMessage = {messageProps?.onSelectMessage}
onSelectMessageUnchecked = {messageProps?.onSelectMessageUnchecked}
onShowDetail = {messageProps?.onShowDetail}
onShowUserDetails = {messageProps?.onShowUserDetails}
previews = {messageProps?.previews}
quote = {quoteProps || undefined}
selected = {messageProps?.selected}
senderIsModerator = {messageProps?.senderIsModerator}
status = {messageProps?.status}
textPending = {messageProps?.textPending}
2020-02-25 05:20:34 +01:00
/>
);
2020-02-25 07:26:45 +01:00
2020-02-25 05:20:34 +01:00
}
public renderTimerNotification(timerProps: any) {
return (
<TimerNotification
type={timerProps.type}
phoneNumber={timerProps.phoneNumber}
profileName={timerProps.profileName}
name={timerProps.name}
disabled={timerProps.disabled}
timespan={timerProps.timespan}
i18n={window.i18n}
/>
);
}
2020-02-25 07:26:45 +01:00
public renderFriendRequest(friendRequestProps: any){
return (
<FriendRequest
text={friendRequestProps.text}
direction={friendRequestProps.direction}
status={friendRequestProps.status}
friendStatus={friendRequestProps.friendStatus}
i18n={window.i18n}
isBlocked={friendRequestProps.isBlocked}
timestamp={friendRequestProps.timestamp}
onAccept={friendRequestProps.onAccept}
onDecline={friendRequestProps.onDecline}
onDeleteConversation={friendRequestProps.onDeleteConversation}
onRetrySend={friendRequestProps.onRetrySend}
onBlockUser={friendRequestProps.onBlockUser}
onUnblockUser={friendRequestProps.onUnblockUser}
/>
);
}
2020-02-26 00:33:32 +01:00
public getTimestamp() {
return Math.floor(Date.now() / 1000);
}
public handleScroll() {
// Update unread count
// Get id of message at bottom of screen in full view. This is scroll position by messageID
}
public scrollToUnread() {
const topUnreadMessage = document.getElementById('70fd6220-5292-43d8-9e0d-f98bf4792f43');
topUnreadMessage?.scrollIntoView(false);
}
public scrollToBottom(firstLoad = false) {
this.messagesEndRef.current?.scrollIntoView(
{ behavior: firstLoad ? 'auto' : 'smooth' }
);
}
}
2020-02-25 05:20:34 +01:00