Merge pull request #1466 from Bilb/fix-link-previews

fix previews sent on next message if they are resolved too late
pull/1469/head
Audric Ackermann 4 years ago committed by GitHub
commit 859cbfbe36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -165,6 +165,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
this.onChooseAttachment = this.onChooseAttachment.bind(this);
this.onClickAttachment = this.onClickAttachment.bind(this);
this.renderCaptionEditor = this.renderCaptionEditor.bind(this);
this.abortLinkPreviewFetch = this.abortLinkPreviewFetch.bind(this);
// On Sending
this.onSendMessage = this.onSendMessage.bind(this);
@ -183,7 +184,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
}
public componentWillUnmount() {
this.linkPreviewAbortController?.abort();
this.abortLinkPreviewFetch();
this.linkPreviewAbortController = undefined;
}
public componentDidUpdate(prevProps: Props, _prevState: State) {
@ -566,7 +567,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
},
});
const abortController = new AbortController();
this.linkPreviewAbortController?.abort();
this.abortLinkPreviewFetch();
this.linkPreviewAbortController = abortController;
setTimeout(() => {
abortController.abort();
@ -590,31 +591,64 @@ export class SessionCompositionBox extends React.Component<Props, State> {
}
}
}
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: ret?.title || null,
description: ret?.description || '',
url: ret?.url || null,
domain:
(ret?.url && window.Signal.LinkPreviews.getDomain(ret.url)) || '',
image,
},
});
// we finished loading the preview, and checking the abortConrtoller, we are still not aborted.
// => update the staged preview
if (
this.linkPreviewAbortController &&
!this.linkPreviewAbortController.signal.aborted
) {
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: ret?.title || null,
description: ret?.description || '',
url: ret?.url || null,
domain:
(ret?.url && window.Signal.LinkPreviews.getDomain(ret.url)) ||
'',
image,
},
});
} else if (this.linkPreviewAbortController) {
this.setState({
stagedLinkPreview: {
isLoaded: false,
title: null,
description: null,
url: null,
domain: null,
image: undefined,
},
});
this.linkPreviewAbortController = undefined;
}
})
.catch(err => {
window.log.warn('fetch link preview: ', err);
abortController.abort();
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: null,
domain: null,
description: null,
url: firstLink,
image: undefined,
},
});
const aborted = this.linkPreviewAbortController?.signal.aborted;
this.linkPreviewAbortController = undefined;
// if we were aborted, it either means the UI was unmount, or more probably,
// than the message was sent without the link preview.
// So be sure to reset the staged link preview so it is not sent with the next message.
// if we were not aborted, it's probably just an error on the fetch. Nothing to do excpet mark the fetch as done (with errors)
if (aborted) {
this.setState({
stagedLinkPreview: undefined,
});
} else {
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: null,
description: null,
url: firstLink,
domain: null,
image: undefined,
},
});
}
});
}
@ -751,6 +785,8 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// tslint:disable-next-line: cyclomatic-complexity
private async onSendMessage() {
this.abortLinkPreviewFetch();
// this is dirty but we have to replace all @(xxx) by @xxx manually here
const cleanMentions = (text: string): string => {
const matches = text.match(this.mentionsRegex);
@ -835,10 +871,13 @@ export class SessionCompositionBox extends React.Component<Props, State> {
'attachments'
);
// we consider that a link previews without a title at least is not a preview
const linkPreviews =
(stagedLinkPreview && [
_.pick(stagedLinkPreview, 'url', 'image', 'title'),
]) ||
(stagedLinkPreview &&
stagedLinkPreview.isLoaded &&
stagedLinkPreview.title?.length && [
_.pick(stagedLinkPreview, 'url', 'image', 'title'),
]) ||
[];
try {
@ -854,20 +893,15 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// Message sending sucess
this.props.onMessageSuccess();
this.props.clearAttachments();
// Empty composition box
// Empty composition box and stagedAttachments
this.setState({
message: '',
showEmojiPanel: false,
stagedLinkPreview: undefined,
ignoredLink: undefined,
});
// Empty stagedAttachments
this.props.clearAttachments();
if (stagedLinkPreview && stagedLinkPreview.url) {
this.setState({
stagedLinkPreview: undefined,
ignoredLink: undefined,
});
}
} catch (e) {
// Message sending failed
window.log.error(e);
@ -983,4 +1017,8 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// Focus the textarea when user clicks anywhere in the composition box
this.textarea.current?.focus();
}
private abortLinkPreviewFetch() {
this.linkPreviewAbortController?.abort();
}
}

@ -131,3 +131,11 @@ export async function timeout<T>(
return Promise.race([timeoutPromise, promise]);
}
export async function delay(timeoutMs: number = 2000): Promise<Boolean> {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, timeoutMs);
});
}

@ -9,6 +9,7 @@ import {
IMAGE_WEBP,
MIMEType,
} from '../types/MIME';
import { PromiseUtils } from '../session/utils';
const MAX_REQUEST_COUNT_WITH_REDIRECTS = 20;
// tslint:disable: prefer-for-of

Loading…
Cancel
Save