diff --git a/js/ui/docDisplay.js b/js/ui/docDisplay.js index cb2a53a98..d457d2d29 100644 --- a/js/ui/docDisplay.js +++ b/js/ui/docDisplay.js @@ -14,24 +14,37 @@ const Main = imports.ui.main; /* This class represents a single display item containing information about a document. * * docInfo - DocInfo object containing information about the document + * currentSeconds - current number of seconds since the epoch * availableWidth - total width available for the item */ -function DocDisplayItem(docInfo, availableWidth) { - this._init(docInfo, availableWidth); +function DocDisplayItem(docInfo, currentSecs, availableWidth) { + this._init(docInfo, currentSecs, availableWidth); } DocDisplayItem.prototype = { __proto__: GenericDisplay.GenericDisplayItem.prototype, - _init : function(docInfo, availableWidth) { - GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth); + _init : function(docInfo, currentSecs, availableWidth) { + GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth); this._docInfo = docInfo; - + this._setItemInfo(docInfo.name, ""); + // We take the current number of seconds here to avoid looking up the current + // time for every item + this._resetTimeDisplay(currentSecs); }, //// Public methods //// + getUpdateTimeout: function() { + return this._timeout; + }, + + // Update any relative-time based displays for this item. + redisplay: function(currentSecs) { + this._resetTimeDisplay(currentSecs); + }, + //// Public method overrides //// // Opens a document represented by this display item. @@ -60,6 +73,16 @@ DocDisplayItem.prototype = { return Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.NONE, this._docInfo.uri, availableWidth, availableHeight); + }, + + //// Private Methods //// + + _resetTimeDisplay: function(currentSecs) { + let lastSecs = this._docInfo.lastVisited().getTime() / 1000; + let timeDelta = currentSecs - lastSecs; + let [text, nextUpdate] = Shell.Global.get().format_time_relative_pretty(timeDelta); + this._timeout = nextUpdate; + this._setDescriptionText(text); } }; @@ -79,6 +102,9 @@ DocDisplay.prototype = { GenericDisplay.GenericDisplay.prototype._init.call(this, width); let me = this; + this._updateTimeoutTarget = 0; + this._updateTimeoutId = 0; + this._docManager = DocInfo.getDocManager(GenericDisplay.ITEM_DISPLAY_ICON_SIZE); this._docsStale = true; this._docManager.connect('changed', function(mgr, userData) { @@ -87,8 +113,13 @@ DocDisplay.prototype = { // but redisplaying right away is cool when we use Zephyr. // Also, we might be displaying remote documents, like Google Docs, in the future // which might be edited by someone else. - me._redisplay(false); + me._redisplay(false); }); + + this.connect('destroy', Lang.bind(this, function (o) { + if (this._updateTimeoutId > 0) + Mainloop.source_remove(this._updateTimeoutId); + })); }, //// Protected method overrides //// @@ -165,7 +196,25 @@ DocDisplay.prototype = { // Creates a DocDisplayItem based on itemInfo, which is expected to be a DocInfo object. _createDisplayItem: function(itemInfo, width) { - return new DocDisplayItem(itemInfo, width); + let currentSecs = new Date().getTime() / 1000; + let doc = new DocDisplayItem(itemInfo, currentSecs, width); + if (doc.getUpdateTimeout() < this._updateTimeoutTarget) { + if (this._updateTimeoutId > 0) + Mainloop.source_remove(this._updateTimeoutId); + this._updateTimeoutId = Mainloop.timeout_add_seconds(doc.getUpdateTimeout(), Lang.bind(this, this._docTimeout)); + this._updateTimeoutTarget = doc.getUpdateTimeout(); + } + return doc; + }, + + //// Private Methods //// + _docTimeout: function () { + let currentSecs = new Date().getTime() / 1000; + for (let docId in this._allItems) { + let doc = this._allItems[docId]; + doc.redisplay(currentSecs); + } + return true; } }; diff --git a/js/ui/genericDisplay.js b/js/ui/genericDisplay.js index 4b80bbeca..27b3bffb5 100644 --- a/js/ui/genericDisplay.js +++ b/js/ui/genericDisplay.js @@ -287,6 +287,10 @@ GenericDisplayItem.prototype = { this.actor.add_actor(this._description); }, + _setDescriptionText: function(text) { + this._description.text = text; + }, + //// Virtual protected methods //// // Creates and returns a large preview icon, but only if we have a detailed image. diff --git a/src/shell-global.c b/src/shell-global.c index ea316364b..19ff88ac2 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -963,6 +964,44 @@ root_pixmap_destroy (GObject *sender, gpointer data) global->root_pixmap = NULL; } +/** + * shell_global_format_time_relative_pretty: + * @global: + * @delta: Time in seconds since the current time + * @text: (out): Relative human-consumption-only time string + * @next_update: (out): Time in seconds until we should redisplay the time + * + * Format a time value for human consumption only. The passed time + * value is a delta in terms of seconds from the current time. + */ +void +shell_global_format_time_relative_pretty (ShellGlobal *global, + guint delta, + char **text, + guint *next_update) +{ +#define MINUTE (60) +#define HOUR (MINUTE*60) +#define DAY (HOUR*24) +#define WEEK (DAY*7) + if (delta < MINUTE) { + *text = g_strdup (_("Less than a minute ago")); + *next_update = MINUTE - delta; + } else if (delta < HOUR) { + *text = g_strdup_printf (ngettext ("%d minute ago", "%d minutes ago", delta / MINUTE), delta / MINUTE); + *next_update = MINUTE*(delta-MINUTE + 1) - delta; + } else if (delta < DAY) { + *text = g_strdup_printf (ngettext ("%d hour ago", "%d hours ago", delta / HOUR), delta / HOUR); + *next_update = HOUR*(delta-HOUR + 1) - delta; + } else if (delta < WEEK) { + *text = g_strdup_printf (ngettext ("%d day ago", "%d days ago", delta / DAY), delta / DAY); + *next_update = DAY*(delta-DAY + 1) - delta; + } else { + *text = g_strdup_printf (ngettext ("%d week ago", "%d weeks ago", delta / WEEK), delta / WEEK); + *next_update = WEEK*(delta-WEEK + 1) - delta; + } +} + /** * shell_global_create_root_pixmap_actor: * @global: a #ShellGlobal diff --git a/src/shell-global.h b/src/shell-global.h index e7dce9559..813d42ab8 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -77,6 +77,8 @@ ClutterCairoTexture *shell_global_create_vertical_gradient (ClutterColor *top, ClutterCairoTexture *shell_global_create_horizontal_gradient (ClutterColor *left, ClutterColor *right); +void shell_global_format_time_relative_pretty (ShellGlobal *global, guint delta, char **text, guint *update_time); + ClutterActor *shell_global_create_root_pixmap_actor (ShellGlobal *global); void shell_global_clutter_cairo_texture_draw_clock (ClutterCairoTexture *texture,