From a850f19cd40486a6328ac93c49fa1be3fe7d1945 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Mon, 26 Oct 2015 13:54:54 +0000
Subject: [PATCH 01/12] Separate out the activity watcher from presence code so
 I can hook read receipts into it without tangling it into the presence code.

---
 src/Presence.js                     | 66 +++++++++++++++--------------
 src/UserActivity.js                 | 57 +++++++++++++++++++++++++
 src/controllers/pages/MatrixChat.js |  3 ++
 3 files changed, 95 insertions(+), 31 deletions(-)
 create mode 100644 src/UserActivity.js

diff --git a/src/Presence.js b/src/Presence.js
index d77058abd8..1f5617514a 100644
--- a/src/Presence.js
+++ b/src/Presence.js
@@ -15,58 +15,54 @@ limitations under the License.
 */
 
 var MatrixClientPeg = require("./MatrixClientPeg");
+var dis = require("./dispatcher");
 
  // Time in ms after that a user is considered as unavailable/away
 var UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins
 var PRESENCE_STATES = ["online", "offline", "unavailable"];
 
-// The current presence state
-var state, timer;
-
-module.exports = {
+class Presence {
 
     /**
      * Start listening the user activity to evaluate his presence state.
      * Any state change will be sent to the Home Server.
      */
-    start: function() {
-        var self = this;
+    start() {
         this.running = true;
-        if (undefined === state) {
-            // The user is online if they move the mouse or press a key
-            document.onmousemove = function() { self._resetTimer(); };
-            document.onkeypress = function() { self._resetTimer(); };
+        if (undefined === this.state) {
             this._resetTimer();
+            this.dispatcherRef = dis.register(this._onUserActivity.bind(this));
         }
-    },
+    }
 
     /**
      * Stop tracking user activity
      */
-    stop: function() {
+    stop() {
         this.running = false;
-        if (timer) {
-            clearTimeout(timer);
-            timer = undefined;
+        if (this.timer) {
+            clearInterval(this.timer);
+            this.timer = undefined;
+            dis.unregister(this.dispatcherRef);
         }
-        state = undefined;
-    },
+        this.state = undefined;
+    }
 
     /**
      * Get the current presence state.
      * @returns {string} the presence state (see PRESENCE enum)
      */
-    getState: function() {
-        return state;
-    },
+    getState() {
+        return this.state;
+    }
 
     /**
      * Set the presence state.
      * If the state has changed, the Home Server will be notified.
      * @param {string} newState the new presence state (see PRESENCE enum)
      */
-    setState: function(newState) {
-        if (newState === state) {
+    setState(newState) {
+        if (newState === this.state) {
             return;
         }
         if (PRESENCE_STATES.indexOf(newState) === -1) {
@@ -75,33 +71,41 @@ module.exports = {
         if (!this.running) {
             return;
         }
-        state = newState;
-        MatrixClientPeg.get().setPresence(state).done(function() {
+        var old_state = this.state;
+        this.state = newState;
+        MatrixClientPeg.get().setPresence(this.state).done(function() {
             console.log("Presence: %s", newState);
         }, function(err) {
             console.error("Failed to set presence: %s", err);
+            this.state = old_state;
         });
-    },
+    }
 
     /**
      * Callback called when the user made no action on the page for UNAVAILABLE_TIME ms.
      * @private
      */
-    _onUnavailableTimerFire: function() {
+    _onUnavailableTimerFire() {
         this.setState("unavailable");
-    },
+    }
+
+    _onUserActivity() {
+        this._resetTimer();
+    }
 
     /**
      * Callback called when the user made an action on the page
      * @private
      */
-    _resetTimer: function() {
+    _resetTimer() {
         var self = this;
         this.setState("online");
         // Re-arm the timer
-        clearTimeout(timer);
-        timer = setTimeout(function() {
+        clearTimeout(this.timer);
+        this.timer = setTimeout(function() {
             self._onUnavailableTimerFire();
         }, UNAVAILABLE_TIME_MS);
     } 
-};
+}
+
+module.exports = new Presence();
diff --git a/src/UserActivity.js b/src/UserActivity.js
new file mode 100644
index 0000000000..46a46f0b0e
--- /dev/null
+++ b/src/UserActivity.js
@@ -0,0 +1,57 @@
+/*
+Copyright 2015 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.
+*/
+
+var dis = require("./dispatcher");
+
+var MIN_DISPATCH_INTERVAL = 1 * 1000;
+
+/**
+ * This class watches for user activity (moving the mouse or pressing a key)
+ * and dispatches the user_activity action at times when the user is interacting
+ * with the app (but at a much lower frequency than mouse move events)
+ */
+class UserActivity {
+
+    /**
+     * Start listening to user activity
+     */
+    start() {
+        document.onmousemove = this._onUserActivity.bind(this);
+        document.onkeypress = this._onUserActivity.bind(this);
+        this.lastActivityAt = (new Date).getTime();
+        this.lastDispatchAt = 0;
+    }
+
+    /**
+     * Stop tracking user activity
+     */
+    stop() {
+        document.onmousemove = undefined;
+        document.onkeypress = undefined;
+    }
+
+    _onUserActivity() {
+        this.lastActivityAt = (new Date).getTime();
+        if (this.lastDispatchAt < this.lastActivityAt - MIN_DISPATCH_INTERVAL) {
+            this.lastDispatchAt = this.lastActivityAt;
+            dis.dispatch({
+                action: 'user_activity'
+            });
+        }
+    }
+}
+
+module.exports = new UserActivity();
diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js
index 2a712b22f6..97fc3a1fe1 100644
--- a/src/controllers/pages/MatrixChat.js
+++ b/src/controllers/pages/MatrixChat.js
@@ -16,6 +16,7 @@ limitations under the License.
 
 var MatrixClientPeg = require("../../MatrixClientPeg");
 var RoomListSorter = require("../../RoomListSorter");
+var UserActivity = require("../../UserActivity");
 var Presence = require("../../Presence");
 var dis = require("../../dispatcher");
 
@@ -92,6 +93,7 @@ module.exports = {
                     window.localStorage.clear();
                 }
                 Notifier.stop();
+                UserActivity.stop();
                 Presence.stop();
                 MatrixClientPeg.get().stopClient();
                 MatrixClientPeg.get().removeAllListeners();
@@ -316,6 +318,7 @@ module.exports = {
             });
         });
         Notifier.start();
+        UserActivity.start();
         Presence.start();
         cli.startClient();
     },

From 2365fe8ceb92d908e3050019cfb9f25ce7d3b002 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Wed, 28 Oct 2015 15:15:35 +0000
Subject: [PATCH 02/12] Refresh room & member avatars when a roommember.name
 event comes in

---
 src/controllers/atoms/MemberAvatar.js   | 20 ++++++++++++++++--
 src/controllers/atoms/RoomAvatar.js     | 27 +++++++++++++++++++++----
 src/controllers/organisms/MemberList.js |  5 +++++
 src/controllers/organisms/RoomList.js   |  5 +++++
 src/controllers/pages/MatrixChat.js     |  2 +-
 5 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/src/controllers/atoms/MemberAvatar.js b/src/controllers/atoms/MemberAvatar.js
index a94b4291a0..e170d2e04c 100644
--- a/src/controllers/atoms/MemberAvatar.js
+++ b/src/controllers/atoms/MemberAvatar.js
@@ -35,6 +35,10 @@ module.exports = {
         }
     },
 
+    componentWillReceiveProps: function(nextProps) {
+        this.refreshUrl();
+    },
+
     defaultAvatarUrl: function(member, width, height, resizeMethod) {
         if (this.skinnedDefaultAvatarUrl) {
             return this.skinnedDefaultAvatarUrl(member, width, height, resizeMethod);
@@ -52,7 +56,7 @@ module.exports = {
         });
     },
 
-    getInitialState: function() {
+    _computeUrl: function() {
         var url = this.props.member.getAvatarUrl(
             MatrixClientPeg.get().getHomeserverUrl(),
             this.props.width,
@@ -68,8 +72,20 @@ module.exports = {
                 this.props.resizeMethod
             );
         }
+        return url;
+    },
+
+    refreshUrl: function() {
+        var newUrl = this._computeUrl();
+        if (newUrl != this.currentUrl) {
+            this.currentUrl = newUrl;
+            this.setState({imageUrl: newUrl});
+        }
+    },
+
+    getInitialState: function() {
         return {
-            imageUrl: url
+            imageUrl: this._computeUrl()
         };
     }
 };
diff --git a/src/controllers/atoms/RoomAvatar.js b/src/controllers/atoms/RoomAvatar.js
index 6c55345ead..061a12eb14 100644
--- a/src/controllers/atoms/RoomAvatar.js
+++ b/src/controllers/atoms/RoomAvatar.js
@@ -41,10 +41,29 @@ module.exports = {
     },
 
     componentWillReceiveProps: function(nextProps) {
-        this._update();
-        this.setState({
-            imageUrl: this._nextUrl()
-        });
+        this.refreshImageUrl();
+    },
+
+    refreshImageUrl: function(nextProps) {
+        // If the list has changed, we start from scratch and re-check, but
+        // don't do so unless the list has changed or we'd re-try fetching
+        // images each time we re-rendered
+        var newList = this.getUrlList();
+        var differs = false;
+        for (var i = 0; i < newList.length && i < this.urlList.length; ++i) {
+            if (this.urlList[i] != newList[i]) differs = true;
+        }
+        if (this.urlList.length != newList.length) differs = true;
+
+        if (differs) {
+            console.log("list differs");
+            this._update();
+            this.setState({
+                imageUrl: this._nextUrl()
+            });
+        } else {
+            console.log("list is the same");
+        }
     },
 
     _update: function() {
diff --git a/src/controllers/organisms/MemberList.js b/src/controllers/organisms/MemberList.js
index 48fef531bb..a2298a20ba 100644
--- a/src/controllers/organisms/MemberList.js
+++ b/src/controllers/organisms/MemberList.js
@@ -38,6 +38,7 @@ module.exports = {
     componentWillMount: function() {
         var cli = MatrixClientPeg.get();
         cli.on("RoomState.members", this.onRoomStateMember);
+        cli.on("RoomMember.name", this.onRoomMemberName);
         cli.on("Room", this.onRoom); // invites
     },
 
@@ -97,6 +98,10 @@ module.exports = {
         this._updateList();
     },
 
+    onRoomMemberName: function(ev, member) {
+        this._updateList();
+    },
+
     _updateList: function() {
         this.memberDict = this.getMemberDict();
 
diff --git a/src/controllers/organisms/RoomList.js b/src/controllers/organisms/RoomList.js
index ff3522d9c3..6b5a4c4722 100644
--- a/src/controllers/organisms/RoomList.js
+++ b/src/controllers/organisms/RoomList.js
@@ -29,6 +29,7 @@ module.exports = {
         cli.on("Room.timeline", this.onRoomTimeline);
         cli.on("Room.name", this.onRoomName);
         cli.on("RoomState.events", this.onRoomStateEvents);
+        cli.on("RoomMember.name", this.onRoomMemberName);
 
         var rooms = this.getRoomList();
         this.setState({
@@ -89,6 +90,10 @@ module.exports = {
         this.refreshRoomList();
     },
 
+    onRoomMemberName: function(ev, member) {
+        this.refreshRoomList();
+    },
+
     refreshRoomList: function() {
         var rooms = this.getRoomList();
         this.setState({
diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js
index 97fc3a1fe1..edb55eb1b0 100644
--- a/src/controllers/pages/MatrixChat.js
+++ b/src/controllers/pages/MatrixChat.js
@@ -320,7 +320,7 @@ module.exports = {
         Notifier.start();
         UserActivity.start();
         Presence.start();
-        cli.startClient();
+        cli.startClient({resolveInvitesToProfiles: true});
     },
 
     onKeyDown: function(ev) {

From c46f40c816ff63cdaee7ca3839583ac6b78aca51 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Wed, 28 Oct 2015 18:02:50 +0000
Subject: [PATCH 03/12] bump js-sdk -> 0.3.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index f28cfdf215..ff7d75e712 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
     "flux": "^2.0.3",
     "glob": "^5.0.14",
     "linkifyjs": "^2.0.0-beta.4",
-    "matrix-js-sdk": "^0.2.2",
+    "matrix-js-sdk": "^0.3.0",
     "optimist": "^0.6.1",
     "q": "^1.4.1",
     "react": "^0.13.3",

From 7c9b773bf8bb162d3e16c662d626d5c7ddf3e9e5 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Tue, 3 Nov 2015 11:22:18 +0000
Subject: [PATCH 04/12] unintentionally comitted logging

---
 src/controllers/atoms/RoomAvatar.js | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/controllers/atoms/RoomAvatar.js b/src/controllers/atoms/RoomAvatar.js
index 061a12eb14..57c9a71842 100644
--- a/src/controllers/atoms/RoomAvatar.js
+++ b/src/controllers/atoms/RoomAvatar.js
@@ -56,13 +56,10 @@ module.exports = {
         if (this.urlList.length != newList.length) differs = true;
 
         if (differs) {
-            console.log("list differs");
             this._update();
             this.setState({
                 imageUrl: this._nextUrl()
             });
-        } else {
-            console.log("list is the same");
         }
     },
 

From 5a72f199e1b69f0acfb6f6a50f593849e4a3e319 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Tue, 3 Nov 2015 11:41:18 +0000
Subject: [PATCH 05/12] listen for read receipts

---
 src/controllers/organisms/RoomView.js | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js
index 931dbb5bcb..925f896556 100644
--- a/src/controllers/organisms/RoomView.js
+++ b/src/controllers/organisms/RoomView.js
@@ -43,6 +43,7 @@ module.exports = {
         this.dispatcherRef = dis.register(this.onAction);
         MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
         MatrixClientPeg.get().on("Room.name", this.onRoomName);
+        MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt);
         MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
         this.atBottom = true;
     },
@@ -59,6 +60,7 @@ module.exports = {
         if (MatrixClientPeg.get()) {
             MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
             MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
+            MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt);
             MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping);
         }
     },
@@ -149,6 +151,12 @@ module.exports = {
         }
     },
 
+    onRoomReceipt: function(receiptEvent, room) {
+        if (room.roomId == this.props.roomId) {
+            this.forceUpdate();
+        }
+    },
+
     onRoomMemberTyping: function(ev, member) {
         this.forceUpdate();
     },

From 86ef0e762ed50773d307e6f66d598bef4df311f5 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Tue, 3 Nov 2015 14:08:51 +0000
Subject: [PATCH 06/12] Merge code to send read receipts into react-sdk
 RoomView controller

---
 src/controllers/organisms/RoomView.js | 55 ++++++++++++++++++++++++++-
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js
index 925f896556..2dc9e1bf26 100644
--- a/src/controllers/organisms/RoomView.js
+++ b/src/controllers/organisms/RoomView.js
@@ -89,6 +89,9 @@ module.exports = {
                     messageWrapper.scrollTop = messageWrapper.scrollHeight;
                 }
                 break;
+            case 'user_activity':
+                this.sendReadReceipt();
+                break;
         }
     },
 
@@ -172,6 +175,8 @@ module.exports = {
 
             messageWrapper.scrollTop = messageWrapper.scrollHeight;
 
+            this.sendReadReceipt();
+
             this.fillSpace();
         }
     },
@@ -354,7 +359,7 @@ module.exports = {
                 }
             }
             ret.unshift(
-                <li key={mxEv.getId()}><EventTile mxEvent={mxEv} continuation={continuation} last={last}/></li>
+                <li ref={this._collectEventNode.bind(this, mxEv.getId())} key={mxEv.getId()}><EventTile mxEvent={mxEv} continuation={continuation} last={last}/></li>
             );
             ++count;
         }
@@ -446,5 +451,53 @@ module.exports = {
                 uploadingRoomSettings: false,
             });
         }
+    },
+
+    _collectEventNode: function(eventId, node) {
+        if (this.eventNodes == undefined) this.eventNodes = {};
+        this.eventNodes[eventId] = node;
+    },
+
+    _indexForEventId(evId) {
+        for (var i = 0; i < this.state.room.timeline.length; ++i) {
+            if (evId == this.state.room.timeline[i].getId()) {
+                return i;
+            }
+        }
+        return null;
+    },
+
+    sendReadReceipt: function() {
+        var currentReadUpToEventId = this.state.room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId);
+        var currentReadUpToEventIndex = this._indexForEventId(currentReadUpToEventId);
+
+        var lastReadEventIndex = this._getLastDisplayedEventIndex();
+        if (lastReadEventIndex === null) return;
+
+        if (lastReadEventIndex > currentReadUpToEventIndex) {
+            MatrixClientPeg.get().sendReadReceipt(this.state.room.timeline[lastReadEventIndex]);
+        }
+    },
+
+    _getLastDisplayedEventIndex: function() {
+        if (this.eventNodes === undefined) return null;
+
+        var messageWrapper = this.refs.messageWrapper;
+        if (messageWrapper === undefined) return null;
+        var wrapperRect = messageWrapper.getDOMNode().getBoundingClientRect();
+
+        for (var i = this.state.room.timeline.length-1; i >= 0; --i) {
+            var ev = this.state.room.timeline[i];
+            var node = this.eventNodes[ev.getId()];
+            if (node === undefined) continue;
+
+            var domNode = node.getDOMNode();
+            var boundingRect = domNode.getBoundingClientRect();
+
+            if (boundingRect.bottom < wrapperRect.bottom) {
+                return i;
+            }
+        }
+        return null;
     }
 };

From f9385b455a1be6598dca926935fc00211cf0df36 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Thu, 5 Nov 2015 13:27:03 +0000
Subject: [PATCH 07/12] Don't try to send read receipts if the room is null

---
 src/controllers/organisms/RoomView.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js
index 2dc9e1bf26..7ab59b497a 100644
--- a/src/controllers/organisms/RoomView.js
+++ b/src/controllers/organisms/RoomView.js
@@ -468,6 +468,7 @@ module.exports = {
     },
 
     sendReadReceipt: function() {
+        if (!this.state.room) return;
         var currentReadUpToEventId = this.state.room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId);
         var currentReadUpToEventIndex = this._indexForEventId(currentReadUpToEventId);
 

From d8edbd2e3c79984a01c7ae6dec0bc9b45e60af90 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Thu, 5 Nov 2015 14:45:48 +0000
Subject: [PATCH 08/12] Requires js-sdk develop

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index ff7d75e712..c1c7f5fbe5 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
     "flux": "^2.0.3",
     "glob": "^5.0.14",
     "linkifyjs": "^2.0.0-beta.4",
-    "matrix-js-sdk": "^0.3.0",
+    "matrix-js-sdk": "https://github.com/matrix-org/matrix-js-sdk.git#develop",
     "optimist": "^0.6.1",
     "q": "^1.4.1",
     "react": "^0.13.3",

From f4e65f8e17524994321d62c52a65dbc084dcd720 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Thu, 5 Nov 2015 15:07:46 +0000
Subject: [PATCH 09/12] Remove name event listener

---
 src/controllers/organisms/MemberList.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/controllers/organisms/MemberList.js b/src/controllers/organisms/MemberList.js
index a2298a20ba..4dfe5330e1 100644
--- a/src/controllers/organisms/MemberList.js
+++ b/src/controllers/organisms/MemberList.js
@@ -46,6 +46,7 @@ module.exports = {
         if (MatrixClientPeg.get()) {
             MatrixClientPeg.get().removeListener("Room", this.onRoom);
             MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
+            MatrixClientPeg.get().removeListener("RoomMember.name", this.onRoomMemberName);
             MatrixClientPeg.get().removeListener("User.presence", this.userPresenceFn);
         }
     },

From 95cdbe3a48b081c988e87c32918e424cab6370ee Mon Sep 17 00:00:00 2001
From: Matthew Hodgson <matthew@matrix.org>
Date: Tue, 17 Nov 2015 17:36:15 +0000
Subject: [PATCH 10/12] stop launch from wedging solid for 5 minutes >:(

---
 src/controllers/pages/MatrixChat.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js
index 2fdb9eb8ef..ea34ec13b3 100644
--- a/src/controllers/pages/MatrixChat.js
+++ b/src/controllers/pages/MatrixChat.js
@@ -351,7 +351,7 @@ module.exports = {
         Notifier.start();
         UserActivity.start();
         Presence.start();
-        cli.startClient({resolveInvitesToProfiles: true});
+        cli.startClient();
     },
 
     onKeyDown: function(ev) {

From 0df0935b9c4079c8d75e749de59cc4cafb5900db Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Wed, 18 Nov 2015 09:57:14 +0000
Subject: [PATCH 11/12] Fix presence exception. Yay, javascript.

---
 src/Presence.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/Presence.js b/src/Presence.js
index 1f5617514a..e776cca078 100644
--- a/src/Presence.js
+++ b/src/Presence.js
@@ -73,11 +73,12 @@ class Presence {
         }
         var old_state = this.state;
         this.state = newState;
+        var self = this;
         MatrixClientPeg.get().setPresence(this.state).done(function() {
             console.log("Presence: %s", newState);
         }, function(err) {
             console.error("Failed to set presence: %s", err);
-            this.state = old_state;
+            self.state = old_state;
         });
     }
 

From 31b083d93ec3870ba62bb9e43c5e01979500bc6a Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Wed, 18 Nov 2015 14:51:06 +0000
Subject: [PATCH 12/12] new Date() syntax & units on var name

---
 src/UserActivity.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/UserActivity.js b/src/UserActivity.js
index 46a46f0b0e..cee1b4efe2 100644
--- a/src/UserActivity.js
+++ b/src/UserActivity.js
@@ -31,8 +31,8 @@ class UserActivity {
     start() {
         document.onmousemove = this._onUserActivity.bind(this);
         document.onkeypress = this._onUserActivity.bind(this);
-        this.lastActivityAt = (new Date).getTime();
-        this.lastDispatchAt = 0;
+        this.lastActivityAtTs = new Date().getTime();
+        this.lastDispatchAtTs = 0;
     }
 
     /**
@@ -44,9 +44,9 @@ class UserActivity {
     }
 
     _onUserActivity() {
-        this.lastActivityAt = (new Date).getTime();
-        if (this.lastDispatchAt < this.lastActivityAt - MIN_DISPATCH_INTERVAL) {
-            this.lastDispatchAt = this.lastActivityAt;
+        this.lastActivityAtTs = (new Date).getTime();
+        if (this.lastDispatchAtTs < this.lastActivityAtTs - MIN_DISPATCH_INTERVAL) {
+            this.lastDispatchAtTs = this.lastActivityAtTs;
             dis.dispatch({
                 action: 'user_activity'
             });