From fc935170949dc6a745cc949c9b77217baeb0a32e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 31 May 2017 13:36:19 +0100 Subject: [PATCH 01/25] WIP join/part hiding - Doesn't work with MELS - Doesn't work with read markers - Doesn't work with jumping to events Shelving this for now as I fix some of this mess. --- src/components/structures/MessagePanel.js | 57 +++++++++++++++++++---- src/components/structures/UserSettings.js | 4 ++ src/i18n/strings/en_EN.json | 1 + 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 6b80223e42..25d1ec425f 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -20,6 +20,7 @@ var dis = require("../../dispatcher"); var sdk = require('../../index'); var MatrixClientPeg = require('../../MatrixClientPeg'); +const UserSettingsStore = require('../../UserSettingsStore'); const MILLIS_IN_DAY = 86400000; @@ -235,6 +236,44 @@ module.exports = React.createClass({ return !this._isMounted; }, + // TODO: Implement granular (per-room) hide options + _shouldShowEvent: function(mxEv) { + console.log("_shouldShowEvent " + mxEv.getId()); + const EventTile = sdk.getComponent('rooms.EventTile'); + if (!EventTile.haveTileForEvent(mxEv)) { + return false; // no tile = no show + } + + const isMemberEvent = mxEv.getType() === "m.room.member" && mxEv.getStateKey() !== undefined; + if (!isMemberEvent) { + return true; // bail early: all the checks below concern member events only + } + + // TODO: These checks are done to make sure we're dealing with membership transitions not avatar changes / dupe joins + // These checks are also being done in TextForEvent and should really reside in the JS SDK as a helper function + const membership = mxEv.getContent().membership; + const prevMembership = mxEv.getPrevContent().membership; + if (membership === prevMembership && membership === "join") { + // join -> join : This happens when display names change / avatars are set / genuine dupe joins with no changes. + // Find out which we're dealing with. + if (mxEv.getPrevContent().displayname !== mxEv.getContent().displayname) { + return true; // display name changed + } + if (mxEv.getPrevContent().avatar_url !== mxEv.getContent().avatar_url) { + return true; // avatar url changed + } + // dupe join event, fall through to hide rules + } + + // this only applies to joins/leaves not invites/kicks/bans + const isJoinOrLeave = membership === "join" || (membership === "leave" && mxEv.getStateKey() === mxEv.getSender()); + const hideJoinLeavesGlobally = UserSettingsStore.getSyncedSetting("hideJoinLeaves", false); + if (isJoinOrLeave && hideJoinLeavesGlobally) { + return false; + } + return true; + }, + _getEventTiles: function() { const EventTile = sdk.getComponent('rooms.EventTile'); const DateSeparator = sdk.getComponent('messages.DateSeparator'); @@ -246,7 +285,7 @@ module.exports = React.createClass({ // first figure out which is the last event in the list which we're // actually going to show; this allows us to behave slightly - // differently for the last event in the list. + // differently for the last event in the list. (eg show timestamps) // // we also need to figure out which is the last event we show which isn't // a local echo, to manage the read-marker. @@ -254,7 +293,7 @@ module.exports = React.createClass({ var lastShownNonLocalEchoIndex = -1; for (i = this.props.events.length-1; i >= 0; i--) { var mxEv = this.props.events[i]; - if (!EventTile.haveTileForEvent(mxEv)) { + if (!this._shouldShowEvent(mxEv)) { continue; } @@ -289,16 +328,14 @@ module.exports = React.createClass({ for (i = 0; i < this.props.events.length; i++) { let mxEv = this.props.events[i]; - let wantTile = true; let eventId = mxEv.getId(); let readMarkerInMels = false; - - if (!EventTile.haveTileForEvent(mxEv)) { - wantTile = false; - } - let last = (i == lastShownEventIndex); + if (!this._shouldShowEvent(mxEv)) { + continue; + } + // Wrap consecutive member events in a ListSummary, ignore if redacted if (isMembershipChange(mxEv) && EventTile.haveTileForEvent(mxEv) && @@ -346,7 +383,7 @@ module.exports = React.createClass({ // of MemberEventListSummary, render each member event as if the previous // one was itself. This way, the timestamp of the previous event === the // timestamp of the current event, and no DateSeperator is inserted. - let ret = this._getTilesForEvent(e, e); + let ret = this._getTilesForEvent(e, e, last); prevEvent = e; return ret; } @@ -373,7 +410,7 @@ module.exports = React.createClass({ continue; } - if (wantTile) { + if (EventTile.haveTileForEvent(mxEv)) { // make sure we unpack the array returned by _getTilesForEvent, // otherwise react will auto-generate keys and we will end up // replacing all of the DOM elements every time we paginate. diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 101ec2c378..968406a4ee 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -79,6 +79,10 @@ const SETTINGS_LABELS = [ id: 'showTwelveHourTimestamps', label: 'Show timestamps in 12 hour format (e.g. 2:30pm)', }, + { + id: 'hideJoinLeaves', + label: 'Hide join/leave messages (invites/kicks/bans unaffected)', + } /* { id: 'useCompactLayout', diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 36b9486cd0..a5c5342296 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -288,6 +288,7 @@ "Guests cannot join this room even if explicitly invited.": "Guests cannot join this room even if explicitly invited.", "had": "had", "Hangup": "Hangup", + "Hide join/leave messages (invites/kicks/bans unaffected)": "Hide join/leave messages (invites/kicks/bans unaffected)", "Hide read receipts": "Hide read receipts", "Hide Text Formatting Toolbar": "Hide Text Formatting Toolbar", "Historical": "Historical", From a0a4fe62d57c314871e5e85f9b8ce705296c9bd2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 15 Jun 2017 19:53:34 +0100 Subject: [PATCH 02/25] make hide joins/parts work for MELS and highlighted/permalink event Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/MessagePanel.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 3c0e486e22..a97041a712 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -241,12 +241,15 @@ module.exports = React.createClass({ // TODO: Implement granular (per-room) hide options _shouldShowEvent: function(mxEv) { - console.log("_shouldShowEvent " + mxEv.getId()); + console.log("_shouldShowEvent ", mxEv.getId(), mxEv); const EventTile = sdk.getComponent('rooms.EventTile'); if (!EventTile.haveTileForEvent(mxEv)) { return false; // no tile = no show } + // Always show highlighted event + if (this.props.highlightedEventId === mxEv.getId()) return true; + const isMemberEvent = mxEv.getType() === "m.room.member" && mxEv.getStateKey() !== undefined; if (!isMemberEvent) { return true; // bail early: all the checks below concern member events only @@ -365,7 +368,7 @@ module.exports = React.createClass({ let collapsedMxEv = this.props.events[i + 1]; // Ignore redacted member events - if (!EventTile.haveTileForEvent(collapsedMxEv)) { + if (!EventTile.haveTileForEvent(collapsedMxEv) || !this._shouldShowEvent(collapsedMxEv)) { continue; } From 4b34a2b169f2c2c3e572c63fbc734a4f4bc60ee0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 15 Jun 2017 19:57:48 +0100 Subject: [PATCH 03/25] modernize imports Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/MessagePanel.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index a97041a712..704ae228be 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -var React = require('react'); -var ReactDOM = require("react-dom"); -var dis = require("../../dispatcher"); -var sdk = require('../../index'); +import React from 'react'; +import ReactDOM from 'react-dom'; +import dis from "../../dispatcher"; +import sdk from '../../index'; -var MatrixClientPeg = require('../../MatrixClientPeg'); -const UserSettingsStore = require('../../UserSettingsStore'); +import MatrixClientPeg from '../../MatrixClientPeg'; +import UserSettingsStore from '../../UserSettingsStore'; const MILLIS_IN_DAY = 86400000; From c53fb084539630881245c0f7de3c0c29d1fbdf8c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 15 Jun 2017 20:02:17 +0100 Subject: [PATCH 04/25] pass user settings from above Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/MessagePanel.js | 6 ++++-- src/components/structures/TimelinePanel.js | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 704ae228be..8b9ada14e7 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -20,7 +20,6 @@ import dis from "../../dispatcher"; import sdk from '../../index'; import MatrixClientPeg from '../../MatrixClientPeg'; -import UserSettingsStore from '../../UserSettingsStore'; const MILLIS_IN_DAY = 86400000; @@ -94,6 +93,9 @@ module.exports = React.createClass({ // hide redacted events as per old behaviour hideRedactions: React.PropTypes.bool, + + // hide membership joins and parts + hideJoinLeaves: React.PropTypes.bool, }, componentWillMount: function() { @@ -273,7 +275,7 @@ module.exports = React.createClass({ // this only applies to joins/leaves not invites/kicks/bans const isJoinOrLeave = membership === "join" || (membership === "leave" && mxEv.getStateKey() === mxEv.getSender()); - const hideJoinLeavesGlobally = UserSettingsStore.getSyncedSetting("hideJoinLeaves", false); + const hideJoinLeavesGlobally = this.props.hideJoinLeaves; if (isJoinOrLeave && hideJoinLeavesGlobally) { return false; } diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 928e2405aa..9642887fd5 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -184,6 +184,9 @@ var TimelinePanel = React.createClass({ // hide redacted events as per old behaviour hideRedactions: syncedSettings.hideRedactions, + + // hide membership joins and leaves + hideJoinLeaves: syncedSettings.hideJoinLeaves, }; }, @@ -1122,6 +1125,7 @@ var TimelinePanel = React.createClass({ return (