Show timestamp in expanded chat

When the last message is older than SCROLLBACK_IMMEDIATE_TIME (1
minutes), show a timestamp in the middle, indicating the time it
was sent.
Use the same style for presence changes, but show them on the left.

https://bugzilla.gnome.org/show_bug.cgi?id=617228
This commit is contained in:
Giovanni Campagna 2010-11-25 15:29:41 +01:00
parent 4f7a28863c
commit 926ddc2bdf
3 changed files with 72 additions and 19 deletions

View File

@ -957,6 +957,13 @@ StTooltip StLabel {
border-radius: 4px; border-radius: 4px;
} }
.chat-meta-message {
padding-left: 4px;
border-radius: 4px;
font-size: 14px;
color: #bbbbbb;
}
.chat-response { .chat-response {
padding: 4px; padding: 4px;
border-radius: 4px; border-radius: 4px;

View File

@ -365,7 +365,7 @@ Notification.prototype = {
// @actor: actor to add to the body of the notification // @actor: actor to add to the body of the notification
// //
// Appends @actor to the notification's body // Appends @actor to the notification's body
addActor: function(actor) { addActor: function(actor, style) {
if (!this._scrollArea) { if (!this._scrollArea) {
this.actor.add_style_class_name('multi-line-notification'); this.actor.add_style_class_name('multi-line-notification');
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview', this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
@ -382,21 +382,22 @@ Notification.prototype = {
this._addBannerBody(); this._addBannerBody();
} }
this._contentArea.add(actor); this._contentArea.add(actor, style ? style : {});
this._updated(); this._updated();
}, },
// addBody: // addBody:
// @text: the text // @text: the text
// @markup: %true if @text contains pango markup // @markup: %true if @text contains pango markup
// @style: style to use when adding the actor containing the text
// //
// Adds a multi-line label containing @text to the notification. // Adds a multi-line label containing @text to the notification.
// //
// Return value: the newly-added label // Return value: the newly-added label
addBody: function(text, markup) { addBody: function(text, markup, style) {
let label = new URLHighlighter(text, true, markup); let label = new URLHighlighter(text, true, markup);
this.addActor(label.actor); this.addActor(label.actor, style);
return label.actor; return label.actor;
}, },

View File

@ -3,6 +3,7 @@
const DBus = imports.dbus; const DBus = imports.dbus;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals; const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell'); const Gettext = imports.gettext.domain('gnome-shell');
@ -16,6 +17,7 @@ let contactManager;
let channelDispatcher; let channelDispatcher;
// See Notification.appendMessage // See Notification.appendMessage
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
const SCROLLBACK_RECENT_LENGTH = 20; const SCROLLBACK_RECENT_LENGTH = 20;
const SCROLLBACK_IDLE_LENGTH = 5; const SCROLLBACK_IDLE_LENGTH = 5;
@ -531,7 +533,7 @@ Source.prototype = {
_messageReceived: function(channel, id, timestamp, sender, _messageReceived: function(channel, id, timestamp, sender,
type, flags, text) { type, flags, text) {
this._ensureNotification(); this._ensureNotification();
this._notification.appendMessage(text); this._notification.appendMessage(text, timestamp);
this.notify(this._notification); this.notify(this._notification);
}, },
@ -565,7 +567,7 @@ Source.prototype = {
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>'; msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
this._ensureNotification(); this._ensureNotification();
this._notification.appendMessage(msg, true); this._notification.appendPresence(msg, notify);
if (notify) if (notify)
this.notify(this._notification); this.notify(this._notification);
} }
@ -586,23 +588,40 @@ Notification.prototype = {
this.setActionArea(this._responseEntry); this.setActionArea(this._responseEntry);
this._history = []; this._history = [];
this._timestampTimeoutId = 0;
}, },
appendMessage: function(text, asTitle) { appendMessage: function(text, timestamp) {
if (asTitle)
this.update(text, null, { customContent: true });
else
this.update(this.source.title, text, { customContent: true }); this.update(this.source.title, text, { customContent: true });
this._append(text, 'chat-received'); this._append(text, 'chat-received', timestamp);
}, },
_append: function(text, style) { _append: function(text, style, timestamp) {
let currentTime = (Date.now() / 1000);
if (!timestamp)
timestamp = currentTime;
let lastMessageTime = -1;
if (this._history.length > 0)
lastMessageTime = this._history[0].time;
// Reset the old message timeout
if (this._timestampTimeoutId)
Mainloop.source_remove(this._timestampTimeoutId);
let body = this.addBody(text); let body = this.addBody(text);
body.add_style_class_name(style); body.add_style_class_name(style);
this.scrollTo(St.Side.BOTTOM); this.scrollTo(St.Side.BOTTOM);
let now = new Date().getTime() / 1000; this._history.unshift({ actor: body, time: timestamp, realMessage: true });
this._history.unshift({ actor: body, time: now });
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME)
this._appendTimestamp();
else
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
// from the timestamp of the message.
this._timestampTimeoutId = Mainloop.timeout_add_seconds(
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
Lang.bind(this, this._appendTimestamp));
if (this._history.length > 1) { if (this._history.length > 1) {
// Keep the scrollback from growing too long. If the most // Keep the scrollback from growing too long. If the most
@ -611,17 +630,43 @@ Notification.prototype = {
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise // SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
// we'll keep SCROLLBACK_IDLE_LENGTH messages. // we'll keep SCROLLBACK_IDLE_LENGTH messages.
let lastMessageTime = this._history[1].time; let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
let maxLength = (lastMessageTime < now - SCROLLBACK_RECENT_TIME) ?
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH; SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
if (this._history.length > maxLength) { let filteredHistory = this._history.filter(function(item) { return item.realMessage });
let expired = this._history.splice(maxLength); if (filteredHistory.length > maxLength) {
let lastMessageToKeep = filteredHistory[maxLength];
let expired = this._history.splice(this._history.indexOf(lastMessageToKeep));
for (let i = 0; i < expired.length; i++) for (let i = 0; i < expired.length; i++)
expired[i].actor.destroy(); expired[i].actor.destroy();
} }
} }
}, },
_appendTimestamp: function() {
let lastMessageTime = this._history[0].time;
let lastMessageDate = new Date(lastMessageTime * 1000);
/* Translators: this is a time format string followed by a date.
If applicable, replace %X with a strftime format valid for your
locale, without seconds. */
let timeLabel = this.addBody(lastMessageDate.toLocaleFormat(_("Sent at %X on %A")), false, { expand: true, x_fill: false, x_align: St.Align.END });
timeLabel.add_style_class_name('chat-meta-message');
this._history.unshift({ actor: timeLabel, time: lastMessageTime, realMessage: false });
this._timestampTimeoutId = 0;
return false;
},
appendPresence: function(text, asTitle) {
if (asTitle)
this.update(text, null, { customContent: true });
else
this.update(this.source.title, null, { customContent: true });
let label = this.addBody(text);
label.add_style_class_name('chat-meta-message');
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false});
},
grabFocus: function(lockTray) { grabFocus: function(lockTray) {
// Need to call the base class function first so that // Need to call the base class function first so that
// it saves where the key focus was before. // it saves where the key focus was before.