|
|
@ -93,6 +93,7 @@ import {
|
|
|
|
} from '../../interactions/messageInteractions';
|
|
|
|
} from '../../interactions/messageInteractions';
|
|
|
|
import { updateUserDetailsModal } from '../../state/ducks/modalDialog';
|
|
|
|
import { updateUserDetailsModal } from '../../state/ducks/modalDialog';
|
|
|
|
import { MessageInteraction } from '../../interactions';
|
|
|
|
import { MessageInteraction } from '../../interactions';
|
|
|
|
|
|
|
|
import { useState } from 'react';
|
|
|
|
|
|
|
|
|
|
|
|
// Same as MIN_WIDTH in ImageGrid.tsx
|
|
|
|
// Same as MIN_WIDTH in ImageGrid.tsx
|
|
|
|
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
|
|
|
|
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
|
|
|
@ -107,91 +108,99 @@ interface State {
|
|
|
|
const EXPIRATION_CHECK_MINIMUM = 2000;
|
|
|
|
const EXPIRATION_CHECK_MINIMUM = 2000;
|
|
|
|
const EXPIRED_DELAY = 600;
|
|
|
|
const EXPIRED_DELAY = 600;
|
|
|
|
|
|
|
|
|
|
|
|
class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
const MessageInner = (props: MessageRegularProps) => {
|
|
|
|
public handleImageErrorBound: () => void;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public expirationCheckInterval: any;
|
|
|
|
let handleImageErrorBound: () => void;
|
|
|
|
public expiredTimeout: any;
|
|
|
|
|
|
|
|
public ctxMenuID: string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public constructor(props: MessageRegularProps) {
|
|
|
|
let expirationCheckInterval: any;
|
|
|
|
super(props);
|
|
|
|
let expiredTimeout: any;
|
|
|
|
|
|
|
|
let ctxMenuID: string;
|
|
|
|
|
|
|
|
|
|
|
|
this.handleImageErrorBound = this.handleImageError.bind(this);
|
|
|
|
// public constructor(props: MessageRegularProps) {
|
|
|
|
this.onReplyPrivate = this.onReplyPrivate.bind(this);
|
|
|
|
// super(props);
|
|
|
|
this.handleContextMenu = this.handleContextMenu.bind(this);
|
|
|
|
|
|
|
|
this.onAddModerator = this.onAddModerator.bind(this);
|
|
|
|
|
|
|
|
this.onRemoveFromModerator = this.onRemoveFromModerator.bind(this);
|
|
|
|
|
|
|
|
this.updatePlaybackSpeed = this.updatePlaybackSpeed.bind(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
// this.handleImageErrorBound = this.handleImageError.bind(this);
|
|
|
|
expiring: false,
|
|
|
|
// this.onReplyPrivate = this.onReplyPrivate.bind(this);
|
|
|
|
expired: false,
|
|
|
|
// this.handleContextMenu = this.handleContextMenu.bind(this);
|
|
|
|
imageBroken: false,
|
|
|
|
// this.onAddModerator = this.onAddModerator.bind(this);
|
|
|
|
playbackSpeed: 1,
|
|
|
|
// this.onRemoveFromModerator = this.onRemoveFromModerator.bind(this);
|
|
|
|
};
|
|
|
|
// this.updatePlaybackSpeed = this.updatePlaybackSpeed.bind(this);
|
|
|
|
this.ctxMenuID = `ctx-menu-message-${uuid()}`;
|
|
|
|
|
|
|
|
}
|
|
|
|
// this.state = {
|
|
|
|
|
|
|
|
// expiring: false,
|
|
|
|
|
|
|
|
// expired: false,
|
|
|
|
|
|
|
|
// imageBroken: false,
|
|
|
|
|
|
|
|
// playbackSpeed: 1,
|
|
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
// this.ctxMenuID = `ctx-menu-message-${uuid()}`;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [expiring, setExpiring] = useState(false);
|
|
|
|
|
|
|
|
const [expired, setExpired] = useState(false);
|
|
|
|
|
|
|
|
const [image, setImageBroken] = useState(false);
|
|
|
|
|
|
|
|
const [playbackSpeed, setPlaybackSpeed] = useState(1);
|
|
|
|
|
|
|
|
|
|
|
|
public componentDidMount() {
|
|
|
|
ctxMenuID = `ctx-menu-message-${uuid()}`;
|
|
|
|
const { expirationLength } = this.props;
|
|
|
|
|
|
|
|
if (!expirationLength) {
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
|
|
if (!props.expirationLength) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { expirationLength } = props;
|
|
|
|
|
|
|
|
|
|
|
|
const increment = getIncrement(expirationLength);
|
|
|
|
const increment = getIncrement(expirationLength);
|
|
|
|
const checkFrequency = Math.max(EXPIRATION_CHECK_MINIMUM, increment);
|
|
|
|
const checkFrequency = Math.max(EXPIRATION_CHECK_MINIMUM, increment);
|
|
|
|
|
|
|
|
|
|
|
|
this.checkExpired();
|
|
|
|
checkExpired();
|
|
|
|
|
|
|
|
|
|
|
|
this.expirationCheckInterval = setInterval(() => {
|
|
|
|
expirationCheckInterval = setInterval(() => {
|
|
|
|
this.checkExpired();
|
|
|
|
checkExpired();
|
|
|
|
}, checkFrequency);
|
|
|
|
}, checkFrequency);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public componentWillUnmount() {
|
|
|
|
}, [])
|
|
|
|
if (this.expirationCheckInterval) {
|
|
|
|
|
|
|
|
clearInterval(this.expirationCheckInterval);
|
|
|
|
|
|
|
|
}
|
|
|
|
// equivalent to componentWillUpdate
|
|
|
|
if (this.expiredTimeout) {
|
|
|
|
useEffect(() => {
|
|
|
|
clearTimeout(this.expiredTimeout);
|
|
|
|
checkExpired();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return occurs on unmount equivalent to componentWillUnmount
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
|
|
if (expirationCheckInterval) {
|
|
|
|
|
|
|
|
clearInterval(expirationCheckInterval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (expiredTimeout) {
|
|
|
|
|
|
|
|
clearTimeout(expiredTimeout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public componentDidUpdate() {
|
|
|
|
|
|
|
|
this.checkExpired();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
public checkExpired() {
|
|
|
|
const checkExpired = () => {
|
|
|
|
const now = Date.now();
|
|
|
|
const now = Date.now();
|
|
|
|
const { isExpired, expirationTimestamp, expirationLength } = this.props;
|
|
|
|
const { isExpired, expirationTimestamp, expirationLength } = props;
|
|
|
|
|
|
|
|
|
|
|
|
if (!expirationTimestamp || !expirationLength) {
|
|
|
|
if (!expirationTimestamp || !expirationLength) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.expiredTimeout) {
|
|
|
|
if (expiredTimeout) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (isExpired || now >= expirationTimestamp) {
|
|
|
|
if (isExpired || now >= expirationTimestamp) {
|
|
|
|
this.setState({
|
|
|
|
setExpiring(true);
|
|
|
|
expiring: true,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const setExpired = () => {
|
|
|
|
const triggerSetExpired = () => {
|
|
|
|
this.setState({
|
|
|
|
setExpired(true)
|
|
|
|
expired: true,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
this.expiredTimeout = setTimeout(setExpired, EXPIRED_DELAY);
|
|
|
|
expiredTimeout = setTimeout(triggerSetExpired(), EXPIRED_DELAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public handleImageError() {
|
|
|
|
const handleImageError = () => {
|
|
|
|
this.setState({
|
|
|
|
setImageBroken(true);
|
|
|
|
imageBroken: true,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// tslint:disable-next-line max-func-body-length cyclomatic-complexity
|
|
|
|
// tslint:disable-next-line max-func-body-length cyclomatic-complexity
|
|
|
|
public renderAttachment() {
|
|
|
|
public renderAttachment() {
|
|
|
@ -328,7 +337,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// tslint:disable-next-line cyclomatic-complexity
|
|
|
|
// tslint:disable-next-line cyclomatic-complexity
|
|
|
|
public renderPreview() {
|
|
|
|
public renderPreview() {
|
|
|
@ -419,7 +428,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public renderQuote() {
|
|
|
|
public renderQuote() {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
@ -472,7 +481,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
withContentAbove={withContentAbove}
|
|
|
|
withContentAbove={withContentAbove}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public renderAvatar() {
|
|
|
|
public renderAvatar() {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
@ -521,7 +530,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
)}
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public renderText() {
|
|
|
|
public renderText() {
|
|
|
|
const { text, direction, status, conversationType, convoId, multiSelectMode } = this.props;
|
|
|
|
const { text, direction, status, conversationType, convoId, multiSelectMode } = this.props;
|
|
|
@ -550,7 +559,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public renderError(isCorrectSide: boolean) {
|
|
|
|
public renderError(isCorrectSide: boolean) {
|
|
|
|
const { status, direction } = this.props;
|
|
|
|
const { status, direction } = this.props;
|
|
|
@ -566,7 +575,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public renderContextMenu() {
|
|
|
|
public renderContextMenu() {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
@ -680,7 +689,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
) : null}
|
|
|
|
) : null}
|
|
|
|
</Menu>
|
|
|
|
</Menu>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getWidth(): number | undefined {
|
|
|
|
public getWidth(): number | undefined {
|
|
|
|
const { attachments, previews } = this.props;
|
|
|
|
const { attachments, previews } = this.props;
|
|
|
@ -709,7 +718,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public isShowingImage(): boolean {
|
|
|
|
public isShowingImage(): boolean {
|
|
|
|
const { attachments, previews } = this.props;
|
|
|
|
const { attachments, previews } = this.props;
|
|
|
@ -741,7 +750,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// tslint:disable-next-line: cyclomatic-complexity
|
|
|
|
// tslint:disable-next-line: cyclomatic-complexity
|
|
|
|
public render() {
|
|
|
|
public render() {
|
|
|
@ -870,7 +879,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</InView>
|
|
|
|
</InView>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Doubles / halves the playback speed based on the current playback speed.
|
|
|
|
* Doubles / halves the playback speed based on the current playback speed.
|
|
|
@ -880,7 +889,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
...this.state,
|
|
|
|
...this.state,
|
|
|
|
playbackSpeed: this.state.playbackSpeed === 1 ? 2 : 1,
|
|
|
|
playbackSpeed: this.state.playbackSpeed === 1 ? 2 : 1,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private handleContextMenu(e: any) {
|
|
|
|
private handleContextMenu(e: any) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.preventDefault();
|
|
|
@ -896,7 +905,7 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
event: e,
|
|
|
|
event: e,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private renderAuthor() {
|
|
|
|
private renderAuthor() {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
@ -930,21 +939,21 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private onReplyPrivate(e: any) {
|
|
|
|
private onReplyPrivate(e: any) {
|
|
|
|
if (this.props && this.props.onReply) {
|
|
|
|
if (this.props && this.props.onReply) {
|
|
|
|
this.props.onReply(this.props.timestamp);
|
|
|
|
this.props.onReply(this.props.timestamp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async onAddModerator() {
|
|
|
|
private async onAddModerator() {
|
|
|
|
await addSenderAsModerator(this.props.authorPhoneNumber, this.props.convoId);
|
|
|
|
await addSenderAsModerator(this.props.authorPhoneNumber, this.props.convoId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async onRemoveFromModerator() {
|
|
|
|
private async onRemoveFromModerator() {
|
|
|
|
await removeSenderFromModerator(this.props.authorPhoneNumber, this.props.convoId);
|
|
|
|
await removeSenderFromModerator(this.props.authorPhoneNumber, this.props.convoId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export const Message = withTheme(MessageInner);
|
|
|
|
export const Message = withTheme(MessageInner);
|
|
|
|