More consistent timestamps

* Apply the same rounding to in message bubbles and conversation list.
  Also make them consistent with Android's relative times. Fixes #682
* Show full timestamps when hovering on relative time
* Compute timestamp update delays more precisely:
  Set timestamps to self-update as soon as they are able to change
  rather than a fixed time since the last update.
* Refactor for customizable/localizable relative times
* Update timestamp tests
* Log timestamp update intervals to help debug #460
This commit is contained in:
lilia 2016-04-18 19:48:54 -07:00
parent dd7d72a77d
commit 7b29a567b5
4 changed files with 128 additions and 93 deletions

View file

@ -29,21 +29,21 @@ describe('MessageView', function() {
var view = new Whisper.MessageView({model: message});
message.set({'sent_at': Date.now() - 5000});
view.render();
assert.match(view.$el.html(), /seconds ago/);
assert.match(view.$el.html(), /now/);
message.set({'sent_at': Date.now() - 60000});
view.render();
assert.match(view.$el.html(), /minute ago/);
assert.match(view.$el.html(), /min/);
message.set({'sent_at': Date.now() - 3600000});
view.render();
assert.match(view.$el.html(), /hour ago/);
assert.match(view.$el.html(), /hour/);
});
it('should not imply messages are from the future', function() {
var view = new Whisper.MessageView({model: message});
message.set({'sent_at': Date.now() + 60000});
view.render();
assert.match(view.$el.html(), /seconds ago/);
assert.match(view.$el.html(), /now/);
});
it('should go away when the model is destroyed', function() {

View file

@ -6,7 +6,7 @@
describe('TimestampView', function() {
it('formats long-ago timestamps correctly', function() {
var timestamp = Date.now();
var brief_view = new Whisper.BriefTimestampView().render(),
var brief_view = new Whisper.TimestampView({brief: true}).render(),
ext_view = new Whisper.ExtendedTimestampView().render();
// Helper functions to check absolute and relative timestamps
@ -40,15 +40,14 @@ describe('TimestampView', function() {
};
// check integer timestamp, JS Date object and moment object
checkAbs(timestamp, 'now', 'a few seconds ago');
checkAbs(new Date(), 'now', 'a few seconds ago');
checkAbs(moment(), 'now', 'a few seconds ago');
checkAbs(timestamp, 'now', 'now');
checkAbs(new Date(), 'now', 'now');
checkAbs(moment(), 'now', 'now');
// check recent timestamps
checkDiff(30, 'now', 'a few seconds ago'); // 30 seconds
checkDiff(50, '1 min', 'a minute ago'); // >= 45 seconds => 1 minute
checkDiff(30, 'now', 'now'); // 30 seconds
checkDiff(40*60, '40 min', '40 minutes ago');
checkDiff(60*60, '1 hour', 'an hour ago');
checkDiff(60*60, '1 hour', '1 hour ago');
checkDiff(125*60, '2 hours', '2 hours ago');
// set to third of month to avoid problems on the 29th/30th/31st
@ -72,16 +71,54 @@ describe('TimestampView', function() {
});
it('updates at reasonable intervals', function() {
var view = new Whisper.TimestampView();
assert.isBelow(view.computeDelay(1000), 60 * 1000); // < minute
assert.strictEqual(view.computeDelay(1000 * 60 * 5), 60 * 1000); // minute
assert.strictEqual(view.computeDelay(1000 * 60 * 60 * 5), 60 * 60 * 1000); // hour
describe('updates within a minute reasonable intervals', function() {
var view;
beforeEach(function() {
view = new Whisper.TimestampView();
});
afterEach(function() {
clearTimeout(view.timeout);
});
assert.isBelow(view.computeDelay(6 * 24 * 60 * 60 * 1000), 7 * 24 * 60 * 60 * 1000); // < week
it('updates timestamps this minute within a minute', function() {
var now = Date.now();
view.$el.attr('data-timestamp', now - 1000);
view.update();
assert.isAbove(view.delay, 0); // non zero
assert.isBelow(view.delay, 60 * 1000); // < minute
});
// return falsey value for long ago dates that don't update
assert.notOk(view.computeDelay(1000 * 60 * 60 * 24 * 8));
it('updates timestamps from this hour within a minute', function() {
var now = Date.now();
view.$el.attr('data-timestamp', now - 1000 - 1000*60*5); // 5 minutes and 1 sec ago
view.update();
assert.isAbove(view.delay, 0); // non zero
assert.isBelow(view.delay, 60 * 1000); // minute
});
it('updates timestamps from today within an hour', function() {
var now = Date.now();
view.$el.attr('data-timestamp', now - 1000 - 1000*60*60*5); // 5 hours and 1 sec ago
view.update();
assert.isAbove(view.delay, 60 * 1000); // minute
assert.isBelow(view.delay, 60 * 60 * 1000); // hour
});
it('updates timestamps from this week within a day', function() {
var now = Date.now();
view.$el.attr('data-timestamp', now - 1000 - 6*24*60*60*1000); // 6 days and 1 sec ago
view.update();
assert.isAbove(view.delay, 60 * 60 * 1000); // hour
assert.isBelow(view.delay, 24 * 60 * 60 * 1000); // day
});
it('does not updates very old timestamps', function() {
var now = Date.now();
// return falsey value for long ago dates that don't update
view.$el.attr('data-timestamp', now - 8*24*60*60*1000);
view.update();
assert.notOk(view.delay);
});
});