From 798d68b4c800476d588d8d3f162c876d1c53a067 Mon Sep 17 00:00:00 2001 From: Zero Date: Mon, 14 Aug 2017 19:42:00 +0200 Subject: [PATCH 01/35] Include magnet scheme in sanitize HTML params Update HtmlUtils sanitze-html params to include the magnet scheme --- src/HtmlUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 87e714083b..f1ce6a6a12 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -152,7 +152,7 @@ const sanitizeHtmlParams = { // Lots of these won't come up by default because we don't allow them selfClosing: ['img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta'], // URL schemes we permit - allowedSchemes: ['http', 'https', 'ftp', 'mailto'], + allowedSchemes: ['http', 'https', 'ftp', 'mailto', 'magnet'], allowProtocolRelative: false, From d1af424b3fad847b725270f519e932275808a06e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 6 Sep 2017 10:56:08 +0100 Subject: [PATCH 02/35] allow hiding of notification body for privacy reasons Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/Notifier.js | 22 ++++++++++++++++++---- src/UserSettingsStore.js | 11 +++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Notifier.js b/src/Notifier.js index 155564dcdf..93ef192fe0 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -80,10 +80,11 @@ const Notifier = { if (ev.getContent().body) msg = ev.getContent().body; } - const avatarUrl = ev.sender ? Avatar.avatarUrlForMember( - ev.sender, 40, 40, 'crop' - ) : null; + if (!this.isBodyEnabled()) { + msg = ''; + } + const avatarUrl = ev.sender ? Avatar.avatarUrlForMember(ev.sender, 40, 40, 'crop') : null; const notif = plaf.displayNotification(title, msg, avatarUrl, room); // if displayNotification returns non-null, the platform supports @@ -195,6 +196,19 @@ const Notifier = { return enabled === 'true'; }, + setBodyEnabled: function(enable) { + if (!global.localStorage) return; + global.localStorage.setItem('notifications_body_enabled', enable ? 'true' : 'false'); + }, + + isBodyEnabled: function() { + if (!global.localStorage) return true; + const enabled = global.localStorage.getItem('notifications_body_enabled'); + // default to true if the popups are enabled + if (enabled === null) return this.isEnabled(); + return enabled === 'true'; + }, + setAudioEnabled: function(enable) { if (!global.localStorage) return; global.localStorage.setItem('audio_notifications_enabled', @@ -303,7 +317,7 @@ const Notifier = { this._playAudioNotification(ev, room); } } - } + }, }; if (!global.mxNotifier) { diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 68a1ba229f..ec95c99e6b 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -73,6 +73,17 @@ export default { Notifier.setEnabled(enable); }, + getEnableNotificationBody: function() { + return Notifier.isBodyEnabled(); + }, + + setEnableNotificationBody: function(enable) { + if (!Notifier.supportsDesktopNotifications()) { + return; + } + Notifier.setBodyEnabled(enable); + }, + getEnableAudioNotifications: function() { return Notifier.isAudioEnabled(); }, From 3a58e1c0665c3f0b12ec2d26723f0ceb61105268 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Sep 2017 11:03:13 -0600 Subject: [PATCH 03/35] Show pinned message changes in the timeline Signed-off-by: Travis Ralston --- src/TextForEvent.js | 6 ++++++ src/components/views/rooms/EventTile.js | 1 + src/i18n/strings/en_EN.json | 1 + src/i18n/strings/en_US.json | 1 + 4 files changed, 9 insertions(+) diff --git a/src/TextForEvent.js b/src/TextForEvent.js index a21eb5c251..06b847c19a 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -259,6 +259,11 @@ function textForPowerEvent(event) { }); } +function textForPinnedEvent(event) { + const senderName = event.getSender(); + return _t("%(senderName)s changed the pinned messages for the room.", {senderName}); +} + function textForWidgetEvent(event) { const senderName = event.getSender(); const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent(); @@ -301,6 +306,7 @@ const handlers = { 'm.room.history_visibility': textForHistoryVisibilityEvent, 'm.room.encryption': textForEncryptionEvent, 'm.room.power_levels': textForPowerEvent, + 'm.room.pinned_events': textForPinnedEvent, 'im.vector.modular.widgets': textForWidgetEvent, }; diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index 7328cfe0b6..9bdee42cc1 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -44,6 +44,7 @@ var eventTileTypes = { 'm.room.history_visibility' : 'messages.TextualEvent', 'm.room.encryption' : 'messages.TextualEvent', 'm.room.power_levels' : 'messages.TextualEvent', + 'm.room.pinned_events' : 'messages.TextualEvent', 'im.vector.modular.widgets': 'messages.TextualEvent', }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 87fd6d4364..0cd70c91c3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -875,6 +875,7 @@ "Add rooms to the group summary": "Add rooms to the group summary", "Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?", "Room name or alias": "Room name or alias", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.", "You are an administrator of this group": "You are an administrator of this group", "Failed to add the following rooms to the summary of %(groupId)s:": "Failed to add the following rooms to the summary of %(groupId)s:", "Failed to remove the room from the summary of %(groupId)s": "Failed to remove the room from the summary of %(groupId)s", diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index 928f1a9d0f..1ec7bbce83 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -852,6 +852,7 @@ "%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s", "Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser", "Verifies a user, device, and pubkey tuple": "Verifies a user, device, and pubkey tuple", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.", "It is currently only possible to create groups on your own home server: use a group ID ending with %(domain)s": "It is currently only possible to create groups on your own home server: use a group ID ending with %(domain)s", "To join an existing group you'll have to know its group identifier; this will look something like +example:matrix.org.": "To join an existing group you'll have to know its group identifier; this will look something like +example:matrix.org." } From 874d383a8fdfaffbb6dd605e45209d663e2120db Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Sep 2017 15:32:51 -0600 Subject: [PATCH 04/35] Add dock for pinned messages at the top of the room Signed-off-by: Travis Ralston --- src/components/structures/RoomView.js | 14 ++++++++++++-- src/components/views/rooms/RoomHeader.js | 10 ++++++++++ src/i18n/strings/en_EN.json | 1 + src/i18n/strings/en_US.json | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index e0332b1b19..5b07459299 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1128,6 +1128,10 @@ module.exports = React.createClass({ return ret; }, + onPinnedClick: function() { + this.setState({showingPinned: !this.state.showingPinned, searching: false}); + }, + onSettingsClick: function() { this.showSettings(true); }, @@ -1248,7 +1252,7 @@ module.exports = React.createClass({ }, onSearchClick: function() { - this.setState({ searching: true }); + this.setState({ searching: true, showingPinned: false }); }, onCancelSearchClick: function() { @@ -1447,6 +1451,7 @@ module.exports = React.createClass({ const RoomSettings = sdk.getComponent("rooms.RoomSettings"); const AuxPanel = sdk.getComponent("rooms.AuxPanel"); const SearchBar = sdk.getComponent("rooms.SearchBar"); + const PinnedEventsPanel = sdk.getComponent("rooms.PinnedEventsPanel"); const ScrollPanel = sdk.getComponent("structures.ScrollPanel"); const TintableSvg = sdk.getComponent("elements.TintableSvg"); const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar"); @@ -1587,7 +1592,11 @@ module.exports = React.createClass({ aux = ; } else if (this.state.searching) { hideCancel = true; // has own cancel - aux = ; + aux = ; + } else if (this.state.showingPinned) { + hideCancel = true; // has own cancel + aux = ; } else if (!myMember || myMember.membership !== "join") { // We do have a room object for this room, but we're not currently in it. // We may have a 3rd party invite to it. @@ -1761,6 +1770,7 @@ module.exports = React.createClass({ collapsedRhs={ this.props.collapsedRhs } onSearchClick={this.onSearchClick} onSettingsClick={this.onSettingsClick} + onPinnedClick={this.onPinnedClick} onSaveClick={this.onSettingsSaveClick} onCancelClick={(aux && !hideCancel) ? this.onCancelClick : null} onForgetClick={(myMember && myMember.membership === "leave") ? this.onForgetClick : null} diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 42cbb90cd9..3e02db5793 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -45,6 +45,7 @@ module.exports = React.createClass({ inRoom: React.PropTypes.bool, collapsedRhs: React.PropTypes.bool, onSettingsClick: React.PropTypes.func, + onPinnedClick: React.PropTypes.func, onSaveClick: React.PropTypes.func, onSearchClick: React.PropTypes.func, onLeaveClick: React.PropTypes.func, @@ -172,6 +173,7 @@ module.exports = React.createClass({ let spinner = null; let saveButton = null; let settingsButton = null; + let pinnedEventsButton = null; let canSetRoomName; let canSetRoomAvatar; @@ -290,6 +292,13 @@ module.exports = React.createClass({ ; } + if (this.props.onPinnedClick) { + pinnedEventsButton = + + + ; + } + // var leave_button; // if (this.props.onLeaveClick) { // leave_button = @@ -334,6 +343,7 @@ module.exports = React.createClass({ rightRow =
{ settingsButton } + { pinnedEventsButton } { manageIntegsButton } { forgetButton } { searchButton } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0cd70c91c3..7adcb02f64 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -875,6 +875,7 @@ "Add rooms to the group summary": "Add rooms to the group summary", "Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?", "Room name or alias": "Room name or alias", + "Pinned Messages": "Pinned Messages", "%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.", "You are an administrator of this group": "You are an administrator of this group", "Failed to add the following rooms to the summary of %(groupId)s:": "Failed to add the following rooms to the summary of %(groupId)s:", diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index 1ec7bbce83..98796ff32e 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -837,6 +837,7 @@ "+example:%(domain)s": "+example:%(domain)s", "Group IDs must be of the form +localpart:%(domain)s": "Group IDs must be of the form +localpart:%(domain)s", "Room creation failed": "Room creation failed", + "Pinned Messages": "Pinned Messages", "You are a member of these groups:": "You are a member of these groups:", "Create a group to represent your community! Define a set of rooms and your own custom homepage to mark out your space in the Matrix universe.": "Create a group to represent your community! Define a set of rooms and your own custom homepage to mark out your space in the Matrix universe.", "Join an existing group": "Join an existing group", From f71e07670d193e127836f769be9f70ddab5c9390 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Sep 2017 17:00:26 -0600 Subject: [PATCH 05/35] Send toggle handler for the cancel button in the pinned events pane Signed-off-by: Travis Ralston --- src/components/structures/RoomView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 5b07459299..23e5833468 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1596,7 +1596,7 @@ module.exports = React.createClass({ onCancelClick={this.onCancelSearchClick} onSearch={this.onSearch}/>; } else if (this.state.showingPinned) { hideCancel = true; // has own cancel - aux = ; + aux = ; } else if (!myMember || myMember.membership !== "join") { // We do have a room object for this room, but we're not currently in it. // We may have a 3rd party invite to it. From 0f2fd9f69882b6fed86615d9b04e3b4c1a5d2cbd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Sep 2017 13:14:56 -0600 Subject: [PATCH 06/35] Move the PinnedEventsPanel to the react-sdk Signed-off-by: Travis Ralston --- src/components/views/rooms/PinnedEventTile.js | 86 +++++++++++++++ .../views/rooms/PinnedEventsPanel.js | 101 ++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 src/components/views/rooms/PinnedEventTile.js create mode 100644 src/components/views/rooms/PinnedEventsPanel.js diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js new file mode 100644 index 0000000000..555718709b --- /dev/null +++ b/src/components/views/rooms/PinnedEventTile.js @@ -0,0 +1,86 @@ +/* +Copyright 2017 Travis Ralston + +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 MatrixClientPeg from "../../../MatrixClientPeg"; +import dis from "../../../dispatcher"; +import AccessibleButton from "../elements/AccessibleButton"; +import MessageEvent from "../messages/MessageEvent"; +import MemberAvatar from "../avatars/MemberAvatar"; +import { _t } from '../../../languageHandler'; + +module.exports = React.createClass({ + displayName: 'PinnedEventTile', + propTypes: { + mxRoom: React.PropTypes.object.isRequired, + mxEvent: React.PropTypes.object.isRequired, + onUnpinned: React.PropTypes.func, + }, + onTileClicked: function() { + dis.dispatch({ + action: 'view_room', + event_id: this.props.mxEvent.getId(), + highlighted: true, + room_id: this.props.mxEvent.getRoomId(), + }); + }, + onUnpinClicked: function() { + const pinnedEvents = this.props.mxRoom.currentState.getStateEvents("m.room.pinned_events", ""); + if (!pinnedEvents || !pinnedEvents.getContent().pinned) { + // Nothing to do: already unpinned + if (this.props.onUnpinned) this.props.onUnpinned(); + } else { + const pinned = pinnedEvents.getContent().pinned; + const index = pinned.indexOf(this.props.mxEvent.getId()); + if (index !== -1) { + pinned.splice(index, 1); + MatrixClientPeg.get().sendStateEvent(this.props.mxRoom.roomId, 'm.room.pinned_events', {pinned}, '').then(() => { + if (this.props.onUnpinned) this.props.onUnpinned(); + }); + } else if (this.props.onUnpinned) this.props.onUnpinned(); + } + }, + _canUnpin: function() { + return this.props.mxRoom.currentState.mayClientSendStateEvent('m.room.pinned_events', MatrixClientPeg.get()); + }, + render: function() { + const sender = this.props.mxRoom.getMember(this.props.mxEvent.getSender()); + const avatarSize = 40; + + let unpinButton = null; + if (this._canUnpin()) { + unpinButton = {_t('Unpin; + } + + return ( +
+
+ + { _t("Jump to message") } + + { unpinButton } +
+ + + + {sender.name} + + +
+ ); + } +}); diff --git a/src/components/views/rooms/PinnedEventsPanel.js b/src/components/views/rooms/PinnedEventsPanel.js new file mode 100644 index 0000000000..02df29fc72 --- /dev/null +++ b/src/components/views/rooms/PinnedEventsPanel.js @@ -0,0 +1,101 @@ +/* +Copyright 2017 Travis Ralston + +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 MatrixClientPeg from "../../../MatrixClientPeg"; +import AccessibleButton from "../elements/AccessibleButton"; +import PinnedEventTile from "./PinnedEventTile"; +import { _t } from '../../../languageHandler'; + +module.exports = React.createClass({ + displayName: 'PinnedEventsPanel', + propTypes: { + // The Room from the js-sdk we're going to show pinned events for + room: React.PropTypes.object.isRequired, + + onCancelClick: React.PropTypes.func, + }, + + getInitialState: function() { + return { + loading: true, + }; + }, + + componentDidMount: function() { + this._updatePinnedMessages(); + }, + + _updatePinnedMessages: function() { + const pinnedEvents = this.props.room.currentState.getStateEvents("m.room.pinned_events", ""); + if (!pinnedEvents || !pinnedEvents.getContent().pinned) { + this.setState({ loading: false, pinned: [] }); + } else { + const promises = []; + const cli = MatrixClientPeg.get(); + + pinnedEvents.getContent().pinned.map(eventId => { + promises.push(cli.getEventTimeline(this.props.room.getUnfilteredTimelineSet(), eventId, 0).then(timeline => { + const event = timeline.getEvents().find(e => e.getId() === eventId); + return {eventId, timeline, event}; + }).catch(err => { + console.error("Error looking up pinned event " + eventId + " in room " + this.props.room.roomId); + console.error(err); + return null; // return lack of context to avoid unhandled errors + })); + }); + + Promise.all(promises).then(contexts => { + // Filter out the messages before we try to render them + const pinned = contexts.filter(context => { + if (!context) return false; // no context == not applicable for the room + if (context.event.getType() !== "m.room.message") return false; + if (context.event.isRedacted()) return false; + return true; + }); + + this.setState({ loading: false, pinned }); + }); + } + }, + + _getPinnedTiles: function() { + if (this.state.pinned.length == 0) { + return (
{ _t("No pinned messages.") }
); + } + + return this.state.pinned.map(context => { + return (); + }); + }, + + render: function() { + let tiles =
{ _t("Loading...") }
; + if (this.state && !this.state.loading) { + tiles = this._getPinnedTiles(); + } + + return ( +
+
+ +

{_t("Pinned Messages")}

+ { tiles } +
+
+ ); + } +}); From a01387f7a63757fc64eac730165a7d288c801ebd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Sep 2017 13:32:25 -0600 Subject: [PATCH 07/35] Use an AccessibleButton for unpinning from the pane. Signed-off-by: Travis Ralston --- src/components/views/rooms/PinnedEventTile.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js index 555718709b..e4b5b1ff96 100644 --- a/src/components/views/rooms/PinnedEventTile.js +++ b/src/components/views/rooms/PinnedEventTile.js @@ -62,8 +62,11 @@ module.exports = React.createClass({ let unpinButton = null; if (this._canUnpin()) { - unpinButton = {_t('Unpin; + unpinButton = ( + + {_t('Unpin + + ); } return ( From 0e2a1c90d55a5b6bedd9c7332bff18bd2ba4ed47 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Sep 2017 16:08:50 -0600 Subject: [PATCH 08/35] Don't suggest grey as a color scheme for a room Fixes https://github.com/vector-im/riot-web/issues/5045 Signed-off-by: Travis Ralston --- src/components/views/room_settings/ColorSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js index b37802d304..ea19fb6a89 100644 --- a/src/components/views/room_settings/ColorSettings.js +++ b/src/components/views/room_settings/ColorSettings.js @@ -34,7 +34,7 @@ var ROOM_COLORS = [ ["#dad658", "#f5f4ea"], ["#80c553", "#eef5ea"], ["#bb814e", "#eee8e3"], - ["#595959", "#ececec"], + //["#595959", "#ececec"], // Grey makes everything appear disabled, so remove it for now ]; module.exports = React.createClass({ From d54cea54298041379738367ae2996de8643c3368 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 7 Oct 2017 19:25:13 +0100 Subject: [PATCH 09/35] Add a way to jump to a user's Read Receipt from MemberInfo Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/MemberInfo.js | 35 +++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index f705cf97d2..83f4f7e4c6 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -628,23 +628,50 @@ module.exports = withMatrixClient(React.createClass({ }, _renderUserOptions: function() { - // Only allow the user to ignore the user if its not ourselves + const cli = this.props.matrixClient; + const member = this.props.member; + let ignoreButton = null; - if (this.props.member.userId !== this.props.matrixClient.getUserId()) { + let readReceiptButton = null; + + // Only allow the user to ignore the user if its not ourselves + // same goes for jumping to read receipt + if (member.userId !== cli.getUserId()) { ignoreButton = ( {this.state.isIgnoring ? _t("Unignore") : _t("Ignore")} ); + + if (member.roomId) { + const room = cli.getRoom(member.roomId); + const eventId = room.getEventReadUpTo(member.userId); + + const onReadReceiptButton = function() { + dis.dispatch({ + action: 'view_room', + highlighted: true, + event_id: eventId, + room_id: member.roomId, + }); + }; + + readReceiptButton = ( + + Jump to read receipt + + ); + } } - if (!ignoreButton) return null; + if (!ignoreButton && !readReceiptButton) return null; return (

{ _t("User Options") }

- {ignoreButton} + { readReceiptButton } + { ignoreButton }
); From dbb6f5a44d2cdc4b0531c245fcd0b5fa1575d11a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 7 Oct 2017 19:27:49 +0100 Subject: [PATCH 10/35] i18n the Jump to Read Receipt in MemberInfo Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/MemberInfo.js | 4 ++-- src/i18n/strings/en_EN.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 83f4f7e4c6..5dfdeb303b 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -639,7 +639,7 @@ module.exports = withMatrixClient(React.createClass({ if (member.userId !== cli.getUserId()) { ignoreButton = ( - {this.state.isIgnoring ? _t("Unignore") : _t("Ignore")} + { this.state.isIgnoring ? _t("Unignore") : _t("Ignore") } ); @@ -658,7 +658,7 @@ module.exports = withMatrixClient(React.createClass({ readReceiptButton = ( - Jump to read receipt + { _t('Jump to read receipt') } ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6acaba9fae..5ebf6116ee 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -249,6 +249,7 @@ "%(targetName)s joined the room.": "%(targetName)s joined the room.", "Joins room with given alias": "Joins room with given alias", "Jump to first unread message.": "Jump to first unread message.", + "Jump to read receipt": "Jump to read receipt", "%(senderName)s kicked %(targetName)s.": "%(senderName)s kicked %(targetName)s.", "Kick": "Kick", "Kicks user with given id": "Kicks user with given id", From 52f3e1295bd37b197aef724f3787ae4f54858f89 Mon Sep 17 00:00:00 2001 From: Stefan Parviainen Date: Wed, 11 Oct 2017 09:14:11 +0200 Subject: [PATCH 11/35] Don't use string interpolation in _tJsx as it uses regexes for that Signed-off-by: Stefan Parviainen --- src/languageHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languageHandler.js b/src/languageHandler.js index 12242a2e15..b846980dc1 100644 --- a/src/languageHandler.js +++ b/src/languageHandler.js @@ -109,7 +109,7 @@ export function _tJsx(jsxText, patterns, subs) { } // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution) - const tJsxText = _t(jsxText); + const tJsxText = _t(jsxText, {interpolate: false}); let output = [tJsxText]; for (let i = 0; i < patterns.length; i++) { // convert the last element in 'output' into 3 elements (pre-text, sub function, post-text). From 581abcb4b78f07a7f3c0a5ac347416f108fa0c39 Mon Sep 17 00:00:00 2001 From: Stefan Parviainen Date: Wed, 11 Oct 2017 09:15:15 +0200 Subject: [PATCH 12/35] Consistent subsitution variable in translations Signed-off-by: Stefan Parviainen --- src/components/views/messages/RoomAvatarEvent.js | 4 ++-- src/i18n/strings/de_DE.json | 2 +- src/i18n/strings/el.json | 2 +- src/i18n/strings/en_EN.json | 2 +- src/i18n/strings/en_US.json | 2 +- src/i18n/strings/eu.json | 2 +- src/i18n/strings/fr.json | 2 +- src/i18n/strings/hu.json | 2 +- src/i18n/strings/ko.json | 2 +- src/i18n/strings/lv.json | 2 +- src/i18n/strings/nl.json | 2 +- src/i18n/strings/pl.json | 2 +- src/i18n/strings/pt.json | 2 +- src/i18n/strings/pt_BR.json | 2 +- src/i18n/strings/ru.json | 2 +- src/i18n/strings/tr.json | 2 +- src/i18n/strings/zh_Hant.json | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/views/messages/RoomAvatarEvent.js b/src/components/views/messages/RoomAvatarEvent.js index ed790953dc..c7625b0165 100644 --- a/src/components/views/messages/RoomAvatarEvent.js +++ b/src/components/views/messages/RoomAvatarEvent.js @@ -70,9 +70,9 @@ module.exports = React.createClass({ // it sucks that _tJsx doesn't support normal _t substitutions :(( return (
- { _tJsx('$senderDisplayName changed the room avatar to ', + { _tJsx('%(senderDisplayName)s changed the room avatar to ', [ - /\$senderDisplayName/, + /%\(senderDisplayName\)s/, //, ], [ diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index aa114e241d..3fd7a4858f 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -734,7 +734,7 @@ "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "WARNUNG: SCHLÜSSEL-VERIFIZIERUNG FEHLGESCHLAGEN! Der Signatur-Schlüssel für %(userId)s und das Gerät %(deviceId)s ist \"%(fprint)s\", welcher nicht mit dem bereitgestellten Schlüssel \"%(fingerprint)s\" übereinstimmt. Dies kann bedeuten, dass deine Kommunikation abgehört wird!", "You have disabled URL previews by default.": "Du hast die URL-Vorschau standardmäßig deaktiviert.", "You have enabled URL previews by default.": "Du hast die URL-Vorschau standardmäßig aktiviert.", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName hat das Raum-Bild geändert zu ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s hat das Raum-Bild geändert zu ", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s hat das Raum-Bild für %(roomName)s geändert", "Hide removed messages": "Gelöschte Nachrichten verbergen", "Start new chat": "Neuen Chat starten", diff --git a/src/i18n/strings/el.json b/src/i18n/strings/el.json index bc45e6da9e..474ae70160 100644 --- a/src/i18n/strings/el.json +++ b/src/i18n/strings/el.json @@ -647,7 +647,7 @@ "Disable URL previews by default for participants in this room": "Απενεργοποίηση της προεπισκόπησης συνδέσμων για όλους τους συμμετέχοντες στο δωμάτιο", "Disable URL previews for this room (affects only you)": "Απενεργοποίηση της προεπισκόπησης συνδέσμων για αυτό το δωμάτιο (επηρεάζει μόνο εσάς)", " (unsupported)": " (μη υποστηριζόμενο)", - "$senderDisplayName changed the room avatar to ": "Ο $senderDisplayName άλλαξε την εικόνα του δωματίου σε ", + "%(senderDisplayName)s changed the room avatar to ": "Ο %(senderDisplayName)s άλλαξε την εικόνα του δωματίου σε ", "Missing Media Permissions, click here to request.": "Λείπουν τα δικαιώματα πολύμεσων, κάντε κλικ για να ζητήσετε.", "You may need to manually permit Riot to access your microphone/webcam": "Μπορεί να χρειαστεί να ορίσετε χειροκίνητα την πρόσβαση του Riot στο μικρόφωνο/κάμερα", "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Δεν είναι δυνατή η σύνδεση στον διακομιστή - παρακαλούμε ελέγξτε την συνδεσιμότητα, βεβαιωθείτε ότι το πιστοποιητικό SSL του διακομιστή είναι έμπιστο και ότι κάποιο πρόσθετο περιηγητή δεν αποτρέπει τα αιτήματα.", diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6acaba9fae..36d50679e2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -790,7 +790,7 @@ "Start chatting": "Start chatting", "Start Chatting": "Start Chatting", "Click on the button below to start chatting!": "Click on the button below to start chatting!", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName changed the room avatar to ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s changed the room avatar to ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s", "Username available": "Username available", diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index 928f1a9d0f..d4f210bc08 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -698,7 +698,7 @@ "Idle": "Idle", "Offline": "Offline", "Disable URL previews for this room (affects only you)": "Disable URL previews for this room (affects only you)", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName changed the room avatar to ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s changed the room avatar to ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s", "Active call (%(roomName)s)": "Active call (%(roomName)s)", diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 9f3d06ec52..9aa8112382 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -744,7 +744,7 @@ "Start chatting": "Hasi txateatzen", "Start Chatting": "Hasi txateatzen", "Click on the button below to start chatting!": "Egin klik beheko botoian txateatzen hasteko!", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName erabiltzaileak gelaren abatarra aldatu du beste honetara: ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s erabiltzaileak gelaren abatarra aldatu du beste honetara: ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s erabiltzaileak gelaren abatarra ezabatu du.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s erabiltzaileak %(roomName)s gelaren abatarra aldatu du", "Username available": "Erabiltzaile-izena eskuragarri dago", diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 585e47f5a3..22e901ba5e 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -635,7 +635,7 @@ "for %(amount)sm": "depuis %(amount)sm", "for %(amount)sh": "depuis %(amount)sh", "for %(amount)sd": "depuis %(amount)sj", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName a changé l’image de profil du salon en ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s a changé l’image de profil du salon en ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s a supprimé l’image de profil du salon.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s a changé l’image de profil de %(roomName)s", "Device already verified!": "Appareil déjà vérifié !", diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 2c34e05b1a..0801ecbc7b 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -730,7 +730,7 @@ "Start chatting": "Csevegés indítása", "Start Chatting": "Csevegés indítása", "Click on the button below to start chatting!": "Csevegés indításához kattints a gombra alább!", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName megváltoztatta a szoba avatar képét: ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s megváltoztatta a szoba avatar képét: ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s törölte a szoba avatar képét.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s megváltoztatta %(roomName)s szoba avatar képét", "Username available": "Szabad felhasználói név", diff --git a/src/i18n/strings/ko.json b/src/i18n/strings/ko.json index 8b6e233437..ac182570df 100644 --- a/src/i18n/strings/ko.json +++ b/src/i18n/strings/ko.json @@ -751,7 +751,7 @@ "Start chatting": "이야기하기", "Start Chatting": "이야기하기", "Click on the button below to start chatting!": "이야기하려면 아래 버튼을 누르세요!", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName님이 방 아바타를 로 바꾸셨어요", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s님이 방 아바타를 로 바꾸셨어요", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s님이 방 아바타를 지우셨어요.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s가 %(roomName)s 방의 아바타를 바꾸셨어요", "Username available": "쓸 수 있는 사용자 이름", diff --git a/src/i18n/strings/lv.json b/src/i18n/strings/lv.json index 5f58fd9515..6891f130b5 100644 --- a/src/i18n/strings/lv.json +++ b/src/i18n/strings/lv.json @@ -626,7 +626,7 @@ "Dec": "Dec.", "Set a display name:": "Iestatīt redzamo vārdu:", "This image cannot be displayed.": "Šo attēlu nav iespējams parādīt.", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName nomainīja istabas attēlu uz ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s nomainīja istabas attēlu uz ", "Upload an avatar:": "Augšuplādē profila attēlu:", "This server does not support authentication with a phone number.": "Šis serveris neatbalsta autentifikāciju pēc telefona numura.", "Missing password.": "Trūkst parole.", diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index f770e335cf..82e0731653 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -753,7 +753,7 @@ "Start chatting": "Start met praten", "Start Chatting": "Start Met Praten", "Click on the button below to start chatting!": "Klik op de knop hieronder om te starten met praten!", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName heeft de ruimte avatar aangepast naar ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s heeft de ruimte avatar aangepast naar ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s heeft de ruimte avatar verwijderd.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s veranderde de avatar voor %(roomName)s", "Username available": "Gebruikersnaam beschikbaar", diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index bd1e4c5c24..c78bc0f300 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -778,7 +778,7 @@ "for %(amount)sd": "%(amount)s dni", "Idle": "Bezczynny", "Check for update": "Sprawdź aktualizacje", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName zmienił awatar pokoju na ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s zmienił awatar pokoju na ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s usunął awatar pokoju.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s zmienił awatar %(roomName)s", "This will be your account name on the homeserver, or you can pick a different server.": "To będzie twoja nazwa konta na serwerze domowym; możesz też wybrać inny serwer.", diff --git a/src/i18n/strings/pt.json b/src/i18n/strings/pt.json index ba4968b7ad..e4aedecf3e 100644 --- a/src/i18n/strings/pt.json +++ b/src/i18n/strings/pt.json @@ -707,7 +707,7 @@ "for %(amount)sd": "por %(amount)sd", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removeu a imagem da sala.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s alterou a imagem da sala %(roomName)s", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName alterou a imagem da sala para ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s alterou a imagem da sala para ", "Missing Media Permissions, click here to request.": "Faltam permissões para uso de mídia no seu computador. Clique aqui para solicitá-las.", "No Microphones detected": "Não foi detectado nenhum microfone", "No Webcams detected": "Não foi detectada nenhuma Webcam", diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index af4804bd85..f6c945c20c 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -704,7 +704,7 @@ "for %(amount)sd": "por %(amount)sd", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removeu a imagem da sala.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s alterou a imagem da sala %(roomName)s", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName alterou a imagem da sala para ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s alterou a imagem da sala para ", "Missing Media Permissions, click here to request.": "Faltam permissões para uso de mídia no seu computador. Clique aqui para solicitá-las.", "No Microphones detected": "Não foi detectado nenhum microfone", "No Webcams detected": "Não foi detectada nenhuma Webcam", diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index cfab960e32..3a99d78420 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -712,7 +712,7 @@ "Idle": "Неактивен", "Offline": "Не в сети", "Disable URL previews for this room (affects only you)": "Отключить предпросмотр URL-адресов для этой комнаты (влияет только на вас)", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName сменил аватар комнаты на ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s сменил аватар комнаты на ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s удалил аватар комнаты.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s сменил аватар для %(roomName)s", "Create new room": "Создать новую комнату", diff --git a/src/i18n/strings/tr.json b/src/i18n/strings/tr.json index 23d4e284bc..7cbdeee173 100644 --- a/src/i18n/strings/tr.json +++ b/src/i18n/strings/tr.json @@ -746,7 +746,7 @@ "Start chatting": "Sohbeti başlat", "Start Chatting": "Sohbeti Başlat", "Click on the button below to start chatting!": "Sohbeti başlatmak için aşağıdaki butona tıklayın!", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName odanın avatarını olarak çevirdi", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s odanın avatarını olarak çevirdi", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s odanın avatarını kaldırdı.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s %(roomName)s için avatarı değiştirdi", "Username available": "Kullanıcı ismi uygun", diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 596bc55a01..5828d7a614 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -228,7 +228,7 @@ "Idle": "閒置", "Offline": "下線", "Disable URL previews for this room (affects only you)": "在這個房間禁止URL預覽(只影響你)", - "$senderDisplayName changed the room avatar to ": "$senderDisplayName 更改了聊天室的圖像為 ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s 更改了聊天室的圖像為 ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s 移除了聊天室圖片。", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s 更改了聊天室 %(roomName)s 圖像", "Cancel": "取消", From 36666b3fc387ef7888f477f019ffc8546c76501a Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 11 Oct 2017 15:04:52 +0100 Subject: [PATCH 13/35] Add warm fuzzy dialog for inviting users to a group --- src/GroupAddressPicker.js | 7 +++++++ src/i18n/strings/en_EN.json | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js index cfd2590780..ca495de16d 100644 --- a/src/GroupAddressPicker.js +++ b/src/GroupAddressPicker.js @@ -76,6 +76,13 @@ 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 group invitations have been sent."), + hasCancelButton: false, + }); } }).catch((err) => { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6acaba9fae..aaabea1011 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -906,5 +906,7 @@ "Related Groups": "Related Groups", "Related groups for this room:": "Related groups for this room:", "This room has no related groups": "This room has no related groups", - "New group ID (e.g. +foo:%(localDomain)s)": "New group ID (e.g. +foo:%(localDomain)s)" + "New group ID (e.g. +foo:%(localDomain)s)": "New group ID (e.g. +foo:%(localDomain)s)", + "Invites sent": "Invites sent", + "Your group invitations have been sent.": "Your group invitations have been sent." } From f3b1baa3c0f021c458b5bc3937171b1e462c505b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 11 Oct 2017 21:15:00 -0600 Subject: [PATCH 14/35] Suggest to invite people when speaking in an empty room Adds vector-im/riot-web#1053 Signed-off-by: Travis Ralston --- src/components/structures/RoomStatusBar.js | 30 +++++++++++++++++- src/components/structures/RoomView.js | 36 ++++++++++++++++++++++ src/i18n/strings/en_EN.json | 1 + 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index 3a2ab33db8..cad55351d1 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -43,6 +43,10 @@ module.exports = React.createClass({ // the end of the live timeline. atEndOfLiveTimeline: React.PropTypes.bool, + // This is true when the user is alone in the room, but has also sent a message. + // Used to suggest to the user to invite someone + sentMessageAndIsAlone: React.PropTypes.bool, + // true if there is an active call in this room (means we show // the 'Active Call' text in the status bar if there is nothing // more interesting) @@ -60,6 +64,14 @@ module.exports = React.createClass({ // 'unsent messages' bar onCancelAllClick: React.PropTypes.func, + // callback for when the user clicks on the 'invite others' button in the + // 'you are alone' bar + onInviteClick: React.PropTypes.func, + + // callback for when the user clicks on the 'stop warning me' button in the + // 'you are alone' bar + onStopWarningClick: React.PropTypes.func, + // callback for when the user clicks on the 'scroll to bottom' button onScrollToBottomClick: React.PropTypes.func, @@ -140,7 +152,8 @@ module.exports = React.createClass({ (this.state.usersTyping.length > 0) || this.props.numUnreadMessages || !this.props.atEndOfLiveTimeline || - this.props.hasActiveCall + this.props.hasActiveCall || + this.props.sentMessageAndIsAlone ) { return STATUS_BAR_EXPANDED; } else if (this.props.unsentMessageError) { @@ -305,6 +318,21 @@ module.exports = React.createClass({ ); } + // If you're alone in the room, and have sent a message, suggest to invite someone + if (this.props.sentMessageAndIsAlone) { + return ( +
+ { _tJsx("There's no one else here! Would you like to invite others or stop warning about the empty room?", + [/(.*?)<\/a>/, /(.*?)<\/a>/], + [ + (sub) => { sub }, + (sub) => { sub }, + ], + ) } +
+ ); + } + return null; }, diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 14273fc95f..c75b0f61b0 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -117,6 +117,7 @@ module.exports = React.createClass({ guestsCanJoin: false, canPeek: false, showApps: false, + isAlone: false, // error object, as from the matrix client/server API // If we failed to load information about the room, @@ -453,6 +454,8 @@ module.exports = React.createClass({ switch (payload.action) { case 'message_send_failed': case 'message_sent': + this._checkIfAlone(this.state.room); + // no break; to intentionally fall through case 'message_send_cancelled': this.setState({ unsentMessageError: this._getUnsentMessageError(this.state.room), @@ -732,6 +735,20 @@ module.exports = React.createClass({ } }, 500), + _checkIfAlone: function(room) { + let warnedAboutLonelyRoom = false; + if (localStorage) { + warnedAboutLonelyRoom = localStorage.getItem('mx_user_alone_warned_' + this.state.room.roomId); + } + if (warnedAboutLonelyRoom) { + if (this.state.isAlone) this.setState({isAlone: false}); + return; + } + + const joinedMembers = room.currentState.getMembers().filter(m => m.membership === "join" || m.membership === "invite"); + this.setState({isAlone: joinedMembers.length === 1}); + }, + _getUnsentMessageError: function(room) { const unsentMessages = this._getUnsentMessages(room); if (!unsentMessages.length) return ""; @@ -813,6 +830,22 @@ module.exports = React.createClass({ Resend.cancelUnsentEvents(this.state.room); }, + onInviteButtonClick: function() { + // call AddressPickerDialog + dis.dispatch({ + action: 'view_invite', + roomId: this.state.room.roomId, + }); + this.setState({isAlone: false}); // there's a good chance they'll invite someone + }, + + onStopAloneWarningClick: function() { + if (localStorage) { + localStorage.setItem('mx_user_alone_warned_' + this.state.room.roomId, true); + } + this.setState({isAlone: false}); + }, + onJoinButtonClicked: function(ev) { const cli = MatrixClientPeg.get(); @@ -1573,9 +1606,12 @@ module.exports = React.createClass({ numUnreadMessages={this.state.numUnreadMessages} unsentMessageError={this.state.unsentMessageError} atEndOfLiveTimeline={this.state.atEndOfLiveTimeline} + sentMessageAndIsAlone={this.state.isAlone} hasActiveCall={inCall} onResendAllClick={this.onResendAllClick} onCancelAllClick={this.onCancelAllClick} + onInviteClick={this.onInviteButtonClick} + onStopWarningClick={this.onStopAloneWarningClick} onScrollToBottomClick={this.jumpToLiveTimeline} onResize={this.onChildResize} onVisible={this.onStatusBarVisible} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e542253641..7226b5fcd5 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -609,6 +609,7 @@ "Room": "Room", "Copied!": "Copied!", "Failed to copy": "Failed to copy", + "There's no one else here! Would you like to invite others or stop warning about the empty room?": "There's no one else here! Would you like to invite others or stop warning about the empty room?", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", "Resend all or cancel all now. You can also select individual messages to resend or cancel.": "Resend all or cancel all now. You can also select individual messages to resend or cancel.", From 710c952428fff4682dfb51174d643695c46c6432 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 12 Oct 2017 18:45:04 +0100 Subject: [PATCH 15/35] Make features disabled by default So we can then put them in labs on /develop & others can enable them as desired. --- src/UserSettingsStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 050e28e5b7..1071448b5b 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -193,7 +193,7 @@ export default { isFeatureEnabled: function(featureId: string): boolean { const featuresConfig = SdkConfig.get()['features']; - let sdkConfigValue = 'labs'; + let sdkConfigValue = 'disable'; if (featuresConfig && featuresConfig[featureId] !== undefined) { sdkConfigValue = featuresConfig[featureId]; } From cd64c9bcbbd171c8cf0784d148e174d719837150 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 13 Oct 2017 11:48:44 +0100 Subject: [PATCH 16/35] Don't show labs features by default Previous PR disabled them but still showed the (broken) option --- src/UserSettingsStore.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 1071448b5b..0acc6e5634 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -38,7 +38,8 @@ export default { return FEATURES.filter((f) => { const sdkConfigValue = featuresConfig[f.id]; - if (!['enable', 'disable'].includes(sdkConfigValue)) { + + if (sdkConfigValue === 'labs') { return true; } }).map((f) => { From f94873bd5dad0eed04f7d70786b7bf265a9f57d2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 13 Oct 2017 13:58:24 +0100 Subject: [PATCH 17/35] Honour the (now legacy) enableLabs flag --- src/UserSettingsStore.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 1071448b5b..7bcef8b7be 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -36,9 +36,16 @@ export default { getLabsFeatures() { const featuresConfig = SdkConfig.get()['features'] || {}; + // The old flag: honourned for backwards compat + const enableLabs = SdkConfig.get()['enableLabs']; + return FEATURES.filter((f) => { + if (enableLabs) { + return true; + } + const sdkConfigValue = featuresConfig[f.id]; - if (!['enable', 'disable'].includes(sdkConfigValue)) { + if (sdkConfigValue === 'labs') { return true; } }).map((f) => { From 4e793d4f68ad5c02af02330cef16cedb210b82de Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 13 Oct 2017 14:11:21 +0100 Subject: [PATCH 18/35] skip unnecessary filter --- src/UserSettingsStore.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 7bcef8b7be..0a992dfbad 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -39,16 +39,18 @@ export default { // The old flag: honourned for backwards compat const enableLabs = SdkConfig.get()['enableLabs']; - return FEATURES.filter((f) => { - if (enableLabs) { - return true; - } - - const sdkConfigValue = featuresConfig[f.id]; - if (sdkConfigValue === 'labs') { - return true; - } - }).map((f) => { + let labsFeatures; + if (enableLabs) { + labsFeatures = FEATURES; + } else { + labsFeatures.filter((f) => { + const sdkConfigValue = featuresConfig[f.id]; + if (sdkConfigValue === 'labs') { + return true; + } + }); + } + return labsFeatures.map((f) => { return f.id; }); }, From 5214a867db5902491f90cbb5e34d97447363e5ca Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 13 Oct 2017 14:43:26 +0100 Subject: [PATCH 19/35] Fix labs again --- src/UserSettingsStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 0a992dfbad..d6b32fab5e 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -43,7 +43,7 @@ export default { if (enableLabs) { labsFeatures = FEATURES; } else { - labsFeatures.filter((f) => { + labsFeatures = FEATURES.filter((f) => { const sdkConfigValue = featuresConfig[f.id]; if (sdkConfigValue === 'labs') { return true; From d0759a537bfdde4095ba0955cee8d5d1a7824176 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 13 Oct 2017 16:06:17 +0100 Subject: [PATCH 20/35] Fix the enableLabs flag, again We were showing the options but ignoring them --- src/UserSettingsStore.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index d6b32fab5e..6f689735a7 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -202,7 +202,10 @@ export default { isFeatureEnabled: function(featureId: string): boolean { const featuresConfig = SdkConfig.get()['features']; - let sdkConfigValue = 'disable'; + // The old flag: honourned for backwards compat + const enableLabs = SdkConfig.get()['enableLabs']; + + let sdkConfigValue = enableLabs ? 'labs' : 'disable'; if (featuresConfig && featuresConfig[featureId] !== undefined) { sdkConfigValue = featuresConfig[featureId]; } From e5c8e3e7ad32794ad244f56cbffad9d76546f4b5 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 13 Oct 2017 20:57:15 -0600 Subject: [PATCH 21/35] Add option to unset room avatar Signed-off-by: Travis Ralston --- src/components/views/rooms/RoomHeader.js | 12 ++++++++-- src/components/views/settings/ChangeAvatar.js | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 42cbb90cd9..3d2dee9e64 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -129,6 +129,10 @@ module.exports = React.createClass({ }).done(); }, + onAvatarRemoveClick: function() { + MatrixClientPeg.get().sendStateEvent(this.props.room.roomId, 'm.room.avatar', {url: null}, ''); + }, + onShowRhsClick: function(ev) { dis.dispatch({ action: 'show_right_panel' }); }, @@ -268,11 +272,15 @@ module.exports = React.createClass({
+
+ {_t("Remove +
); } else if (this.props.room || (this.props.oobData && this.props.oobData.name)) { diff --git a/src/components/views/settings/ChangeAvatar.js b/src/components/views/settings/ChangeAvatar.js index b3204ab86e..7d8b1d9534 100644 --- a/src/components/views/settings/ChangeAvatar.js +++ b/src/components/views/settings/ChangeAvatar.js @@ -53,6 +53,10 @@ module.exports = React.createClass({ }; }, + componentWillMount: function() { + MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents); + }, + componentWillReceiveProps: function(newProps) { if (this.avatarSet) { // don't clobber what the user has just set @@ -63,6 +67,24 @@ module.exports = React.createClass({ }); }, + componentWillUnmount: function() { + if (MatrixClientPeg.get()) { + MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); + } + }, + + onRoomStateEvents: function(ev) { + if (ev.getRoomId() !== this.props.room.roomId || ev.getType() !== 'm.room.avatar' + || ev.getSender() !== MatrixClientPeg.get().getUserId()) { + return; + } + + if (!ev.getContent().url) { + this.avatarSet = false; + this.setState({}); // force update + } + }, + setAvatarFromFile: function(file) { let newUrl = null; From 6e7f0d649b17cbd9150d2c37976b9253e6027a10 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 13 Oct 2017 21:13:32 -0600 Subject: [PATCH 22/35] Add option to unset your own avatar Signed-off-by: Travis Ralston --- src/components/structures/UserSettings.js | 11 ++++++++++- src/components/views/settings/ChangeAvatar.js | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index d83434f5a8..d24ff5ad4c 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -423,6 +423,11 @@ module.exports = React.createClass({ }); }, + onAvatarRemoveClick: function() { + MatrixClientPeg.get().setAvatarUrl(null); + this.setState({avatarUrl: null}); // the avatar update will complete async for us + }, + onLogoutClicked: function(ev) { const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); Modal.createTrackedDialog('Logout E2E Export', '', QuestionDialog, { @@ -1318,7 +1323,11 @@ module.exports = React.createClass({
-
+
+ {_t("Remove +
+
diff --git a/src/components/views/settings/ChangeAvatar.js b/src/components/views/settings/ChangeAvatar.js index 7d8b1d9534..a363dc2c60 100644 --- a/src/components/views/settings/ChangeAvatar.js +++ b/src/components/views/settings/ChangeAvatar.js @@ -74,6 +74,10 @@ module.exports = React.createClass({ }, onRoomStateEvents: function(ev) { + if (!this.props.room) { + return; + } + if (ev.getRoomId() !== this.props.room.roomId || ev.getType() !== 'm.room.avatar' || ev.getSender() !== MatrixClientPeg.get().getUserId()) { return; From 97ebd271751b8c61778d7b040f417b416abfb9b9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 13 Oct 2017 23:08:41 -0600 Subject: [PATCH 23/35] Add missing translation Signed-off-by: Travis Ralston --- src/i18n/strings/en_EN.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ed07e503ce..abb5cf40a0 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -632,6 +632,7 @@ "quote": "quote", "bullet": "bullet", "numbullet": "numbullet", + "Remove avatar": "Remove avatar", "%(severalUsers)sjoined %(repeats)s times": "%(severalUsers)sjoined %(repeats)s times", "%(oneUser)sjoined %(repeats)s times": "%(oneUser)sjoined %(repeats)s times", "%(severalUsers)sjoined": "%(severalUsers)sjoined", From a0004399480cffcab14377534ce5f47743bf7b55 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 14 Oct 2017 17:09:30 +0100 Subject: [PATCH 24/35] pass search query to filter fn in _updateList Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/MemberList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 0713a4ae8a..781126c543 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -146,8 +146,8 @@ module.exports = React.createClass({ const newState = { members: this.roomMembers(), }; - newState.filteredJoinedMembers = this._filterMembers(newState.members, 'join'); - newState.filteredInvitedMembers = this._filterMembers(newState.members, 'invite'); + newState.filteredJoinedMembers = this._filterMembers(newState.members, 'join', this.state.searchQuery); + newState.filteredInvitedMembers = this._filterMembers(newState.members, 'invite', this.state.searchQuery); this.setState(newState); }, 500), From 6ad8532bedc5ef881a39770e4ff320f3384b85e0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 14 Oct 2017 17:09:58 +0100 Subject: [PATCH 25/35] lowerCase query so that searching for `Erik` will actually find `Erik`.. Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/MemberList.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 781126c543..4789dda192 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -302,6 +302,7 @@ module.exports = React.createClass({ const m = this.memberDict[userId]; if (query) { + query = query.toLowerCase(); const matchesName = m.name.toLowerCase().indexOf(query) !== -1; const matchesId = m.userId.toLowerCase().indexOf(query) !== -1; @@ -399,7 +400,7 @@ module.exports = React.createClass({
+ placeholder={ _t('Filter room members') } />
); @@ -412,9 +413,9 @@ module.exports = React.createClass({ getChildren={this._getChildrenJoined} getChildCount={this._getChildCountJoined} /> - { invitedSection } + {invitedSection}
); - }, + } }); From e79f9ef0115fcee0d078e8eb88c51d574587ed68 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 14 Oct 2017 17:10:51 +0100 Subject: [PATCH 26/35] === > == Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/MemberList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 4789dda192..f4d81d19f0 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -187,7 +187,7 @@ module.exports = React.createClass({ const user_id = all_user_ids[i]; const m = all_members[user_id]; - if (m.membership == 'join' || m.membership == 'invite') { + if (m.membership === 'join' || m.membership === 'invite') { if ((ConferenceHandler && !ConferenceHandler.isConferenceUser(user_id)) || !ConferenceHandler) { to_display.push(user_id); ++count; @@ -311,7 +311,7 @@ module.exports = React.createClass({ } } - return m.membership == membership; + return m.membership === membership; }); }, From b0b7472901f8840599d86c21cb3fcb99887cc643 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 14 Oct 2017 17:14:17 +0100 Subject: [PATCH 27/35] undo bad merge Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/MemberList.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index f4d81d19f0..04b6089559 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -400,7 +400,7 @@ module.exports = React.createClass({
+ placeholder={_t('Filter room members')} />
); @@ -413,9 +413,9 @@ module.exports = React.createClass({ getChildren={this._getChildrenJoined} getChildCount={this._getChildCountJoined} /> - {invitedSection} + { invitedSection }
); - } + }, }); From c1edc0c32e72307669291370458f343861b3173c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 14 Oct 2017 19:40:45 +0100 Subject: [PATCH 28/35] add option to disable BigEmoji Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/HtmlUtils.js | 7 +++---- src/components/structures/UserSettings.js | 4 ++++ src/components/views/messages/TextualBody.js | 4 +++- src/i18n/strings/en_EN.json | 1 + 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 5620bc06df..b8a1c63dfb 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -385,10 +385,9 @@ class TextHighlighter extends BaseHighlighter { * highlights: optional list of words to highlight, ordered by longest word first * * opts.highlightLink: optional href to add to highlighted words + * opts.disableBigEmoji: optional argument to disable the big emoji class. */ -export function bodyToHtml(content, highlights, opts) { - opts = opts || {}; - +export function bodyToHtml(content, highlights, opts={}) { const isHtml = (content.format === "org.matrix.custom.html"); const body = isHtml ? content.formatted_body : escape(content.body); @@ -418,7 +417,7 @@ export function bodyToHtml(content, highlights, opts) { } let emojiBody = false; - if (bodyHasEmoji) { + if (!opts.disableBigEmoji && bodyHasEmoji) { EMOJI_REGEX.lastIndex = 0; const contentBodyTrimmed = content.body !== undefined ? content.body.trim() : ''; const match = EMOJI_REGEX.exec(contentBodyTrimmed); diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index d83434f5a8..25960f5182 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -114,6 +114,10 @@ const SETTINGS_LABELS = [ id: 'Pill.shouldHidePillAvatar', label: _td('Hide avatars in user and room mentions'), }, + { + id: 'TextualBody.disableBigEmoji', + label: _td('Disable big emoji in chat'), + } /* { id: 'useFixedWidthFont', diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index c0468c38c2..64b23238e5 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -354,7 +354,9 @@ module.exports = React.createClass({ const mxEvent = this.props.mxEvent; const content = mxEvent.getContent(); - let body = HtmlUtils.bodyToHtml(content, this.props.highlights, {}); + let body = HtmlUtils.bodyToHtml(content, this.props.highlights, { + disableBigEmoji: UserSettingsStore.getSyncedSetting('TextualBody.disableBigEmoji', false), + }); if (this.props.highlightLink) { body = { body }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ed07e503ce..6f46fd3257 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -289,6 +289,7 @@ "matrix-react-sdk version:": "matrix-react-sdk version:", "Matrix Apps": "Matrix Apps", "Members only": "Members only", + "Disable big emoji in chat": "Disable big emoji in chat", "Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing", "Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present", "Missing room_id in request": "Missing room_id in request", From c7c28c7ad2e7cbebf805216441d889a85f592bb6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 14 Oct 2017 19:53:08 +0100 Subject: [PATCH 29/35] make linter happy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/UserSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 25960f5182..7e8dbeff76 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -117,7 +117,7 @@ const SETTINGS_LABELS = [ { id: 'TextualBody.disableBigEmoji', label: _td('Disable big emoji in chat'), - } + }, /* { id: 'useFixedWidthFont', From 8d6f0db3e2737a165a29043dfd0b85da15459761 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 14 Oct 2017 22:13:00 +0100 Subject: [PATCH 30/35] be explicit in remove button height --- src/components/structures/UserSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index d24ff5ad4c..3b147104e1 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -1324,7 +1324,7 @@ module.exports = React.createClass({
- {_t("Remove
From 8a641c7173dd39722322eac7abe4028ec639ee14 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 14 Oct 2017 16:40:10 -0600 Subject: [PATCH 31/35] Hide message pinning behind a labs setting Signed-off-by: Travis Ralston --- src/UserSettingsStore.js | 4 ++++ src/components/views/rooms/RoomHeader.js | 3 ++- src/i18n/strings/en_EN.json | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index f9d0a9cda8..b274e6a594 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -30,6 +30,10 @@ const FEATURES = [ id: 'feature_groups', name: _td("Groups"), }, + { + id: 'feature_pinning', + name: _td("Message Pinning"), + }, ]; export default { diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 59d8937aa6..4df0ff738c 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -31,6 +31,7 @@ import linkifyMatrix from '../../../linkify-matrix'; import AccessibleButton from '../elements/AccessibleButton'; import ManageIntegsButton from '../elements/ManageIntegsButton'; import {CancelButton} from './SimpleRoomHeader'; +import UserSettingsStore from "../../../UserSettingsStore"; linkifyMatrix(linkify); @@ -300,7 +301,7 @@ module.exports = React.createClass({ ; } - if (this.props.onPinnedClick) { + if (this.props.onPinnedClick && UserSettingsStore.isFeatureEnabled('feature_pinning')) { pinnedEventsButton = diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 95a8fcdd58..86ad0631e2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -618,6 +618,7 @@ "(~%(count)s results)|other": "(~%(count)s results)", "Cancel": "Cancel", "or": "or", + "Message Pinning": "Message Pinning", "Active call": "Active call", "Monday": "Monday", "Tuesday": "Tuesday", From c55ffe1be7d275182b9c2a9fe38882d7c38b4836 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 14 Oct 2017 16:41:02 -0600 Subject: [PATCH 32/35] Remove duplicate declaration that breaks the build Signed-off-by: Travis Ralston --- src/Notifier.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Notifier.js b/src/Notifier.js index 6f4da260ec..93ef192fe0 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -84,10 +84,6 @@ const Notifier = { msg = ''; } - const avatarUrl = ev.sender ? Avatar.avatarUrlForMember( - ev.sender, 40, 40, 'crop', - ) : null; - const avatarUrl = ev.sender ? Avatar.avatarUrlForMember(ev.sender, 40, 40, 'crop') : null; const notif = plaf.displayNotification(title, msg, avatarUrl, room); From 247e32115f525e15c699ac0810aa40368dc1d8ef Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 15 Oct 2017 01:13:52 +0100 Subject: [PATCH 33/35] bizarrely strict linting :/ --- src/components/views/rooms/PinnedEventTile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js index e4b5b1ff96..514a84cc86 100644 --- a/src/components/views/rooms/PinnedEventTile.js +++ b/src/components/views/rooms/PinnedEventTile.js @@ -80,10 +80,10 @@ module.exports = React.createClass({ - {sender.name} + { sender.name }
); - } + }, }); From 635996c083563fab1ee983e785df3dd395e0ca2f Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 15 Oct 2017 01:19:06 +0100 Subject: [PATCH 34/35] more bizarrely strict linting :/ --- src/components/views/rooms/PinnedEventsPanel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/PinnedEventsPanel.js b/src/components/views/rooms/PinnedEventsPanel.js index 02df29fc72..2e3f6e8390 100644 --- a/src/components/views/rooms/PinnedEventsPanel.js +++ b/src/components/views/rooms/PinnedEventsPanel.js @@ -92,10 +92,10 @@ module.exports = React.createClass({
-

{_t("Pinned Messages")}

+

{ _t("Pinned Messages") }

{ tiles }
); - } + }, }); From 1d75d9e90dafd443558d5518efe612fea314b3ba Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 15 Oct 2017 01:47:11 +0100 Subject: [PATCH 35/35] yet more horrifically strict linting :/ --- src/components/views/rooms/PinnedEventTile.js | 3 ++- .../views/rooms/PinnedEventsPanel.js | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js index 514a84cc86..65b41d946a 100644 --- a/src/components/views/rooms/PinnedEventTile.js +++ b/src/components/views/rooms/PinnedEventTile.js @@ -47,7 +47,8 @@ module.exports = React.createClass({ const index = pinned.indexOf(this.props.mxEvent.getId()); if (index !== -1) { pinned.splice(index, 1); - MatrixClientPeg.get().sendStateEvent(this.props.mxRoom.roomId, 'm.room.pinned_events', {pinned}, '').then(() => { + MatrixClientPeg.get().sendStateEvent(this.props.mxRoom.roomId, 'm.room.pinned_events', {pinned}, '') + .then(() => { if (this.props.onUnpinned) this.props.onUnpinned(); }); } else if (this.props.onUnpinned) this.props.onUnpinned(); diff --git a/src/components/views/rooms/PinnedEventsPanel.js b/src/components/views/rooms/PinnedEventsPanel.js index 2e3f6e8390..deea03f030 100644 --- a/src/components/views/rooms/PinnedEventsPanel.js +++ b/src/components/views/rooms/PinnedEventsPanel.js @@ -47,20 +47,21 @@ module.exports = React.createClass({ const promises = []; const cli = MatrixClientPeg.get(); - pinnedEvents.getContent().pinned.map(eventId => { - promises.push(cli.getEventTimeline(this.props.room.getUnfilteredTimelineSet(), eventId, 0).then(timeline => { - const event = timeline.getEvents().find(e => e.getId() === eventId); + pinnedEvents.getContent().pinned.map((eventId) => { + promises.push(cli.getEventTimeline(this.props.room.getUnfilteredTimelineSet(), eventId, 0).then( + (timeline) => { + const event = timeline.getEvents().find((e) => e.getId() === eventId); return {eventId, timeline, event}; - }).catch(err => { + }).catch((err) => { console.error("Error looking up pinned event " + eventId + " in room " + this.props.room.roomId); console.error(err); return null; // return lack of context to avoid unhandled errors })); }); - Promise.all(promises).then(contexts => { + Promise.all(promises).then((contexts) => { // Filter out the messages before we try to render them - const pinned = contexts.filter(context => { + const pinned = contexts.filter((context) => { if (!context) return false; // no context == not applicable for the room if (context.event.getType() !== "m.room.message") return false; if (context.event.isRedacted()) return false; @@ -77,8 +78,11 @@ module.exports = React.createClass({ return (
{ _t("No pinned messages.") }
); } - return this.state.pinned.map(context => { - return (); + return this.state.pinned.map((context) => { + return (); }); },