Browse Source

Improved message date format

Added date splitters when messages were sent on different days
Closes #286
master
Igor Zhukov 11 years ago
parent
commit
8682586ca9
  1. 10
      app/css/app.css
  2. 43
      app/js/controllers.js
  3. 31
      app/js/filters.js
  4. 26
      app/js/lib/mtproto.js
  5. 59
      app/js/services.js
  6. 6
      app/partials/message.html

10
app/css/app.css

@ -1818,6 +1818,16 @@ img.im_message_document_thumb {
padding: 0 0 20px 10px; padding: 0 0 20px 10px;
} }
.im_message_date_seconds {
padding: 0;
margin: 0;
position: absolute;
display: none;
}
.im_message_meta:hover .im_message_date_seconds {
display: inline;
}
@media (max-width: 900px) { @media (max-width: 900px) {
/* Status ticks */ /* Status ticks */

43
app/js/controllers.js

@ -728,39 +728,6 @@ angular.module('myApp.controllers', [])
} }
} }
function updateHistoryGroups (limit) {
var start = 0,
end = $scope.history.length,
i, curMessage, prevMessage;
if (limit > 0) {
end = limit;
} else if (limit < 0) {
start = end + limit;
}
for (i = start; i < end; i++) {
curMessage = $scope.history[i];
if (prevMessage &&
curMessage.from_id == prevMessage.from_id &&
!prevMessage.fwd_from_id == !curMessage.fwd_from_id &&
!prevMessage.action &&
!curMessage.action &&
curMessage.date < prevMessage.date + 900) {
var singleLine = curMessage.message && curMessage.message.length < 70 && curMessage.message.indexOf("\n") == -1;
if (curMessage.fwd_from_id && curMessage.fwd_from_id == prevMessage.fwd_from_id) {
curMessage.grouped = singleLine ? 4 : 3;
} else {
curMessage.grouped = !curMessage.fwd_from_id && singleLine ? 1 : 2;
}
} else if (prevMessage || !i) {
delete curMessage.grouped;
}
prevMessage = curMessage;
}
}
function messageFocusHistory () { function messageFocusHistory () {
var i, found = false; var i, found = false;
for (i = 0; i < $scope.history.length; i++) { for (i = 0; i < $scope.history.length; i++) {
@ -803,7 +770,7 @@ angular.module('myApp.controllers', [])
minID = historyResult.history.length >= backLimit minID = historyResult.history.length >= backLimit
? historyResult.history[0] ? historyResult.history[0]
: 0; : 0;
updateHistoryGroups(-backLimit); AppMessagesManager.regroupWrappedHistory($scope.history, -backLimit);
$scope.$broadcast('ui_history_append'); $scope.$broadcast('ui_history_append');
} else { } else {
minID = 0; minID = 0;
@ -837,7 +804,7 @@ angular.module('myApp.controllers', [])
if (historyResult.history.length) { if (historyResult.history.length) {
maxID = historyResult.history[historyResult.history.length - 1]; maxID = historyResult.history[historyResult.history.length - 1];
updateHistoryGroups(historyResult.history.length + 1); AppMessagesManager.regroupWrappedHistory($scope.history, historyResult.history.length + 1);
$scope.$broadcast('ui_history_prepend'); $scope.$broadcast('ui_history_prepend');
} }
}); });
@ -898,7 +865,7 @@ angular.module('myApp.controllers', [])
}); });
$scope.history.reverse(); $scope.history.reverse();
updateHistoryGroups(); AppMessagesManager.regroupWrappedHistory($scope.history);
if (historyResult.unreadOffset) { if (historyResult.unreadOffset) {
$scope.historyUnreadAfter = historyResult.history[historyResult.unreadOffset - 1]; $scope.historyUnreadAfter = historyResult.history[historyResult.unreadOffset - 1];
@ -1074,7 +1041,7 @@ angular.module('myApp.controllers', [])
// console.log('append', addedMessage); // console.log('append', addedMessage);
// console.trace(); // console.trace();
$scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID)); $scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID));
updateHistoryGroups(-3); AppMessagesManager.regroupWrappedHistory($scope.history, -3);
$scope.typing = {}; $scope.typing = {};
$scope.$broadcast('ui_history_append_new', {my: addedMessage.my}); $scope.$broadcast('ui_history_append_new', {my: addedMessage.my});
if (addedMessage.my) { if (addedMessage.my) {
@ -1100,7 +1067,7 @@ angular.module('myApp.controllers', [])
} }
}; };
$scope.history = newHistory; $scope.history = newHistory;
updateHistoryGroups(); AppMessagesManager.regroupWrappedHistory($scope.history);
} }
}); });

