Merge pull request #22 from ttyniwa/feature/fix_sharp_12_and_18_merge_bug

Manually no-ff merged

Finally:
* Highlighted posts in the active channel is counted as mentions
* Badge-notify on navbar-toggle is counted as mentions(mention and DM)
* For other unread channels, '•' is used for "there are new messages"
* In active channel, counts are cleared when the tab is activated.
This commit is contained in:
Yuya Ochiai
2016-02-02 22:47:35 +09:00
2 changed files with 101 additions and 78 deletions

View File

@@ -25,7 +25,8 @@ var MainPage = React.createClass({
key: 0,
unreadCounts: new Array(this.props.teams.length),
mentionCounts: new Array(this.props.teams.length),
unreadAtActive: new Array(this.props.teams.length)
unreadAtActive: new Array(this.props.teams.length),
mentionAtActiveCounts: new Array(this.props.teams.length)
};
},
componentDidMount: function() {
@@ -49,22 +50,36 @@ var MainPage = React.createClass({
});
this.handleOnTeamFocused(key);
},
handleUnreadCountChange: function(index, unreadCount, mentionCount) {
handleUnreadCountChange: function(index, unreadCount, mentionCount, isUnread, isMentioned) {
var unreadCounts = this.state.unreadCounts;
var mentionCounts = this.state.mentionCounts;
var unreadAtActive = this.state.unreadAtActive;
var mentionAtActiveCounts = this.state.mentionAtActiveCounts;
unreadCounts[index] = unreadCount;
mentionCounts[index] = mentionCount;
// Never turn on the unreadAtActive flag at current focused tab.
if (this.state.key !== index || !remote.getCurrentWindow().isFocused()) {
unreadAtActive[index] = unreadAtActive[index] || isUnread;
if (isMentioned) {
mentionAtActiveCounts[index]++;
}
}
this.setState({
unreadCounts: unreadCounts,
mentionCounts: mentionCounts
mentionCounts: mentionCounts,
unreadAtActive: unreadAtActive,
mentionAtActiveCounts: mentionAtActiveCounts
});
this.handleUnreadCountTotalChange();
},
handleUnreadAtActiveChange: function(index, state) {
markReadAtActive: function(index) {
var unreadAtActive = this.state.unreadAtActive;
unreadAtActive[index] = state;
var mentionAtActiveCounts = this.state.mentionAtActiveCounts;
unreadAtActive[index] = false;
mentionAtActiveCounts[index] = 0;
this.setState({
unreadAtActive: unreadAtActive
unreadAtActive: unreadAtActive,
mentionAtActiveCounts: mentionAtActiveCounts
});
this.handleUnreadCountTotalChange();
},
@@ -81,19 +96,15 @@ var MainPage = React.createClass({
var allMentionCount = this.state.mentionCounts.reduce(function(prev, curr) {
return prev + curr;
}, 0);
this.state.mentionAtActiveCounts.forEach(function(count) {
allMentionCount += count;
});
this.props.onUnreadCountChange(allUnreadCount, allMentionCount);
}
},
handleNotify: function(index) {
// Never turn on the unreadAtActive flag at current focused tab.
if (this.state.key === index && remote.getCurrentWindow().isFocused()) {
return;
}
this.handleUnreadAtActiveChange(index, true);
},
handleOnTeamFocused: function(index) {
// Turn off the flag to indicate whether unread message of active channel contains at current tab.
this.handleUnreadAtActiveChange(index, false);
this.markReadAtActive(index);
},
visibleStyle: function(visible) {
@@ -114,24 +125,21 @@ var MainPage = React.createClass({
if (this.props.teams.length > 1) {
tabs_row = (
<Row>
<TabBar id="tabBar" teams={ this.props.teams } unreadCounts={ this.state.unreadCounts } mentionCounts={ this.state.mentionCounts } unreadAtActive={ this.state.unreadAtActive } activeKey={ this.state.key }
onSelect={ this.handleSelect }></TabBar>
<TabBar id="tabBar" teams={ this.props.teams } unreadCounts={ this.state.unreadCounts } mentionCounts={ this.state.mentionCounts } unreadAtActive={ this.state.unreadAtActive } mentionAtActiveCounts={ this.state.mentionAtActiveCounts }
activeKey={ this.state.key } onSelect={ this.handleSelect }></TabBar>
</Row>
);
}
var views = this.props.teams.map(function(team, index) {
var handleUnreadCountChange = function(unreadCount, mentionCount) {
thisObj.handleUnreadCountChange(index, unreadCount, mentionCount);
};
var handleNotify = function() {
thisObj.handleNotify(index);
var handleUnreadCountChange = function(unreadCount, mentionCount, isUnread, isMentioned) {
thisObj.handleUnreadCountChange(index, unreadCount, mentionCount, isUnread, isMentioned);
};
var handleNotificationClick = function() {
thisObj.handleSelect(index);
}
return (<MattermostView id={ 'mattermostView' + index } style={ thisObj.visibleStyle(thisObj.state.key === index) } src={ team.url } onUnreadCountChange={ handleUnreadCountChange } onNotify={ handleNotify }
onNotificationClick={ handleNotificationClick } />)
return (<MattermostView id={ 'mattermostView' + index } style={ thisObj.visibleStyle(thisObj.state.key === index) } src={ team.url } onUnreadCountChange={ handleUnreadCountChange } onNotificationClick={ handleNotificationClick }
/>)
});
var views_row = (<Row>
{ views }
@@ -149,7 +157,6 @@ var TabBar = React.createClass({
render: function() {
var thisObj = this;
var tabs = this.props.teams.map(function(team, index) {
var badge;
var unreadCount = 0;
if (thisObj.props.unreadCounts[index] > 0) {
unreadCount = thisObj.props.unreadCounts[index];
@@ -157,9 +164,19 @@ var TabBar = React.createClass({
if (thisObj.props.unreadAtActive[index]) {
unreadCount += 1;
}
if (thisObj.props.mentionCounts[index] != 0) {
var mentionCount = 0;
if (thisObj.props.mentionCounts[index] > 0) {
mentionCount = thisObj.props.mentionCounts[index];
}
if (thisObj.props.mentionAtActiveCounts[index] > 0) {
mentionCount += thisObj.props.mentionAtActiveCounts[index];
}
var badge;
if (mentionCount != 0) {
badge = (<Badge>
{ thisObj.props.mentionCounts[index] }
{ mentionCount }
</Badge>);
} else if (unreadCount > 0) {
badge = (<Badge>
@@ -183,23 +200,11 @@ var TabBar = React.createClass({
var MattermostView = React.createClass({
getInitialState: function() {
return {
unreadCount: 0,
mentionCount: 0
};
},
handleUnreadCountChange: function(unreadCount, mentionCount) {
this.setState({
unreadCount: unreadCount,
mentionCount: mentionCount
});
handleUnreadCountChange: function(unreadCount, mentionCount, isUnread, isMentioned) {
if (this.props.onUnreadCountChange) {
this.props.onUnreadCountChange(unreadCount, mentionCount);
}
},
handleNotify: function() {
if (this.props.onNotify) {
this.props.onNotify();
this.props.onUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
}
},
@@ -251,7 +256,10 @@ var MattermostView = React.createClass({
case 'onUnreadCountChange':
var unreadCount = event.args[0];
var mentionCount = event.args[1];
thisObj.handleUnreadCountChange(unreadCount, mentionCount);
// isUnread and isMentioned is pulse flag.
var isUnread = event.args[2];
var isMentioned = event.args[3];
thisObj.handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
break;
case 'onNotificationClick':
thisObj.props.onNotificationClick();
@@ -259,9 +267,6 @@ var MattermostView = React.createClass({
case 'console':
console.log(event.args[0]);
break;
case 'onActiveChannelNotify':
thisObj.handleNotify();
break;
}
});

View File

@@ -15,41 +15,73 @@ var unreadCountTimer = setInterval(function() {
// unreadCount in sidebar
// Note: the active channel doesn't have '.unread-title'.
var unreadCount = document.getElementsByClassName('unread-title').length;
// mentionCount in sidebar
var elem = document.getElementsByClassName('badge')
// mentionCount in mobile navbar-toggle
var mentionBadge = document.getElementsByClassName('badge-notify');
var mentionCount = 0;
for (var i = 0; i < elem.length; i++) {
if (elem[i].offsetHeight != 0) {
mentionCount++;
if (mentionBadge.length > 0) { // older mattermost doesn't have badges.
mentionCount = Number(mentionBadge[0].innerHTML);
}
var postAttrName = 'data-reactid';
var lastPostElem = document.querySelector('div[' + postAttrName + '="' + this.lastCheckedPostId + '"]');
var isUnread = false;
var isMentioned = false;
if (lastPostElem === null || !isElementVisible(lastPostElem)) {
// When load channel or change channel, this.lastCheckedPostId is invalid.
// So we get latest post and save lastCheckedPostId.
// find active post-list.
var postLists = document.querySelectorAll('div.post-list__content');
var post;
for (var i = 0; i < postLists.length; i++) {
if (isElementVisible(postLists[i])) {
post = postLists[i].children[0];
}
}
// unreadCount for active channel
var newSeparators = document.getElementsByClassName('new-separator');
var post;
for (var i = 0; i < newSeparators.length; i++) {
if (newSeparators[i].offsetParent !== null) {
post = newSeparators[i];
}
}
// mentionCount for active channel
if (post != null) {
// find latest post and save.
while (post = post.nextSibling) {
var highlight = post.getElementsByClassName('mention-highlight');
if (highlight.length != 0 && highlight[0].offsetHeight != null) {
mentionCount++;
if (post.nextSibling === null) {
if (post.getAttribute(postAttrName) !== null) {
this.lastCheckedPostId = post.getAttribute(postAttrName);
}
}
}
}
else if (lastPostElem !== null) {
var newPostElem = lastPostElem;
while (newPostElem = newPostElem.nextSibling) {
this.lastCheckedPostId = newPostElem.getAttribute(postAttrName);
isUnread = true;
var activeChannel = document.querySelector('.active .sidebar-channel');
var closeButton = activeChannel.getElementsByClassName('btn-close');
if (closeButton.length === 1 && closeButton[0].getAttribute('aria-describedby') === 'remove-dm-tooltip') {
// If active channel is DM, all posts is treated as menion.
isMentioned = true;
break;
}
else {
// If active channel is public/private channel, only mentioned post is treated as mention.
var highlight = newPostElem.getElementsByClassName('mention-highlight');
if (highlight.length != 0 && isElementVisible(highlight[0])) {
isMentioned = true;
break;
}
}
}
}
if (this.unreadCount != unreadCount || this.mentionCount != mentionCount) {
ipc.sendToHost('onUnreadCountChange', unreadCount, mentionCount);
if (this.unreadCount != unreadCount || this.mentionCount != mentionCount || isUnread || isMentioned) {
ipc.sendToHost('onUnreadCountChange', unreadCount, mentionCount, isUnread, isMentioned);
}
this.unreadCount = unreadCount;
this.mentionCount = mentionCount;
}, 1000);
function isElementVisible(elem) {
return elem.offsetHeight !== 0;
}
// On Windows 8.1 and Windows 8, a shortcut with a Application User Model ID must be installed to the Start screen.
// In current version, use tray balloon for notification
function isLowerThanOrEqualWindows8_1() {
@@ -67,12 +99,6 @@ function overrideNotificationWithBalloon() {
title: title,
options: options
});
// Send notification event at active channel.
var activeChannel = document.querySelector('.active .sidebar-channel').text;
if (activeChannel === title) {
ipc.sendToHost('onActiveChannelNotify');
}
};
Notification.requestPermission = function(callback) {
callback('granted');
@@ -84,14 +110,6 @@ function overrideNotificationWithBalloon() {
function overrideNotification() {
Notification = function(title, options) {
this.notification = new NativeNotification(title, options);
// Send notification event at active channel.
var activeChannel = document.querySelector('.active .sidebar-channel').text;
console.log(activeChannel);
console.log(title);
if (activeChannel === title) {
ipc.sendToHost('onActiveChannelNotify');
}
};
Notification.requestPermission = function(callback) {
callback('granted');