Fix up notification setting listener in roomtile

The previous dispatch only did binary muted/non-muted but we now have 4 states. We now just listen for the push rules account data and update on that so it stays in sync if the pishrules are changed elsewhere.

Also add util functions used here for getting the notif state and in vector for both getting and setting it.
This commit is contained in:
David Baker 2016-08-17 18:26:37 +01:00
parent 5a83adc2b6
commit 87f94bde62
2 changed files with 162 additions and 27 deletions

137
src/RoomNotifs.js Normal file
View file

@ -0,0 +1,137 @@
/*
Copyright 2016 OpenMarket Ltd
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 MatrixClientPeg from './MatrixClientPeg';
import PushProcessor from 'matrix-js-sdk/lib/pushprocessor';
import q from 'q';
export function getRoomNotifsState(roomId) {
// look through the override rules for a rule affecting this room:
// if one exists, it will take precedence.
const muteRule = findOverrideMuteRule(roomId);
if (muteRule && muteRule.enabled) {
return 'mute';
}
// for everything else, look at the room rule.
const roomRule = MatrixClientPeg.get().getRoomPushRule('global', roomId);
// XXX: We have to assume the default is to notify for all messages
// (in particular this will be 'wrong' for one to one rooms because
// they will notify loudly for all messages)
if (!roomRule || !roomRule.enabled) return 'all_messages';
// a mute at the room level will still allow mentions
// to notify
if (isMuteRule(roomRule)) return 'mentions_only';
const actionsObject = PushProcessor.actionListToActionsObject(roomRule.actions);
if (actionsObject.tweaks.sound) return 'all_messages_loud';
return null;
}
export function setRoomNotifsState(roomId, newState) {
const cli = MatrixClientPeg.get();
const promises = [];
if (newState == 'mute') {
// delete the room rule
const roomRule = MatrixClientPeg.get().getRoomPushRule('global', roomId);
if (roomRule) {
promises.push(cli.deletePushRule('global', 'room', roomRule.rule_id));
}
// add an override rule to squelch everything in this room
promises.push(cli.addPushRule('global', 'override', roomId, {
conditions: [
{
kind: 'event_match',
key: 'room_id',
pattern: roomId,
}
],
actions: [
'dont_notify',
]
}));
} else {
const overrideMuteRule = findOverrideMuteRule(roomId);
if (overrideMuteRule) {
promises.push(cli.deletePushRule('global', 'override', overrideMuteRule.rule_id));
}
if (newState == 'all_messages') {
promises.push(cli.deletePushRule('global', 'room', roomId));
} else if (newState == 'mentions_only') {
promises.push(cli.addPushRule('global', 'room', roomId, {
actions: [
'dont_notify',
]
}));
// https://matrix.org/jira/browse/SPEC-400
promises.push(cli.setPushRuleEnabled('global', 'room', roomId, true));
} else if ('all_messages_loud') {
promises.push(cli.addPushRule('global', 'room', roomId, {
actions: [
'notify',
{
set_tweak: 'sound',
value: 'default',
}
]
}));
// https://matrix.org/jira/browse/SPEC-400
promises.push(cli.setPushRuleEnabled('global', 'room', roomId, true));
}
}
return q.all(promises);
}
function findOverrideMuteRule(roomId) {
for (const rule of MatrixClientPeg.get().pushRules['global'].override) {
if (isRuleForRoom(roomId, rule)) {
if (isMuteRule(rule)) {
return rule;
}
}
}
return null;
}
function isRuleForRoom(roomId, rule) {
if (rule.conditions.length !== 1) {
return false;
}
const cond = rule.conditions[0];
if (
cond.kind == 'event_match' &&
cond.key == 'room_id' &&
cond.pattern == roomId
) {
return true;
}
return false;
}
function isMuteRule(rule) {
return (
rule.actions.length == 1 &&
rule.actions[0] == 'dont_notify'
);
}

View file

@ -22,6 +22,7 @@ var dis = require("../../../dispatcher");
var MatrixClientPeg = require('../../../MatrixClientPeg');
var sdk = require('../../../index');
var ContextualMenu = require('../../structures/ContextualMenu');
var RoomNotifs = require('../../../RoomNotifs');
module.exports = React.createClass({
displayName: 'RoomTile',
@ -43,43 +44,40 @@ module.exports = React.createClass({
},
getInitialState: function() {
var areNotifsMuted = false;
var cli = MatrixClientPeg.get();
if (!cli.isGuest()) {
var roomPushRule = cli.getRoomPushRule("global", this.props.room.roomId);
if (roomPushRule) {
if (0 <= roomPushRule.actions.indexOf("dont_notify")) {
areNotifsMuted = true;
}
}
}
return({
hover : false,
badgeHover : false,
notificationTagMenu: false,
roomTagMenu: false,
areNotifsMuted: areNotifsMuted,
showBadge: this._shouldShowBadge(),
});
},
onAction: function(payload) {
switch (payload.action) {
case 'notification_change':
// Is the notification about this room?
if (payload.roomId === this.props.room.roomId) {
this.setState( { areNotifsMuted : payload.areNotifsMuted });
}
break;
_shouldShowBadge: function() {
if (MatrixClientPeg.get().isGuest()) return true;
const showBadgeInStates = ['all_messages', 'all_messages_loud'];
const currentState = RoomNotifs.getRoomNotifsState(this.props.room.roomId);
return showBadgeInStates.indexOf(currentState) > -1;
},
onAccountData: function(accountDataEvent) {
if (accountDataEvent.getType() == 'm.push_rules') {
this.setState({
showBadge: this._shouldShowBadge(),
});
}
},
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
componentWillMount: function() {
MatrixClientPeg.get().on("accountData", this.onAccountData);
},
componentWillUnmount: function() {
dis.unregister(this.dispatcherRef);
var cli = MatrixClientPeg.get();
if (cli) {
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
}
},
onClick: function() {
@ -183,11 +181,11 @@ module.exports = React.createClass({
'mx_RoomTile': true,
'mx_RoomTile_selected': this.props.selected,
'mx_RoomTile_unread': this.props.unread,
'mx_RoomTile_unreadNotify': notificationCount > 0 && !this.state.areNotifsMuted,
'mx_RoomTile_unreadNotify': notificationCount > 0 && this.state.showBadge,
'mx_RoomTile_highlight': this.props.highlight,
'mx_RoomTile_invited': (me && me.membership == 'invite'),
'mx_RoomTile_notificationTagMenu': this.state.notificationTagMenu,
'mx_RoomTile_noBadges': !(this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted))
'mx_RoomTile_noBadges': !(this.props.highlight || (notificationCount > 0 && this.state.showBadge))
});
var avatarClasses = classNames({
@ -214,7 +212,7 @@ module.exports = React.createClass({
if (this.state.badgeHover || this.state.notificationTagMenu) {
badgeContent = "\u00B7\u00B7\u00B7";
} else if (this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted)) {
} else if (this.props.highlight || (notificationCount > 0 && this.state.showBadge)) {
var limitedCount = (notificationCount > 99) ? '99+' : notificationCount;
badgeContent = notificationCount ? limitedCount : '!';
} else {
@ -230,7 +228,7 @@ module.exports = React.createClass({
var nameClasses = classNames({
'mx_RoomTile_name': true,
'mx_RoomTile_invite': this.props.isInvite,
'mx_RoomTile_badgeShown': this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted) || this.state.badgeHover || this.state.notificationTagMenu,
'mx_RoomTile_badgeShown': this.props.highlight || (notificationCount > 0 && this.state.showBadge) || this.state.badgeHover || this.state.notificationTagMenu,
});
if (this.props.selected) {