diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 498dfb8818..28e56e6e32 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -6,7 +6,6 @@ src/autocomplete/Autocompleter.js src/autocomplete/Components.js src/autocomplete/DuckDuckGoProvider.js src/autocomplete/EmojiProvider.js -src/autocomplete/RoomProvider.js src/autocomplete/UserProvider.js src/CallHandler.js src/component-index.js @@ -35,7 +34,6 @@ src/components/views/create_room/RoomAlias.js src/components/views/dialogs/ChatCreateOrReuseDialog.js src/components/views/dialogs/DeactivateAccountDialog.js src/components/views/dialogs/InteractiveAuthDialog.js -src/components/views/dialogs/SetMxIdDialog.js src/components/views/dialogs/UnknownDeviceDialog.js src/components/views/elements/AccessibleButton.js src/components/views/elements/ActionButton.js @@ -89,7 +87,6 @@ src/components/views/rooms/MemberList.js src/components/views/rooms/MemberTile.js src/components/views/rooms/MessageComposer.js src/components/views/rooms/MessageComposerInput.js -src/components/views/rooms/MessageComposerInputOld.js src/components/views/rooms/PresenceLabel.js src/components/views/rooms/ReadReceiptMarker.js src/components/views/rooms/RoomList.js @@ -100,7 +97,6 @@ src/components/views/rooms/RoomTile.js src/components/views/rooms/RoomTopicEditor.js src/components/views/rooms/SearchableEntityList.js src/components/views/rooms/SearchResultTile.js -src/components/views/rooms/TabCompleteBar.js src/components/views/rooms/TopUnreadMessagesBar.js src/components/views/rooms/UserTile.js src/components/views/settings/AddPhoneNumber.js @@ -128,8 +124,6 @@ src/Roles.js src/Rooms.js src/ScalarAuthClient.js src/ScalarMessaging.js -src/TabComplete.js -src/TabCompleteEntries.js src/TextForEvent.js src/Tinter.js src/UiEffects.js @@ -142,7 +136,7 @@ src/utils/Receipt.js src/Velociraptor.js src/VelocityBounce.js src/WhoIsTyping.js -src/wrappers/WithMatrixClient.js +src/wrappers/withMatrixClient.js test/all-tests.js test/components/structures/login/Registration-test.js test/components/structures/MessagePanel-test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bc4bbcfce..b5e596144e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,76 @@ +Changes in [0.10.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.10.2) (2017-08-24) +===================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.10.1...v0.10.2) + + * Force update on timelinepanel when event decrypted + [\#1334](https://github.com/matrix-org/matrix-react-sdk/pull/1334) + * Dispatch incoming_call synchronously + [\#1337](https://github.com/matrix-org/matrix-react-sdk/pull/1337) + * Fix React crying on machines without internet due to return undefined + [\#1335](https://github.com/matrix-org/matrix-react-sdk/pull/1335) + * Catch the promise rejection if scalar fails + [\#1333](https://github.com/matrix-org/matrix-react-sdk/pull/1333) + * Update from Weblate. + [\#1329](https://github.com/matrix-org/matrix-react-sdk/pull/1329) + +Changes in [0.10.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.10.1) (2017-08-23) +===================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.10.1-rc.1...v0.10.1) + + * [No changes] + +Changes in [0.10.1-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.10.1-rc.1) (2017-08-22) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.10.0-rc.2...v0.10.1-rc.1) + + * Matthew/multiple widgets + [\#1327](https://github.com/matrix-org/matrix-react-sdk/pull/1327) + * Fix proptypes on UserPickerDialog + [\#1326](https://github.com/matrix-org/matrix-react-sdk/pull/1326) + * AppsDrawer: Remove unnecessary bind + [\#1325](https://github.com/matrix-org/matrix-react-sdk/pull/1325) + * Position add app widget link + [\#1322](https://github.com/matrix-org/matrix-react-sdk/pull/1322) + * Remove app tile beta tag. + [\#1323](https://github.com/matrix-org/matrix-react-sdk/pull/1323) + * Add missing translation. + [\#1324](https://github.com/matrix-org/matrix-react-sdk/pull/1324) + * Note that apps are not E2EE + [\#1319](https://github.com/matrix-org/matrix-react-sdk/pull/1319) + * Only render appTile body (including warnings) if drawer shown. + [\#1321](https://github.com/matrix-org/matrix-react-sdk/pull/1321) + * Timeline improvements + [\#1320](https://github.com/matrix-org/matrix-react-sdk/pull/1320) + * Add a space between widget name and "widget" in widget event tiles + [\#1318](https://github.com/matrix-org/matrix-react-sdk/pull/1318) + * Move manage integrations button from settings page to room header as a + stand-alone component + [\#1286](https://github.com/matrix-org/matrix-react-sdk/pull/1286) + * Don't apply case logic to app names + [\#1316](https://github.com/matrix-org/matrix-react-sdk/pull/1316) + * Stop integ manager opening on every room switch + [\#1315](https://github.com/matrix-org/matrix-react-sdk/pull/1315) + * Add behaviour to toggle app draw on app tile header click + [\#1313](https://github.com/matrix-org/matrix-react-sdk/pull/1313) + * Change OOO so that MELS generation will continue over hidden events + [\#1308](https://github.com/matrix-org/matrix-react-sdk/pull/1308) + * Implement TextualEvent tiles for im.vector.modular.widgets + [\#1312](https://github.com/matrix-org/matrix-react-sdk/pull/1312) + * Don't show widget security warning to the person that added it to the room + [\#1314](https://github.com/matrix-org/matrix-react-sdk/pull/1314) + * remove unused strings introduced by string change + [\#1311](https://github.com/matrix-org/matrix-react-sdk/pull/1311) + * hotfix bad fn signature regression + [\#1310](https://github.com/matrix-org/matrix-react-sdk/pull/1310) + * Show a dialog if the maximum number of widgets allowed has been reached. + [\#1291](https://github.com/matrix-org/matrix-react-sdk/pull/1291) + * Fix Robot translation + [\#1309](https://github.com/matrix-org/matrix-react-sdk/pull/1309) + * Refactor ChatInviteDialog to be UserPickerDialog + [\#1300](https://github.com/matrix-org/matrix-react-sdk/pull/1300) + * Update Link to Translation status + [\#1302](https://github.com/matrix-org/matrix-react-sdk/pull/1302) + Changes in [0.9.7](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.9.7) (2017-06-22) =================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.9.6...v0.9.7) diff --git a/package.json b/package.json index 661db4b6bc..cc352cb8db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.9.7", + "version": "0.10.2", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -66,7 +66,7 @@ "isomorphic-fetch": "^2.2.1", "linkifyjs": "^2.1.3", "lodash": "^4.13.1", - "matrix-js-sdk": "matrix-org/matrix-js-sdk#develop", + "matrix-js-sdk": "0.8.2", "optimist": "^0.6.1", "prop-types": "^15.5.8", "react": "^15.4.0", diff --git a/src/Notifier.js b/src/Notifier.js index 1bb435307d..155564dcdf 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -1,6 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +Copyright 2017 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -33,9 +34,16 @@ import Modal from './Modal'; * } */ +const MAX_PENDING_ENCRYPTED = 20; + const Notifier = { notifsByRoom: {}, + // A list of event IDs that we've received but need to wait until + // they're decrypted until we decide whether to notify for them + // or not + pendingEncryptedEventIds: [], + notificationMessageForEvent: function(ev) { return TextForEvent.textForEvent(ev); }, @@ -89,17 +97,18 @@ const Notifier = { _playAudioNotification: function(ev, room) { const e = document.getElementById("messageAudio"); if (e) { - e.load(); e.play(); } }, start: function() { - this.boundOnRoomTimeline = this.onRoomTimeline.bind(this); + this.boundOnEvent = this.onEvent.bind(this); this.boundOnSyncStateChange = this.onSyncStateChange.bind(this); this.boundOnRoomReceipt = this.onRoomReceipt.bind(this); - MatrixClientPeg.get().on('Room.timeline', this.boundOnRoomTimeline); + this.boundOnEventDecrypted = this.onEventDecrypted.bind(this); + MatrixClientPeg.get().on('event', this.boundOnEvent); MatrixClientPeg.get().on('Room.receipt', this.boundOnRoomReceipt); + MatrixClientPeg.get().on('Event.decrypted', this.boundOnEventDecrypted); MatrixClientPeg.get().on("sync", this.boundOnSyncStateChange); this.toolbarHidden = false; this.isSyncing = false; @@ -107,8 +116,9 @@ const Notifier = { stop: function() { if (MatrixClientPeg.get() && this.boundOnRoomTimeline) { - MatrixClientPeg.get().removeListener('Room.timeline', this.boundOnRoomTimeline); + MatrixClientPeg.get().removeListener('Event', this.boundOnEvent); MatrixClientPeg.get().removeListener('Room.receipt', this.boundOnRoomReceipt); + MatrixClientPeg.get().removeListener('Event.decrypted', this.boundOnEventDecrypted); MatrixClientPeg.get().removeListener('sync', this.boundOnSyncStateChange); } this.isSyncing = false; @@ -237,23 +247,30 @@ const Notifier = { } }, - onRoomTimeline: function(ev, room, toStartOfTimeline, removed, data) { - if (toStartOfTimeline) return; - if (!room) return; + onEvent: function(ev) { if (!this.isSyncing) return; // don't alert for any messages initially if (ev.sender && ev.sender.userId === MatrixClientPeg.get().credentials.userId) return; - if (data.timeline.getTimelineSet() !== room.getUnfilteredTimelineSet()) return; - const actions = MatrixClientPeg.get().getPushActionsForEvent(ev); - if (actions && actions.notify) { - if (this.isEnabled()) { - this._displayPopupNotification(ev, room); - } - if (actions.tweaks.sound && this.isAudioEnabled()) { - PlatformPeg.get().loudNotification(ev, room); - this._playAudioNotification(ev, room); + // If it's an encrypted event and the type is still 'm.room.encrypted', + // it hasn't yet been decrypted, so wait until it is. + if (ev.isBeingDecrypted() || ev.isDecryptionFailure()) { + this.pendingEncryptedEventIds.push(ev.getId()); + // don't let the list fill up indefinitely + while (this.pendingEncryptedEventIds.length > MAX_PENDING_ENCRYPTED) { + this.pendingEncryptedEventIds.shift(); } + return; } + + this._evaluateEvent(ev); + }, + + onEventDecrypted: function(ev) { + const idx = this.pendingEncryptedEventIds.indexOf(ev.getId()); + if (idx === -1) return; + + this.pendingEncryptedEventIds.splice(idx, 1); + this._evaluateEvent(ev); }, onRoomReceipt: function(ev, room) { @@ -273,6 +290,20 @@ const Notifier = { delete this.notifsByRoom[room.roomId]; } }, + + _evaluateEvent: function(ev) { + const room = MatrixClientPeg.get().getRoom(ev.getRoomId()); + const actions = MatrixClientPeg.get().getPushActionsForEvent(ev); + if (actions && actions.notify) { + if (this.isEnabled()) { + this._displayPopupNotification(ev, room); + } + if (actions.tweaks.sound && this.isAudioEnabled()) { + PlatformPeg.get().loudNotification(ev, room); + this._playAudioNotification(ev, room); + } + } + } }; if (!global.mxNotifier) { diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 95066912ac..36b8b538a7 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -244,15 +244,16 @@ function textForPowerEvent(event) { } return _t('%(senderName)s changed the power level of %(powerLevelDiffText)s.', { senderName: senderName, - powerLevelDiffText: diff.join(", ") + powerLevelDiffText: diff.join(", "), }); } function textForWidgetEvent(event) { - const senderName = event.sender ? event.sender.name : event.getSender(); - const previousContent = event.getPrevContent() || {}; + const senderName = event.getSender(); + const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent(); const {name, type, url} = event.getContent() || {}; - let widgetName = name || previousContent.name || type || previousContent.type || ''; + + let widgetName = name || prevName || type || prevType || ''; // Apply sentence case to widget name if (widgetName && widgetName.length > 0) { widgetName = widgetName[0].toUpperCase() + widgetName.slice(1) + ' '; @@ -261,9 +262,15 @@ function textForWidgetEvent(event) { // If the widget was removed, its content should be {}, but this is sufficiently // equivalent to that condition. if (url) { - return _t('%(widgetName)s widget added by %(senderName)s', { - widgetName, senderName, - }); + if (prevUrl) { + return _t('%(widgetName)s widget modified by %(senderName)s', { + widgetName, senderName, + }); + } else { + return _t('%(widgetName)s widget added by %(senderName)s', { + widgetName, senderName, + }); + } } else { return _t('%(widgetName)s widget removed by %(senderName)s', { widgetName, senderName, diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 4d671d9cad..bbe345933e 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1068,10 +1068,13 @@ module.exports = React.createClass({ self.setState({ready: true}); }); cli.on('Call.incoming', function(call) { + // we dispatch this synchronously to make sure that the event + // handlers on the call are set up immediately (so that if + // we get an immediate hangup, we don't get a stuck call) dis.dispatch({ action: 'incoming_call', call: call, - }); + }, true); }); cli.on('Session.logged_out', function(call) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 460ed43e82..e5884973c6 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -65,7 +65,7 @@ module.exports = React.createClass({ suppressFirstDateSeparator: React.PropTypes.bool, // whether to show read receipts - manageReadReceipts: React.PropTypes.bool, + showReadReceipts: React.PropTypes.bool, // true if updates to the event list should cause the scroll panel to // scroll down when we are at the bottom of the window. See ScrollPanel @@ -491,7 +491,7 @@ module.exports = React.createClass({ var scrollToken = mxEv.status ? undefined : eventId; var readReceipts; - if (this.props.manageReadReceipts) { + if (this.props.showReadReceipts) { readReceipts = this._getReadReceiptsForEvent(mxEv); } ret.push( diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index f825d1efbb..87bed1ed08 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -20,6 +20,8 @@ limitations under the License. // - Drag and drop // - File uploading - uploadFile() +import shouldHideEvent from "../../shouldHideEvent"; + var React = require("react"); var ReactDOM = require("react-dom"); import Promise from 'bluebird'; @@ -143,6 +145,8 @@ module.exports = React.createClass({ MatrixClientPeg.get().on("RoomMember.membership", this.onRoomMemberMembership); MatrixClientPeg.get().on("accountData", this.onAccountData); + this._syncedSettings = UserSettingsStore.getSyncedSettings(); + // Start listening for RoomViewStore updates this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); this._onRoomViewStoreUpdate(true); @@ -497,8 +501,7 @@ module.exports = React.createClass({ // update unread count when scrolled up if (!this.state.searchResults && this.state.atEndOfLiveTimeline) { // no change - } - else { + } else if (!shouldHideEvent(ev, this._syncedSettings)) { this.setState((state, props) => { return {numUnreadMessages: state.numUnreadMessages + 1}; }); @@ -1716,7 +1719,8 @@ module.exports = React.createClass({ var messagePanel = (