Merge branch 'develop' into export-conversations

This commit is contained in:
Jaiwanth 2021-09-22 18:07:01 +05:30
commit 94e4fb71c1
498 changed files with 13790 additions and 23008 deletions

View file

@ -21,6 +21,7 @@ import { EventType } from "matrix-js-sdk/src/@types/event";
import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Relations } from "matrix-js-sdk/src/models/relations";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread';
import ReplyThread from "../elements/ReplyThread";
import { _t } from '../../../languageHandler';
@ -32,7 +33,7 @@ import { formatTime } from "../../../DateUtils";
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { ALL_RULE_TYPES } from "../../../mjolnir/BanList";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { E2E_STATE } from "./E2EIcon";
import { E2EState } from "./E2EIcon";
import { toRem } from "../../../utils/units";
import { WidgetType } from "../../../widgets/WidgetType";
import RoomAvatar from "../avatars/RoomAvatar";
@ -55,6 +56,8 @@ import ReadReceiptMarker from "./ReadReceiptMarker";
import MessageActionBar from "../messages/MessageActionBar";
import ReactionsRow from '../messages/ReactionsRow';
import { getEventDisplayInfo } from '../../../utils/EventUtils';
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
import SettingsStore from "../../../settings/SettingsStore";
const eventTileTypes = {
[EventType.RoomMessage]: 'messages.MessageEvent',
@ -240,6 +243,7 @@ interface IProps {
// opaque readreceipt info for each userId; used by ReadReceiptMarker
// to manage its animations. Should be an empty object when the room
// first loads
// TODO: Proper typing for RR info
readReceiptMap?: any;
// A function which is used to check if the parent panel is being
@ -301,6 +305,9 @@ interface IProps {
// whether or not to display the sender
hideSender?: boolean;
// whether or not to display thread info
showThreadInfo?: boolean;
}
interface IState {
@ -317,6 +324,8 @@ interface IState {
reactions: Relations;
hover: boolean;
thread?: Thread;
}
@replaceableComponent("views.rooms.EventTile")
@ -354,6 +363,8 @@ export default class EventTile extends React.Component<IProps, IState> {
reactions: this.getReactions(),
hover: false,
thread: this.props.mxEvent?.getThread(),
};
// don't do RR animations until we are mounted
@ -456,8 +467,20 @@ export default class EventTile extends React.Component<IProps, IState> {
this.isListeningForReceipts = true;
}
}
if (SettingsStore.getValue("feature_thread")) {
this.props.mxEvent.once(ThreadEvent.Ready, this.updateThread);
this.props.mxEvent.on(ThreadEvent.Update, this.updateThread);
}
}
private updateThread = (thread) => {
this.setState({
thread,
});
this.forceUpdate();
};
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line
UNSAFE_componentWillReceiveProps(nextProps) {
@ -468,7 +491,7 @@ export default class EventTile extends React.Component<IProps, IState> {
}
}
shouldComponentUpdate(nextProps, nextState) {
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (objectHasDiff(this.state, nextState)) {
return true;
}
@ -496,6 +519,43 @@ export default class EventTile extends React.Component<IProps, IState> {
}
}
private renderThreadInfo(): React.ReactNode {
if (!SettingsStore.getValue("feature_thread")) {
return null;
}
const thread = this.state.thread;
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
if (!thread || this.props.showThreadInfo === false || thread.length <= 1) {
return null;
}
const avatars = Array.from(thread.participants).map((mxId: string) => {
const member = room.getMember(mxId);
return <MemberAvatar key={member.userId} member={member} width={14} height={14} />;
});
return (
<div
className="mx_ThreadInfo"
onClick={() => {
dis.dispatch({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.ThreadView,
refireParams: {
event: this.props.mxEvent,
},
});
}}
>
<span className="mx_EventListSummary_avatars">
{ avatars }
</span>
{ thread.length - 1 } { thread.length === 2 ? 'reply' : 'replies' }
</div>
);
}
private onRoomReceipt = (ev, room) => {
// ignore events for other rooms
const tileRoom = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
@ -550,7 +610,7 @@ export default class EventTile extends React.Component<IProps, IState> {
if (encryptionInfo.mismatchedSender) {
// something definitely wrong is going on here
this.setState({
verified: E2E_STATE.WARNING,
verified: E2EState.Warning,
}, this.props.onHeightChanged); // Decryption may have caused a change in size
return;
}
@ -558,7 +618,7 @@ export default class EventTile extends React.Component<IProps, IState> {
if (!userTrust.isCrossSigningVerified()) {
// user is not verified, so default to everything is normal
this.setState({
verified: E2E_STATE.NORMAL,
verified: E2EState.Normal,
}, this.props.onHeightChanged); // Decryption may have caused a change in size
return;
}
@ -568,27 +628,27 @@ export default class EventTile extends React.Component<IProps, IState> {
);
if (!eventSenderTrust) {
this.setState({
verified: E2E_STATE.UNKNOWN,
verified: E2EState.Unknown,
}, this.props.onHeightChanged); // Decryption may have caused a change in size
return;
}
if (!eventSenderTrust.isVerified()) {
this.setState({
verified: E2E_STATE.WARNING,
verified: E2EState.Warning,
}, this.props.onHeightChanged); // Decryption may have caused a change in size
return;
}
if (!encryptionInfo.authenticated) {
this.setState({
verified: E2E_STATE.UNAUTHENTICATED,
verified: E2EState.Unauthenticated,
}, this.props.onHeightChanged); // Decryption may have caused a change in size
return;
}
this.setState({
verified: E2E_STATE.VERIFIED,
verified: E2EState.Verified,
}, this.props.onHeightChanged); // Decryption may have caused a change in size
}
@ -796,13 +856,13 @@ export default class EventTile extends React.Component<IProps, IState> {
// event is encrypted, display padlock corresponding to whether or not it is verified
if (ev.isEncrypted()) {
if (this.state.verified === E2E_STATE.NORMAL) {
if (this.state.verified === E2EState.Normal) {
return; // no icon if we've not even cross-signed the user
} else if (this.state.verified === E2E_STATE.VERIFIED) {
} else if (this.state.verified === E2EState.Verified) {
return; // no icon for verified
} else if (this.state.verified === E2E_STATE.UNAUTHENTICATED) {
} else if (this.state.verified === E2EState.Unauthenticated) {
return (<E2ePadlockUnauthenticated />);
} else if (this.state.verified === E2E_STATE.UNKNOWN) {
} else if (this.state.verified === E2EState.Unknown) {
return (<E2ePadlockUnknown />);
} else {
return (<E2ePadlockUnverified />);
@ -907,9 +967,9 @@ export default class EventTile extends React.Component<IProps, IState> {
mx_EventTile_lastInSection: this.props.lastInSection,
mx_EventTile_contextual: this.props.contextual,
mx_EventTile_actionBarFocused: this.state.actionBarFocused,
mx_EventTile_verified: !isBubbleMessage && this.state.verified === E2E_STATE.VERIFIED,
mx_EventTile_unverified: !isBubbleMessage && this.state.verified === E2E_STATE.WARNING,
mx_EventTile_unknown: !isBubbleMessage && this.state.verified === E2E_STATE.UNKNOWN,
mx_EventTile_verified: !isBubbleMessage && this.state.verified === E2EState.Verified,
mx_EventTile_unverified: !isBubbleMessage && this.state.verified === E2EState.Warning,
mx_EventTile_unknown: !isBubbleMessage && this.state.verified === E2EState.Unknown,
mx_EventTile_bad: isEncryptionFailure,
mx_EventTile_emote: msgtype === 'm.emote',
mx_EventTile_noSender: this.props.hideSender,
@ -1139,15 +1199,20 @@ export default class EventTile extends React.Component<IProps, IState> {
}
default: {
const thread = ReplyThread.makeThread(
this.props.mxEvent,
this.props.onHeightChanged,
this.props.permalinkCreator,
this.replyThread,
this.props.layout,
this.props.forExport,
this.props.alwaysShowTimestamps || this.state.hover,
);
let thread;
// When the "showHiddenEventsInTimeline" lab is enabled,
// avoid showing replies for hidden events (events without tiles)
if (haveTileForEvent(this.props.mxEvent)) {
thread = ReplyThread.makeThread(
this.props.mxEvent,
this.props.onHeightChanged,
this.props.permalinkCreator,
this.replyThread,
this.props.layout,
this.props.forExport,
this.props.alwaysShowTimestamps || this.state.hover,
);
}
const isOwnEvent = this.props.mxEvent?.sender?.userId === MatrixClientPeg.get().getUserId();
@ -1189,6 +1254,7 @@ export default class EventTile extends React.Component<IProps, IState> {
{ keyRequestInfo }
{ actionBar }
{ this.props.layout === Layout.IRC && (reactionsRow) }
{ this.renderThreadInfo() }
</div>
{ this.props.layout !== Layout.IRC && (reactionsRow) }
{ msgOption }