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:
parent
4f7a28863c
commit
926ddc2bdf
@ -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;
|
||||||
|
@ -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;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user