Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/fix/17686

This commit is contained in:
Michael Telatynski 2021-06-18 10:05:58 +01:00
commit 56fe7f8763
23 changed files with 123 additions and 112 deletions

View file

@ -14,18 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {RoomMember} from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import {User} from "matrix-js-sdk/src/models/user"; import { User } from "matrix-js-sdk/src/models/user";
import {Room} from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import DMRoomMap from './utils/DMRoomMap'; import DMRoomMap from './utils/DMRoomMap';
import {mediaFromMxc} from "./customisations/Media"; import { mediaFromMxc } from "./customisations/Media";
import SettingsStore from "./settings/SettingsStore"; import SettingsStore from "./settings/SettingsStore";
export type ResizeMethod = "crop" | "scale"; export type ResizeMethod = "crop" | "scale";
// Not to be used for BaseAvatar urls as that has similar default avatar fallback already // Not to be used for BaseAvatar urls as that has similar default avatar fallback already
export function avatarUrlForMember(member: RoomMember, width: number, height: number, resizeMethod: ResizeMethod) { export function avatarUrlForMember(
member: RoomMember,
width: number,
height: number,
resizeMethod: ResizeMethod,
): string {
let url: string; let url: string;
if (member?.getMxcAvatarUrl()) { if (member?.getMxcAvatarUrl()) {
url = mediaFromMxc(member.getMxcAvatarUrl()).getThumbnailOfSourceHttp(width, height, resizeMethod); url = mediaFromMxc(member.getMxcAvatarUrl()).getThumbnailOfSourceHttp(width, height, resizeMethod);
@ -39,7 +44,12 @@ export function avatarUrlForMember(member: RoomMember, width: number, height: nu
return url; return url;
} }
export function avatarUrlForUser(user: User, width: number, height: number, resizeMethod?: ResizeMethod) { export function avatarUrlForUser(
user: Pick<User, "avatarUrl">,
width: number,
height: number,
resizeMethod?: ResizeMethod,
): string | null {
if (!user.avatarUrl) return null; if (!user.avatarUrl) return null;
return mediaFromMxc(user.avatarUrl).getThumbnailOfSourceHttp(width, height, resizeMethod); return mediaFromMxc(user.avatarUrl).getThumbnailOfSourceHttp(width, height, resizeMethod);
} }

View file

@ -468,7 +468,7 @@ function restoreEncryptionInfo(searchResultSlice = []) {
ev.event.curve25519Key, ev.event.curve25519Key,
ev.event.ed25519Key, ev.event.ed25519Key,
); );
ev._forwardingCurve25519KeyChain = ev.event.forwardingCurve25519KeyChain; ev.forwardingCurve25519KeyChain = ev.event.forwardingCurve25519KeyChain;
delete ev.event.curve25519Key; delete ev.event.curve25519Key;
delete ev.event.ed25519Key; delete ev.event.ed25519Key;

View file

@ -20,19 +20,19 @@ limitations under the License.
import React from 'react'; import React from 'react';
import { _t } from '../languageHandler'; import { _t } from '../languageHandler';
import AutocompleteProvider from './AutocompleteProvider'; import AutocompleteProvider from './AutocompleteProvider';
import {PillCompletion} from './Components'; import { PillCompletion } from './Components';
import * as sdk from '../index'; import * as sdk from '../index';
import QueryMatcher from './QueryMatcher'; import QueryMatcher from './QueryMatcher';
import {sortBy} from 'lodash'; import { sortBy } from 'lodash';
import {MatrixClientPeg} from '../MatrixClientPeg'; import { MatrixClientPeg } from '../MatrixClientPeg';
import MatrixEvent from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import Room from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import RoomMember from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import RoomState from "matrix-js-sdk/src/models/room-state"; import { RoomState } from "matrix-js-sdk/src/models/room-state";
import EventTimeline from "matrix-js-sdk/src/models/event-timeline"; import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
import {makeUserPermalink} from "../utils/permalinks/Permalinks"; import { makeUserPermalink } from "../utils/permalinks/Permalinks";
import {ICompletion, ISelectionRange} from "./Autocompleter"; import { ICompletion, ISelectionRange } from "./Autocompleter";
const USER_REGEX = /\B@\S*/g; const USER_REGEX = /\B@\S*/g;

View file

@ -25,6 +25,7 @@ import React, { createRef } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { SearchResult } from "matrix-js-sdk/src/models/search-result";
import { EventSubscription } from "fbemitter"; import { EventSubscription } from "fbemitter";
import shouldHideEvent from '../../shouldHideEvent'; import shouldHideEvent from '../../shouldHideEvent';
@ -142,7 +143,7 @@ export interface IState {
searchResults?: XOR<{}, { searchResults?: XOR<{}, {
count: number; count: number;
highlights: string[]; highlights: string[];
results: MatrixEvent[]; results: SearchResult[];
next_batch: string; // eslint-disable-line camelcase next_batch: string; // eslint-disable-line camelcase
}>; }>;
searchHighlights?: string[]; searchHighlights?: string[];

View file

@ -525,11 +525,11 @@ class RoomStateExplorer extends React.PureComponent<IExplorerProps, IRoomStateEx
} }
interface IAccountDataExplorerState { interface IAccountDataExplorerState {
[inputId: string]: boolean | string | any;
isRoomAccountData: boolean; isRoomAccountData: boolean;
event?: MatrixEvent; event?: MatrixEvent;
editing: boolean; editing: boolean;
queryEventType: string; queryEventType: string;
[inputId: string]: boolean | string;
} }
class AccountDataExplorer extends React.PureComponent<IExplorerProps, IAccountDataExplorerState> { class AccountDataExplorer extends React.PureComponent<IExplorerProps, IAccountDataExplorerState> {

View file

@ -153,8 +153,8 @@ class ThreepidMember extends Member {
} }
interface IDMUserTileProps { interface IDMUserTileProps {
member: RoomMember; member: Member;
onRemove(member: RoomMember): void; onRemove(member: Member): void;
} }
class DMUserTile extends React.PureComponent<IDMUserTileProps> { class DMUserTile extends React.PureComponent<IDMUserTileProps> {
@ -168,7 +168,7 @@ class DMUserTile extends React.PureComponent<IDMUserTileProps> {
render() { render() {
const avatarSize = 20; const avatarSize = 20;
const avatar = this.props.member.isEmail const avatar = (this.props.member as ThreepidMember).isEmail
? <img ? <img
className='mx_InviteDialog_userTile_avatar mx_InviteDialog_userTile_threepidAvatar' className='mx_InviteDialog_userTile_avatar mx_InviteDialog_userTile_threepidAvatar'
src={require("../../../../res/img/icon-email-pill-avatar.svg")} src={require("../../../../res/img/icon-email-pill-avatar.svg")}
@ -210,9 +210,9 @@ class DMUserTile extends React.PureComponent<IDMUserTileProps> {
} }
interface IDMRoomTileProps { interface IDMRoomTileProps {
member: RoomMember; member: Member;
lastActiveTs: number; lastActiveTs: number;
onToggle(member: RoomMember): void; onToggle(member: Member): void;
highlightWord: string; highlightWord: string;
isSelected: boolean; isSelected: boolean;
} }
@ -270,7 +270,7 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
} }
const avatarSize = 36; const avatarSize = 36;
const avatar = this.props.member.isEmail const avatar = (this.props.member as ThreepidMember).isEmail
? <img ? <img
src={require("../../../../res/img/icon-email-pill-avatar.svg")} src={require("../../../../res/img/icon-email-pill-avatar.svg")}
width={avatarSize} height={avatarSize} /> width={avatarSize} height={avatarSize} />
@ -298,7 +298,7 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
</span> </span>
); );
const caption = this.props.member.isEmail const caption = (this.props.member as ThreepidMember).isEmail
? _t("Invite by email") ? _t("Invite by email")
: this.highlightName(this.props.member.userId); : this.highlightName(this.props.member.userId);
@ -334,7 +334,7 @@ interface IInviteDialogProps {
} }
interface IInviteDialogState { interface IInviteDialogState {
targets: RoomMember[]; // array of Member objects (see interface above) targets: Member[]; // array of Member objects (see interface above)
filterText: string; filterText: string;
recents: { user: Member, userId: string }[]; recents: { user: Member, userId: string }[];
numRecentsShown: number; numRecentsShown: number;

View file

@ -24,7 +24,7 @@ import { _t } from '../../../languageHandler';
import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils';
import { isValid3pidInvite } from "../../../RoomInvite"; import { isValid3pidInvite } from "../../../RoomInvite";
import EventListSummary from "./EventListSummary"; import EventListSummary from "./EventListSummary";
import {replaceableComponent} from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps { interface IProps {
// An array of member events to summarise // An array of member events to summarise
@ -303,7 +303,7 @@ export default class MemberEventListSummary extends React.Component<IProps> {
return res; return res;
} }
private static getTransitionSequence(events: MatrixEvent[]) { private static getTransitionSequence(events: IUserEvents[]) {
return events.map(MemberEventListSummary.getTransition); return events.map(MemberEventListSummary.getTransition);
} }
@ -315,7 +315,7 @@ export default class MemberEventListSummary extends React.Component<IProps> {
* @returns {string?} the transition type given to this event. This defaults to `null` * @returns {string?} the transition type given to this event. This defaults to `null`
* if a transition is not recognised. * if a transition is not recognised.
*/ */
private static getTransition(e: MatrixEvent): TransitionType { private static getTransition(e: IUserEvents): TransitionType {
if (e.mxEvent.getType() === 'm.room.third_party_invite') { if (e.mxEvent.getType() === 'm.room.third_party_invite') {
// Handle 3pid invites the same as invites so they get bundled together // Handle 3pid invites the same as invites so they get bundled together
if (!isValid3pidInvite(e.mxEvent)) { if (!isValid3pidInvite(e.mxEvent)) {

View file

@ -24,6 +24,7 @@ import {_t} from "../../../languageHandler";
import {mediaFromContent} from "../../../customisations/Media"; import {mediaFromContent} from "../../../customisations/Media";
import {decryptFile} from "../../../utils/DecryptFile"; import {decryptFile} from "../../../utils/DecryptFile";
import RecordingPlayback from "../voice_messages/RecordingPlayback"; import RecordingPlayback from "../voice_messages/RecordingPlayback";
import {IMediaEventContent} from "../../../customisations/models/IMediaEventContent";
interface IProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
@ -45,7 +46,7 @@ export default class MVoiceMessageBody extends React.PureComponent<IProps, IStat
public async componentDidMount() { public async componentDidMount() {
let buffer: ArrayBuffer; let buffer: ArrayBuffer;
const content = this.props.mxEvent.getContent(); const content: IMediaEventContent = this.props.mxEvent.getContent();
const media = mediaFromContent(content); const media = mediaFromContent(content);
if (media.isEncrypted) { if (media.isEncrypted) {
try { try {

View file

@ -17,10 +17,10 @@
import React from 'react'; import React from 'react';
import Flair from '../elements/Flair.js'; import Flair from '../elements/Flair.js';
import FlairStore from '../../../stores/FlairStore'; import FlairStore from '../../../stores/FlairStore';
import {getUserNameColorClass} from '../../../utils/FormattingUtils'; import { getUserNameColorClass } from '../../../utils/FormattingUtils';
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {replaceableComponent} from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import MatrixEvent from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
interface IProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;

View file

@ -17,8 +17,9 @@ limitations under the License.
import React from "react"; import React from "react";
import * as sdk from "../../../index"; import * as sdk from "../../../index";
import {_t} from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import {RoomMember} from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { User } from "matrix-js-sdk/src/models/user";
export const PendingActionSpinner = ({text}) => { export const PendingActionSpinner = ({text}) => {
const Spinner = sdk.getComponent('elements.Spinner'); const Spinner = sdk.getComponent('elements.Spinner');
@ -31,7 +32,7 @@ export const PendingActionSpinner = ({text}) => {
interface IProps { interface IProps {
waitingForOtherParty: boolean; waitingForOtherParty: boolean;
waitingForNetwork: boolean; waitingForNetwork: boolean;
member: RoomMember; member: RoomMember | User;
onStartVerification: () => Promise<void>; onStartVerification: () => Promise<void>;
isRoomEncrypted: boolean; isRoomEncrypted: boolean;
inDialog: boolean; inDialog: boolean;
@ -55,7 +56,7 @@ const EncryptionInfo: React.FC<IProps> = ({
text = _t("Accept on your other login…"); text = _t("Accept on your other login…");
} else { } else {
text = _t("Waiting for %(displayName)s to accept…", { text = _t("Waiting for %(displayName)s to accept…", {
displayName: member.displayName || member.name || member.userId, displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
}); });
} }
} else { } else {

View file

@ -147,7 +147,7 @@ async function openDMForUser(matrixClient: MatrixClient, userId: string) {
type SetUpdating = (updating: boolean) => void; type SetUpdating = (updating: boolean) => void;
function useHasCrossSigningKeys(cli: MatrixClient, member: RoomMember, canVerify: boolean, setUpdating: SetUpdating) { function useHasCrossSigningKeys(cli: MatrixClient, member: User, canVerify: boolean, setUpdating: SetUpdating) {
return useAsyncMemo(async () => { return useAsyncMemo(async () => {
if (!canVerify) { if (!canVerify) {
return undefined; return undefined;
@ -972,7 +972,7 @@ interface IRoomPermissions {
canInvite: boolean; canInvite: boolean;
} }
function useRoomPermissions(cli: MatrixClient, room: Room, user: User): IRoomPermissions { function useRoomPermissions(cli: MatrixClient, room: Room, user: RoomMember): IRoomPermissions {
const [roomPermissions, setRoomPermissions] = useState<IRoomPermissions>({ const [roomPermissions, setRoomPermissions] = useState<IRoomPermissions>({
// modifyLevelMax is the max PL we can set this user to, typically min(their PL, our PL) && canSetPL // modifyLevelMax is the max PL we can set this user to, typically min(their PL, our PL) && canSetPL
modifyLevelMax: -1, modifyLevelMax: -1,
@ -1029,7 +1029,7 @@ function useRoomPermissions(cli: MatrixClient, room: Room, user: User): IRoomPer
} }
const PowerLevelSection: React.FC<{ const PowerLevelSection: React.FC<{
user: User; user: RoomMember;
room: Room; room: Room;
roomPermissions: IRoomPermissions; roomPermissions: IRoomPermissions;
powerLevels: IPowerLevelsContent; powerLevels: IPowerLevelsContent;
@ -1038,7 +1038,7 @@ const PowerLevelSection: React.FC<{
return (<PowerLevelEditor user={user} room={room} roomPermissions={roomPermissions} />); return (<PowerLevelEditor user={user} room={room} roomPermissions={roomPermissions} />);
} else { } else {
const powerLevelUsersDefault = powerLevels.users_default || 0; const powerLevelUsersDefault = powerLevels.users_default || 0;
const powerLevel = parseInt(user.powerLevel, 10); const powerLevel = user.powerLevel;
const role = textualPowerLevel(powerLevel, powerLevelUsersDefault); const role = textualPowerLevel(powerLevel, powerLevelUsersDefault);
return ( return (
<div className="mx_UserInfo_profileField"> <div className="mx_UserInfo_profileField">
@ -1049,13 +1049,13 @@ const PowerLevelSection: React.FC<{
}; };
const PowerLevelEditor: React.FC<{ const PowerLevelEditor: React.FC<{
user: User; user: RoomMember;
room: Room; room: Room;
roomPermissions: IRoomPermissions; roomPermissions: IRoomPermissions;
}> = ({user, room, roomPermissions}) => { }> = ({user, room, roomPermissions}) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const [selectedPowerLevel, setSelectedPowerLevel] = useState(parseInt(user.powerLevel, 10)); const [selectedPowerLevel, setSelectedPowerLevel] = useState(user.powerLevel);
const onPowerChange = useCallback(async (powerLevelStr: string) => { const onPowerChange = useCallback(async (powerLevelStr: string) => {
const powerLevel = parseInt(powerLevelStr, 10); const powerLevel = parseInt(powerLevelStr, 10);
setSelectedPowerLevel(powerLevel); setSelectedPowerLevel(powerLevel);
@ -1232,7 +1232,7 @@ const BasicUserInfo: React.FC<{
setPendingUpdateCount(pendingUpdateCount - 1); setPendingUpdateCount(pendingUpdateCount - 1);
}, [pendingUpdateCount]); }, [pendingUpdateCount]);
const roomPermissions = useRoomPermissions(cli, room, member); const roomPermissions = useRoomPermissions(cli, room, member as RoomMember);
const onSynapseDeactivate = useCallback(async () => { const onSynapseDeactivate = useCallback(async () => {
const {finished} = Modal.createTrackedDialog('Synapse User Deactivation', '', QuestionDialog, { const {finished} = Modal.createTrackedDialog('Synapse User Deactivation', '', QuestionDialog, {
@ -1276,12 +1276,26 @@ const BasicUserInfo: React.FC<{
); );
} }
let memberDetails;
let adminToolsContainer; let adminToolsContainer;
if (room && member.roomId) { if (room && (member as RoomMember).roomId) {
// hide the Roles section for DMs as it doesn't make sense there
if (!DMRoomMap.shared().getUserIdForRoomId((member as RoomMember).roomId)) {
memberDetails = <div className="mx_UserInfo_container">
<h3>{ _t("Role") }</h3>
<PowerLevelSection
powerLevels={powerLevels}
user={member as RoomMember}
room={room}
roomPermissions={roomPermissions}
/>
</div>;
}
adminToolsContainer = ( adminToolsContainer = (
<RoomAdminToolsContainer <RoomAdminToolsContainer
powerLevels={powerLevels} powerLevels={powerLevels}
member={member} member={member as RoomMember}
room={room} room={room}
startUpdating={startUpdating} startUpdating={startUpdating}
stopUpdating={stopUpdating}> stopUpdating={stopUpdating}>
@ -1310,20 +1324,6 @@ const BasicUserInfo: React.FC<{
spinner = <Spinner />; spinner = <Spinner />;
} }
let memberDetails;
// hide the Roles section for DMs as it doesn't make sense there
if (room && member.roomId && !DMRoomMap.shared().getUserIdForRoomId(member.roomId)) {
memberDetails = <div className="mx_UserInfo_container">
<h3>{ _t("Role") }</h3>
<PowerLevelSection
powerLevels={powerLevels}
user={member}
room={room}
roomPermissions={roomPermissions}
/>
</div>;
}
// only display the devices list if our client supports E2E // only display the devices list if our client supports E2E
const cryptoEnabled = cli.isCryptoEnabled(); const cryptoEnabled = cli.isCryptoEnabled();
@ -1350,8 +1350,7 @@ const BasicUserInfo: React.FC<{
const setUpdating = (updating) => { const setUpdating = (updating) => {
setPendingUpdateCount(count => count + (updating ? 1 : -1)); setPendingUpdateCount(count => count + (updating ? 1 : -1));
}; };
const hasCrossSigningKeys = const hasCrossSigningKeys = useHasCrossSigningKeys(cli, member as User, canVerify, setUpdating);
useHasCrossSigningKeys(cli, member, canVerify, setUpdating );
const showDeviceListSpinner = devices === undefined; const showDeviceListSpinner = devices === undefined;
if (canVerify) { if (canVerify) {
@ -1360,9 +1359,9 @@ const BasicUserInfo: React.FC<{
verifyButton = ( verifyButton = (
<AccessibleButton className="mx_UserInfo_field mx_UserInfo_verifyButton" onClick={() => { <AccessibleButton className="mx_UserInfo_field mx_UserInfo_verifyButton" onClick={() => {
if (hasCrossSigningKeys) { if (hasCrossSigningKeys) {
verifyUser(member); verifyUser(member as User);
} else { } else {
legacyVerifyUser(member); legacyVerifyUser(member as User);
} }
}}> }}>
{_t("Verify")} {_t("Verify")}
@ -1410,7 +1409,7 @@ const BasicUserInfo: React.FC<{
<UserOptionsSection <UserOptionsSection
canInvite={roomPermissions.canInvite} canInvite={roomPermissions.canInvite}
isIgnored={isIgnored} isIgnored={isIgnored}
member={member} member={member as RoomMember}
isSpace={SettingsStore.getValue("feature_spaces") && room?.isSpaceRoom()} isSpace={SettingsStore.getValue("feature_spaces") && room?.isSpaceRoom()}
/> />
@ -1429,13 +1428,15 @@ const UserInfoHeader: React.FC<{
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const onMemberAvatarClick = useCallback(() => { const onMemberAvatarClick = useCallback(() => {
const avatarUrl = member.getMxcAvatarUrl ? member.getMxcAvatarUrl() : member.avatarUrl; const avatarUrl = (member as RoomMember).getMxcAvatarUrl
? (member as RoomMember).getMxcAvatarUrl()
: (member as User).avatarUrl;
if (!avatarUrl) return; if (!avatarUrl) return;
const httpUrl = mediaFromMxc(avatarUrl).srcHttp; const httpUrl = mediaFromMxc(avatarUrl).srcHttp;
const params = { const params = {
src: httpUrl, src: httpUrl,
name: member.name, name: (member as RoomMember).name || (member as User).displayName,
}; };
Modal.createDialog(ImageView, params, "mx_Dialog_lightbox", null, true); Modal.createDialog(ImageView, params, "mx_Dialog_lightbox", null, true);
@ -1447,13 +1448,13 @@ const UserInfoHeader: React.FC<{
<div> <div>
<MemberAvatar <MemberAvatar
key={member.userId} // to instantly blank the avatar when UserInfo changes members key={member.userId} // to instantly blank the avatar when UserInfo changes members
member={member} member={member as RoomMember}
width={2 * 0.3 * UIStore.instance.windowHeight} // 2x@30vh width={2 * 0.3 * UIStore.instance.windowHeight} // 2x@30vh
height={2 * 0.3 * UIStore.instance.windowHeight} // 2x@30vh height={2 * 0.3 * UIStore.instance.windowHeight} // 2x@30vh
resizeMethod="scale" resizeMethod="scale"
fallbackUserId={member.userId} fallbackUserId={member.userId}
onClick={onMemberAvatarClick} onClick={onMemberAvatarClick}
urls={member.avatarUrl ? [member.avatarUrl] : undefined} /> urls={(member as User).avatarUrl ? [(member as User).avatarUrl] : undefined} />
</div> </div>
</div> </div>
</div> </div>
@ -1470,7 +1471,11 @@ const UserInfoHeader: React.FC<{
presenceCurrentlyActive = member.user.currentlyActive; presenceCurrentlyActive = member.user.currentlyActive;
if (SettingsStore.getValue("feature_custom_status")) { if (SettingsStore.getValue("feature_custom_status")) {
statusMessage = member.user._unstable_statusMessage; if ((member as RoomMember).user) {
statusMessage = member.user.unstable_statusMessage;
} else {
statusMessage = (member as unknown as User).unstable_statusMessage;
}
} }
} }
@ -1501,7 +1506,7 @@ const UserInfoHeader: React.FC<{
e2eIcon = <E2EIcon size={18} status={e2eStatus} isUser={true} />; e2eIcon = <E2EIcon size={18} status={e2eStatus} isUser={true} />;
} }
const displayName = member.rawDisplayName || member.displayname; const displayName = (member as RoomMember).rawDisplayName || (member as GroupMember).displayname;
return <React.Fragment> return <React.Fragment>
{ avatarElement } { avatarElement }

View file

@ -22,6 +22,7 @@ import {verificationMethods} from 'matrix-js-sdk/src/crypto';
import {SCAN_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode"; import {SCAN_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import {RoomMember} from "matrix-js-sdk/src/models/room-member"; import {RoomMember} from "matrix-js-sdk/src/models/room-member";
import { User } from "matrix-js-sdk/src/models/user";
import {ReciprocateQRCode} from "matrix-js-sdk/src/crypto/verification/QRCode"; import {ReciprocateQRCode} from "matrix-js-sdk/src/crypto/verification/QRCode";
import {SAS} from "matrix-js-sdk/src/crypto/verification/SAS"; import {SAS} from "matrix-js-sdk/src/crypto/verification/SAS";
@ -51,7 +52,7 @@ enum VerificationPhase {
interface IProps { interface IProps {
layout: string; layout: string;
request: VerificationRequest; request: VerificationRequest;
member: RoomMember; member: RoomMember | User;
phase: VerificationPhase; phase: VerificationPhase;
onClose: () => void; onClose: () => void;
isRoomEncrypted: boolean; isRoomEncrypted: boolean;
@ -134,7 +135,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
qrBlock = <div className="mx_UserInfo_container"> qrBlock = <div className="mx_UserInfo_container">
<h3>{_t("Verify by scanning")}</h3> <h3>{_t("Verify by scanning")}</h3>
<p>{_t("Ask %(displayName)s to scan your code:", { <p>{_t("Ask %(displayName)s to scan your code:", {
displayName: member.displayName || member.name || member.userId, displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
})}</p> })}</p>
<div className="mx_VerificationPanel_qrCode"> <div className="mx_VerificationPanel_qrCode">
@ -205,7 +206,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
const description = request.isSelfVerification ? const description = request.isSelfVerification ?
_t("Almost there! Is your other session showing the same shield?") : _t("Almost there! Is your other session showing the same shield?") :
_t("Almost there! Is %(displayName)s showing the same shield?", { _t("Almost there! Is %(displayName)s showing the same shield?", {
displayName: member.displayName || member.name || member.userId, displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
}); });
let body: JSX.Element; let body: JSX.Element;
if (this.state.reciprocateQREvent) { if (this.state.reciprocateQREvent) {
@ -264,7 +265,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
} }
} else { } else {
description = _t("You've successfully verified %(displayName)s!", { description = _t("You've successfully verified %(displayName)s!", {
displayName: member.displayName || member.name || member.userId, displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
}); });
} }
@ -302,7 +303,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
text = _t("You cancelled verification on your other session."); text = _t("You cancelled verification on your other session.");
} else { } else {
text = _t("%(displayName)s cancelled verification.", { text = _t("%(displayName)s cancelled verification.", {
displayName: member.displayName || member.name || member.userId, displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
}); });
} }
text = `${text} ${startAgainInstruction}`; text = `${text} ${startAgainInstruction}`;
@ -325,7 +326,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
public render() { public render() {
const {member, phase, request} = this.props; const {member, phase, request} = this.props;
const displayName = member.displayName || member.name || member.userId; const displayName = (member as User).displayName || (member as RoomMember).name || member.userId;
switch (phase) { switch (phase) {
case PHASE_READY: case PHASE_READY:

View file

@ -378,7 +378,7 @@ export default class EventTile extends React.Component<IProps, IState> {
EventType.RoomMessage, EventType.RoomMessage,
EventType.RoomMessageEncrypted, EventType.RoomMessageEncrypted,
]; ];
if (!simpleSendableEvents.includes(this.props.mxEvent.getType())) return false; if (!simpleSendableEvents.includes(this.props.mxEvent.getType() as EventType)) return false;
// Default case // Default case
return true; return true;

View file

@ -44,14 +44,11 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
return <BridgeTile key={event.getId()} room={room} ev={event} />; return <BridgeTile key={event.getId()} room={room} ev={event} />;
} }
static getBridgeStateEvents(roomId: string) { static getBridgeStateEvents(roomId: string): MatrixEvent[] {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
const roomState = client.getRoom(roomId).currentState; const roomState = client.getRoom(roomId).currentState;
return BRIDGE_EVENT_TYPES.map(typeName => { return BRIDGE_EVENT_TYPES.map(typeName => roomState.getStateEvents(typeName)).flat(1);
const events = roomState.events.get(typeName);
return events ? Array.from(events.values()) : [];
}).flat(1);
} }
render() { render() {

View file

@ -17,6 +17,7 @@ limitations under the License.
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { User } from "matrix-js-sdk/src/models/user";
import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
import { ActionPayload } from "../payloads"; import { ActionPayload } from "../payloads";
import { Action } from "../actions"; import { Action } from "../actions";
@ -29,7 +30,7 @@ export interface SetRightPanelPhasePayload extends ActionPayload {
} }
export interface SetRightPanelPhaseRefireParams { export interface SetRightPanelPhaseRefireParams {
member?: RoomMember; member?: RoomMember | User;
verificationRequest?: VerificationRequest; verificationRequest?: VerificationRequest;
groupId?: string; groupId?: string;
groupRoomId?: string; groupRoomId?: string;

View file

@ -21,11 +21,11 @@ import {Room} from "matrix-js-sdk/src/models/room";
import {useEventEmitter} from "./useEventEmitter"; import {useEventEmitter} from "./useEventEmitter";
const tryGetContent = (ev?: MatrixEvent) => ev ? ev.getContent() : undefined; const tryGetContent = <T extends {}>(ev?: MatrixEvent) => ev ? ev.getContent<T>() : undefined;
// Hook to simplify listening to Matrix account data // Hook to simplify listening to Matrix account data
export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: string) => { export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: string) => {
const [value, setValue] = useState<T>(() => tryGetContent(cli.getAccountData(eventType))); const [value, setValue] = useState<T>(() => tryGetContent<T>(cli.getAccountData(eventType)));
const handler = useCallback((event) => { const handler = useCallback((event) => {
if (event.getType() !== eventType) return; if (event.getType() !== eventType) return;
@ -38,7 +38,7 @@ export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: strin
// Hook to simplify listening to Matrix room account data // Hook to simplify listening to Matrix room account data
export const useRoomAccountData = <T extends {}>(room: Room, eventType: string) => { export const useRoomAccountData = <T extends {}>(room: Room, eventType: string) => {
const [value, setValue] = useState<T>(() => tryGetContent(room.getAccountData(eventType))); const [value, setValue] = useState<T>(() => tryGetContent<T>(room.getAccountData(eventType)));
const handler = useCallback((event) => { const handler = useCallback((event) => {
if (event.getType() !== eventType) return; if (event.getType() !== eventType) return;

View file

@ -300,7 +300,7 @@ export default class EventIndex extends EventEmitter {
} }
private eventToJson(ev: MatrixEvent) { private eventToJson(ev: MatrixEvent) {
const jsonEvent = ev.toJSON(); const jsonEvent: any = ev.toJSON();
const e = ev.isEncrypted() ? jsonEvent.decrypted : jsonEvent; const e = ev.isEncrypted() ? jsonEvent.decrypted : jsonEvent;
if (ev.isEncrypted()) { if (ev.isEncrypted()) {

View file

@ -16,8 +16,8 @@ limitations under the License.
import EventEmitter from 'events'; import EventEmitter from 'events';
import { IWidget } from 'matrix-widget-api'; import { IWidget } from 'matrix-widget-api';
import MatrixEvent from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import {WidgetType} from "../widgets/WidgetType"; import { WidgetType } from "../widgets/WidgetType";
/** /**
* Acts as a place to get & set widget state, storing local echo state and * Acts as a place to get & set widget state, storing local echo state and

View file

@ -51,7 +51,7 @@ import ThemeWatcher from "../../settings/watchers/ThemeWatcher";
import {getCustomTheme} from "../../theme"; import {getCustomTheme} from "../../theme";
import CountlyAnalytics from "../../CountlyAnalytics"; import CountlyAnalytics from "../../CountlyAnalytics";
import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities"; import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent, IEvent } from "matrix-js-sdk/src/models/event";
import { ELEMENT_CLIENT_ID } from "../../identifiers"; import { ELEMENT_CLIENT_ID } from "../../identifiers";
import { getUserLanguage } from "../../languageHandler"; import { getUserLanguage } from "../../languageHandler";
@ -415,7 +415,7 @@ export class StopGapWidget extends EventEmitter {
private feedEvent(ev: MatrixEvent) { private feedEvent(ev: MatrixEvent) {
if (!this.messaging) return; if (!this.messaging) return;
const raw = ev.event; const raw = ev.event as IEvent;
this.messaging.feedEvent(raw).catch(e => { this.messaging.feedEvent(raw).catch(e => {
console.error("Error sending event to widget: ", e); console.error("Error sending event to widget: ", e);
}); });

View file

@ -145,7 +145,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
return {roomId, eventId: r.event_id}; return {roomId, eventId: r.event_id};
} }
public async readRoomEvents(eventType: string, msgtype: string | undefined, limit: number): Promise<MatrixEvent[]> { public async readRoomEvents(eventType: string, msgtype: string | undefined, limit: number): Promise<object[]> {
limit = limit > 0 ? Math.min(limit, 25) : 25; // arbitrary choice limit = limit > 0 ? Math.min(limit, 25) : 25; // arbitrary choice
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
@ -167,9 +167,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
return results.map(e => e.event); return results.map(e => e.event);
} }
public async readStateEvents( public async readStateEvents(eventType: string, stateKey: string | undefined, limit: number): Promise<object[]> {
eventType: string, stateKey: string | undefined, limit: number,
): Promise<MatrixEvent[]> {
limit = limit > 0 ? Math.min(limit, 100) : 100; // arbitrary choice limit = limit > 0 ? Math.min(limit, 100) : 100; // arbitrary choice
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
@ -178,7 +176,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
if (!client || !roomId || !room) throw new Error("Not in a room or not attached to a client"); if (!client || !roomId || !room) throw new Error("Not in a room or not attached to a client");
const results: MatrixEvent[] = []; const results: MatrixEvent[] = [];
const state = room.currentState.events.get(eventType); const state: Map<string, MatrixEvent> = room.currentState.events.get(eventType);
if (state) { if (state) {
if (stateKey === "" || !!stateKey) { if (stateKey === "" || !!stateKey) {
const forKey = state.get(stateKey); const forKey = state.get(stateKey);

View file

@ -14,11 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {MatrixClientPeg} from '../MatrixClientPeg'; import { uniq } from "lodash";
import {uniq} from "lodash"; import { Room } from "matrix-js-sdk/src/models/room";
import {Room} from "matrix-js-sdk/src/models/room"; import { MatrixClient } from "matrix-js-sdk/src/client";
import {Event} from "matrix-js-sdk/src/models/event";
import {MatrixClient} from "matrix-js-sdk/src/client"; import { MatrixClientPeg } from '../MatrixClientPeg';
/** /**
* Class that takes a Matrix Client and flips the m.direct map * Class that takes a Matrix Client and flips the m.direct map
@ -30,15 +30,13 @@ import {MatrixClient} from "matrix-js-sdk/src/client";
export default class DMRoomMap { export default class DMRoomMap {
private static sharedInstance: DMRoomMap; private static sharedInstance: DMRoomMap;
private matrixClient: MatrixClient;
// TODO: convert these to maps // TODO: convert these to maps
private roomToUser: {[key: string]: string} = null; private roomToUser: {[key: string]: string} = null;
private userToRooms: {[key: string]: string[]} = null; private userToRooms: {[key: string]: string[]} = null;
private hasSentOutPatchDirectAccountDataPatch: boolean; private hasSentOutPatchDirectAccountDataPatch: boolean;
private mDirectEvent: Event; private mDirectEvent: object;
constructor(matrixClient) { constructor(private readonly matrixClient: MatrixClient) {
this.matrixClient = matrixClient;
// see onAccountData // see onAccountData
this.hasSentOutPatchDirectAccountDataPatch = false; this.hasSentOutPatchDirectAccountDataPatch = false;

View file

@ -392,7 +392,7 @@ export default class WidgetUtils {
} }
const widgets = client.getAccountData('m.widgets'); const widgets = client.getAccountData('m.widgets');
if (!widgets) return; if (!widgets) return;
const userWidgets: IWidgetEvent[] = widgets.getContent() || {}; const userWidgets: Record<string, IWidgetEvent> = widgets.getContent() || {};
Object.entries(userWidgets).forEach(([key, widget]) => { Object.entries(userWidgets).forEach(([key, widget]) => {
if (widget.content && widget.content.type === "m.integration_manager") { if (widget.content && widget.content.type === "m.integration_manager") {
delete userWidgets[key]; delete userWidgets[key];

View file

@ -30,9 +30,7 @@ function createFailedDecryptionEvent() {
const event = new MatrixEvent({ const event = new MatrixEvent({
event_id: "event-id-" + Math.random().toString(16).slice(2), event_id: "event-id-" + Math.random().toString(16).slice(2),
}); });
event._setClearData( event.setClearData(event.badEncryptedMessage(":("));
event._badEncryptedMessage(":("),
);
return event; return event;
} }
@ -67,7 +65,7 @@ describe('DecryptionFailureTracker', function() {
tracker.eventDecrypted(decryptedEvent, err); tracker.eventDecrypted(decryptedEvent, err);
// Indicate successful decryption: clear data can be anything where the msgtype is not m.bad.encrypted // Indicate successful decryption: clear data can be anything where the msgtype is not m.bad.encrypted
decryptedEvent._setClearData({}); decryptedEvent.setClearData({});
tracker.eventDecrypted(decryptedEvent, null); tracker.eventDecrypted(decryptedEvent, null);
// Pretend "now" is Infinity // Pretend "now" is Infinity