From 52cdf609540f1883abfec9bb3998f330fa2e5bf0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 26 May 2018 20:27:48 -0600 Subject: [PATCH 1/2] Add options to pin unread/mentioned rooms to the top of the room list Fixes https://github.com/vector-im/riot-web/issues/6604 Fixes https://github.com/vector-im/riot-web/issues/732 Fixes https://github.com/vector-im/riot-web/issues/1104 Signed-off-by: Travis Ralston --- src/components/structures/RoomSubList.js | 21 ++++++++++++++++++++- src/components/structures/UserSettings.js | 2 ++ src/i18n/strings/en_EN.json | 2 ++ src/settings/Settings.js | 10 ++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index fb82ee067b..b3c9d5f1b6 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -17,6 +17,8 @@ limitations under the License. 'use strict'; +import SettingsStore from "../../settings/SettingsStore"; + var React = require('react'); var ReactDOM = require('react-dom'); var classNames = require('classnames'); @@ -98,8 +100,10 @@ var RoomSubList = React.createClass({ componentWillReceiveProps: function(newProps) { // order the room list appropriately before we re-render //if (debug) console.log("received new props, list = " + newProps.list); + const filteredRooms = this.applySearchFilter(newProps.list, newProps.searchFilter); + const sortedRooms = newProps.order === "recent" ? this.applyPinnedTileRules(filteredRooms) : filteredRooms; this.setState({ - sortedList: this.applySearchFilter(newProps.list, newProps.searchFilter), + sortedList: sortedRooms, }); }, @@ -110,6 +114,21 @@ var RoomSubList = React.createClass({ }); }, + applyPinnedTileRules: function(list) { + const pinUnread = SettingsStore.getValue("pinUnreadRooms"); + const pinMentioned = SettingsStore.getValue("pinMentionedRooms"); + if (!pinUnread && !pinMentioned) { + return list; // Nothing to sort + } + + const mentioned = !pinMentioned ? [] : list.filter(room => room.getUnreadNotificationCount("highlight") > 0); + const unread = !pinUnread ? [] : list.filter(room => Unread.doesRoomHaveUnreadMessages(room)); + + return mentioned + .concat(unread.filter(room => !mentioned.find(other => other === room))) + .concat(list.filter(room => !unread.find(other => other === room))); + }, + // The header is collapsable if it is hidden or not stuck // The dataset elements are added in the RoomList _initAndPositionStickyHeaders method isCollapsableOnClick: function() { diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index c8ce79905d..3695e0cf9f 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -81,6 +81,8 @@ const SIMPLE_SETTINGS = [ { id: "VideoView.flipVideoHorizontally" }, { id: "TagPanel.disableTagPanel" }, { id: "enableWidgetScreenshots" }, + { id: "pinMentionedRooms" }, + { id: "pinUnreadRooms" }, ]; // These settings must be defined in SettingsStore diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index bf9e395bee..1b378c34d3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -218,6 +218,8 @@ "Enable URL previews for this room (only affects you)": "Enable URL previews for this room (only affects you)", "Enable URL previews by default for participants in this room": "Enable URL previews by default for participants in this room", "Room Colour": "Room Colour", + "Pin unread rooms to the top of the room list": "Pin unread rooms to the top of the room list", + "Pin rooms I'm mentioned in to the top of the room list": "Pin rooms I'm mentioned in to the top of the room list", "Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index b1bc4161fd..1665a59dfd 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -269,6 +269,16 @@ export const SETTINGS = { default: true, controller: new AudioNotificationsEnabledController(), }, + "pinMentionedRooms": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td("Pin rooms I'm mentioned in to the top of the room list"), + default: false, + }, + "pinUnreadRooms": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td("Pin unread rooms to the top of the room list"), + default: false, + }, "enableWidgetScreenshots": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Enable widget screenshots on supported widgets'), From 3d8f0adf56d0bd0607d6ad553c47cf915a87cf95 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 12 Oct 2018 14:35:54 -0600 Subject: [PATCH 2/2] Move pinned rooms check to the RoomListStore --- src/components/structures/RoomSubList.js | 20 +------------------ src/stores/RoomListStore.js | 25 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 6aaa875e48..d798070659 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -19,7 +19,6 @@ limitations under the License. import React from 'react'; import classNames from 'classnames'; import sdk from '../../index'; -import SettingsStore from "../../settings/SettingsStore"; import { Droppable } from 'react-beautiful-dnd'; import { _t } from '../../languageHandler'; import dis from '../../dispatcher'; @@ -100,10 +99,8 @@ const RoomSubList = React.createClass({ componentWillReceiveProps: function(newProps) { // order the room list appropriately before we re-render //if (debug) console.log("received new props, list = " + newProps.list); - const filteredRooms = this.applySearchFilter(newProps.list, newProps.searchFilter); - const sortedRooms = newProps.order === "recent" ? this.applyPinnedTileRules(filteredRooms) : filteredRooms; this.setState({ - sortedList: sortedRooms, + sortedList: this.applySearchFilter(newProps.list, newProps.searchFilter), }); }, @@ -116,21 +113,6 @@ const RoomSubList = React.createClass({ (filter[0] === '#' && room.getAliases().some((alias) => alias.toLowerCase().startsWith(lcFilter)))); }, - applyPinnedTileRules: function(list) { - const pinUnread = SettingsStore.getValue("pinUnreadRooms"); - const pinMentioned = SettingsStore.getValue("pinMentionedRooms"); - if (!pinUnread && !pinMentioned) { - return list; // Nothing to sort - } - - const mentioned = !pinMentioned ? [] : list.filter(room => room.getUnreadNotificationCount("highlight") > 0); - const unread = !pinUnread ? [] : list.filter(room => Unread.doesRoomHaveUnreadMessages(room)); - - return mentioned - .concat(unread.filter(room => !mentioned.find(other => other === room))) - .concat(list.filter(room => !unread.find(other => other === room))); - }, - // The header is collapsable if it is hidden or not stuck // The dataset elements are added in the RoomList _initAndPositionStickyHeaders method isCollapsableOnClick: function() { diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 67c0c13be7..4c3e10e77f 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -17,6 +17,7 @@ import {Store} from 'flux/utils'; import dis from '../dispatcher'; import DMRoomMap from '../utils/DMRoomMap'; import Unread from '../Unread'; +import SettingsStore from "../settings/SettingsStore"; /** * A class for storing application state for categorising rooms in @@ -263,6 +264,30 @@ class RoomListStore extends Store { } _recentsComparator(roomA, roomB) { + const pinUnread = SettingsStore.getValue("pinUnreadRooms"); + const pinMentioned = SettingsStore.getValue("pinMentionedRooms"); + + // We try and set the ordering to be Mentioned > Unread > Recent + // assuming the user has the right settings, of course + + if (pinMentioned) { + const mentionsA = roomA.getUnreadNotificationCount("highlight") > 0; + const mentionsB = roomB.getUnreadNotificationCount("highlight") > 0; + if (mentionsA && !mentionsB) return -1; + if (!mentionsA && mentionsB) return 1; + if (mentionsA && mentionsB) return 0; + // If neither have mentions, fall through to remaining checks + } + + if (pinUnread) { + const unreadA = Unread.doesRoomHaveUnreadMessages(roomA); + const unreadB = Unread.doesRoomHaveUnreadMessages(roomB); + if (unreadA && !unreadB) return -1; + if (!unreadA && unreadB) return 1; + if (unreadA && unreadB) return 0; + // If neither have unread messages, fall through to remaining checks + } + // XXX: We could use a cache here and update it when we see new // events that trigger a reorder return this._tsOfNewestEvent(roomB) - this._tsOfNewestEvent(roomA);