{_t(
"Access your secure message history and set up secure " +
"messaging by entering your recovery key.",
- )}
+ )}
= this.topCount &&
+ (range.topCount + range.renderCount) <= (this.topCount + this.renderCount);
+ }
+
+ expand(amount) {
+ const topGrow = Math.min(amount, this.topCount);
+ const bottomGrow = Math.min(amount, this.bottomCount);
+ return new ItemRange(
+ this.topCount - topGrow,
+ this.renderCount + topGrow + bottomGrow,
+ this.bottomCount - bottomGrow,
+ );
+ }
+}
+
+export default class LazyRenderList extends React.Component {
+ constructor(props) {
+ super(props);
+ const renderRange = LazyRenderList.getVisibleRangeFromProps(props).expand(OVERFLOW_ITEMS);
+ this.state = {renderRange};
+ }
+
+ static getVisibleRangeFromProps(props) {
+ const {items, itemHeight, scrollTop, height} = props;
+ const length = items ? items.length : 0;
+ const topCount = Math.max(0, Math.floor(scrollTop / itemHeight));
+ const itemsAfterTop = length - topCount;
+ const renderCount = Math.min(Math.ceil(height / itemHeight), itemsAfterTop);
+ const bottomCount = itemsAfterTop - renderCount;
+ return new ItemRange(topCount, renderCount, bottomCount);
+ }
+
+ componentWillReceiveProps(props) {
+ const state = this.state;
+ const range = LazyRenderList.getVisibleRangeFromProps(props);
+ const intersectRange = range.expand(OVERFLOW_MARGIN);
+
+ const prevSize = this.props.items ? this.props.items.length : 0;
+ const listHasChangedSize = props.items.length !== prevSize;
+ // only update renderRange if the list has shrunk/grown and we need to adjust padding or
+ // if the new range isn't contained by the old anymore
+ if (listHasChangedSize || !state.renderRange || !state.renderRange.contains(intersectRange)) {
+ this.setState({renderRange: range.expand(OVERFLOW_ITEMS)});
+ }
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ const itemsChanged = nextProps.items !== this.props.items;
+ const rangeChanged = nextState.renderRange !== this.state.renderRange;
+ return itemsChanged || rangeChanged;
+ }
+
+ render() {
+ const {itemHeight, items, renderItem} = this.props;
+
+ const {renderRange} = this.state;
+ const paddingTop = renderRange.topCount * itemHeight;
+ const paddingBottom = renderRange.bottomCount * itemHeight;
+ const renderedItems = (items || []).slice(
+ renderRange.topCount,
+ renderRange.topCount + renderRange.renderCount,
+ );
+
+ return (
+ { renderedItems.map(renderItem) }
+
);
+ }
+}
diff --git a/src/components/views/elements/ManageIntegsButton.js b/src/components/views/elements/ManageIntegsButton.js
index e5cc21d85e..3240050b6a 100644
--- a/src/components/views/elements/ManageIntegsButton.js
+++ b/src/components/views/elements/ManageIntegsButton.js
@@ -24,7 +24,6 @@ import ScalarMessaging from '../../../ScalarMessaging';
import Modal from "../../../Modal";
import { _t } from '../../../languageHandler';
import AccessibleButton from './AccessibleButton';
-import TintableSvg from './TintableSvg';
export default class ManageIntegsButton extends React.Component {
constructor(props) {
@@ -76,6 +75,7 @@ export default class ManageIntegsButton extends React.Component {
if (this.scalarClient !== null) {
const integrationsButtonClasses = classNames({
mx_RoomHeader_button: true,
+ mx_RoomHeader_manageIntegsButton: true,
mx_ManageIntegsButton_error: !!this.state.scalarError,
});
@@ -94,8 +94,10 @@ export default class ManageIntegsButton extends React.Component {
}
integrationsButton = (
-
-
+
{ integrationsWarningTriangle }
{ integrationsErrorPopup }
diff --git a/src/components/views/right_panel/GroupHeaderButtons.js b/src/components/views/right_panel/GroupHeaderButtons.js
index 6867b0bb9d..13379d49e3 100644
--- a/src/components/views/right_panel/GroupHeaderButtons.js
+++ b/src/components/views/right_panel/GroupHeaderButtons.js
@@ -65,12 +65,14 @@ export default class GroupHeaderButtons extends HeaderButtons {
];
return [
- ,
-
-
- ;
+ onClick={this.onClick}>
+ ;
}
}
@@ -62,14 +61,14 @@ HeaderButton.propTypes = {
isHighlighted: PropTypes.bool.isRequired,
// The phase to swap to when the button is clicked
clickPhase: PropTypes.string.isRequired,
- // The source file of the icon to display
- iconSrc: PropTypes.string.isRequired,
// The badge to display above the icon
badge: PropTypes.node,
// The parameters to track the click event
analytics: PropTypes.arrayOf(PropTypes.string).isRequired,
+ // Button name
+ name: PropTypes.string.isRequired,
// Button title
title: PropTypes.string.isRequired,
};
diff --git a/src/components/views/right_panel/HeaderButtons.js b/src/components/views/right_panel/HeaderButtons.js
index 3f5f58121d..b7155b922f 100644
--- a/src/components/views/right_panel/HeaderButtons.js
+++ b/src/components/views/right_panel/HeaderButtons.js
@@ -88,7 +88,7 @@ export default class HeaderButtons extends React.Component {
render() {
// inline style as this will be swapped around in future commits
- return
+ return
{ this.renderButtons() }
;
}
diff --git a/src/components/views/right_panel/RoomHeaderButtons.js b/src/components/views/right_panel/RoomHeaderButtons.js
index 1985909f4a..8d10094637 100644
--- a/src/components/views/right_panel/RoomHeaderButtons.js
+++ b/src/components/views/right_panel/RoomHeaderButtons.js
@@ -52,17 +52,20 @@ export default class RoomHeaderButtons extends HeaderButtons {
];
return [
-
,
-
,
-
);
+ const icon = (
);
+ if (props.onClick) {
+ return (
{ icon });
+ } else {
+ return icon;
+ }
}
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index 8520d804e0..8e1fb5af9f 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -327,6 +327,7 @@ module.exports = withMatrixClient(React.createClass({
top: y,
eventTileOps: tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined,
collapseReplyThread: replyThread && replyThread.canCollapse() ? replyThread.collapse : undefined,
+ e2eInfoCallback: () => this.onCryptoClicked(),
onFinished: function() {
self.setState({menu: false});
},
@@ -773,29 +774,31 @@ module.exports.haveTileForEvent = function(e) {
function E2ePadlockUndecryptable(props) {
return (
-
+
);
}
function E2ePadlockUnverified(props) {
return (
-
+
);
}
function E2ePadlockUnencrypted(props) {
return (
-
+
);
}
function E2ePadlock(props) {
if (SettingsStore.getValue("alwaysShowEncryptionIcons")) {
- return
;
+ return (
);
} else {
- return
;
+ return (
);
}
}
diff --git a/src/components/views/rooms/MemberDeviceInfo.js b/src/components/views/rooms/MemberDeviceInfo.js
index 67f99e4d1d..ff88c6f6e6 100644
--- a/src/components/views/rooms/MemberDeviceInfo.js
+++ b/src/components/views/rooms/MemberDeviceInfo.js
@@ -30,7 +30,7 @@ export default class MemberDeviceInfo extends React.Component {
mx_MemberDeviceInfo_icon_unverified: this.props.device.isUnverified(),
});
const indicator = (
);
- const deviceName = this.props.device.ambiguous ?
+ 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();
diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js
index 5df0da7491..f4c600af8d 100644
--- a/src/components/views/rooms/MemberInfo.js
+++ b/src/components/views/rooms/MemberInfo.js
@@ -941,6 +941,8 @@ module.exports = withMatrixClient(React.createClass({
}
let roomMemberDetails = null;
+ let e2eIconElement;
+
if (this.props.member.roomId) { // is in room
const PowerSelector = sdk.getComponent('elements.PowerSelector');
roomMemberDetails =
@@ -959,6 +961,11 @@ module.exports = withMatrixClient(React.createClass({
{statusLabel}
;
+
+ const isEncrypted = this.props.matrixClient.isRoomEncrypted(this.props.member.roomId);
+ if (this.state.e2eStatus && isEncrypted) {
+ e2eIconElement = (
);
+ }
}
const avatarUrl = this.props.member.getMxcAvatarUrl();
@@ -967,7 +974,7 @@ module.exports = withMatrixClient(React.createClass({
const httpUrl = this.props.matrixClient.mxcUrlToHttp(avatarUrl, 800, 800);
avatarElement =

-
+
;
}
const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper");
@@ -979,7 +986,7 @@ module.exports = withMatrixClient(React.createClass({
: undefined }
+ { e2eIconElement }