Skip to content
This repository was archived by the owner on May 18, 2025. It is now read-only.

Commit 173669b

Browse files
committedDec 6, 2018
Show the number of unread notifications above the bell on the right
Fixes element-hq/element-web#3383 This achieves the result by counting up the number of highlights across all rooms and setting that as the badge above the icon. If there are no highlights, nothing is displayed. The red highlight on the bell is done by abusing how the Tinter works: because it has access to the properties of the SVG that we'd need to override it, we give it a collection of colors it should use instead of the theme/tint it is trying to apply. This results in the Tinter using our warning color instead of whatever it was going to apply. The RightPanel now listens for events to update the count too, otherwise when the user receives a ping they'd have to switch rooms to see the change.
1 parent 31b7a0d commit 173669b

File tree

4 files changed

+40
-8
lines changed

4 files changed

+40
-8
lines changed
 

‎res/css/structures/_RightPanel.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ limitations under the License.
5555
padding-bottom: 3px;
5656
}
5757

58+
.mx_RightPanel_headerButton_badgeHighlight .mx_RightPanel_headerButton_badge {
59+
color: $warning-color;
60+
}
61+
5862
.mx_RightPanel_headerButton_highlight {
5963
width: 25px;
6064
height: 5px;

‎src/Tinter.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ class Tinter {
390390
// XXX: we could just move this all into TintableSvg, but as it's so similar
391391
// to the CSS fixup stuff in Tinter (just that the fixups are stored in TintableSvg)
392392
// keeping it here for now.
393-
calcSvgFixups(svgs) {
393+
calcSvgFixups(svgs, forceColors) {
394394
// go through manually fixing up SVG colours.
395395
// we could do this by stylesheets, but keeping the stylesheets
396396
// updated would be a PITA, so just brute-force search for the
@@ -418,13 +418,14 @@ class Tinter {
418418
const tag = tags[j];
419419
for (let k = 0; k < this.svgAttrs.length; k++) {
420420
const attr = this.svgAttrs[k];
421-
for (let l = 0; l < this.keyHex.length; l++) {
421+
for (let m = 0; m < this.keyHex.length; m++) { // dev note: don't use L please.
422422
if (tag.getAttribute(attr) &&
423-
tag.getAttribute(attr).toUpperCase() === this.keyHex[l]) {
423+
tag.getAttribute(attr).toUpperCase() === this.keyHex[m]) {
424424
fixups.push({
425425
node: tag,
426426
attr: attr,
427-
index: l,
427+
index: m,
428+
forceColors: forceColors,
428429
});
429430
}
430431
}
@@ -440,7 +441,9 @@ class Tinter {
440441
if (DEBUG) console.log("applySvgFixups start for " + fixups);
441442
for (let i = 0; i < fixups.length; i++) {
442443
const svgFixup = fixups[i];
443-
svgFixup.node.setAttribute(svgFixup.attr, this.colors[svgFixup.index]);
444+
const forcedColor = svgFixup.forceColors ? svgFixup.forceColors[svgFixup.index] : null;
445+
if (forcedColor) console.log(forcedColor);
446+
svgFixup.node.setAttribute(svgFixup.attr, forcedColor ? forcedColor : this.colors[svgFixup.index]);
444447
}
445448
if (DEBUG) console.log("applySvgFixups end");
446449
}

‎src/components/structures/RightPanel.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddres
3030
import GroupStore from '../../stores/GroupStore';
3131

3232
import { formatCount } from '../../utils/FormattingUtils';
33+
import MatrixClientPeg from "../../MatrixClientPeg";
3334

3435
class HeaderButton extends React.Component {
3536
constructor() {
@@ -49,17 +50,26 @@ class HeaderButton extends React.Component {
4950
const TintableSvg = sdk.getComponent("elements.TintableSvg");
5051
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
5152

53+
// XXX: We really shouldn't be hardcoding colors here, but the way TintableSvg
54+
// works kinda prevents us from using normal CSS tactics. We use $warning-color
55+
// here.
56+
// Note: This array gets passed along to the Tinter's forceColors eventually.
57+
const tintableColors = this.props.badgeHighlight ? ["#ff0064"] : null;
58+
59+
const classNames = ["mx_RightPanel_headerButton"];
60+
if (this.props.badgeHighlight) classNames.push("mx_RightPanel_headerButton_badgeHighlight");
61+
5262
return <AccessibleButton
5363
aria-label={this.props.title}
5464
aria-expanded={this.props.isHighlighted}
5565
title={this.props.title}
56-
className="mx_RightPanel_headerButton"
66+
className={classNames.join(" ")}
5767
onClick={this.onClick} >
5868

5969
<div className="mx_RightPanel_headerButton_badge">
6070
{ this.props.badge ? this.props.badge : <span>&nbsp;</span> }
6171
</div>
62-
<TintableSvg src={this.props.iconSrc} width="25" height="25" />
72+
<TintableSvg src={this.props.iconSrc} width="25" height="25" forceColors={tintableColors} />
6373
{ this.props.isHighlighted ? <div className="mx_RightPanel_headerButton_highlight" /> : <div /> }
6474

6575
</AccessibleButton>;
@@ -76,6 +86,7 @@ HeaderButton.propTypes = {
7686

7787
// The badge to display above the icon
7888
badge: PropTypes.node,
89+
badgeHighlight: PropTypes.bool,
7990
// The parameters to track the click event
8091
analytics: PropTypes.arrayOf(PropTypes.string).isRequired,
8192

@@ -113,6 +124,7 @@ module.exports = React.createClass({
113124
this.dispatcherRef = dis.register(this.onAction);
114125
const cli = this.context.matrixClient;
115126
cli.on("RoomState.members", this.onRoomStateMember);
127+
cli.on("Room.notificationCounts", this.onRoomNotifications);
116128
this._initGroupStore(this.props.groupId);
117129
},
118130

@@ -200,6 +212,10 @@ module.exports = React.createClass({
200212
}
201213
},
202214

215+
onRoomNotifications: function(room, type, count) {
216+
if (type === "highlight") this.forceUpdate();
217+
},
218+
203219
_delayedUpdate: new RateLimitedFunc(function() {
204220
this.forceUpdate(); // eslint-disable-line babel/no-invalid-this
205221
}, 500),
@@ -308,6 +324,13 @@ module.exports = React.createClass({
308324

309325
let headerButtons = [];
310326
if (this.props.roomId) {
327+
let notifCountBadge;
328+
let notifCount = 0;
329+
MatrixClientPeg.get().getRooms().forEach(r => notifCount += (r.getUnreadNotificationCount('highlight') || 0));
330+
if (notifCount > 0) {
331+
notifCountBadge = <div title={_t("%counts Notifications")}>{ formatCount(notifCount) }</div>;
332+
}
333+
311334
headerButtons = [
312335
<HeaderButton key="_membersButton" title={membersTitle} iconSrc="img/icons-people.svg"
313336
isHighlighted={[this.Phase.RoomMemberList, this.Phase.RoomMemberInfo].includes(this.state.phase)}
@@ -323,6 +346,7 @@ module.exports = React.createClass({
323346
<HeaderButton key="_notifsButton" title={_t('Notifications')} iconSrc="img/icons-notifications.svg"
324347
isHighlighted={this.state.phase === this.Phase.NotificationPanel}
325348
clickPhase={this.Phase.NotificationPanel}
349+
badge={notifCountBadge} badgeHighlight={notifCount > 0}
326350
analytics={['Right Panel', 'Notification List Button', 'click']}
327351
/>,
328352
];

‎src/components/views/elements/TintableSvg.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var TintableSvg = React.createClass({
2929
width: PropTypes.string.isRequired,
3030
height: PropTypes.string.isRequired,
3131
className: PropTypes.string,
32+
forceColors: PropTypes.arrayOf(PropTypes.string),
3233
},
3334

3435
statics: {
@@ -58,7 +59,7 @@ var TintableSvg = React.createClass({
5859

5960
onLoad: function(event) {
6061
// console.log("TintableSvg.onLoad for " + this.props.src);
61-
this.fixups = Tinter.calcSvgFixups([event.target]);
62+
this.fixups = Tinter.calcSvgFixups([event.target], this.props.forceColors);
6263
Tinter.applySvgFixups(this.fixups);
6364
},
6465

0 commit comments

Comments
 (0)
This repository has been archived.