Merge branch 'develop' into t3chguy/ts/11

This commit is contained in:
Michael Telatynski 2021-07-02 11:03:54 +01:00 committed by GitHub
commit 82119a08f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 467 additions and 766 deletions

View file

@ -21,8 +21,8 @@ interface IProps extends Omit<HTMLAttributes<HTMLDivElement>, "onScroll"> {
className?: string;
onScroll?: (event: Event) => void;
onWheel?: (event: WheelEvent) => void;
style?: React.CSSProperties
tabIndex?: number,
style?: React.CSSProperties;
tabIndex?: number;
wrappedRef?: (ref: HTMLDivElement) => void;
}

View file

@ -38,7 +38,7 @@ import ResizeNotifier from '../../utils/ResizeNotifier';
interface IProps {
roomId: string;
onClose: () => void;
resizeNotifier: ResizeNotifier
resizeNotifier: ResizeNotifier;
}
interface IState {

View file

@ -48,7 +48,7 @@ import { ViewRoomDeltaPayload } from "../../dispatcher/payloads/ViewRoomDeltaPay
import RoomListStore from "../../stores/room-list/RoomListStore";
import NonUrgentToastContainer from "./NonUrgentToastContainer";
import { ToggleRightPanelPayload } from "../../dispatcher/payloads/ToggleRightPanelPayload";
import { IThreepidInvite } from "../../stores/ThreepidInviteStore";
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
import Modal from "../../Modal";
import { ICollapseConfig } from "../../resizer/distributors/collapse";
import HostSignupContainer from '../views/host_signup/HostSignupContainer';
@ -81,14 +81,14 @@ interface IProps {
page_type: string;
autoJoin: boolean;
threepidInvite?: IThreepidInvite;
roomOobData?: object;
roomOobData?: IOOBData;
currentRoomId: string;
collapseLhs: boolean;
config: {
piwik: {
policyUrl: string;
},
[key: string]: any,
};
[key: string]: any;
};
currentUserId?: string;
currentGroupId?: string;

View file

@ -204,7 +204,7 @@ interface IState {
resizeNotifier: ResizeNotifier;
serverConfig?: ValidatedServerConfig;
ready: boolean;
threepidInvite?: IThreepidInvite,
threepidInvite?: IThreepidInvite;
roomOobData?: object;
pendingInitialSync?: boolean;
justRegistered?: boolean;

View file

@ -24,7 +24,7 @@ interface IProps {
}
interface IState {
toasts: ComponentClass[],
toasts: ComponentClass[];
}
@replaceableComponent("structures.NonUrgentToastContainer")

View file

@ -370,7 +370,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
private onFilterChange = (alias: string) => {
this.setState({
filterString: alias || null,
filterString: alias || "",
});
// don't send the request for a little bit,
@ -389,7 +389,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
private onFilterClear = () => {
// update immediately
this.setState({
filterString: null,
filterString: "",
}, this.refreshRoomList);
if (this.filterTimeout) {

View file

@ -63,7 +63,7 @@ import RoomUpgradeWarningBar from "../views/rooms/RoomUpgradeWarningBar";
import AuxPanel from "../views/rooms/AuxPanel";
import RoomHeader from "../views/rooms/RoomHeader";
import { XOR } from "../../@types/common";
import { IThreepidInvite } from "../../stores/ThreepidInviteStore";
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
import EffectsOverlay from "../views/elements/EffectsOverlay";
import { containsEmoji } from '../../effects/utils';
import { CHAT_EFFECTS } from '../../effects';
@ -94,22 +94,8 @@ if (DEBUG) {
}
interface IProps {
threepidInvite: IThreepidInvite,
// Any data about the room that would normally come from the homeserver
// but has been passed out-of-band, eg. the room name and avatar URL
// from an email invite (a workaround for the fact that we can't
// get this information from the HS using an email invite).
// Fields:
// * name (string) The room's name
// * avatarUrl (string) The mxc:// avatar URL for the room
// * inviterName (string) The display name of the person who
// * invited us to the room
oobData?: {
name?: string;
avatarUrl?: string;
inviterName?: string;
};
threepidInvite: IThreepidInvite;
oobData?: IOOBData;
resizeNotifier: ResizeNotifier;
justCreatedOpts?: IOpts;
@ -1261,7 +1247,7 @@ export default class RoomView extends React.Component<IProps, IState> {
});
};
private injectSticker(url, info, text) {
private injectSticker(url: string, info: object, text: string) {
if (this.context.isGuest()) {
dis.dispatch({ action: 'require_registration' });
return;
@ -1460,13 +1446,6 @@ export default class RoomView extends React.Component<IProps, IState> {
});
};
private onLeaveClick = () => {
dis.dispatch({
action: 'leave_room',
room_id: this.state.room.roomId,
});
};
private onForgetClick = () => {
dis.dispatch({
action: 'forget_room',
@ -2106,7 +2085,6 @@ export default class RoomView extends React.Component<IProps, IState> {
onSearchClick={this.onSearchClick}
onSettingsClick={this.onSettingsClick}
onForgetClick={(myMembership === "leave") ? this.onForgetClick : null}
onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null}
e2eStatus={this.state.e2eStatus}
onAppsClick={this.state.hasPinnedWidgets ? this.onAppsClick : null}
appsShown={this.state.showApps}

View file

@ -58,7 +58,7 @@ export interface ISpaceSummaryRoom {
avatar_url?: string;
guest_can_join: boolean;
name?: string;
num_joined_members: number
num_joined_members: number;
room_id: string;
topic?: string;
world_readable: boolean;

View file

@ -125,7 +125,7 @@ interface IProps {
onReadMarkerUpdated?(): void;
// callback which is called when we wish to paginate the timeline window.
onPaginationRequest?(timelineWindow: TimelineWindow, direction: string, size: number): Promise<boolean>,
onPaginationRequest?(timelineWindow: TimelineWindow, direction: string, size: number): Promise<boolean>;
}
interface IState {

View file

@ -26,6 +26,7 @@ import ProgressBar from "../views/elements/ProgressBar";
import AccessibleButton from "../views/elements/AccessibleButton";
import { IUpload } from "../../models/IUpload";
import { replaceableComponent } from "../../utils/replaceableComponent";
import MatrixClientContext from "../../contexts/MatrixClientContext";
interface IProps {
room: Room;
@ -38,6 +39,8 @@ interface IState {
@replaceableComponent("structures.UploadBar")
export default class UploadBar extends React.Component<IProps, IState> {
static contextType = MatrixClientContext;
private dispatcherRef: string;
private mounted: boolean;
@ -82,7 +85,7 @@ export default class UploadBar extends React.Component<IProps, IState> {
private onCancelClick = (ev) => {
ev.preventDefault();
ContentMessages.sharedInstance().cancelUpload(this.state.currentUpload.promise);
ContentMessages.sharedInstance().cancelUpload(this.state.currentUpload.promise, this.context);
};
render() {

View file

@ -49,7 +49,7 @@ interface IProps {
// for operations like uploading cross-signing keys).
onLoggedIn(params: {
userId: string;
deviceId: string
deviceId: string;
homeserverUrl: string;
identityServerUrl?: string;
accessToken: string;

View file

@ -49,7 +49,7 @@ interface IProps {
fragmentAfterLogin?: string;
// Called when the SSO login completes
onTokenLoginCompleted: () => void,
onTokenLoginCompleted: () => void;
}
interface IState {

View file

@ -52,8 +52,8 @@ interface IProps {
interface IState {
fieldValid: Partial<Record<LoginField, boolean>>;
loginType: LoginField.Email | LoginField.MatrixId | LoginField.Phone,
password: "",
loginType: LoginField.Email | LoginField.MatrixId | LoginField.Phone;
password: "";
}
enum LoginField {

View file

@ -30,13 +30,14 @@ import { _t } from "../../../languageHandler";
import TextWithTooltip from "../elements/TextWithTooltip";
import DMRoomMap from "../../../utils/DMRoomMap";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { IOOBData } from "../../../stores/ThreepidInviteStore";
interface IProps {
room: Room;
avatarSize: number;
displayBadge?: boolean;
forceCount?: boolean;
oobData?: object;
oobData?: IOOBData;
viewAvatarOnClick?: boolean;
}

View file

@ -24,14 +24,14 @@ import Modal from '../../../Modal';
import * as Avatar from '../../../Avatar';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { mediaFromMxc } from "../../../customisations/Media";
import { IOOBData } from '../../../stores/ThreepidInviteStore';
interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url" | "onClick"> {
// Room may be left unset here, but if it is,
// oobData.avatarUrl should be set (else there
// would be nowhere to get the avatar from)
room?: Room;
// TODO: type when js-sdk has types
oobData?: any;
oobData?: IOOBData;
width?: number;
height?: number;
resizeMethod?: ResizeMethod;

View file

@ -29,7 +29,7 @@ interface IProps {
// group member object. Supply either this or 'member'
groupMember: GroupMemberType;
// needed if a group member is specified
matrixClient?: MatrixClient,
matrixClient?: MatrixClient;
action: string; // eg. 'Ban'
title: string; // eg. 'Ban this user?'

View file

@ -70,9 +70,9 @@ import GenericTextContextMenu from "../context_menus/GenericTextContextMenu";
/* eslint-disable camelcase */
interface IRecentUser {
userId: string,
user: RoomMember,
lastActive: number,
userId: string;
user: RoomMember;
lastActive: number;
}
export const KIND_DM = "dm";
@ -330,16 +330,16 @@ interface IInviteDialogProps {
// The kind of invite being performed. Assumed to be KIND_DM if
// not provided.
kind: string,
kind: string;
// The room ID this dialog is for. Only required for KIND_INVITE.
roomId: string,
roomId: string;
// The call to transfer. Only required for KIND_CALL_TRANSFER.
call: MatrixCall,
call: MatrixCall;
// Initial value to populate the filter with
initialText: string,
initialText: string;
}
interface IInviteDialogState {
@ -356,8 +356,8 @@ interface IInviteDialogState {
consultFirst: boolean;
// These two flags are used for the 'Go' button to communicate what is going on.
busy: boolean,
errorText: string,
busy: boolean;
errorText: string;
}
@replaceableComponent("views.dialogs.InviteDialog")

View file

@ -46,19 +46,19 @@ interface ITermsDialogProps {
* Array of [Service, policies] pairs, where policies is the response from the
* /terms endpoint for that service
*/
policiesAndServicePairs: any[],
policiesAndServicePairs: any[];
/**
* urls that the user has already agreed to
*/
agreedUrls?: string[],
agreedUrls?: string[];
/**
* Called with:
* * success {bool} True if the user accepted any douments, false if cancelled
* * agreedUrls {string[]} List of agreed URLs
*/
onFinished: (success: boolean, agreedUrls?: string[]) => void,
onFinished: (success: boolean, agreedUrls?: string[]) => void;
}
interface IState {

View file

@ -0,0 +1,56 @@
/*
Copyright 2020 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.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { decode } from "blurhash";
interface IProps {
blurhash: string;
width: number;
height: number;
}
export default class BlurhashPlaceholder extends React.PureComponent<IProps> {
private canvas: React.RefObject<HTMLCanvasElement> = React.createRef();
public componentDidMount() {
this.draw();
}
public componentDidUpdate() {
this.draw();
}
private draw() {
if (!this.canvas.current) return;
try {
const { width, height } = this.props;
const pixels = decode(this.props.blurhash, Math.ceil(width), Math.ceil(height));
const ctx = this.canvas.current.getContext("2d");
const imgData = ctx.createImageData(width, height);
imgData.data.set(pixels);
ctx.putImageData(imgData, 0, 0);
} catch (e) {
console.error("Error rendering blurhash: ", e);
}
}
public render() {
return <canvas height={this.props.height} width={this.props.width} ref={this.canvas} />;
}
}

View file

@ -29,7 +29,7 @@ interface IProps {
// The minimum number of events needed to trigger summarisation
threshold?: number;
// Whether or not to begin with state.expanded=true
startExpanded?: boolean,
startExpanded?: boolean;
// The list of room members for which to show avatars next to the summary
summaryMembers?: RoomMember[];
// The text to show as the summary of this event list

View file

@ -44,31 +44,31 @@ const ZOOM_COEFFICIENT = 0.0025;
const ZOOM_DISTANCE = 10;
interface IProps {
src: string, // the source of the image being displayed
name?: string, // the main title ('name') for the image
link?: string, // the link (if any) applied to the name of the image
width?: number, // width of the image src in pixels
height?: number, // height of the image src in pixels
fileSize?: number, // size of the image src in bytes
onFinished(): void, // callback when the lightbox is dismissed
src: string; // the source of the image being displayed
name?: string; // the main title ('name') for the image
link?: string; // the link (if any) applied to the name of the image
width?: number; // width of the image src in pixels
height?: number; // height of the image src in pixels
fileSize?: number; // size of the image src in bytes
onFinished(): void; // callback when the lightbox is dismissed
// the event (if any) that the Image is displaying. Used for event-specific stuff like
// redactions, senders, timestamps etc. Other descriptors are taken from the explicit
// properties above, which let us use lightboxes to display images which aren't associated
// with events.
mxEvent: MatrixEvent,
permalinkCreator: RoomPermalinkCreator,
mxEvent: MatrixEvent;
permalinkCreator: RoomPermalinkCreator;
}
interface IState {
zoom: number,
minZoom: number,
maxZoom: number,
rotation: number,
translationX: number,
translationY: number,
moving: boolean,
contextMenuDisplayed: boolean,
zoom: number;
minZoom: number;
maxZoom: number;
rotation: number;
translationX: number;
translationY: number;
moving: boolean;
contextMenuDisplayed: boolean;
}
@replaceableComponent("views.elements.ImageView")

View file

@ -30,14 +30,14 @@ function languageMatchesSearchQuery(query, language) {
}
interface SpellCheckLanguagesDropdownIProps {
className: string,
value: string,
onOptionChange(language: string),
className: string;
value: string;
onOptionChange(language: string);
}
interface SpellCheckLanguagesDropdownIState {
searchQuery: string,
languages: any,
searchQuery: string;
languages: any;
}
@replaceableComponent("views.elements.SpellCheckLanguagesDropdown")

View file

@ -25,7 +25,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
categories: ICategory[];
onAnchorClick(id: CategoryKey): void
onAnchorClick(id: CategoryKey): void;
}
@replaceableComponent("views.emojipicker.Header")

View file

@ -29,6 +29,8 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
import InlineSpinner from '../elements/InlineSpinner';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { mediaFromContent } from "../../../customisations/Media";
import BlurhashPlaceholder from "../elements/BlurhashPlaceholder";
import { BLURHASH_FIELD } from "../../../ContentMessages";
@replaceableComponent("views.messages.MImageBody")
export default class MImageBody extends React.Component {
@ -333,7 +335,8 @@ export default class MImageBody extends React.Component {
infoWidth = content.info.w;
infoHeight = content.info.h;
} else {
// Whilst the image loads, display nothing.
// Whilst the image loads, display nothing. We also don't display a blurhash image
// because we don't really know what size of image we'll end up with.
//
// Once loaded, use the loaded image dimensions stored in `loadedImageDimensions`.
//
@ -368,12 +371,8 @@ export default class MImageBody extends React.Component {
let placeholder = null;
let gifLabel = null;
// e2e image hasn't been decrypted yet
if (content.file !== undefined && this.state.decryptedUrl === null) {
placeholder = <InlineSpinner w={32} h={32} />;
} else if (!this.state.imgLoaded) {
// Deliberately, getSpinner is left unimplemented here, MStickerBody overides
placeholder = this.getPlaceholder();
if (!this.state.imgLoaded) {
placeholder = this.getPlaceholder(maxWidth, maxHeight);
}
let showPlaceholder = Boolean(placeholder);
@ -395,7 +394,7 @@ export default class MImageBody extends React.Component {
if (!this.state.showImage) {
img = <HiddenImagePlaceholder style={{ maxWidth: maxWidth + "px" }} />;
showPlaceholder = false; // because we're hiding the image, so don't show the sticker icon.
showPlaceholder = false; // because we're hiding the image, so don't show the placeholder.
}
if (this._isGif() && !SettingsStore.getValue("autoplayGifsAndVideos") && !this.state.hover) {
@ -411,9 +410,7 @@ export default class MImageBody extends React.Component {
// Constrain width here so that spinner appears central to the loaded thumbnail
maxWidth: infoWidth + "px",
}}>
<div className="mx_MImageBody_thumbnail_spinner">
{ placeholder }
</div>
{ placeholder }
</div>
}
@ -437,9 +434,12 @@ export default class MImageBody extends React.Component {
}
// Overidden by MStickerBody
getPlaceholder() {
// MImageBody doesn't show a placeholder whilst the image loads, (but it could do)
return null;
getPlaceholder(width, height) {
const blurhash = this.props.mxEvent.getContent().info[BLURHASH_FIELD];
if (blurhash) return <BlurhashPlaceholder blurhash={blurhash} width={width} height={height} />;
return <div className="mx_MImageBody_thumbnail_spinner">
<InlineSpinner w={32} h={32} />
</div>;
}
// Overidden by MStickerBody

View file

@ -28,7 +28,7 @@ import EventTileBubble from "./EventTileBubble";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
mxEvent: MatrixEvent
mxEvent: MatrixEvent;
}
@replaceableComponent("views.messages.MKeyVerificationRequest")

View file

@ -18,6 +18,7 @@ import React from 'react';
import MImageBody from './MImageBody';
import * as sdk from '../../../index';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { BLURHASH_FIELD } from "../../../ContentMessages";
@replaceableComponent("views.messages.MStickerBody")
export default class MStickerBody extends MImageBody {
@ -41,7 +42,8 @@ export default class MStickerBody extends MImageBody {
// Placeholder to show in place of the sticker image if
// img onLoad hasn't fired yet.
getPlaceholder() {
getPlaceholder(width, height) {
if (this.props.mxEvent.getContent().info[BLURHASH_FIELD]) return super.getPlaceholder(width, height);
return <img src={require("../../../../res/img/icons-show-stickers.svg")} width="75" height="75" />;
}

View file

@ -16,6 +16,8 @@ limitations under the License.
*/
import React from 'react';
import { decode } from "blurhash";
import MFileBody from './MFileBody';
import { decryptFile } from '../../../utils/DecryptFile';
import { _t } from '../../../languageHandler';
@ -23,6 +25,7 @@ import SettingsStore from "../../../settings/SettingsStore";
import InlineSpinner from '../elements/InlineSpinner';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { mediaFromContent } from "../../../customisations/Media";
import { BLURHASH_FIELD } from "../../../ContentMessages";
interface IProps {
/* the MatrixEvent to show */
@ -32,11 +35,13 @@ interface IProps {
}
interface IState {
decryptedUrl: string|null,
decryptedThumbnailUrl: string|null,
decryptedBlob: Blob|null,
error: any|null,
fetchingData: boolean,
decryptedUrl?: string;
decryptedThumbnailUrl?: string;
decryptedBlob?: Blob;
error?: any;
fetchingData: boolean;
posterLoading: boolean;
blurhashUrl: string;
}
@replaceableComponent("views.messages.MVideoBody")
@ -51,10 +56,12 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
decryptedThumbnailUrl: null,
decryptedBlob: null,
error: null,
posterLoading: false,
blurhashUrl: null,
};
}
thumbScale(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number) {
thumbScale(fullWidth: number, fullHeight: number, thumbWidth = 480, thumbHeight = 360) {
if (!fullWidth || !fullHeight) {
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
// log this because it's spammy
@ -92,8 +99,11 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
private getThumbUrl(): string|null {
const content = this.props.mxEvent.getContent();
const media = mediaFromContent(content);
if (media.isEncrypted) {
if (media.isEncrypted && this.state.decryptedThumbnailUrl) {
return this.state.decryptedThumbnailUrl;
} else if (this.state.posterLoading) {
return this.state.blurhashUrl;
} else if (media.hasThumbnail) {
return media.thumbnailHttp;
} else {
@ -101,18 +111,57 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
}
}
private loadBlurhash() {
const info = this.props.mxEvent.getContent()?.info;
if (!info[BLURHASH_FIELD]) return;
const canvas = document.createElement("canvas");
let width = info.w;
let height = info.h;
const scale = this.thumbScale(info.w, info.h);
if (scale) {
width = Math.floor(info.w * scale);
height = Math.floor(info.h * scale);
}
canvas.width = width;
canvas.height = height;
const pixels = decode(info[BLURHASH_FIELD], width, height);
const ctx = canvas.getContext("2d");
const imgData = ctx.createImageData(width, height);
imgData.data.set(pixels);
ctx.putImageData(imgData, 0, 0);
this.setState({
blurhashUrl: canvas.toDataURL(),
posterLoading: true,
});
const content = this.props.mxEvent.getContent();
const media = mediaFromContent(content);
if (media.hasThumbnail) {
const image = new Image();
image.onload = () => {
this.setState({ posterLoading: false });
};
image.src = media.thumbnailHttp;
}
}
async componentDidMount() {
const autoplay = SettingsStore.getValue("autoplayGifsAndVideos") as boolean;
const content = this.props.mxEvent.getContent();
this.loadBlurhash();
if (content.file !== undefined && this.state.decryptedUrl === null) {
let thumbnailPromise = Promise.resolve(null);
if (content.info && content.info.thumbnail_file) {
thumbnailPromise = decryptFile(
content.info.thumbnail_file,
).then(function(blob) {
return URL.createObjectURL(blob);
});
if (content?.info?.thumbnail_file) {
thumbnailPromise = decryptFile(content.info.thumbnail_file)
.then(blob => URL.createObjectURL(blob));
}
try {
const thumbnailUrl = await thumbnailPromise;
if (autoplay) {
@ -218,7 +267,7 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
let poster = null;
let preload = "metadata";
if (content.info) {
const scale = this.thumbScale(content.info.w, content.info.h, 480, 360);
const scale = this.thumbScale(content.info.w, content.info.h);
if (scale) {
width = Math.floor(content.info.w * scale);
height = Math.floor(content.info.h * scale);

View file

@ -67,7 +67,7 @@ interface IProps {
replacingEventId?: string;
/* callback for when our widget has loaded */
onHeightChanged(): void,
onHeightChanged(): void;
}
interface IState {

View file

@ -32,32 +32,32 @@ import { throttle } from 'lodash';
interface IProps {
// js-sdk room object
room: Room,
userId: string,
showApps: boolean, // Render apps
room: Room;
userId: string;
showApps: boolean; // Render apps
// maxHeight attribute for the aux panel and the video
// therein
maxHeight: number,
maxHeight: number;
// a callback which is called when the content of the aux panel changes
// content in a way that is likely to make it change size.
onResize: () => void,
fullHeight: boolean,
onResize: () => void;
fullHeight: boolean;
resizeNotifier: ResizeNotifier,
resizeNotifier: ResizeNotifier;
}
interface Counter {
title: string,
value: number,
link: string,
severity: string,
stateKey: string,
title: string;
value: number;
link: string;
severity: string;
stateKey: string;
}
interface IState {
counters: Counter[],
counters: Counter[];
}
@replaceableComponent("views.rooms.AuxPanel")

View file

@ -287,10 +287,10 @@ interface IProps {
permalinkCreator?: RoomPermalinkCreator;
// Symbol of the root node
as?: string
as?: string;
// whether or not to always show timestamps
alwaysShowTimestamps?: boolean
alwaysShowTimestamps?: boolean;
}
interface IState {

View file

@ -1,6 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2019, 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,6 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
@ -31,53 +30,64 @@ import RoomName from "../elements/RoomName";
import { PlaceCallType } from "../../../CallHandler";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { throttle } from 'lodash';
import { MatrixEvent, Room, RoomState } from 'matrix-js-sdk/src';
import { E2EStatus } from '../../../utils/ShieldUtils';
import { IOOBData } from '../../../stores/ThreepidInviteStore';
import { SearchScope } from './SearchBar';
export interface ISearchInfo {
searchTerm: string;
searchScope: SearchScope;
searchCount: number;
}
interface IProps {
room: Room;
oobData?: IOOBData;
inRoom: boolean;
onSettingsClick: () => void;
onSearchClick: () => void;
onForgetClick: () => void;
onCallPlaced: (type: PlaceCallType) => void;
onAppsClick: () => void;
e2eStatus: E2EStatus;
appsShown: boolean;
searchInfo: ISearchInfo;
}
@replaceableComponent("views.rooms.RoomHeader")
export default class RoomHeader extends React.Component {
static propTypes = {
room: PropTypes.object,
oobData: PropTypes.object,
inRoom: PropTypes.bool,
onSettingsClick: PropTypes.func,
onSearchClick: PropTypes.func,
onLeaveClick: PropTypes.func,
e2eStatus: PropTypes.string,
onAppsClick: PropTypes.func,
appsShown: PropTypes.bool,
onCallPlaced: PropTypes.func, // (PlaceCallType) => void;
};
export default class RoomHeader extends React.Component<IProps> {
static defaultProps = {
editing: false,
inRoom: false,
};
componentDidMount() {
public componentDidMount() {
const cli = MatrixClientPeg.get();
cli.on("RoomState.events", this._onRoomStateEvents);
cli.on("RoomState.events", this.onRoomStateEvents);
}
componentWillUnmount() {
public componentWillUnmount() {
const cli = MatrixClientPeg.get();
if (cli) {
cli.removeListener("RoomState.events", this._onRoomStateEvents);
cli.removeListener("RoomState.events", this.onRoomStateEvents);
}
}
_onRoomStateEvents = (event, state) => {
private onRoomStateEvents = (event: MatrixEvent, state: RoomState) => {
if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
return;
}
// redisplay the room name, topic, etc.
this._rateLimitedUpdate();
this.rateLimitedUpdate();
};
_rateLimitedUpdate = throttle(() => {
private rateLimitedUpdate = throttle(() => {
this.forceUpdate();
}, 500, { leading: true, trailing: true });
render() {
public render() {
let searchStatus = null;
// don't display the search count until the search completes and

View file

@ -22,7 +22,7 @@ import { useEventEmitter } from "../../../hooks/useEventEmitter";
import SpaceStore from "../../../stores/SpaceStore";
interface IProps {
onVisibilityChange?: () => void
onVisibilityChange?: () => void;
}
const RoomListNumResults: React.FC<IProps> = ({ onVisibilityChange }) => {

View file

@ -21,17 +21,17 @@ import { _t } from "../../../languageHandler";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface ExistingSpellCheckLanguageIProps {
language: string,
onRemoved(language: string),
language: string;
onRemoved(language: string);
}
interface SpellCheckLanguagesIProps {
languages: Array<string>,
onLanguagesChange(languages: Array<string>),
languages: Array<string>;
onLanguagesChange(languages: Array<string>);
}
interface SpellCheckLanguagesIState {
newLanguage: string,
newLanguage: string;
}
export class ExistingSpellCheckLanguage extends React.Component<ExistingSpellCheckLanguageIProps> {

View file

@ -23,7 +23,7 @@ import Field from "../elements/Field";
interface IProps {
avatarUrl?: string;
avatarDisabled?: boolean;
name?: string,
name?: string;
nameDisabled?: boolean;
topic?: string;
topicDisabled?: boolean;

View file

@ -20,7 +20,7 @@ import { logger } from 'matrix-js-sdk/src/logger';
import MediaDeviceHandler, { MediaDeviceHandlerEvent } from "../../../MediaDeviceHandler";
interface IProps {
feed: CallFeed,
feed: CallFeed;
}
export default class AudioFeed extends React.Component<IProps> {

View file

@ -35,10 +35,10 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
// The call for us to display
call: MatrixCall,
call: MatrixCall;
// Another ongoing call to display information about
secondaryCall?: MatrixCall,
secondaryCall?: MatrixCall;
// a callback which is called when the content in the CallView changes
// in a way that is likely to cause a resize.
@ -52,15 +52,15 @@ interface IProps {
}
interface IState {
isLocalOnHold: boolean,
isRemoteOnHold: boolean,
micMuted: boolean,
vidMuted: boolean,
callState: CallState,
controlsVisible: boolean,
showMoreMenu: boolean,
showDialpad: boolean,
feeds: CallFeed[],
isLocalOnHold: boolean;
isRemoteOnHold: boolean;
micMuted: boolean;
vidMuted: boolean;
callState: CallState;
controlsVisible: boolean;
showMoreMenu: boolean;
showDialpad: boolean;
feeds: CallFeed[];
}
function getFullScreenElement() {

View file

@ -25,16 +25,16 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
// What room we should display the call for
roomId: string,
roomId: string;
// maxHeight style attribute for the video panel
maxVideoHeight?: number;
resizeNotifier: ResizeNotifier,
resizeNotifier: ResizeNotifier;
}
interface IState {
call: MatrixCall,
call: MatrixCall;
}
/*

View file

@ -24,9 +24,9 @@ import MemberAvatar from "../avatars/MemberAvatar";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
call: MatrixCall,
call: MatrixCall;
feed: CallFeed,
feed: CallFeed;
// Whether this call view is for picture-in-picture mode
// otherwise, it's the larger call view when viewing the room the call is in.
@ -36,7 +36,7 @@ interface IProps {
// a callback which is called when the video element is resized
// due to a change in video metadata
onResize?: (e: Event) => void,
onResize?: (e: Event) => void;
}
interface IState {