31
app/js/filters.js

@ -74,6 +74,37 @@ angular.module('myApp.filters', [])
} }
}]) }])
.filter('time', ['$filter', function($filter) {
var cachedDates = {};
return function (timestamp) {
if (cachedDates[timestamp]) {
return cachedDates[timestamp];
}
return cachedDates[timestamp] = $filter('date')(timestamp * 1000, 'HH:mm');
}
}])
.filter('myDate', ['$filter', function($filter) {
var cachedDates = {};
return function (timestamp) {
if (cachedDates[timestamp]) {
return cachedDates[timestamp];
}
return cachedDates[timestamp] = $filter('date')(timestamp * 1000, 'fullDate');
}
}])
.filter('seconds', function($filter) {
return function (timestamp) {
var sec = timestamp % 60;
return sec < 10 ? '0' + sec : sec;
}
})
.filter('duration', [function() { .filter('duration', [function() {
return function (duration) { return function (duration) {
var secs = duration % 60, var secs = duration % 60,

26
app/js/lib/mtproto.js

@ -118,7 +118,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
return new SecureRandom(); return new SecureRandom();
}) })
.factory('MtpDateManager', function (Storage) { .factory('MtpTimeManager', function (Storage) {
var lastMessageID = [0, 0], var lastMessageID = [0, 0],
timeOffset = 0; timeOffset = 0;
@ -171,7 +171,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
}; };
}) })
.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpDateManager, CryptoWorker, $http, $q, $timeout) { .factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpTimeManager, CryptoWorker, $http, $q, $timeout) {
function mtpSendPlainRequest (dcID, requestBuffer) { function mtpSendPlainRequest (dcID, requestBuffer) {
var requestLength = requestBuffer.byteLength, var requestLength = requestBuffer.byteLength,
@ -179,7 +179,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var header = new TLSerialization(); var header = new TLSerialization();
header.storeLongP(0, 0, 'auth_key_id'); // Auth key header.storeLongP(0, 0, 'auth_key_id'); // Auth key
header.storeLong(MtpDateManager.generateID(), 'msg_id'); // Msg_id header.storeLong(MtpTimeManager.generateID(), 'msg_id'); // Msg_id
header.storeInt(requestLength, 'request_length'); header.storeInt(requestLength, 'request_length');
var headerBuffer = header.getBuffer(), var headerBuffer = header.getBuffer(),
@ -391,7 +391,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
throw new Error('server_DH_inner_data SHA1-hash mismatch'); throw new Error('server_DH_inner_data SHA1-hash mismatch');
} }
MtpDateManager.applyServerTime(auth.serverTime, auth.localTime); MtpTimeManager.applyServerTime(auth.serverTime, auth.localTime);
}; };
function mtpSendSetClientDhParams(auth) { function mtpSendSetClientDhParams(auth) {
@ -539,7 +539,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
}) })
.factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpDateManager, MtpSecureRandom, Storage, CryptoWorker, $http, $q, $timeout, $interval, $rootScope) { .factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpTimeManager, MtpSecureRandom, Storage, CryptoWorker, $http, $q, $timeout, $interval, $rootScope) {
var updatesProcessor, var updatesProcessor,
iii = 0, iii = 0,
@ -642,7 +642,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
sentMessage.inner = newInner; sentMessage.inner = newInner;
} }
sentMessage.msg_id = MtpDateManager.generateID(); sentMessage.msg_id = MtpTimeManager.generateID();
sentMessage.seq_no = this.generateSeqNo( sentMessage.seq_no = this.generateSeqNo(
sentMessage.notContentRelated || sentMessage.notContentRelated ||
sentMessage.container sentMessage.container
@ -669,7 +669,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
serializer.storeMethod(method, params); serializer.storeMethod(method, params);
var messageID = MtpDateManager.generateID(), var messageID = MtpTimeManager.generateID(),
seqNo = this.generateSeqNo(), seqNo = this.generateSeqNo(),
message = { message = {
msg_id: messageID, msg_id: messageID,
@ -690,7 +690,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var serializer = new TLSerialization({mtproto: true}); var serializer = new TLSerialization({mtproto: true});
serializer.storeObject(object, 'Object'); serializer.storeObject(object, 'Object');
var messageID = MtpDateManager.generateID(), var messageID = MtpTimeManager.generateID(),
seqNo = this.generateSeqNo(options.notContentRelated), seqNo = this.generateSeqNo(options.notContentRelated),
message = { message = {
msg_id: messageID, msg_id: messageID,
@ -725,7 +725,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
options.resultType = serializer.storeMethod(method, params); options.resultType = serializer.storeMethod(method, params);
var messageID = MtpDateManager.generateID(), var messageID = MtpTimeManager.generateID(),
seqNo = this.generateSeqNo(), seqNo = this.generateSeqNo(),
message = { message = {
msg_id: messageID, msg_id: messageID,
@ -849,7 +849,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
serializer.storeMethod('ping', {ping_id: pingID}); serializer.storeMethod('ping', {ping_id: pingID});
var pingMessage = { var pingMessage = {
msg_id: MtpDateManager.generateID(), msg_id: MtpTimeManager.generateID(),
seq_no: this.generateSeqNo(true), seq_no: this.generateSeqNo(true),
body: serializer.getBytes() body: serializer.getBytes()
}; };
@ -964,7 +964,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var serializer = new TLSerialization({mtproto: true}); var serializer = new TLSerialization({mtproto: true});
serializer.storeMethod('http_wait', {max_delay: 0, wait_after: 0, max_wait: 1000}); serializer.storeMethod('http_wait', {max_delay: 0, wait_after: 0, max_wait: 1000});
messages.push({ messages.push({
msg_id: MtpDateManager.generateID(), msg_id: MtpTimeManager.generateID(),
seq_no: this.generateSeqNo(), seq_no: this.generateSeqNo(),
body: serializer.getBytes() body: serializer.getBytes()
}); });
@ -995,7 +995,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
} }
var containerSentMessage = { var containerSentMessage = {
msg_id: MtpDateManager.generateID(), msg_id: MtpTimeManager.generateID(),
seq_no: this.generateSeqNo(true), seq_no: this.generateSeqNo(true),
container: true, container: true,
inner: innerMessages inner: innerMessages
@ -1345,7 +1345,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
} }
if (message.error_code == 16 || message.error_code == 17) { if (message.error_code == 16 || message.error_code == 17) {
if (MtpDateManager.applyServerTime( if (MtpTimeManager.applyServerTime(
bigStringInt(messageID).shiftRight(32).toString(10) bigStringInt(messageID).shiftRight(32).toString(10)
)) { )) {
this.updateSession(); this.updateSession();

59
app/js/services.js

@ -673,7 +673,7 @@ angular.module('myApp.services', [])
} }
}) })
.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager) { .service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, MtpTimeManager, RichTextProcessor, NotificationsManager, SearchIndexManager) {
var messagesStorage = {}; var messagesStorage = {};
var messagesForHistory = {}; var messagesForHistory = {};
@ -692,6 +692,17 @@ angular.module('myApp.services', [])
var lastSearchFilter = {}, var lastSearchFilter = {},
lastSearchResults = []; lastSearchResults = [];
var serverTimeOffset = MtpTimeManager.getTimeOffset(),
timestampNow = tsNow(true),
midnightNoOffset = timestampNow - (timestampNow % 86400),
midnightOffseted = new Date(),
midnightOffset;
midnightOffseted.setHours(0);
midnightOffseted.setMinutes(0);
midnightOffseted.setSeconds(0);
midnightOffset = midnightNoOffset - (Math.floor(+midnightOffseted / 1000));
NotificationsManager.start(); NotificationsManager.start();
function getDialogs (query, maxID, limit) { function getDialogs (query, maxID, limit) {
@ -1773,6 +1784,46 @@ angular.module('myApp.services', [])
return messagesForHistory[msgID] = message; return messagesForHistory[msgID] = message;
} }
function regroupWrappedHistory (history, limit) {
var start = 0,
end = history.length,
i, curDay, prevDay, curMessage, prevMessage;
if (limit > 0) {
end = limit;
} else if (limit < 0) {
start = end + limit;
}
for (i = start; i < end; i++) {
curMessage = history[i];
curDay = Math.floor((curMessage.date - midnightOffset) / 86400);
if (curDay !== prevDay) {
curMessage.needDate = true;
} else if (prevMessage) {
delete curMessage.needDate;
}
if (prevMessage &&
curMessage.from_id == prevMessage.from_id &&
!prevMessage.fwd_from_id == !curMessage.fwd_from_id &&
!prevMessage.action &&
!curMessage.action &&
curMessage.date < prevMessage.date + 900) {
var singleLine = curMessage.message && curMessage.message.length < 70 && curMessage.message.indexOf("\n") == -1;
if (curMessage.fwd_from_id && curMessage.fwd_from_id == prevMessage.fwd_from_id) {
curMessage.grouped = singleLine ? 4 : 3;
} else {
curMessage.grouped = !curMessage.fwd_from_id && singleLine ? 1 : 2;
}
} else if (prevMessage || !i) {
delete curMessage.grouped;
}
prevMessage = curMessage;
prevDay = curDay;
}
}
function getDialogByPeerID (peerID) { function getDialogByPeerID (peerID) {
for (var i = 0; i < dialogsStorage.dialogs.length; i++) { for (var i = 0; i < dialogsStorage.dialogs.length; i++) {
if (dialogsStorage.dialogs[i].peerID == peerID) { if (dialogsStorage.dialogs[i].peerID == peerID) {
@ -1886,6 +1937,9 @@ angular.module('myApp.services', [])
historyStorage = historiesStorage[peerID] = {count: null, history: [message.id], pending: []}; historyStorage = historiesStorage[peerID] = {count: null, history: [message.id], pending: []};
} }
// Fix time offset
message.date -= serverTimeOffset;
saveMessages([message]); saveMessages([message]);
if (historyStorage.count !== null) { if (historyStorage.count !== null) {
@ -2054,7 +2108,8 @@ angular.module('myApp.services', [])
forwardMessages: forwardMessages, forwardMessages: forwardMessages,
getMessagePeer: getMessagePeer, getMessagePeer: getMessagePeer,
wrapForDialog: wrapForDialog, wrapForDialog: wrapForDialog,
wrapForHistory: wrapForHistory wrapForHistory: wrapForHistory,
regroupWrappedHistory: regroupWrappedHistory
} }
}) })

6
app/partials/message.html

@ -2,6 +2,10 @@
Unread messages Unread messages
</div> </div>
<div class="im_message_date_split im_service_message_wrap" bo-if="historyMessage.needDate" ng-show="historyMessage.needDate">
<div class="im_service_message" ng-bind="historyMessage.date | myDate"></div>
</div>
<div class="im_message_outer_wrap" ng-class="[ selectedMsgs[historyMessage.id] &amp;&amp; 'im_message_selected', historyMessage.grouped &amp;&amp; ('im_message_grouped' + historyMessage.grouped) , historyFocus == historyMessage.id &amp;&amp; 'im_message_focus']" ng-click="toggleMessage(historyMessage.id, $event)"> <div class="im_message_outer_wrap" ng-class="[ selectedMsgs[historyMessage.id] &amp;&amp; 'im_message_selected', historyMessage.grouped &amp;&amp; ('im_message_grouped' + historyMessage.grouped) , historyFocus == historyMessage.id &amp;&amp; 'im_message_focus']" ng-click="toggleMessage(historyMessage.id, $event)">
@ -77,7 +81,7 @@
</a> </a>
<div class="im_message_meta pull-right text-right"> <div class="im_message_meta pull-right text-right">
<i class="icon-message-status-tick"></i> <i class="icon-message-status-tick"></i>
<span class="im_message_date" bo-bind="historyMessage.date | dateOrTime"></span> <span class="im_message_date" ng-bind="historyMessage.date | time"></span><span class="im_message_date im_message_date_seconds">:<span ng-bind="historyMessage.date | seconds"></span></span>
</div> </div>
<div class="im_message_body"> <div class="im_message_body">

Loading…
Cancel
Save