Merge branch 'develop' into improved-forwarding-ui
This commit is contained in:
commit
678b298bab
67 changed files with 2134 additions and 567 deletions
|
@ -50,6 +50,9 @@ class FilePanel extends React.Component {
|
|||
if (room?.roomId !== this.props?.roomId) return;
|
||||
if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return;
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
client.decryptEventIfNeeded(ev);
|
||||
|
||||
if (ev.isBeingDecrypted()) {
|
||||
this.decryptingEvents.add(ev.getId());
|
||||
} else {
|
||||
|
|
|
@ -27,7 +27,7 @@ import CallMediaHandler from '../../CallMediaHandler';
|
|||
import { fixupColorFonts } from '../../utils/FontManager';
|
||||
import * as sdk from '../../index';
|
||||
import dis from '../../dispatcher/dispatcher';
|
||||
import {MatrixClientPeg, IMatrixClientCreds} from '../../MatrixClientPeg';
|
||||
import { IMatrixClientCreds } from '../../MatrixClientPeg';
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
|
||||
import TagOrderActions from '../../actions/TagOrderActions';
|
||||
|
@ -219,16 +219,6 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
// Child components assume that the client peg will not be null, so give them some
|
||||
// sort of assurance here by only allowing a re-render if the client is truthy.
|
||||
//
|
||||
// This is required because `LoggedInView` maintains its own state and if this state
|
||||
// updates after the client peg has been made null (during logout), then it will
|
||||
// attempt to re-render and the children will throw errors.
|
||||
shouldComponentUpdate() {
|
||||
return Boolean(MatrixClientPeg.get());
|
||||
}
|
||||
|
||||
canResetTimelineInRoom = (roomId) => {
|
||||
if (!this._roomView.current) {
|
||||
return true;
|
||||
|
|
|
@ -86,6 +86,8 @@ import {RoomUpdateCause} from "../../stores/room-list/models";
|
|||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||
import SecurityCustomisations from "../../customisations/Security";
|
||||
|
||||
import PerformanceMonitor, { PerformanceEntryNames } from "../../performance";
|
||||
|
||||
/** constants for MatrixChat.state.view */
|
||||
export enum Views {
|
||||
// a special initial state which is only used at startup, while we are
|
||||
|
@ -484,42 +486,22 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
|
||||
startPageChangeTimer() {
|
||||
// Tor doesn't support performance
|
||||
if (!performance || !performance.mark) return null;
|
||||
|
||||
// This shouldn't happen because UNSAFE_componentWillUpdate and componentDidUpdate
|
||||
// are used.
|
||||
if (this.pageChanging) {
|
||||
console.warn('MatrixChat.startPageChangeTimer: timer already started');
|
||||
return;
|
||||
}
|
||||
this.pageChanging = true;
|
||||
performance.mark('element_MatrixChat_page_change_start');
|
||||
PerformanceMonitor.instance.start(PerformanceEntryNames.PAGE_CHANGE);
|
||||
}
|
||||
|
||||
stopPageChangeTimer() {
|
||||
// Tor doesn't support performance
|
||||
if (!performance || !performance.mark) return null;
|
||||
const perfMonitor = PerformanceMonitor.instance;
|
||||
|
||||
if (!this.pageChanging) {
|
||||
console.warn('MatrixChat.stopPageChangeTimer: timer not started');
|
||||
return;
|
||||
}
|
||||
this.pageChanging = false;
|
||||
performance.mark('element_MatrixChat_page_change_stop');
|
||||
performance.measure(
|
||||
'element_MatrixChat_page_change_delta',
|
||||
'element_MatrixChat_page_change_start',
|
||||
'element_MatrixChat_page_change_stop',
|
||||
);
|
||||
performance.clearMarks('element_MatrixChat_page_change_start');
|
||||
performance.clearMarks('element_MatrixChat_page_change_stop');
|
||||
const measurement = performance.getEntriesByName('element_MatrixChat_page_change_delta').pop();
|
||||
perfMonitor.stop(PerformanceEntryNames.PAGE_CHANGE);
|
||||
|
||||
// In practice, sometimes the entries list is empty, so we get no measurement
|
||||
if (!measurement) return null;
|
||||
const entries = perfMonitor.getEntries({
|
||||
name: PerformanceEntryNames.PAGE_CHANGE,
|
||||
});
|
||||
const measurement = entries.pop();
|
||||
|
||||
return measurement.duration;
|
||||
return measurement
|
||||
? measurement.duration
|
||||
: null;
|
||||
}
|
||||
|
||||
shouldTrackPageChange(prevState: IState, state: IState) {
|
||||
|
@ -1632,11 +1614,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
action: 'start_registration',
|
||||
params: params,
|
||||
});
|
||||
PerformanceMonitor.instance.start(PerformanceEntryNames.REGISTER);
|
||||
} else if (screen === 'login') {
|
||||
dis.dispatch({
|
||||
action: 'start_login',
|
||||
params: params,
|
||||
});
|
||||
PerformanceMonitor.instance.start(PerformanceEntryNames.LOGIN);
|
||||
} else if (screen === 'forgot_password') {
|
||||
dis.dispatch({
|
||||
action: 'start_password_recovery',
|
||||
|
@ -1965,6 +1949,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
// Create and start the client
|
||||
await Lifecycle.setLoggedIn(credentials);
|
||||
await this.postLoginSetup();
|
||||
PerformanceMonitor.instance.stop(PerformanceEntryNames.LOGIN);
|
||||
PerformanceMonitor.instance.stop(PerformanceEntryNames.REGISTER);
|
||||
};
|
||||
|
||||
// complete security / e2e setup has finished
|
||||
|
|
|
@ -473,7 +473,7 @@ export default class MessagePanel extends React.Component {
|
|||
}
|
||||
|
||||
get _roomHasPendingEdit() {
|
||||
return localStorage.getItem(`mx_edit_room_${this.props.room.roomId}`);
|
||||
return this.props.room && localStorage.getItem(`mx_edit_room_${this.props.room.roomId}`);
|
||||
}
|
||||
|
||||
_getEventTiles() {
|
||||
|
|
|
@ -808,7 +808,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onEvent = (ev) => {
|
||||
if (ev.isBeingDecrypted() || ev.isDecryptionFailure()) return;
|
||||
if (ev.isBeingDecrypted() || ev.isDecryptionFailure() || ev.shouldAttemptDecryption()) return;
|
||||
this.handleEffects(ev);
|
||||
};
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ const Tile: React.FC<ITileProps> = ({
|
|||
}
|
||||
|
||||
let description = _t("%(count)s members", { count: room.num_joined_members });
|
||||
if (numChildRooms) {
|
||||
if (numChildRooms !== undefined) {
|
||||
description += " · " + _t("%(count)s rooms", { count: numChildRooms });
|
||||
}
|
||||
if (room.topic) {
|
||||
|
@ -471,8 +471,12 @@ export const SpaceHierarchy: React.FC<IHierarchyProps> = ({
|
|||
try {
|
||||
for (const [parentId, childId] of selectedRelations) {
|
||||
await cli.sendStateEvent(parentId, EventType.SpaceChild, {}, childId);
|
||||
parentChildMap.get(parentId).get(childId).content = {};
|
||||
parentChildMap.set(parentId, new Map(parentChildMap.get(parentId)));
|
||||
parentChildMap.get(parentId).delete(childId);
|
||||
if (parentChildMap.get(parentId).size > 0) {
|
||||
parentChildMap.set(parentId, new Map(parentChildMap.get(parentId)));
|
||||
} else {
|
||||
parentChildMap.delete(parentId);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
setError(_t("Failed to remove some rooms. Try again later"));
|
||||
|
|
|
@ -1149,9 +1149,8 @@ class TimelinePanel extends React.Component {
|
|||
arrayFastClone(events)
|
||||
.reverse()
|
||||
.forEach(event => {
|
||||
if (event.shouldAttemptDecryption()) {
|
||||
event.attemptDecryption(MatrixClientPeg.get()._crypto);
|
||||
}
|
||||
const client = MatrixClientPeg.get();
|
||||
client.decryptEventIfNeeded(event);
|
||||
});
|
||||
|
||||
const firstVisibleEventIndex = this._checkForPreJoinUISI(events);
|
||||
|
|
|
@ -38,6 +38,7 @@ import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/Recent
|
|||
import ProgressBar from "../elements/ProgressBar";
|
||||
import {SpaceFeedbackPrompt} from "../../structures/SpaceRoomView";
|
||||
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
||||
import QueryMatcher from "../../../autocomplete/QueryMatcher";
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
matrixClient: MatrixClient;
|
||||
|
@ -74,37 +75,47 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
|||
onFinished,
|
||||
}) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const visibleRooms = useMemo(() => sortRooms(cli.getVisibleRooms()), [cli]);
|
||||
const visibleRooms = useMemo(() => cli.getVisibleRooms().filter(r => r.getMyMembership() === "join"), [cli]);
|
||||
|
||||
const [selectedToAdd, setSelectedToAdd] = useState(new Set<Room>());
|
||||
const [progress, setProgress] = useState<number>(null);
|
||||
const [error, setError] = useState<Error>(null);
|
||||
const [query, setQuery] = useState("");
|
||||
const lcQuery = query.toLowerCase();
|
||||
const lcQuery = query.toLowerCase().trim();
|
||||
|
||||
const existingSubspaces = SpaceStore.instance.getChildSpaces(space.roomId);
|
||||
const existingSubspacesSet = new Set(existingSubspaces);
|
||||
const existingRoomsSet = new Set(SpaceStore.instance.getChildRooms(space.roomId));
|
||||
const existingSubspacesSet = useMemo(() => new Set(SpaceStore.instance.getChildSpaces(space.roomId)), [space]);
|
||||
const existingRoomsSet = useMemo(() => new Set(SpaceStore.instance.getChildRooms(space.roomId)), [space]);
|
||||
|
||||
const joinRule = space.getJoinRule();
|
||||
const [spaces, rooms, dms] = visibleRooms.reduce((arr, room) => {
|
||||
if (room.getMyMembership() !== "join") return arr;
|
||||
if (!room.name.toLowerCase().includes(lcQuery)) return arr;
|
||||
const [spaces, rooms, dms] = useMemo(() => {
|
||||
let rooms = visibleRooms;
|
||||
|
||||
if (room.isSpaceRoom()) {
|
||||
if (room !== space && !existingSubspacesSet.has(room)) {
|
||||
arr[0].push(room);
|
||||
}
|
||||
} else if (!existingRoomsSet.has(room)) {
|
||||
if (!DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
|
||||
arr[1].push(room);
|
||||
} else if (joinRule !== "public") {
|
||||
// Only show DMs for non-public spaces as they make very little sense in spaces other than "Just Me" ones.
|
||||
arr[2].push(room);
|
||||
}
|
||||
if (lcQuery) {
|
||||
const matcher = new QueryMatcher<Room>(visibleRooms, {
|
||||
keys: ["name"],
|
||||
funcs: [r => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)],
|
||||
shouldMatchWordsOnly: false,
|
||||
});
|
||||
|
||||
rooms = matcher.match(lcQuery);
|
||||
}
|
||||
return arr;
|
||||
}, [[], [], []]);
|
||||
|
||||
const joinRule = space.getJoinRule();
|
||||
return sortRooms(rooms).reduce((arr, room) => {
|
||||
if (room.isSpaceRoom()) {
|
||||
if (room !== space && !existingSubspacesSet.has(room)) {
|
||||
arr[0].push(room);
|
||||
}
|
||||
} else if (!existingRoomsSet.has(room)) {
|
||||
if (!DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
|
||||
arr[1].push(room);
|
||||
} else if (joinRule !== "public") {
|
||||
// Only show DMs for non-public spaces as they make very little sense in spaces other than "Just Me" ones.
|
||||
arr[2].push(room);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}, [[], [], []]);
|
||||
}, [visibleRooms, space, lcQuery, existingRoomsSet, existingSubspacesSet]);
|
||||
|
||||
const addRooms = async () => {
|
||||
setError(null);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import * as React from 'react';
|
||||
import BaseDialog from './BaseDialog';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { _t, getUserLanguage } from '../../../languageHandler';
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import {
|
||||
ClientWidgetApi,
|
||||
|
@ -39,6 +39,8 @@ import {OwnProfileStore} from "../../../stores/OwnProfileStore";
|
|||
import { arrayFastClone } from "../../../utils/arrays";
|
||||
import { ElementWidget } from "../../../stores/widgets/StopGapWidget";
|
||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||
import {ELEMENT_CLIENT_ID} from "../../../identifiers";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
interface IProps {
|
||||
widgetDefinition: IModalWidgetOpenRequestData;
|
||||
|
@ -129,6 +131,9 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
|||
currentUserId: MatrixClientPeg.get().getUserId(),
|
||||
userDisplayName: OwnProfileStore.instance.displayName,
|
||||
userHttpAvatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(),
|
||||
clientId: ELEMENT_CLIENT_ID,
|
||||
clientTheme: SettingsStore.getValue("theme"),
|
||||
clientLanguage: getUserLanguage(),
|
||||
});
|
||||
|
||||
const parsed = new URL(templated);
|
||||
|
|
|
@ -37,7 +37,7 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => {
|
|||
effect = new Effect(options);
|
||||
effectsRef.current[name] = effect;
|
||||
} catch (err) {
|
||||
console.warn('Unable to load effect module at \'../../../effects/${name}\'.', err);
|
||||
console.warn(`Unable to load effect module at '../../../effects/${name}.`, err);
|
||||
}
|
||||
}
|
||||
return effect;
|
||||
|
|
|
@ -58,13 +58,8 @@ export default class LanguageDropdown extends React.Component {
|
|||
// If no value is given, we start with the first
|
||||
// country selected, but our parent component
|
||||
// doesn't know this, therefore we do this.
|
||||
const language = SettingsStore.getValue("language", null, /*excludeDefault:*/true);
|
||||
if (language) {
|
||||
this.props.onOptionChange(language);
|
||||
} else {
|
||||
const language = languageHandler.normalizeLanguageKey(languageHandler.getLanguageFromBrowser());
|
||||
this.props.onOptionChange(language);
|
||||
}
|
||||
const language = languageHandler.getUserLanguage();
|
||||
this.props.onOptionChange(language);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import {RovingAccessibleTooltipButton, useRovingTabIndex} from "../../../accessi
|
|||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||
import {canCancel} from "../context_menus/MessageContextMenu";
|
||||
import Resend from "../../../Resend";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
||||
const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange}) => {
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
|
||||
|
@ -122,6 +123,10 @@ export default class MessageActionBar extends React.PureComponent {
|
|||
if (this.props.mxEvent.status && this.props.mxEvent.status !== EventStatus.SENT) {
|
||||
this.props.mxEvent.on("Event.status", this.onSent);
|
||||
}
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
client.decryptEventIfNeeded(this.props.mxEvent);
|
||||
|
||||
if (this.props.mxEvent.isBeingDecrypted()) {
|
||||
this.props.mxEvent.once("Event.decrypted", this.onDecrypted);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@ const ReactButton = ({ mxEvent, reactions }: IProps) => {
|
|||
})}
|
||||
title={_t("Add reaction")}
|
||||
onClick={openMenu}
|
||||
onContextMenu={e => {
|
||||
e.preventDefault();
|
||||
openMenu();
|
||||
}}
|
||||
isExpanded={menuDisplayed}
|
||||
inputRef={button}
|
||||
/>
|
||||
|
@ -174,6 +178,8 @@ export default class ReactionsRow extends React.PureComponent<IProps, IState> {
|
|||
/>;
|
||||
}).filter(item => !!item);
|
||||
|
||||
if (!items.length) return null;
|
||||
|
||||
// Show the first MAX_ITEMS if there are MAX_ITEMS + 1 or more items.
|
||||
// The "+ 1" ensure that the "show all" reveals something that takes up
|
||||
// more space than the button itself.
|
||||
|
|
|
@ -18,6 +18,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
||||
@replaceableComponent("views.messages.ViewSourceEvent")
|
||||
export default class ViewSourceEvent extends React.PureComponent {
|
||||
|
@ -36,6 +37,10 @@ export default class ViewSourceEvent extends React.PureComponent {
|
|||
|
||||
componentDidMount() {
|
||||
const {mxEvent} = this.props;
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
client.decryptEventIfNeeded(mxEvent);
|
||||
|
||||
if (mxEvent.isBeingDecrypted()) {
|
||||
mxEvent.once("Event.decrypted", () => this.forceUpdate());
|
||||
}
|
||||
|
|
|
@ -133,6 +133,12 @@ export default class MemberList extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
get canInvite() {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const room = cli.getRoom(this.props.roomId);
|
||||
return room && room.canInvite(cli.getUserId());
|
||||
}
|
||||
|
||||
_getMembersState(members) {
|
||||
// set the state after determining _showPresence to make sure it's
|
||||
// taken into account while rerendering
|
||||
|
@ -141,6 +147,7 @@ export default class MemberList extends React.Component {
|
|||
members: members,
|
||||
filteredJoinedMembers: this._filterMembers(members, 'join'),
|
||||
filteredInvitedMembers: this._filterMembers(members, 'invite'),
|
||||
canInvite: this.canInvite,
|
||||
|
||||
// ideally we'd size this to the page height, but
|
||||
// in practice I find that a little constraining
|
||||
|
@ -196,6 +203,8 @@ export default class MemberList extends React.Component {
|
|||
event.getType() === "m.room.third_party_invite") {
|
||||
this._updateList();
|
||||
}
|
||||
|
||||
if (this.canInvite !== this.state.canInvite) this.setState({ canInvite: this.canInvite });
|
||||
};
|
||||
|
||||
_updateList = rate_limited_func(() => {
|
||||
|
@ -455,8 +464,6 @@ export default class MemberList extends React.Component {
|
|||
let inviteButton;
|
||||
|
||||
if (room && room.getMyMembership() === 'join') {
|
||||
const canInvite = room.canInvite(cli.getUserId());
|
||||
|
||||
let inviteButtonText = _t("Invite to this room");
|
||||
const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat();
|
||||
if (chat && chat.roomId === this.props.roomId) {
|
||||
|
@ -467,7 +474,7 @@ export default class MemberList extends React.Component {
|
|||
|
||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
||||
inviteButton =
|
||||
<AccessibleButton className="mx_MemberList_invite" onClick={this.onInviteButtonClick} disabled={!canInvite}>
|
||||
<AccessibleButton className="mx_MemberList_invite" onClick={this.onInviteButtonClick} disabled={!this.state.canInvite}>
|
||||
<span>{ inviteButtonText }</span>
|
||||
</AccessibleButton>;
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
|
||||
private renderSuggestedRooms(): ReactComponentElement<typeof ExtraTile>[] {
|
||||
return this.state.suggestedRooms.map(room => {
|
||||
const name = room.name || room.canonical_alias || room.aliases.pop() || _t("Empty room");
|
||||
const name = room.name || room.canonical_alias || room.aliases?.[0] || _t("Empty room");
|
||||
const avatar = (
|
||||
<RoomAvatar
|
||||
oobData={{
|
||||
|
|
|
@ -100,8 +100,10 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
|||
hasUnsentEvents: this.countUnsentEvents() > 0,
|
||||
|
||||
// generatePreview() will return nothing if the user has previews disabled
|
||||
messagePreview: this.generatePreview(),
|
||||
messagePreview: "",
|
||||
};
|
||||
this.generatePreview();
|
||||
|
||||
this.notificationState = RoomNotificationStateStore.instance.getRoomState(this.props.room);
|
||||
this.roomProps = EchoChamber.forRoom(this.props.room);
|
||||
if (this.props.resizeNotifier) {
|
||||
|
@ -123,7 +125,7 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
|||
|
||||
private onResize = () => {
|
||||
if (this.showMessagePreview && !this.state.messagePreview) {
|
||||
this.setState({messagePreview: this.generatePreview()});
|
||||
this.generatePreview();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -147,7 +149,7 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
|||
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>) {
|
||||
if (prevProps.showMessagePreview !== this.props.showMessagePreview && this.showMessagePreview) {
|
||||
this.setState({messagePreview: this.generatePreview()});
|
||||
this.generatePreview();
|
||||
}
|
||||
if (prevProps.room?.roomId !== this.props.room?.roomId) {
|
||||
MessagePreviewStore.instance.off(
|
||||
|
@ -236,17 +238,17 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
|||
|
||||
private onRoomPreviewChanged = (room: Room) => {
|
||||
if (this.props.room && room.roomId === this.props.room.roomId) {
|
||||
// generatePreview() will return nothing if the user has previews disabled
|
||||
this.setState({messagePreview: this.generatePreview()});
|
||||
this.generatePreview();
|
||||
}
|
||||
};
|
||||
|
||||
private generatePreview(): string | null {
|
||||
private async generatePreview() {
|
||||
if (!this.showMessagePreview) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag);
|
||||
const messagePreview = await MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag);
|
||||
this.setState({ messagePreview });
|
||||
}
|
||||
|
||||
private scrollIntoView = () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue