Merge branch 'develop' into travis/ft-sep1620/04-jitsi-hangup
This commit is contained in:
commit
9df175212e
144 changed files with 3643 additions and 1968 deletions
|
@ -39,15 +39,9 @@ export default class AuxPanel extends React.Component {
|
|||
showApps: PropTypes.bool, // Render apps
|
||||
hideAppsDrawer: PropTypes.bool, // Do not display apps drawer and content (may still be rendered)
|
||||
|
||||
// Conference Handler implementation
|
||||
conferenceHandler: PropTypes.object,
|
||||
|
||||
// set to true to show the file drop target
|
||||
draggingFile: PropTypes.bool,
|
||||
|
||||
// set to true to show the 'active conf call' banner
|
||||
displayConfCallNotification: PropTypes.bool,
|
||||
|
||||
// maxHeight attribute for the aux panel and the video
|
||||
// therein
|
||||
maxHeight: PropTypes.number,
|
||||
|
@ -161,39 +155,9 @@ export default class AuxPanel extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
let conferenceCallNotification = null;
|
||||
if (this.props.displayConfCallNotification) {
|
||||
let supportedText = '';
|
||||
let joinNode;
|
||||
if (!MatrixClientPeg.get().supportsVoip()) {
|
||||
supportedText = _t(" (unsupported)");
|
||||
} else {
|
||||
joinNode = (<span>
|
||||
{ _t(
|
||||
"Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.",
|
||||
{},
|
||||
{
|
||||
'voiceText': (sub) => <a onClick={(event)=>{ this.onConferenceNotificationClick(event, 'voice');}} href="#">{ sub }</a>,
|
||||
'videoText': (sub) => <a onClick={(event)=>{ this.onConferenceNotificationClick(event, 'video');}} href="#">{ sub }</a>,
|
||||
},
|
||||
) }
|
||||
</span>);
|
||||
}
|
||||
// XXX: the translation here isn't great: appending ' (unsupported)' is likely to not make sense in many languages,
|
||||
// but there are translations for this in the languages we do have so I'm leaving it for now.
|
||||
conferenceCallNotification = (
|
||||
<div className="mx_RoomView_ongoingConfCallNotification">
|
||||
{ _t("Ongoing conference call%(supportedText)s.", {supportedText: supportedText}) }
|
||||
|
||||
{ joinNode }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const callView = (
|
||||
<CallView
|
||||
room={this.props.room}
|
||||
ConferenceHandler={this.props.conferenceHandler}
|
||||
onResize={this.props.onResize}
|
||||
maxVideoHeight={this.props.maxHeight}
|
||||
/>
|
||||
|
@ -276,7 +240,6 @@ export default class AuxPanel extends React.Component {
|
|||
{ appsDrawer }
|
||||
{ fileDropTarget }
|
||||
{ callView }
|
||||
{ conferenceCallNotification }
|
||||
{ this.props.children }
|
||||
</AutoHideScrollbar>
|
||||
);
|
||||
|
|
|
@ -34,6 +34,7 @@ import * as ObjectUtils from "../../../ObjectUtils";
|
|||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import {E2E_STATE} from "./E2EIcon";
|
||||
import {toRem} from "../../../utils/units";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
|
||||
const eventTileTypes = {
|
||||
'm.room.message': 'messages.MessageEvent',
|
||||
|
@ -147,6 +148,10 @@ export default class EventTile extends React.Component {
|
|||
*/
|
||||
last: PropTypes.bool,
|
||||
|
||||
// true if the event is the last event in a section (adds a css class for
|
||||
// targeting)
|
||||
lastInSection: PropTypes.bool,
|
||||
|
||||
/* true if this is search context (which has the effect of greying out
|
||||
* the text
|
||||
*/
|
||||
|
@ -206,6 +211,9 @@ export default class EventTile extends React.Component {
|
|||
|
||||
// whether to use the irc layout
|
||||
useIRCLayout: PropTypes.bool,
|
||||
|
||||
// whether or not to show flair at all
|
||||
enableFlair: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -670,6 +678,7 @@ export default class EventTile extends React.Component {
|
|||
mx_EventTile_selected: this.props.isSelectedEvent,
|
||||
mx_EventTile_continuation: this.props.tileShape ? '' : this.props.continuation,
|
||||
mx_EventTile_last: this.props.last,
|
||||
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,
|
||||
|
@ -736,10 +745,10 @@ export default class EventTile extends React.Component {
|
|||
else if (msgtype === 'm.file') text = _td('%(senderName)s uploaded a file');
|
||||
sender = <SenderProfile onClick={this.onSenderProfileClick}
|
||||
mxEvent={this.props.mxEvent}
|
||||
enableFlair={!text}
|
||||
enableFlair={this.props.enableFlair && !text}
|
||||
text={text} />;
|
||||
} else {
|
||||
sender = <SenderProfile mxEvent={this.props.mxEvent} enableFlair={true} />;
|
||||
sender = <SenderProfile mxEvent={this.props.mxEvent} enableFlair={this.props.enableFlair} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -818,6 +827,7 @@ export default class EventTile extends React.Component {
|
|||
return (
|
||||
<div className={classes} aria-live={ariaLive} aria-atomic="true">
|
||||
<div className="mx_EventTile_roomName">
|
||||
<RoomAvatar room={room} width={28} height={28} />
|
||||
<a href={permalink} onClick={this.onPermalinkClicked}>
|
||||
{ room ? room.name : '' }
|
||||
</a>
|
||||
|
|
|
@ -24,7 +24,6 @@ import {isValid3pidInvite} from "../../../RoomInvite";
|
|||
import rate_limited_func from "../../../ratelimitedfunc";
|
||||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
||||
import * as sdk from "../../../index";
|
||||
import CallHandler from "../../../CallHandler";
|
||||
import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
|
||||
import BaseCard from "../right_panel/BaseCard";
|
||||
import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
|
||||
|
@ -233,15 +232,10 @@ export default class MemberList extends React.Component {
|
|||
}
|
||||
|
||||
roomMembers() {
|
||||
const ConferenceHandler = CallHandler.getConferenceHandler();
|
||||
|
||||
const allMembers = this.getMembersWithUser();
|
||||
const filteredAndSortedMembers = allMembers.filter((m) => {
|
||||
return (
|
||||
m.membership === 'join' || m.membership === 'invite'
|
||||
) && (
|
||||
!ConferenceHandler ||
|
||||
(ConferenceHandler && !ConferenceHandler.isConferenceUser(m.userId))
|
||||
);
|
||||
});
|
||||
filteredAndSortedMembers.sort(this.memberSort);
|
||||
|
|
|
@ -99,7 +99,7 @@ function HangupButton(props) {
|
|||
return;
|
||||
}
|
||||
|
||||
const call = CallHandler.getCallForRoom(props.roomId);
|
||||
const call = CallHandler.sharedInstance().getCallForRoom(props.roomId);
|
||||
if (!call) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import RoomViewStore from '../../../stores/RoomViewStore';
|
|||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import PropTypes from "prop-types";
|
||||
import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks";
|
||||
import {UIFeature} from "../../../settings/UIFeature";
|
||||
|
||||
function cancelQuoting() {
|
||||
dis.dispatch({
|
||||
|
@ -80,11 +81,14 @@ export default class ReplyPreview extends React.Component {
|
|||
onClick={cancelQuoting} />
|
||||
</div>
|
||||
<div className="mx_ReplyPreview_clear" />
|
||||
<EventTile last={true}
|
||||
tileShape="reply_preview"
|
||||
mxEvent={this.state.event}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
isTwelveHour={SettingsStore.getValue("showTwelveHourTimestamps")} />
|
||||
<EventTile
|
||||
last={true}
|
||||
tileShape="reply_preview"
|
||||
mxEvent={this.state.event}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
isTwelveHour={SettingsStore.getValue("showTwelveHourTimestamps")}
|
||||
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
|
||||
/>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
Copyright 2018, 2019 New Vector Ltd
|
||||
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 PropTypes from "prop-types";
|
||||
import * as sdk from "../../../index";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import Modal from "../../../Modal";
|
||||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import {SettingLevel} from "../../../settings/SettingLevel";
|
||||
|
||||
export default class RoomRecoveryReminder extends React.PureComponent {
|
||||
static propTypes = {
|
||||
// called if the user sets the option to suppress this reminder in the future
|
||||
onDontAskAgainSet: PropTypes.func,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
onDontAskAgainSet: function() {},
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true,
|
||||
error: null,
|
||||
backupInfo: null,
|
||||
notNowClicked: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._loadBackupStatus();
|
||||
}
|
||||
|
||||
async _loadBackupStatus() {
|
||||
try {
|
||||
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
||||
this.setState({
|
||||
loading: false,
|
||||
backupInfo,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Unable to fetch key backup status", e);
|
||||
this.setState({
|
||||
loading: false,
|
||||
error: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
showSetupDialog = () => {
|
||||
if (this.state.backupInfo) {
|
||||
// A key backup exists for this account, but the creating device is not
|
||||
// verified, so restore the backup which will give us the keys from it and
|
||||
// allow us to trust it (ie. upload keys to it)
|
||||
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
|
||||
Modal.createTrackedDialog(
|
||||
'Restore Backup', '', RestoreKeyBackupDialog, null, null,
|
||||
/* priority = */ false, /* static = */ true,
|
||||
);
|
||||
} else {
|
||||
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
|
||||
import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
|
||||
null, null, /* priority = */ false, /* static = */ true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onOnNotNowClick = () => {
|
||||
this.setState({notNowClicked: true});
|
||||
}
|
||||
|
||||
onDontAskAgainClick = () => {
|
||||
// When you choose "Don't ask again" from the room reminder, we show a
|
||||
// dialog to confirm the choice.
|
||||
Modal.createTrackedDialogAsync("Ignore Recovery Reminder", "Ignore Recovery Reminder",
|
||||
import("../../../async-components/views/dialogs/keybackup/IgnoreRecoveryReminderDialog"),
|
||||
{
|
||||
onDontAskAgain: async () => {
|
||||
await SettingsStore.setValue(
|
||||
"showRoomRecoveryReminder",
|
||||
null,
|
||||
SettingLevel.ACCOUNT,
|
||||
false,
|
||||
);
|
||||
this.props.onDontAskAgainSet();
|
||||
},
|
||||
onSetup: () => {
|
||||
this.showSetupDialog();
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onSetupClick = () => {
|
||||
this.showSetupDialog();
|
||||
}
|
||||
|
||||
render() {
|
||||
// If there was an error loading just don't display the banner: we'll try again
|
||||
// next time the user switchs to the room.
|
||||
if (this.state.error || this.state.loading || this.state.notNowClicked) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
|
||||
|
||||
let setupCaption;
|
||||
if (this.state.backupInfo) {
|
||||
setupCaption = _t("Connect this session to Key Backup");
|
||||
} else {
|
||||
setupCaption = _t("Start using Key Backup");
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_RoomRecoveryReminder">
|
||||
<div className="mx_RoomRecoveryReminder_header">{_t(
|
||||
"Never lose encrypted messages",
|
||||
)}</div>
|
||||
<div className="mx_RoomRecoveryReminder_body">
|
||||
<p>{_t(
|
||||
"Messages in this room are secured with end-to-end " +
|
||||
"encryption. Only you and the recipient(s) have the " +
|
||||
"keys to read these messages.",
|
||||
)}</p>
|
||||
<p>{_t(
|
||||
"Securely back up your keys to avoid losing them. " +
|
||||
"<a>Learn more.</a>", {},
|
||||
{
|
||||
// TODO: We don't have this link yet: this will prevent the translators
|
||||
// having to re-translate the string when we do.
|
||||
a: sub => '',
|
||||
},
|
||||
)}</p>
|
||||
</div>
|
||||
<div className="mx_RoomRecoveryReminder_buttons">
|
||||
<AccessibleButton kind="primary"
|
||||
onClick={this.onSetupClick}>
|
||||
{setupCaption}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className="mx_RoomRecoveryReminder_secondary mx_linkButton"
|
||||
onClick={this.onOnNotNowClick}>
|
||||
{ _t("Not now") }
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className="mx_RoomRecoveryReminder_secondary mx_linkButton"
|
||||
onClick={this.onDontAskAgainClick}>
|
||||
{ _t("Don't ask me again") }
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
Copyright 2018-2020 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -28,6 +28,11 @@ export default class RoomUpgradeWarningBar extends React.Component {
|
|||
recommendation: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const tombstone = this.props.room.currentState.getStateEvents("m.room.tombstone", "");
|
||||
this.setState({upgraded: tombstone && tombstone.getContent().replacement_room});
|
||||
|
@ -35,6 +40,13 @@ export default class RoomUpgradeWarningBar extends React.Component {
|
|||
MatrixClientPeg.get().on("RoomState.events", this._onStateEvents);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const cli = MatrixClientPeg.get();
|
||||
if (cli) {
|
||||
cli.removeListener("RoomState.events", this._onStateEvents);
|
||||
}
|
||||
}
|
||||
|
||||
_onStateEvents = (event, state) => {
|
||||
if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
|
||||
return;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
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.
|
||||
|
@ -19,6 +20,7 @@ import AccessibleButton from "../elements/AccessibleButton";
|
|||
import classNames from "classnames";
|
||||
import { _t } from '../../../languageHandler';
|
||||
import {Key} from "../../../Keyboard";
|
||||
import DesktopBuildsNotice, {WarningKind} from "../elements/DesktopBuildsNotice";
|
||||
|
||||
export default class SearchBar extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -72,21 +74,24 @@ export default class SearchBar extends React.Component {
|
|||
});
|
||||
|
||||
return (
|
||||
<div className="mx_SearchBar">
|
||||
<div className="mx_SearchBar_buttons" role="radiogroup">
|
||||
<AccessibleButton className={ thisRoomClasses } onClick={this.onThisRoomClick} aria-checked={this.state.scope === 'Room'} role="radio">
|
||||
{_t("This Room")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className={ allRoomsClasses } onClick={this.onAllRoomsClick} aria-checked={this.state.scope === 'All'} role="radio">
|
||||
{_t("All Rooms")}
|
||||
</AccessibleButton>
|
||||
<>
|
||||
<div className="mx_SearchBar">
|
||||
<div className="mx_SearchBar_buttons" role="radiogroup">
|
||||
<AccessibleButton className={ thisRoomClasses } onClick={this.onThisRoomClick} aria-checked={this.state.scope === 'Room'} role="radio">
|
||||
{_t("This Room")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton className={ allRoomsClasses } onClick={this.onAllRoomsClick} aria-checked={this.state.scope === 'All'} role="radio">
|
||||
{_t("All Rooms")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
<div className="mx_SearchBar_input mx_textinput">
|
||||
<input ref={this._search_term} type="text" autoFocus={true} placeholder={_t("Search…")} onKeyDown={this.onSearchChange} />
|
||||
<AccessibleButton className={ searchButtonClasses } onClick={this.onSearch} />
|
||||
</div>
|
||||
<AccessibleButton className="mx_SearchBar_cancel" onClick={this.props.onCancelClick} />
|
||||
</div>
|
||||
<div className="mx_SearchBar_input mx_textinput">
|
||||
<input ref={this._search_term} type="text" autoFocus={true} placeholder={_t("Search…")} onKeyDown={this.onSearchChange} />
|
||||
<AccessibleButton className={ searchButtonClasses } onClick={this.onSearch} />
|
||||
</div>
|
||||
<AccessibleButton className="mx_SearchBar_cancel" onClick={this.props.onCancelClick} />
|
||||
</div>
|
||||
<DesktopBuildsNotice isRoomEncrypted={this.props.isRoomEncrypted} kind={WarningKind.Search} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import * as sdk from '../../../index';
|
||||
import {haveTileForEvent} from "./EventTile";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import {UIFeature} from "../../../settings/UIFeature";
|
||||
|
||||
export default class SearchResultTile extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -45,22 +47,31 @@ export default class SearchResultTile extends React.Component {
|
|||
const ret = [<DateSeparator key={ts1 + "-search"} ts={ts1} />];
|
||||
|
||||
const timeline = result.context.getTimeline();
|
||||
for (var j = 0; j < timeline.length; j++) {
|
||||
for (let j = 0; j < timeline.length; j++) {
|
||||
const ev = timeline[j];
|
||||
var highlights;
|
||||
let highlights;
|
||||
const contextual = (j != result.context.getOurEventIndex());
|
||||
if (!contextual) {
|
||||
highlights = this.props.searchHighlights;
|
||||
}
|
||||
if (haveTileForEvent(ev)) {
|
||||
ret.push(<EventTile key={eventId+"+"+j} mxEvent={ev} contextual={contextual} highlights={highlights}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
highlightLink={this.props.resultLink}
|
||||
onHeightChanged={this.props.onHeightChanged} />);
|
||||
ret.push((
|
||||
<EventTile
|
||||
key={`${eventId}+${j}`}
|
||||
mxEvent={ev}
|
||||
contextual={contextual}
|
||||
highlights={highlights}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
highlightLink={this.props.resultLink}
|
||||
onHeightChanged={this.props.onHeightChanged}
|
||||
isTwelveHour={SettingsStore.getValue("showTwelveHourTimestamps")}
|
||||
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
|
||||
/>
|
||||
));
|
||||
}
|
||||
}
|
||||
return (
|
||||
<li data-scroll-tokens={eventId+"+"+j}>
|
||||
<li data-scroll-tokens={eventId}>
|
||||
{ ret }
|
||||
</li>);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue