diff --git a/scripts/gen-i18n.js b/scripts/gen-i18n.js index d58bce2e63..dd990b5210 100755 --- a/scripts/gen-i18n.js +++ b/scripts/gen-i18n.js @@ -232,9 +232,14 @@ for (const path of SEARCH_PATHS) { const trObj = {}; for (const tr of translatables) { - trObj[tr] = tr; if (tr.includes("|")) { - trObj[tr] = inputTranslationsRaw[tr]; + if (inputTranslationsRaw[tr]) { + trObj[tr] = inputTranslationsRaw[tr]; + } else { + trObj[tr] = tr.split("|")[0]; + } + } else { + trObj[tr] = tr; } } diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js index 0b039074f0..595f0cfe46 100644 --- a/src/GroupAddressPicker.js +++ b/src/GroupAddressPicker.js @@ -96,13 +96,6 @@ function _onGroupInviteFinished(groupId, addrs) { title: _t("Failed to invite the following users to %(groupId)s:", {groupId: groupId}), description: errorList.join(", "), }); - } else { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - Modal.createTrackedDialog('Group invitations sent', '', QuestionDialog, { - title: _t("Invites sent"), - description: _t("Your community invitations have been sent."), - hasCancelButton: false, - }); } }).catch((err) => { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); diff --git a/src/RoomInvite.js b/src/RoomInvite.js index 427f549eb0..1979c6d111 100644 --- a/src/RoomInvite.js +++ b/src/RoomInvite.js @@ -21,6 +21,8 @@ import Modal from './Modal'; import { getAddressType } from './UserAddress'; import createRoom from './createRoom'; import sdk from './'; +import dis from './dispatcher'; +import DMRoomMap from './utils/DMRoomMap'; import { _t } from './languageHandler'; export function inviteToRoom(roomId, addr) { @@ -79,15 +81,40 @@ function _onStartChatFinished(shouldInvite, addrs) { const addrTexts = addrs.map((addr) => addr.address); if (_isDmChat(addrTexts)) { - // Start a new DM chat - createRoom({dmUserId: addrTexts[0]}).catch((err) => { - console.error(err.stack); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Failed to invite user', '', ErrorDialog, { - title: _t("Failed to invite user"), - description: ((err && err.message) ? err.message : _t("Operation failed")), + const rooms = _getDirectMessageRooms(addrTexts[0]); + if (rooms.length > 0) { + // A Direct Message room already exists for this user, so select a + // room from a list that is similar to the one in MemberInfo panel + const ChatCreateOrReuseDialog = sdk.getComponent( + "views.dialogs.ChatCreateOrReuseDialog", + ); + const close = Modal.createTrackedDialog('Create or Reuse', '', ChatCreateOrReuseDialog, { + userId: addrTexts[0], + onNewDMClick: () => { + dis.dispatch({ + action: 'start_chat', + user_id: addrTexts[0], + }); + close(true); + }, + onExistingRoomSelected: (roomId) => { + dis.dispatch({ + action: 'view_room', + room_id: roomId, + }); + close(true); + }, + }).close; + } else { + // Start a new DM chat + createRoom({dmUserId: addrTexts[0]}).catch((err) => { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createTrackedDialog('Failed to invite user', '', ErrorDialog, { + title: _t("Failed to invite user"), + description: ((err && err.message) ? err.message : _t("Operation failed")), + }); }); - }); + } } else { // Start multi user chat let room; @@ -153,3 +180,19 @@ function _showAnyInviteErrors(addrs, room) { return addrs; } +function _getDirectMessageRooms(addr) { + const dmRoomMap = new DMRoomMap(MatrixClientPeg.get()); + const dmRooms = dmRoomMap.getDMRoomsForUserId(addr); + const rooms = []; + dmRooms.forEach((dmRoom) => { + const room = MatrixClientPeg.get().getRoom(dmRoom); + if (room) { + const me = room.getMember(MatrixClientPeg.get().credentials.userId); + if (me.membership == 'join') { + rooms.push(room); + } + } + }); + return rooms; +} + diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js index 6696f3cc0f..23feb4cf30 100644 --- a/src/components/structures/FilePanel.js +++ b/src/components/structures/FilePanel.js @@ -116,7 +116,6 @@ const FilePanel = React.createClass({ timelineSet={this.state.timelineSet} showUrlPreview = {false} tileShape="file_grid" - opacity={this.props.opacity} empty={_t('There are no visible files in this room')} /> ); diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 9acef413a0..1564efd8d3 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -447,7 +447,7 @@ export default React.createClass({ _initGroupStore: function(groupId) { this._groupStore = GroupStoreCache.getGroupStore(MatrixClientPeg.get(), groupId); - this._groupStore.on('update', () => { + this._groupStore.registerListener(() => { const summary = this._groupStore.getSummary(); if (summary.profile) { // Default profile fields should be "" for later sending to the server (which @@ -464,7 +464,6 @@ export default React.createClass({ }); }); this._groupStore.on('error', (err) => { - console.error(err); this.setState({ summary: null, error: err, @@ -481,6 +480,10 @@ export default React.createClass({ editing: true, profileForm: Object.assign({}, this.state.summary.profile), }); + dis.dispatch({ + action: 'panel_disable', + sideDisabled: true, + }); }, _onCancelClick: function() { @@ -488,6 +491,7 @@ export default React.createClass({ editing: false, profileForm: null, }); + dis.dispatch({action: 'panel_disable'}); }, _onNameChange: function(value) { @@ -535,12 +539,16 @@ export default React.createClass({ _onSaveClick: function() { this.setState({saving: true}); - MatrixClientPeg.get().setGroupProfile(this.props.groupId, this.state.profileForm).then((result) => { + const savePromise = this.state.isUserPrivileged ? + MatrixClientPeg.get().setGroupProfile(this.props.groupId, this.state.profileForm) : + Promise.resolve(); + savePromise.then((result) => { this.setState({ saving: false, editing: false, summary: null, }); + dis.dispatch({action: 'panel_disable'}); this._initGroupStore(this.props.groupId); }).catch((e) => { this.setState({ @@ -624,23 +632,40 @@ export default React.createClass({ }); }, + _getGroupSection: function() { + const groupSettingsSectionClasses = classnames({ + "mx_GroupView_group": this.state.editing, + "mx_GroupView_group_disabled": this.state.editing && !this.state.isUserPrivileged, + }); + + const header = this.state.editing ?

{ _t('Community Settings') }

:
; + return
+ { header } + { this._getLongDescriptionNode() } + { this._getRoomsNode() } +
; + }, + _getRoomsNode: function() { const RoomDetailList = sdk.getComponent('rooms.RoomDetailList'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const TintableSvg = sdk.getComponent('elements.TintableSvg'); - const addButton = this.state.editing ? - ( -
+ + const addRoomRow = this.state.editing ? + ( +
-
+
{ _t('Add rooms to this community') }
) :
; return

{ _t('Rooms') }

- { addButton } + { addRoomRow }
; @@ -761,8 +786,8 @@ export default React.createClass({
; } else if (group.myMembership === 'join' && this.state.editing) { const leaveButtonTooltip = this.state.isUserPrivileged ? - _t("You are a member of this community") : - _t("You are an administrator of this community"); + _t("You are an administrator of this community") : + _t("You are a member of this community"); const leaveButtonClasses = classnames({ "mx_RoomHeader_textButton": true, "mx_GroupView_textButton": true, @@ -790,7 +815,7 @@ export default React.createClass({ _getMemberSettingsSection: function() { return
-

{ _t("Community Member Settings") }

+

{ _t("Community Member Settings") }

+ const groupDescEditingClasses = classnames({ + "mx_GroupView_groupDesc": true, + "mx_GroupView_groupDesc_disabled": !this.state.isUserPrivileged, + }); + + return this.state.editing ? +

{ _t("Long Description (HTML)") }