diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js index 595f0cfe46..c4b3744575 100644 --- a/src/GroupAddressPicker.js +++ b/src/GroupAddressPicker.js @@ -49,20 +49,26 @@ export function showGroupInviteDialog(groupId) { export function showGroupAddRoomDialog(groupId) { return new Promise((resolve, reject) => { + let addRoomsPublicly = false; + const onCheckboxClicked = (e) => { + addRoomsPublicly = e.target.checked; + }; const description =
{ _t("Which rooms would you like to add to this community?") }
-
- { _t( - "Warning: any room you add to a community will be publicly "+ - "visible to anyone who knows the community ID", - ) } -
; + const checkboxContainer = ; + const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); Modal.createTrackedDialog('Add Rooms to Group', '', AddressPickerDialog, { title: _t("Add rooms to the community"), description: description, + extraNode: checkboxContainer, placeholder: _t("Room name or alias"), button: _t("Add to community"), pickerType: 'room', @@ -70,7 +76,7 @@ export function showGroupAddRoomDialog(groupId) { onFinished: (success, addrs) => { if (!success) return; - _onGroupAddRoomFinished(groupId, addrs).then(resolve, reject); + _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly).then(resolve, reject); }, }); }); @@ -106,13 +112,13 @@ function _onGroupInviteFinished(groupId, addrs) { }); } -function _onGroupAddRoomFinished(groupId, addrs) { +function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) { const matrixClient = MatrixClientPeg.get(); const groupStore = GroupStoreCache.getGroupStore(matrixClient, groupId); const errorList = []; return Promise.all(addrs.map((addr) => { return groupStore - .addRoomToGroup(addr.address) + .addRoomToGroup(addr.address, addRoomsPublicly) .catch(() => { errorList.push(addr.address); }) .then(() => { const roomId = addr.address; diff --git a/src/UnknownDeviceErrorHandler.js b/src/UnknownDeviceErrorHandler.js index 664fe14eb5..e7d77b3b66 100644 --- a/src/UnknownDeviceErrorHandler.js +++ b/src/UnknownDeviceErrorHandler.js @@ -25,6 +25,7 @@ const onAction = function(payload) { const UnknownDeviceDialog = sdk.getComponent('dialogs.UnknownDeviceDialog'); isDialogOpen = true; Modal.createTrackedDialog('Unknown Device Error', '', UnknownDeviceDialog, { + devices: payload.err.devices, room: payload.room, onFinished: (r) => { isDialogOpen = false; diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 647ffee37a..caa5e7cb01 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -430,6 +430,7 @@ export default React.createClass({ uploadingAvatar: false, membershipBusy: false, publicityBusy: false, + inviterProfile: null, }; }, @@ -463,6 +464,10 @@ export default React.createClass({ }, _initGroupStore: function(groupId, firstInit) { + const group = MatrixClientPeg.get().getGroup(groupId); + if (group && group.inviter && group.inviter.userId) { + this._fetchInviterProfile(group.inviter.userId); + } this._groupStore = GroupStoreCache.getGroupStore(MatrixClientPeg.get(), groupId); this._groupStore.registerListener(() => { const summary = this._groupStore.getSummary(); @@ -497,6 +502,26 @@ export default React.createClass({ }); }, + _fetchInviterProfile(userId) { + this.setState({ + inviterProfileBusy: true, + }); + MatrixClientPeg.get().getProfileInfo(userId).then((resp) => { + this.setState({ + inviterProfile: { + avatarUrl: resp.avatar_url, + displayName: resp.displayname, + }, + }); + }).catch((e) => { + console.error('Error getting group inviter profile', e); + }).finally(() => { + this.setState({ + inviterProfileBusy: false, + }); + }); + }, + _onShowRhsClick: function(ev) { dis.dispatch({ action: 'show_right_panel' }); }, @@ -591,7 +616,7 @@ export default React.createClass({ _onAcceptInviteClick: function() { this.setState({membershipBusy: true}); - MatrixClientPeg.get().acceptGroupInvite(this.props.groupId).then(() => { + this._groupStore.acceptGroupInvite().then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync }).catch((e) => { this.setState({membershipBusy: false}); @@ -802,20 +827,37 @@ export default React.createClass({ _getMembershipSection: function() { const Spinner = sdk.getComponent("elements.Spinner"); + const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); const group = MatrixClientPeg.get().getGroup(this.props.groupId); if (!group) return null; if (group.myMembership === 'invite') { - if (this.state.membershipBusy) { + if (this.state.membershipBusy || this.state.inviterProfileBusy) { return
; } + const httpInviterAvatar = this.state.inviterProfile ? + MatrixClientPeg.get().mxcUrlToHttp( + this.state.inviterProfile.avatarUrl, 36, 36, + ) : null; + + let inviterName = group.inviter.userId; + if (this.state.inviterProfile) { + inviterName = this.state.inviterProfile.displayName || group.inviter.userId; + } return
- { _t("%(inviter)s has invited you to join this community", {inviter: group.inviter.userId}) } + + { _t("%(inviter)s has invited you to join this community", { + inviter: inviterName, + }) }
{ + let rank = Infinity; const nameEvent = room.currentState.getStateEvents('m.room.name', ''); - const topicEvent = room.currentState.getStateEvents('m.room.topic', ''); const name = nameEvent ? nameEvent.getContent().name : ''; const canonicalAlias = room.getCanonicalAlias(); const aliasEvents = room.currentState.getStateEvents('m.room.aliases'); const aliases = aliasEvents.map((ev) => ev.getContent().aliases).reduce((a, b) => { return a.concat(b); }, []); - const topic = topicEvent ? topicEvent.getContent().topic : ''; const nameMatch = (name || '').toLowerCase().includes(lowerCaseQuery); - const aliasMatch = aliases.some((alias) => - (alias || '').toLowerCase().includes(lowerCaseQuery), - ); - const topicMatch = (topic || '').toLowerCase().includes(lowerCaseQuery); - if (!(nameMatch || topicMatch || aliasMatch)) { + let aliasMatch = false; + let shortestMatchingAliasLength = Infinity; + aliases.forEach((alias) => { + if ((alias || '').toLowerCase().includes(lowerCaseQuery)) { + aliasMatch = true; + if (shortestMatchingAliasLength > alias.length) { + shortestMatchingAliasLength = alias.length; + } + } + }); + + if (!(nameMatch || aliasMatch)) { return; } + + if (aliasMatch) { + // A shorter matching alias will give a better rank + rank = shortestMatchingAliasLength; + } + const avatarEvent = room.currentState.getStateEvents('m.room.avatar', ''); const avatarUrl = avatarEvent ? avatarEvent.getContent().url : undefined; results.push({ + rank, room_id: room.roomId, avatar_url: avatarUrl, name: name || canonicalAlias || aliases[0] || _t('Unnamed Room'), }); }); - this._processResults(results, query); + + // Sort by rank ascending (a high rank being less relevant) + const sortedResults = results.sort((a, b) => { + return a.rank - b.rank; + }); + + this._processResults(sortedResults, query); this.setState({ busy: false, }); @@ -574,6 +595,7 @@ module.exports = React.createClass({
{ query }
{ error } { addressSelector } + { this.props.extraNode }