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



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

    chatView: Compress status messages on idle channels
    
    If a channel is idle (no activity in 5 minutes), then
    display 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 |  163 +++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 139 insertions(+), 24 deletions(-)
---
diff --git a/src/chatView.js b/src/chatView.js
index 25547b9..9680078 100644
--- a/src/chatView.js
+++ b/src/chatView.js
@@ -22,6 +22,7 @@ const TIMESTAMP_INTERVAL = 300; // seconds of inactivity after which to
 
 const INACTIVITY_THRESHOLD = 300; // a threshold in seconds used to control
                                   // the visibility of status messages
+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
@@ -140,7 +141,7 @@ const ChatView = new Lang.Class({
         this._onStyleUpdated();
 
         this._room = room;
-        this._state = { lastNick: null, lastTimestamp: 0 };
+        this._state = { lastNick: null, lastTimestamp: 0, lastStatusGroup: 0 };
         this._active = false;
         this._toplevelFocus = false;
         this._joinTime = 0;
@@ -149,6 +150,7 @@ const ChatView = new Lang.Class({
         this._needsIndicator = true;
         this._pending = {};
         this._pendingLogs = [];
+        this._statusCount = { left: 0, joined: 0, total: 0 };
 
         let isRoom = room.type == Tp.HandleType.ROOM;
         let target = new Tpl.Entity({ type: isRoom ? Tpl.EntityType.ROOM
@@ -542,6 +544,12 @@ const ChatView = new Lang.Class({
                     return Gdk.EVENT_STOP;
                 }
                 break;
+            } else if (tags[i].name.startsWith('status-compressed')) {
+                if (isPress && button == Gdk.BUTTON_PRIMARY) {
+                    let statusTag = this._lookupTag('status' + tags[i].name.slice(17)); // 
'status-compressed'.length
+                    statusTag.invisible = !statusTag.invisible;
+                }
+                return Gdk.EVENT_STOP;
             }
         }
         return Gdk.EVENT_PROPAGATE;
@@ -555,7 +563,7 @@ const ChatView = new Lang.Class({
         let tags = iter.get_tags();
         let hovering = false;
         for (let i = 0; i < tags.length && !hovering; i++)
-            if (tags[i]._url)
+            if (tags[i]._url || tags[i].name.startsWith('status-compressed'))
                 hovering = true;
 
         if (this._hoveringLink != hovering) {
@@ -656,7 +664,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) }
         ];
@@ -684,71 +692,107 @@ 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._shouldShowStatus(oldMember.alias)) {
-            this._insertStatus(_("%s is now known as %s").format(oldMember.alias,
-                                                                 newMember.alias));
+            this._insertStatus(text);
+        } else if (time - this._state.lastTimestamp > INACTIVITY_THRESHOLD) {
+            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._shouldShowStatus(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 > INACTIVITY_THRESHOLD) {
+            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._shouldShowStatus(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 > INACTIVITY_THRESHOLD) {
+            this._insertStatusCompressed(message, '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._shouldShowStatus(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 > INACTIVITY_THRESHOLD) {
+            this._insertStatusCompressed(message, 'left');
         }
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.OFFLINE);
     },
 
     _onMemberJoined: function(room, member) {
-        if (this._shouldShowStatus(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._shouldShowStatus(member.alias)) {
+            this._insertStatus(text);
+        } else if (time - this._state.lastTimestamp > INACTIVITY_THRESHOLD) {
+            this._insertStatusCompressed(text, 'joined');
+        }
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.AVAILABLE);
     },
 
     _onMemberLeft: function(room, member, message) {
-        if (this._shouldShowStatus(member.alias)) {
-            let text = _("%s left").format(member.alias);
-            if (message)
-                text += ' (%s)'.format(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._shouldShowStatus(member.alias))
             this._insertStatus(text);
-        }
+        else if (time - this._state.lastTimestamp > INACTIVITY_THRESHOLD)
+            this._insertStatusCompressed(text, 'left');
+
         this._setNickStatus(member.alias, Tp.ConnectionPresenceType.OFFLINE);
     },
 
     _onMessageReceived: function(room, tpMessage) {
         this._insertTpMessage(room, tpMessage);
-
+        this._resetStatusCompressed();
         let nick = tpMessage.sender.alias;
         let nickTag = this._lookupTag('nick' + nick);
         if (!nickTag)
            return;
         nickTag._lastActivity = GLib.get_monotonic_time();
+    },
+
+    _onMessageSent: function(room, tpMessage) {
+        this._insertTpMessage(room, tpMessage);
+        this._resetStatusCompressed();
+    },
+
+    _resetStatusCompressed: function() {
+        let markStart = this._view.buffer.get_mark('idle-status-start');
+        if (!markStart)
+            return;
 
+        this._view.buffer.delete_mark(markStart);
+        this._statusCount =  { left: 0, joined: 0, total: 0 };
+        this._state.lastStatusGroup++;
     },
 
     _shouldShowStatus: function(nick) {
@@ -761,6 +805,77 @@ const ChatView = new Lang.Class({
         return time - nickTag._lastActivity < INACTIVITY_THRESHOLD;
     },
 
+/*
+    _insertStatus: function( The status message, time ? ) {
+
+        // Should the status be grouped?
+            // YES: Is there a group which exists already?
+                // YES: Then insert into the group
+                // NO: Then create a new group
+
+        // Should the status be shown at all? If not, then we return
+    },
+
+*/
+
+
+
+
+    _insertStatusCompressed: function(statusText, status) {
+        let time = GLib.DateTime.new_now_utc().to_unix();
+        if (time - this._joinTime < IGNORE_STATUS_TIME)
+            return;
+
+        this._state.lastNick = null;
+
+        if (this._statusCount.total == 0)
+            this._ensureNewLine();
+
+        if (status == 'left')
+            this._statusCount.left++;
+        else if (status == 'joined')
+            this._statusCount.joined++;
+        this._statusCount.total++;
+
+        let buffer = this._view.buffer;
+        let markStart = buffer.get_mark('idle-status-start');
+        if (!markStart) {
+            let iter = buffer.get_end_iter();
+            markStart = buffer.create_mark('idle-status-start', iter, true);
+        }
+
+        let statusGroupNumber = this._state.lastStatusGroup;
+        let statusGroupTag = this._lookupTag('status' + statusGroupNumber);
+        if (!statusGroupTag) {
+            statusGroupTag = new Gtk.TextTag({ name: 'status' + statusGroupNumber });
+            buffer.tag_table.add(statusGroupTag);
+        }
+
+        let statusTag = this._lookupTag('status');
+        let endIter = buffer.get_end_iter();
+        this._insertWithTags(endIter, statusText + '\n', [statusGroupTag, statusTag]);
+
+        if (this._statusCount.total > STATUS_NOISE_MAXIMUM) {
+            let statusCompressedTag = this._lookupTag('status-compressed' + statusGroupNumber);
+            if (!statusCompressedTag) {
+                statusCompressedTag = new Gtk.TextTag({ name: 'status-compressed' + statusGroupNumber });
+                buffer.tag_table.add(statusCompressedTag);
+                statusGroupTag.invisible = true;
+            }
+
+            let compressedText = this._statusCount.joined + " users joined, "
+                                 + this._statusCount.left + " users left. ";
+
+            let markStartIter = buffer.get_iter_at_mark(markStart);
+            let markEndIter = markStartIter.copy();
+            markEndIter.forward_line();
+            buffer.delete(markStartIter, markEndIter);
+
+            markStartIter = buffer.get_iter_at_mark(markStart);
+            this._insertWithTags(markStartIter, compressedText + ' (\u2026) \n' , [statusTag, 
statusCompressedTag]);
+        }
+    },
+
     _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]