Merge branch 'develop' into travis/split-left-panel

This commit is contained in:
Travis Ralston 2020-06-04 15:09:51 -06:00
commit dc01607ad9
83 changed files with 1185 additions and 3146 deletions

View file

@ -15,8 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import ReactDOM from 'react-dom';
import React, {createRef} from 'react';
import classNames from 'classnames';
import flatMap from 'lodash/flatMap';
import {ICompletion, ISelectionRange, IProviderCompletions} from '../../../autocomplete/Autocompleter';
@ -54,7 +53,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
autocompleter: Autocompleter;
queryRequested: string;
debounceCompletionsRequest: NodeJS.Timeout;
containerRef: React.RefObject<HTMLDivElement>;
private containerRef = createRef<HTMLDivElement>();
constructor(props) {
super(props);
@ -78,8 +77,6 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
forceComplete: false,
};
this.containerRef = React.createRef();
}
componentDidMount() {
@ -256,14 +253,15 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
componentDidUpdate(prevProps: IProps) {
this.applyNewProps(prevProps.query, prevProps.room);
// this is the selected completion, so scroll it into view if needed
const selectedCompletion = this.refs[`completion${this.state.selectionOffset}`];
if (selectedCompletion && this.containerRef.current) {
const domNode = ReactDOM.findDOMNode(selectedCompletion);
const offsetTop = domNode && (domNode as HTMLElement).offsetTop;
if (offsetTop > this.containerRef.current.scrollTop + this.containerRef.current.offsetHeight ||
offsetTop < this.containerRef.current.scrollTop) {
this.containerRef.current.scrollTop = offsetTop - this.containerRef.current.offsetTop;
}
const selectedCompletion = this.refs[`completion${this.state.selectionOffset}`] as HTMLElement;
if (selectedCompletion) {
selectedCompletion.scrollIntoView({
behavior: "auto",
block: "nearest",
});
} else if (this.containerRef.current) {
this.containerRef.current.scrollTo({ top: 0 });
}
}

View file

@ -20,7 +20,6 @@ import PropTypes from "prop-types";
import classNames from 'classnames';
import {_t, _td} from '../../../languageHandler';
import {useSettingValue} from "../../../hooks/useSettings";
import AccessibleButton from "../elements/AccessibleButton";
import Tooltip from "../elements/Tooltip";
@ -42,15 +41,6 @@ const crossSigningRoomTitles = {
[E2E_STATE.VERIFIED]: _td("Everyone in this room is verified"),
};
const legacyUserTitles = {
[E2E_STATE.WARNING]: _td("Some sessions for this user are not trusted"),
[E2E_STATE.VERIFIED]: _td("All sessions for this user are trusted"),
};
const legacyRoomTitles = {
[E2E_STATE.WARNING]: _td("Some sessions in this encrypted room are not trusted"),
[E2E_STATE.VERIFIED]: _td("All sessions in this encrypted room are trusted"),
};
const E2EIcon = ({isUser, status, className, size, onClick, hideTooltip}) => {
const [hover, setHover] = useState(false);
@ -62,15 +52,10 @@ const E2EIcon = ({isUser, status, className, size, onClick, hideTooltip}) => {
}, className);
let e2eTitle;
const crossSigning = useSettingValue("feature_cross_signing");
if (crossSigning && isUser) {
if (isUser) {
e2eTitle = crossSigningUserTitles[status];
} else if (crossSigning && !isUser) {
} else {
e2eTitle = crossSigningRoomTitles[status];
} else if (!crossSigning && isUser) {
e2eTitle = legacyUserTitles[status];
} else if (!crossSigning && !isUser) {
e2eTitle = legacyRoomTitles[status];
}
let style;

View file

@ -104,7 +104,7 @@ export function getHandlerTile(ev) {
// fall back to showing hidden events, if we're viewing hidden events
// XXX: This is extremely a hack. Possibly these components should have an interface for
// declining to render?
if (type === "m.key.verification.cancel" && SettingsStore.getValue("showHiddenEventsInTimeline")) {
if (type === "m.key.verification.cancel" || type === "m.key.verification.done") {
const MKeyVerificationConclusion = sdk.getComponent("messages.MKeyVerificationConclusion");
if (!MKeyVerificationConclusion.prototype._shouldRender.call(null, ev, ev.request)) {
return;
@ -325,15 +325,6 @@ export default createReactClass({
return;
}
// If cross-signing is off, the old behaviour is to scream at the user
// as if they've done something wrong, which they haven't
if (!SettingsStore.getValue("feature_cross_signing")) {
this.setState({
verified: E2E_STATE.WARNING,
}, this.props.onHeightChanged);
return;
}
if (!this.context.checkUserTrust(mxEvent.getSender()).isCrossSigningVerified()) {
this.setState({
verified: E2E_STATE.NORMAL,

View file

@ -1,59 +0,0 @@
/*
Copyright 2016 OpenMarket Ltd
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 PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import classNames from 'classnames';
export default class MemberDeviceInfo extends React.Component {
render() {
const DeviceVerifyButtons = sdk.getComponent('elements.DeviceVerifyButtons');
// XXX: These checks are not cross-signing aware but this component is only used
// from the old, pre-cross-signing memberinfopanel
const iconClasses = classNames({
mx_MemberDeviceInfo_icon: true,
mx_MemberDeviceInfo_icon_blacklisted: this.props.device.isBlocked(),
mx_MemberDeviceInfo_icon_verified: this.props.device.isVerified(),
mx_MemberDeviceInfo_icon_unverified: this.props.device.isUnverified(),
});
const indicator = (<div className={iconClasses} />);
const deviceName = (this.props.device.ambiguous || this.props.showDeviceId) ?
(this.props.device.getDisplayName() ? this.props.device.getDisplayName() : "") + " (" + this.props.device.deviceId + ")" :
this.props.device.getDisplayName();
// add the deviceId as a titletext to help with debugging
return (
<div className="mx_MemberDeviceInfo"
title={_t("device id: ") + this.props.device.deviceId} >
{ indicator }
<div className="mx_MemberDeviceInfo_deviceInfo">
<div className="mx_MemberDeviceInfo_deviceId">
{ deviceName }
</div>
</div>
<DeviceVerifyButtons userId={this.props.userId} device={this.props.device} />
</div>
);
}
}
MemberDeviceInfo.displayName = 'MemberDeviceInfo';
MemberDeviceInfo.propTypes = {
userId: PropTypes.string.isRequired,
device: PropTypes.object.isRequired,
};

File diff suppressed because it is too large Load diff

View file

@ -57,21 +57,19 @@ export default createReactClass({
}
}
if (SettingsStore.getValue("feature_cross_signing")) {
const { roomId } = this.props.member;
if (roomId) {
const isRoomEncrypted = cli.isRoomEncrypted(roomId);
this.setState({
isRoomEncrypted,
});
if (isRoomEncrypted) {
cli.on("userTrustStatusChanged", this.onUserTrustStatusChanged);
cli.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
this.updateE2EStatus();
} else {
// Listen for room to become encrypted
cli.on("RoomState.events", this.onRoomStateEvents);
}
const { roomId } = this.props.member;
if (roomId) {
const isRoomEncrypted = cli.isRoomEncrypted(roomId);
this.setState({
isRoomEncrypted,
});
if (isRoomEncrypted) {
cli.on("userTrustStatusChanged", this.onUserTrustStatusChanged);
cli.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
this.updateE2EStatus();
} else {
// Listen for room to become encrypted
cli.on("RoomState.events", this.onRoomStateEvents);
}
}
},

View file

@ -308,33 +308,17 @@ export default class MessageComposer extends React.Component {
}
renderPlaceholderText() {
if (SettingsStore.getValue("feature_cross_signing")) {
if (this.state.isQuoting) {
if (this.props.e2eStatus) {
return _t('Send an encrypted reply…');
} else {
return _t('Send a reply…');
}
if (this.state.isQuoting) {
if (this.props.e2eStatus) {
return _t('Send an encrypted reply…');
} else {
if (this.props.e2eStatus) {
return _t('Send an encrypted message…');
} else {
return _t('Send a message…');
}
return _t('Send a reply…');
}
} else {
if (this.state.isQuoting) {
if (this.props.e2eStatus) {
return _t('Send an encrypted reply…');
} else {
return _t('Send a reply (unencrypted)…');
}
if (this.props.e2eStatus) {
return _t('Send an encrypted message…');
} else {
if (this.props.e2eStatus) {
return _t('Send an encrypted message…');
} else {
return _t('Send a message (unencrypted)…');
}
return _t('Send a message…');
}
}
}

View file

@ -168,10 +168,8 @@ export default createReactClass({
const joinRule = joinRules && joinRules.getContent().join_rule;
let privateIcon;
// Don't show an invite-only icon for DMs. Users know they're invite-only.
if (!dmUserId && SettingsStore.getValue("feature_cross_signing")) {
if (joinRule == "invite") {
privateIcon = <InviteOnlyIcon />;
}
if (!dmUserId && joinRule === "invite") {
privateIcon = <InviteOnlyIcon />;
}
if (this.props.onCancelClick) {

View file

@ -28,6 +28,8 @@ import { Dispatcher } from "flux";
import dis from "../../../dispatcher/dispatcher";
import RoomSublist2 from "./RoomSublist2";
import { ActionPayload } from "../../../dispatcher/payloads";
import { IFilterCondition } from "../../../stores/room-list/filters/IFilterCondition";
import { NameFilterCondition } from "../../../stores/room-list/filters/NameFilterCondition";
/*******************************************************************
* CAUTION *
@ -130,6 +132,7 @@ export default class RoomList2 extends React.Component<IProps, IState> {
private sublistCollapseStates: { [tagId: string]: boolean } = {};
private unfilteredLayout: Layout;
private filteredLayout: Layout;
private searchFilter: NameFilterCondition = new NameFilterCondition();
constructor(props: IProps) {
super(props);
@ -139,6 +142,21 @@ export default class RoomList2 extends React.Component<IProps, IState> {
this.prepareLayouts();
}
public componentDidUpdate(prevProps: Readonly<IProps>): void {
if (prevProps.searchFilter !== this.props.searchFilter) {
const hadSearch = !!this.searchFilter.search.trim();
const haveSearch = !!this.props.searchFilter.trim();
this.searchFilter.search = this.props.searchFilter;
if (!hadSearch && haveSearch) {
// started a new filter - add the condition
RoomListStore.instance.addFilter(this.searchFilter);
} else if (hadSearch && !haveSearch) {
// cleared a filter - remove the condition
RoomListStore.instance.removeFilter(this.searchFilter);
} // else the filter hasn't changed enough for us to care here
}
}
public componentDidMount(): void {
RoomListStore.instance.on(LISTS_UPDATE_EVENT, (store) => {
console.log("new lists", store.orderedLists);

View file

@ -155,9 +155,6 @@ export default createReactClass({
if (!cli.isRoomEncrypted(this.props.room.roomId)) {
return;
}
if (!SettingsStore.getValue("feature_cross_signing")) {
return;
}
/* At this point, the user has encryption on and cross-signing on */
this.setState({
@ -515,10 +512,8 @@ export default createReactClass({
}
let privateIcon = null;
if (SettingsStore.getValue("feature_cross_signing")) {
if (this.state.joinRule == "invite" && !dmUserId) {
privateIcon = <InviteOnlyIcon collapsedPanel={this.props.collapsed} />;
}
if (this.state.joinRule === "invite" && !dmUserId) {
privateIcon = <InviteOnlyIcon collapsedPanel={this.props.collapsed} />;
}
let e2eIcon = null;