Merge branch 'develop' into dbkr/group_userlist
This commit is contained in:
commit
e9fb5712bd
51 changed files with 890 additions and 333 deletions
|
@ -131,6 +131,9 @@ export default React.createClass({
|
|||
useCompactLayout: event.getContent().useCompactLayout,
|
||||
});
|
||||
}
|
||||
if (event.getType() === "m.ignored_user_list") {
|
||||
dis.dispatch({action: "ignore_state_changed"});
|
||||
}
|
||||
},
|
||||
|
||||
_onKeyDown: function(ev) {
|
||||
|
|
|
@ -672,7 +672,6 @@ module.exports = React.createClass({
|
|||
page_type: PageTypes.RoomView,
|
||||
thirdPartyInvite: roomInfo.third_party_invite,
|
||||
roomOobData: roomInfo.oob_data,
|
||||
autoJoin: roomInfo.auto_join,
|
||||
};
|
||||
|
||||
if (roomInfo.room_alias) {
|
||||
|
|
|
@ -241,6 +241,10 @@ module.exports = React.createClass({
|
|||
|
||||
// TODO: Implement granular (per-room) hide options
|
||||
_shouldShowEvent: function(mxEv) {
|
||||
if (mxEv.sender && MatrixClientPeg.get().isUserIgnored(mxEv.sender.userId)) {
|
||||
return false; // ignored = no show (only happens if the ignore happens after an event was received)
|
||||
}
|
||||
|
||||
const EventTile = sdk.getComponent('rooms.EventTile');
|
||||
if (!EventTile.haveTileForEvent(mxEv)) {
|
||||
return false; // no tile = no show
|
||||
|
@ -361,8 +365,13 @@ module.exports = React.createClass({
|
|||
summarisedEvents.push(collapsedMxEv);
|
||||
}
|
||||
|
||||
let highlightInMels = false;
|
||||
|
||||
// At this point, i = the index of the last event in the summary sequence
|
||||
let eventTiles = summarisedEvents.map((e) => {
|
||||
if (e.getId() === this.props.highlightedEventId) {
|
||||
highlightInMels = true;
|
||||
}
|
||||
// In order to prevent DateSeparators from appearing in the expanded form
|
||||
// of MemberEventListSummary, render each member event as if the previous
|
||||
// one was itself. This way, the timestamp of the previous event === the
|
||||
|
@ -376,15 +385,13 @@ module.exports = React.createClass({
|
|||
eventTiles = null;
|
||||
}
|
||||
|
||||
ret.push(
|
||||
<MemberEventListSummary
|
||||
key={key}
|
||||
events={summarisedEvents}
|
||||
onToggle={this._onWidgetLoad} // Update scroll state
|
||||
>
|
||||
{eventTiles}
|
||||
</MemberEventListSummary>
|
||||
);
|
||||
ret.push(<MemberEventListSummary key={key}
|
||||
events={summarisedEvents}
|
||||
onToggle={this._onWidgetLoad} // Update scroll state
|
||||
startExpanded={highlightInMels}
|
||||
>
|
||||
{eventTiles}
|
||||
</MemberEventListSummary>);
|
||||
|
||||
if (readMarkerInMels) {
|
||||
ret.push(this._getReadMarkerTile(visible));
|
||||
|
@ -549,6 +556,9 @@ module.exports = React.createClass({
|
|||
if (!r.userId || r.type !== "m.read" || r.userId === myUserId) {
|
||||
return; // ignore non-read receipts and receipts from self.
|
||||
}
|
||||
if (MatrixClientPeg.get().isUserIgnored(r.userId)) {
|
||||
return; // ignore ignored users
|
||||
}
|
||||
let member = room.getMember(r.userId);
|
||||
if (!member) {
|
||||
return; // ignore unknown user IDs
|
||||
|
|
|
@ -121,7 +121,7 @@ module.exports = React.createClass({
|
|||
|
||||
onRoomMemberTyping: function(ev, member) {
|
||||
this.setState({
|
||||
usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room),
|
||||
usersTyping: WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room),
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -123,6 +123,9 @@ module.exports = React.createClass({
|
|||
// store the error here.
|
||||
roomLoadError: null,
|
||||
|
||||
// Have we sent a request to join the room that we're waiting to complete?
|
||||
joining: false,
|
||||
|
||||
// this is true if we are fully scrolled-down, and are looking at
|
||||
// the end of the live timeline. It has the effect of hiding the
|
||||
// 'scroll to bottom' knob, among a couple of other things.
|
||||
|
@ -185,10 +188,6 @@ module.exports = React.createClass({
|
|||
shouldPeek: RoomViewStore.shouldPeek(),
|
||||
};
|
||||
|
||||
// finished joining, start waiting for a room and show a spinner. See onRoom.
|
||||
newState.waitingForRoom = this.state.joining && !newState.joining &&
|
||||
!RoomViewStore.getJoinError();
|
||||
|
||||
// Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307
|
||||
console.log(
|
||||
'RVS update:',
|
||||
|
@ -197,7 +196,6 @@ module.exports = React.createClass({
|
|||
'loading?', newState.roomLoading,
|
||||
'joining?', newState.joining,
|
||||
'initial?', initial,
|
||||
'waiting?', newState.waitingForRoom,
|
||||
'shouldPeek?', newState.shouldPeek,
|
||||
);
|
||||
|
||||
|
@ -650,7 +648,6 @@ module.exports = React.createClass({
|
|||
}
|
||||
this.setState({
|
||||
room: room,
|
||||
waitingForRoom: false,
|
||||
}, () => {
|
||||
this._onRoomLoaded(room);
|
||||
});
|
||||
|
@ -706,14 +703,7 @@ module.exports = React.createClass({
|
|||
|
||||
onRoomMemberMembership: function(ev, member, oldMembership) {
|
||||
if (member.userId == MatrixClientPeg.get().credentials.userId) {
|
||||
|
||||
if (member.membership === 'join') {
|
||||
this.setState({
|
||||
waitingForRoom: false,
|
||||
});
|
||||
} else {
|
||||
this.forceUpdate();
|
||||
}
|
||||
this.forceUpdate();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1463,10 +1453,6 @@ module.exports = React.createClass({
|
|||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
|
||||
|
||||
// Whether the preview bar spinner should be shown. We do this when joining or
|
||||
// when waiting for a room to be returned by js-sdk when joining
|
||||
const previewBarSpinner = this.state.joining || this.state.waitingForRoom;
|
||||
|
||||
if (!this.state.room) {
|
||||
if (this.state.roomLoading || this.state.peekLoading) {
|
||||
return (
|
||||
|
@ -1500,7 +1486,7 @@ module.exports = React.createClass({
|
|||
onRejectClick={ this.onRejectThreepidInviteButtonClicked }
|
||||
canPreview={ false } error={ this.state.roomLoadError }
|
||||
roomAlias={roomAlias}
|
||||
spinner={previewBarSpinner}
|
||||
spinner={this.state.joining}
|
||||
inviterName={inviterName}
|
||||
invitedEmail={invitedEmail}
|
||||
room={this.state.room}
|
||||
|
@ -1543,7 +1529,7 @@ module.exports = React.createClass({
|
|||
onRejectClick={ this.onRejectButtonClicked }
|
||||
inviterName={ inviterName }
|
||||
canPreview={ false }
|
||||
spinner={previewBarSpinner}
|
||||
spinner={this.state.joining}
|
||||
room={this.state.room}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1618,7 +1604,7 @@ module.exports = React.createClass({
|
|||
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
|
||||
onForgetClick={ this.onForgetClick }
|
||||
onRejectClick={this.onRejectThreepidInviteButtonClicked}
|
||||
spinner={previewBarSpinner}
|
||||
spinner={this.state.joining}
|
||||
inviterName={inviterName}
|
||||
invitedEmail={invitedEmail}
|
||||
canPreview={this.state.canPeek}
|
||||
|
|
|
@ -384,6 +384,9 @@ var TimelinePanel = React.createClass({
|
|||
this.sendReadReceipt();
|
||||
this.updateReadMarker();
|
||||
break;
|
||||
case 'ignore_state_changed':
|
||||
this.forceUpdate();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -105,6 +105,10 @@ const SETTINGS_LABELS = [
|
|||
id: 'MessageComposerInput.autoReplaceEmoji',
|
||||
label: 'Automatically replace plain text Emoji',
|
||||
},
|
||||
{
|
||||
id: 'MessageComposerInput.dontSuggestEmoji',
|
||||
label: 'Disable Emoji suggestions while typing',
|
||||
},
|
||||
{
|
||||
id: 'Pill.shouldHidePillAvatar',
|
||||
label: 'Hide avatars in user and room mentions',
|
||||
|
@ -172,6 +176,34 @@ const THEMES = [
|
|||
},
|
||||
];
|
||||
|
||||
const IgnoredUser = React.createClass({
|
||||
propTypes: {
|
||||
userId: React.PropTypes.string.isRequired,
|
||||
onUnignored: React.PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
_onUnignoreClick: function() {
|
||||
const ignoredUsers = MatrixClientPeg.get().getIgnoredUsers();
|
||||
const index = ignoredUsers.indexOf(this.props.userId);
|
||||
if (index !== -1) {
|
||||
ignoredUsers.splice(index, 1);
|
||||
MatrixClientPeg.get().setIgnoredUsers(ignoredUsers)
|
||||
.then(() => this.props.onUnignored(this.props.userId));
|
||||
} else this.props.onUnignored(this.props.userId);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<li>
|
||||
<AccessibleButton onClick={this._onUnignoreClick} className="mx_UserSettings_button mx_UserSettings_buttonSmall">
|
||||
{ _t("Unignore") }
|
||||
</AccessibleButton>
|
||||
{ this.props.userId }
|
||||
</li>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'UserSettings',
|
||||
|
||||
|
@ -207,6 +239,7 @@ module.exports = React.createClass({
|
|||
vectorVersion: undefined,
|
||||
rejectingInvites: false,
|
||||
mediaDevices: null,
|
||||
ignoredUsers: [],
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -228,6 +261,7 @@ module.exports = React.createClass({
|
|||
}
|
||||
|
||||
this._refreshMediaDevices();
|
||||
this._refreshIgnoredUsers();
|
||||
|
||||
// Bulk rejecting invites:
|
||||
// /sync won't have had time to return when UserSettings re-renders from state changes, so getRooms()
|
||||
|
@ -346,9 +380,22 @@ module.exports = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
_refreshIgnoredUsers: function(userIdUnignored=null) {
|
||||
const users = MatrixClientPeg.get().getIgnoredUsers();
|
||||
if (userIdUnignored) {
|
||||
const index = users.indexOf(userIdUnignored);
|
||||
if (index !== -1) users.splice(index, 1);
|
||||
}
|
||||
this.setState({
|
||||
ignoredUsers: users,
|
||||
});
|
||||
},
|
||||
|
||||
onAction: function(payload) {
|
||||
if (payload.action === "notifier_enabled") {
|
||||
this.forceUpdate();
|
||||
} else if (payload.action === "ignore_state_changed") {
|
||||
this._refreshIgnoredUsers();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -796,6 +843,26 @@ module.exports = React.createClass({
|
|||
);
|
||||
},
|
||||
|
||||
_renderIgnoredUsers: function() {
|
||||
if (this.state.ignoredUsers.length > 0) {
|
||||
const updateHandler = this._refreshIgnoredUsers;
|
||||
return (
|
||||
<div>
|
||||
<h3>{ _t("Ignored Users") }</h3>
|
||||
<div className="mx_UserSettings_section mx_UserSettings_ignoredUsersSection">
|
||||
<ul>
|
||||
{this.state.ignoredUsers.map(function(userId) {
|
||||
return (<IgnoredUser key={userId}
|
||||
userId={userId}
|
||||
onUnignored={updateHandler}></IgnoredUser>);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else return (<div />);
|
||||
},
|
||||
|
||||
_renderLocalSetting: function(setting) {
|
||||
// TODO: this ought to be a separate component so that we don't need
|
||||
// to rebind the onChange each time we render
|
||||
|
@ -1302,6 +1369,7 @@ module.exports = React.createClass({
|
|||
{this._renderWebRtcSettings()}
|
||||
{this._renderDevicesPanel()}
|
||||
{this._renderCryptoInfo()}
|
||||
{this._renderIgnoredUsers()}
|
||||
{this._renderBulkOptions()}
|
||||
{this._renderBugReport()}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ export default class ManageIntegsButton extends React.Component {
|
|||
this.forceUpdate();
|
||||
}, (err) => {
|
||||
this.setState({ scalarError: err});
|
||||
console.error(err);
|
||||
console.error('Error whilst initialising scalarClient for ManageIntegsButton', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,11 +34,13 @@ module.exports = React.createClass({
|
|||
threshold: React.PropTypes.number,
|
||||
// Called when the MELS expansion is toggled
|
||||
onToggle: React.PropTypes.func,
|
||||
// Whether or not to begin with state.expanded=true
|
||||
startExpanded: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
expanded: false,
|
||||
expanded: Boolean(this.props.startExpanded),
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -376,7 +378,7 @@ module.exports = React.createClass({
|
|||
return items[0];
|
||||
} else if (remaining) {
|
||||
items = items.slice(0, itemLimit);
|
||||
return (remaining > 1)
|
||||
return (remaining > 1)
|
||||
? _t("%(items)s and %(remaining)s others", { items: items.join(', '), remaining: remaining } )
|
||||
: _t("%(items)s and one other", { items: items.join(', ') });
|
||||
} else {
|
||||
|
|
|
@ -23,9 +23,14 @@ module.exports = React.createClass({
|
|||
displayName: 'UnknownBody',
|
||||
|
||||
render: function() {
|
||||
let tooltip = _t("Removed or unknown message type");
|
||||
if (this.props.mxEvent.isRedacted()) {
|
||||
tooltip = _t("Message removed by %(userId)s", {userId: this.props.mxEvent.getSender()});
|
||||
}
|
||||
|
||||
const text = this.props.mxEvent.getContent().body;
|
||||
return (
|
||||
<span className="mx_UnknownBody" title={_t("Removed or unknown message type")}>
|
||||
<span className="mx_UnknownBody" title={tooltip}>
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -62,6 +62,7 @@ module.exports = withMatrixClient(React.createClass({
|
|||
updating: 0,
|
||||
devicesLoading: true,
|
||||
devices: null,
|
||||
isIgnoring: false,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -81,6 +82,8 @@ module.exports = withMatrixClient(React.createClass({
|
|||
cli.on("RoomState.events", this.onRoomStateEvents);
|
||||
cli.on("RoomMember.name", this.onRoomMemberName);
|
||||
cli.on("accountData", this.onAccountData);
|
||||
|
||||
this._checkIgnoreState();
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
|
@ -111,6 +114,11 @@ module.exports = withMatrixClient(React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
_checkIgnoreState: function() {
|
||||
const isIgnoring = this.props.matrixClient.isUserIgnored(this.props.member.userId);
|
||||
this.setState({isIgnoring: isIgnoring});
|
||||
},
|
||||
|
||||
_disambiguateDevices: function(devices) {
|
||||
var names = Object.create(null);
|
||||
for (var i = 0; i < devices.length; i++) {
|
||||
|
@ -225,6 +233,18 @@ module.exports = withMatrixClient(React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
onIgnoreToggle: function() {
|
||||
const ignoredUsers = this.props.matrixClient.getIgnoredUsers();
|
||||
if (this.state.isIgnoring) {
|
||||
const index = ignoredUsers.indexOf(this.props.member.userId);
|
||||
if (index !== -1) ignoredUsers.splice(index, 1);
|
||||
} else {
|
||||
ignoredUsers.push(this.props.member.userId);
|
||||
}
|
||||
|
||||
this.props.matrixClient.setIgnoredUsers(ignoredUsers).then(() => this.setState({isIgnoring: !this.state.isIgnoring}));
|
||||
},
|
||||
|
||||
onKick: function() {
|
||||
const membership = this.props.member.membership;
|
||||
const kickLabel = membership === "invite" ? _t("Disinvite") : _t("Kick");
|
||||
|
@ -607,6 +627,29 @@ module.exports = withMatrixClient(React.createClass({
|
|||
);
|
||||
},
|
||||
|
||||
_renderUserOptions: function() {
|
||||
// Only allow the user to ignore the user if its not ourselves
|
||||
let ignoreButton = null;
|
||||
if (this.props.member.userId !== this.props.matrixClient.getUserId()) {
|
||||
ignoreButton = (
|
||||
<AccessibleButton onClick={this.onIgnoreToggle} className="mx_MemberInfo_field">
|
||||
{this.state.isIgnoring ? _t("Unignore") : _t("Ignore")}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
||||
if (!ignoreButton) return null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>{ _t("User Options") }</h3>
|
||||
<div className="mx_MemberInfo_buttons">
|
||||
{ignoreButton}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var startChat, kickButton, banButton, muteButton, giveModButton, spinner;
|
||||
if (this.props.member.userId !== this.props.matrixClient.credentials.userId) {
|
||||
|
@ -756,6 +799,8 @@ module.exports = withMatrixClient(React.createClass({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{ this._renderUserOptions() }
|
||||
|
||||
{ adminTools }
|
||||
|
||||
{ startChat }
|
||||
|
|
|
@ -332,7 +332,7 @@ module.exports = React.createClass({
|
|||
return;
|
||||
}
|
||||
memberList.push(
|
||||
<EntityTile key={e.getStateKey()} name={e.getContent().display_name} />
|
||||
<EntityTile key={e.getStateKey()} name={e.getContent().display_name} suppressOnHover={true} />
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ module.exports = React.createClass({
|
|||
editing: false,
|
||||
inRoom: false,
|
||||
onSaveClick: function() {},
|
||||
onCancelClick: function() {},
|
||||
onCancelClick: null,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -324,7 +324,7 @@ module.exports = React.createClass({
|
|||
|
||||
let rightRow;
|
||||
let manageIntegsButton;
|
||||
if(this.props.room && this.props.room.roomId) {
|
||||
if(this.props.room && this.props.room.roomId && this.props.inRoom) {
|
||||
manageIntegsButton = <ManageIntegsButton
|
||||
roomId={this.props.room.roomId}
|
||||
/>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue