[polari/wip/bastianilso/status-hiding: 4/5] chatView: Compress status messages on idle channels



commit 32c142f1d42fd8a7fce55cd8bba5224dd097bfbd
Author: Bastian Ilsø <bastianilso src gnome org>
Date:   Wed Jun 24 15:28:34 2015 +0200

    chatView: Compress status messages on idle channels
    
    if channel is idle (no activity in 5 minutes), then
    emit compressed status messages. Clicking on the compressed
    status message will uncompress it (useful, should the user
    be waiting for someone specific to chat with).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=711542

 src/chatView.js |  132 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 112 insertions(+), 20 deletions(-)
---
diff --git a/src/chatView.js b/src/chatView.js
index f0ecff5..fef81d9 100644
--- a/src/chatView.js
+++ b/src/chatView.js
@@ -19,7 +19,8 @@ const SCROLL_TIMEOUT = 100; // ms
 const TIMESTAMP_INTERVAL = 300; // seconds of inactivity after which to
                                 // insert a timestamp
 
-const ACTIVITY_DURATION = 300 // min
+const ACTIVITY_DURATION = 300; // min
+const STATUS_NOISE_MAXIMUM = 4;
 
 const NUM_INITIAL_LOG_EVENTS = 50; // number of log events to fetch on start
 const NUM_LOG_EVENTS = 10; // number of log events to fetch when requesting more
@@ -103,6 +104,13 @@ const ChatView = new Lang.Class({
         this._needsIndicator = true;
         this._pending = {};
         this._pendingLogs = [];
+        this._statusCount = [
+            { name: 'left',
+              count: 0 },
+            { name: 'joined',
+              count: 0 }
+            ];
+        this._statusTexts = [];
 
         let isRoom = room.type == Tp.HandleType.ROOM;
         let target = new Tpl.Entity({ type: isRoom ? Tpl.EntityType.ROOM
@@ -601,7 +609,7 @@ const ChatView = new Lang.Class({
             { name: 'message-received',
               handler: Lang.bind(this, this._onMessageReceived) },
             { name: 'message-sent',
-              handler: Lang.bind(this, this._insertTpMessage) },
+              handler: Lang.bind(this, this._onMessageSent) },
             { name: 'pending-message-removed',
               handler: Lang.bind(this, this._pendingMessageRemoved) }
         ];
@@ -629,58 +637,78 @@ const ChatView = new Lang.Class({
     },
 
     _onMemberRenamed: function(room, oldMember, newMember) {
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        let text = _("%s is now known as %s").format(oldMember.alias, newMember.alias);
         if (this._shouldStatus(oldMember.alias)) {
-            this._insertStatus(_("%s is now known as %s").format(oldMember.alias,
-                                                                 newMember.alias));
+            this._insertStatus(text);
+        } else if (time - this._state.lastTimestamp > ACTIVITY_DURATION) {
+            this._insertStatusCompressed(text, 'renamed');
         }
         this._setNickStatus(oldMember.alias, Tp.ConnectionPresenceType.OFFLINE);
         this._setNickStatus(newMember.alias, Tp.ConnectionPresenceType.AVAILABLE);
     },
 
     _onMemberDisconnected: function(room, member, message) {
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        let text = _("%s has disconnected").format(member.alias);
+        if (message)
+            text += ' (%s)'.format(message);
         if (this._shouldStatus(member.alias)) {
-            let text = _("%s has disconnected").format(member.alias);
-            if (message)
-                text += ' (%s)'.format(message);
             this._insertStatus(text);
+        } else if (time - this._state.lastTimestamp > ACTIVITY_DURATION) {
+            this._insertStatusCompressed(text, 'left');
         }
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.OFFLINE);
     },
 
     _onMemberKicked: function(room, member, actor) {
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        let message =
+            actor ? _("%s has been kicked by %s").format(member.alias,
+                                                         actor.alias)
+                  : _("%s has been kicked").format(member.alias);
         if (this._shouldStatus(member.alias)) {
-            let message =
-                actor ? _("%s has been kicked by %s").format(member.alias,
-                                                             actor.alias)
-                      : _("%s has been kicked").format(member.alias);
             this._insertStatus(message);
+        } else if (time - this._state.lastTimestamp > ACTIVITY_DURATION) {
+            this._insertStatusCompressed(text, 'left');
         }
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.OFFLINE);
     },
 
     _onMemberBanned: function(room, member, actor) {
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        let message =
+            actor ? _("%s has been banned by %s").format(member.alias,
+                                                         actor.alias)
+                  : _("%s has been banned").format(member.alias)
         if (this._shouldStatus(member.alias)) {
-            let message =
-                actor ? _("%s has been banned by %s").format(member.alias,
-                                                             actor.alias)
-                      : _("%s has been banned").format(member.alias)
             this._insertStatus(message);
+        } else if (time - this._state.lastTimestamp > ACTIVITY_DURATION) {
+            this._insertStatusCompressed(text, 'left');
         }
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.OFFLINE);
     },
 
     _onMemberJoined: function(room, member) {
-        if (this._shouldStatus(member.alias))
-            this._insertStatus(_("%s joined").format(member.alias));
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        let text = _("%s joined").format(member.alias);
+        if (this._shouldStatus(member.alias)) {
+            this._insertStatus(text);
+        } else if (time - this._state.lastTimestamp > ACTIVITY_DURATION) {
+            this._insertStatusCompressed(text, 'joined');
+        }
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.AVAILABLE);
     },
 
     _onMemberLeft: function(room, member, message) {
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        let text = _("%s left").format(member.alias);
+        if (message)
+            text += ' (%s)'.format(message);
         if (this._shouldStatus(member.alias)) {
-            let text = _("%s left").format(member.alias);
-            if (message)
-                text += ' (%s)'.format(message);
             this._insertStatus(text);
+        } else if (time - this._state.lastTimestamp > ACTIVITY_DURATION) {
+            this._insertStatusCompressed(text, 'left');
         }
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.OFFLINE);
     },
