From fd09d5c57049083719b59a3bbf65a33015d15269 Mon Sep 17 00:00:00 2001
From: Matthew Hodgson <matthew@matrix.org>
Date: Tue, 17 May 2016 11:14:12 +0100
Subject: [PATCH 1/3] switch badge count to per-conversation, and add per-room
 badges

---
 src/components/structures/MatrixChat.js | 7 +++++--
 src/components/views/rooms/RoomTile.js  | 4 ++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 08b7866b1c..255f7c9b92 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -999,9 +999,12 @@ module.exports = React.createClass({
         var rooms = MatrixClientPeg.get().getRooms();
         for (var i = 0; i < rooms.length; ++i) {
             if (rooms[i].hasMembershipState(MatrixClientPeg.get().credentials.userId, 'invite')) {
-                ++notifCount;
+                notifCount++;
             } else if (rooms[i].getUnreadNotificationCount()) {
-                notifCount += rooms[i].getUnreadNotificationCount();
+                // if we were summing unread notifs:
+                // notifCount += rooms[i].getUnreadNotificationCount();
+                // instead, we just count the number of rooms with notifs.
+                notifCount++;
             }
         }
         try {
diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js
index 69a945df33..55971cdd60 100644
--- a/src/components/views/rooms/RoomTile.js
+++ b/src/components/views/rooms/RoomTile.js
@@ -83,7 +83,7 @@ module.exports = React.createClass({
         name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
         var badge;
         if (this.props.highlight || notificationCount > 0) {
-            badge = <div className="mx_RoomTile_badge"/>;
+            badge = <div className="mx_RoomTile_badge">{ notificationCount ? notificationCount : '!' }</div>;
         }
         /*
         if (this.props.highlight) {
@@ -132,9 +132,9 @@ module.exports = React.createClass({
             <div className={classes} onClick={this.onClick} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
                 <div className="mx_RoomTile_avatar">
                     <RoomAvatar room={this.props.room} width={24} height={24} />
-                    { badge }
                 </div>
                 { label }
+                { badge }
                 { incomingCallBox }
             </div>
         ));

From 7879be1704c48cdecf56112ed7ad6d6967662854 Mon Sep 17 00:00:00 2001
From: Matthew Hodgson <matthew@matrix.org>
Date: Tue, 17 May 2016 20:28:11 +0100
Subject: [PATCH 2/3] implement basic local echo for resetting unread message
 count when opening a room without a scroll offset. hopefully largely fixes
 https://github.com/vector-im/vector-web/issues/967

---
 src/components/structures/RoomView.js      | 4 +---
 src/components/structures/ScrollPanel.js   | 2 +-
 src/components/structures/TimelinePanel.js | 8 ++++++++
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index 9b8322f69e..33bbb510e3 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -132,8 +132,7 @@ module.exports = React.createClass({
         MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
         MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData);
         MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
-        // xchat-style tab complete, add a colon if tab
-        // completing at the start of the text
+
         this.tabComplete = new TabComplete({
             allowLooping: false,
             autoEnterTabComplete: true,
@@ -143,7 +142,6 @@ module.exports = React.createClass({
             }
         });
 
-
         // if this is an unknown room then we're in one of three states:
         // - This is a room we can peek into (search engine) (we can /peek)
         // - This is a room we can publicly join or were invited to. (we can /join)
diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js
index 77569be3bb..63c78d2a3c 100644
--- a/src/components/structures/ScrollPanel.js
+++ b/src/components/structures/ScrollPanel.js
@@ -56,7 +56,7 @@ if (DEBUG_SCROLL) {
  *     offset.  We don't save the absolute scroll offset, because that would be
  *     affected by window width, zoom level, amount of scrollback, etc. Instead
  *     we save an identifier for the last fully-visible message, and the number
- *     of pixels the window was scrolled below it - which is hopefully be near
+ *     of pixels the window was scrolled below it - which is hopefully near
  *     enough.
  *
  * The 'stickyBottom' property controls the behaviour when we reach the bottom
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index 289dd4be25..12cdce267e 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -399,6 +399,14 @@ var TimelinePanel = React.createClass({
     sendReadReceipt: function() {
         if (!this.refs.messagePanel) return;
 
+        // if we are scrolled to the bottom, do a quick-reset of our unreadNotificationCount
+        // to avoid having to wait from the remote echo from the homeserver.
+        if (this.getScrollState().stuckAtBottom) {
+            this.props.room.setUnreadNotificationCount('total', 0);
+            this.props.room.setUnreadNotificationCount('highlight', 0);
+            // XXX: i'm a bit surprised we don't have to emit an event or dispatch to make the echo picked up
+        }
+
         var currentReadUpToEventId = this._getCurrentReadReceipt(true);
         var currentReadUpToEventIndex = this._indexForEventId(currentReadUpToEventId);
 

From 24adf2847eab5b14c37cfb7861793b376b29e0ac Mon Sep 17 00:00:00 2001
From: Matthew Hodgson <matthew@matrix.org>
Date: Tue, 17 May 2016 20:32:38 +0100
Subject: [PATCH 3/3] better comment

---
 src/components/structures/TimelinePanel.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index 12cdce267e..e15993a07c 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -404,7 +404,7 @@ var TimelinePanel = React.createClass({
         if (this.getScrollState().stuckAtBottom) {
             this.props.room.setUnreadNotificationCount('total', 0);
             this.props.room.setUnreadNotificationCount('highlight', 0);
-            // XXX: i'm a bit surprised we don't have to emit an event or dispatch to make the echo picked up
+            // XXX: i'm a bit surprised we don't have to emit an event or dispatch to get this picked up
         }
 
         var currentReadUpToEventId = this._getCurrentReadReceipt(true);