diff --git a/app/css/app.css b/app/css/app.css index 4586ba8a..b7335691 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -1818,6 +1818,16 @@ img.im_message_document_thumb { 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) { /* Status ticks */ diff --git a/app/js/controllers.js b/app/js/controllers.js index 07966859..45eed8a6 100644 --- a/app/js/controllers.js +++ b/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 () { var i, found = false; for (i = 0; i < $scope.history.length; i++) { @@ -803,7 +770,7 @@ angular.module('myApp.controllers', []) minID = historyResult.history.length >= backLimit ? historyResult.history[0] : 0; - updateHistoryGroups(-backLimit); + AppMessagesManager.regroupWrappedHistory($scope.history, -backLimit); $scope.$broadcast('ui_history_append'); } else { minID = 0; @@ -837,7 +804,7 @@ angular.module('myApp.controllers', []) if (historyResult.history.length) { 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'); } }); @@ -898,7 +865,7 @@ angular.module('myApp.controllers', []) }); $scope.history.reverse(); - updateHistoryGroups(); + AppMessagesManager.regroupWrappedHistory($scope.history); if (historyResult.unreadOffset) { $scope.historyUnreadAfter = historyResult.history[historyResult.unreadOffset - 1]; @@ -1074,7 +1041,7 @@ angular.module('myApp.controllers', []) // console.log('append', addedMessage); // console.trace(); $scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID)); - updateHistoryGroups(-3); + AppMessagesManager.regroupWrappedHistory($scope.history, -3); $scope.typing = {}; $scope.$broadcast('ui_history_append_new', {my: addedMessage.my}); if (addedMessage.my) { @@ -1100,7 +1067,7 @@ angular.module('myApp.controllers', []) } }; $scope.history = newHistory; - updateHistoryGroups(); + AppMessagesManager.regroupWrappedHistory($scope.history); } }); diff --git a/app/js/filters.js b/app/js/filters.js index 72946fd9..faf2a155 100644 --- a/app/js/filters.js +++ b/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() { return function (duration) { var secs = duration % 60, diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js index 19050ab1..42ee4577 100644 --- a/app/js/lib/mtproto.js +++ b/app/js/lib/mtproto.js @@ -118,7 +118,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) return new SecureRandom(); }) -.factory('MtpDateManager', function (Storage) { +.factory('MtpTimeManager', function (Storage) { var lastMessageID = [0, 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) { var requestLength = requestBuffer.byteLength, @@ -179,7 +179,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) var header = new TLSerialization(); 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'); var headerBuffer = header.getBuffer(), @@ -391,7 +391,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) 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) { @@ -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, iii = 0, @@ -642,7 +642,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) sentMessage.inner = newInner; } - sentMessage.msg_id = MtpDateManager.generateID(); + sentMessage.msg_id = MtpTimeManager.generateID(); sentMessage.seq_no = this.generateSeqNo( sentMessage.notContentRelated || sentMessage.container @@ -669,7 +669,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) serializer.storeMethod(method, params); - var messageID = MtpDateManager.generateID(), + var messageID = MtpTimeManager.generateID(), seqNo = this.generateSeqNo(), message = { msg_id: messageID, @@ -690,7 +690,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) var serializer = new TLSerialization({mtproto: true}); serializer.storeObject(object, 'Object'); - var messageID = MtpDateManager.generateID(), + var messageID = MtpTimeManager.generateID(), seqNo = this.generateSeqNo(options.notContentRelated), message = { msg_id: messageID, @@ -725,7 +725,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) options.resultType = serializer.storeMethod(method, params); - var messageID = MtpDateManager.generateID(), + var messageID = MtpTimeManager.generateID(), seqNo = this.generateSeqNo(), message = { msg_id: messageID, @@ -849,7 +849,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) serializer.storeMethod('ping', {ping_id: pingID}); var pingMessage = { - msg_id: MtpDateManager.generateID(), + msg_id: MtpTimeManager.generateID(), seq_no: this.generateSeqNo(true), body: serializer.getBytes() }; @@ -964,7 +964,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) var serializer = new TLSerialization({mtproto: true}); serializer.storeMethod('http_wait', {max_delay: 0, wait_after: 0, max_wait: 1000}); messages.push({ - msg_id: MtpDateManager.generateID(), + msg_id: MtpTimeManager.generateID(), seq_no: this.generateSeqNo(), body: serializer.getBytes() }); @@ -995,7 +995,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) } var containerSentMessage = { - msg_id: MtpDateManager.generateID(), + msg_id: MtpTimeManager.generateID(), seq_no: this.generateSeqNo(true), container: true, inner: innerMessages @@ -1345,7 +1345,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) } if (message.error_code == 16 || message.error_code == 17) { - if (MtpDateManager.applyServerTime( + if (MtpTimeManager.applyServerTime( bigStringInt(messageID).shiftRight(32).toString(10) )) { this.updateSession(); diff --git a/app/js/services.js b/app/js/services.js index 88555cc4..99543855 100644 --- a/app/js/services.js +++ b/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 messagesForHistory = {}; @@ -692,6 +692,17 @@ angular.module('myApp.services', []) var lastSearchFilter = {}, 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(); function getDialogs (query, maxID, limit) { @@ -1773,6 +1784,46 @@ angular.module('myApp.services', []) 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) { for (var i = 0; i < dialogsStorage.dialogs.length; i++) { if (dialogsStorage.dialogs[i].peerID == peerID) { @@ -1886,6 +1937,9 @@ angular.module('myApp.services', []) historyStorage = historiesStorage[peerID] = {count: null, history: [message.id], pending: []}; } + // Fix time offset + message.date -= serverTimeOffset; + saveMessages([message]); if (historyStorage.count !== null) { @@ -2054,7 +2108,8 @@ angular.module('myApp.services', []) forwardMessages: forwardMessages, getMessagePeer: getMessagePeer, wrapForDialog: wrapForDialog, - wrapForHistory: wrapForHistory + wrapForHistory: wrapForHistory, + regroupWrappedHistory: regroupWrappedHistory } }) diff --git a/app/partials/message.html b/app/partials/message.html index 353b9f21..ddae6666 100644 --- a/app/partials/message.html +++ b/app/partials/message.html @@ -2,6 +2,10 @@ Unread messages +
+