@@ -693,6 +721,24 @@ const ChatView = new Lang.Class({
         if (!nickTag)
            return;
         nickTag._active = GLib.DateTime.new_now_utc().to_unix();
+        this._resetStatusCompressed();
+    },
+
+    _onMessageSent: function(room, tpMessage) {
+        this._insertTpMessage(room, tpMessage);
+        this._resetStatusCompressed();
+    },
+
+    _resetStatusCompressed: function() {
+        let mark = this._view.buffer.get_mark('idle-status');
+        if (!mark)
+            return;
+
+        this._view.buffer.delete_mark(mark);
+        this._statusTexts = [];
+        this._statusCount.forEach(function(statusEntry) {
+            statusEntry.count = 0;
+        });
     },
 
     _shouldStatus: function(nick) {
@@ -705,6 +751,52 @@ const ChatView = new Lang.Class({
         return time - nickTag._active < ACTIVITY_DURATION;
     },
 
+    _insertStatusCompressed: function(statusText, status) {
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        if (time - this._joinTime < IGNORE_STATUS_TIME)
+            return;
+
+        this._statusTexts.push(statusText);
+
+        let compressedText = '';
+        this._statusCount.forEach(function(statusEntry) {
+            if (statusEntry.name == status)
+                statusEntry.count++;
+
+            if (statusEntry.count) {
+                if (compressedText)
+                    compressedText = compressedText + ', '
+
+                compressedText = compressedText + statusEntry.count +
+                                 ' users ' + statusEntry.name;
+            }
+        });
+        let buffer = this._view.buffer;
+        let mark = buffer.get_mark('idle-status');
+        if (!mark) {
+            let iter = buffer.get_end_iter();
+            buffer.create_mark('idle-status', iter, true);
+        }
+
+        if (this._statusTexts.length > STATUS_NOISE_MAXIMUM) {
+            let markIter = buffer.get_iter_at_mark(mark);
+            let startIter = buffer.get_iter_at_line(markIter.get_line());
+            let endIter = buffer.get_end_iter();
+            buffer.delete(startIter, endIter);
+            let tags = [this._lookupTag('status')];
+            this._state.lastNick = null;
+            this._ensureNewLine();
+            this._insertWithTags(endIter, compressedText + ' ( ', tags);
+            let tag = new Gtk.TextTag();
+            tag._statusTexts = this._statusTexts;
+            this._view.get_buffer().tag_table.add(tag);
+            this._insertWithTags(endIter, '\u2026', tags.concat(this._lookupTag('expandable'), tag));
+            this._insertWithTags(endIter, ' )', tags);
+        } else {
+        this._insertStatus(statusText);
+        }
+    },
+
     _insertStatus: function(text) {
         let time = GLib.DateTime.new_now_utc().to_unix();
         if (time - this._joinTime < IGNORE_STATUS_TIME)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]