diff --git a/app/css/app.css b/app/css/app.css index fce1cadc..6e2d068f 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -834,6 +834,16 @@ a.im_dialog:hover .im_dialog_date { bottom: 0; width: 100%; } + +.im_history_appending { + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -ms-transition: all 0.2s; + -o-transition: all 0.2s; + transition: all 0.2s; +} + + .im_history { /*padding: 20px 0 0 3px;*/ padding: 20px 0 0 0; diff --git a/app/js/controllers.js b/app/js/controllers.js index e6b5c25a..37f99e73 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -223,9 +223,7 @@ angular.module('myApp.controllers', []) var offset = 0, maxID = 0, - hasMore = false, - startLimit = 20, - limit = 100; + hasMore = false; MtpApiManager.invokeApi('account.updateStatus', {offline: false}); $scope.$on('dialogs_need_more', function () { @@ -278,14 +276,14 @@ angular.module('myApp.controllers', []) maxID = 0; hasMore = false; - AppMessagesManager.getDialogs($scope.search.query, maxID, startLimit).then(function (dialogsResult) { + AppMessagesManager.getDialogs($scope.search.query, maxID).then(function (dialogsResult) { $scope.dialogs = []; if (dialogsResult.dialogs.length) { - offset += startLimit; + offset += dialogsResult.dialogs.length; maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message; - hasMore = offset < dialogsResult.count; + hasMore = dialogsResult.count === null || offset < dialogsResult.count; angular.forEach(dialogsResult.dialogs, function (dialog) { $scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count)); @@ -295,7 +293,7 @@ angular.module('myApp.controllers', []) $scope.$broadcast('ui_dialogs_change'); if (!$scope.search.query) { - AppMessagesManager.getDialogs('', maxID, limit); + AppMessagesManager.getDialogs('', maxID); } }, function (error) { @@ -312,10 +310,10 @@ angular.module('myApp.controllers', []) return; } - AppMessagesManager.getDialogs($scope.search.query, maxID, limit).then(function (dialogsResult) { - offset += limit; + AppMessagesManager.getDialogs($scope.search.query, maxID).then(function (dialogsResult) { + offset += dialogsResult.dialogs.length; maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message; - hasMore = offset < dialogsResult.count; + hasMore = dialogsResult.count === null || offset < dialogsResult.count; angular.forEach(dialogsResult.dialogs, function (dialog) { $scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count)); @@ -359,8 +357,6 @@ angular.module('myApp.controllers', []) offset = 0, hasMore = false, maxID = 0, - startLimit = 20, - limit = 50, inputMediaFilters = { photos: 'inputMessagesFilterPhotos', video: 'inputMessagesFilterVideo', @@ -421,12 +417,12 @@ angular.module('myApp.controllers', []) var inputMediaFilter = $scope.mediaType && {_: inputMediaFilters[$scope.mediaType]}, getMessagesPromise = inputMediaFilter - ? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, limit) - : AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit); + ? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID) + : AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID); getMessagesPromise.then(function (historyResult) { - offset += limit; - hasMore = offset < historyResult.count; + offset += historyResult.history.length; + hasMore = historyResult.count === null || offset < historyResult.count; maxID = historyResult.history[historyResult.history.length - 1]; angular.forEach(historyResult.history, function (id) { @@ -447,7 +443,7 @@ angular.module('myApp.controllers', []) var curJump = ++jump, inputMediaFilter = $scope.mediaType && {_: inputMediaFilters[$scope.mediaType]}, getMessagesPromise = inputMediaFilter - ? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, startLimit) + ? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID) : AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID); $scope.historyEmpty = false; @@ -458,7 +454,7 @@ angular.module('myApp.controllers', []) offset += historyResult.history.length; $scope.historyEmpty = !historyResult.count; - hasMore = offset < historyResult.count; + hasMore = historyResult.count === null || offset < historyResult.count; maxID = historyResult.history[historyResult.history.length - 1]; updateHistoryPeer(); @@ -702,7 +698,7 @@ angular.module('myApp.controllers', []) $timeout(function () { var text = $scope.draftMessage.text; - if (!text.length) { + if (!angular.isString(text) || !text.length) { return false; } @@ -982,7 +978,7 @@ angular.module('myApp.controllers', []) photo: {_: 'inputChatPhotoEmpty'} }).then(function (updateResult) { onStatedMessage(updateResult); - }).['finally'](function () { + })['finally'](function () { $scope.photo.updating = false; }); }; diff --git a/app/js/directives.js b/app/js/directives.js index 5a3ca031..94ab79d3 100644 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -149,6 +149,7 @@ angular.module('myApp.directives', ['myApp.filters']) function link (scope, element, attrs) { var historyWrap = $('.im_history_wrap', element)[0], + historyMessagesEl = $('.im_history_messages', element)[0], historyEl = $('.im_history', element)[0], scrollableWrap = $('.im_history_scrollable_wrap', element)[0], scrollable = $('.im_history_scrollable', element)[0], @@ -173,8 +174,19 @@ angular.module('myApp.directives', ['myApp.filters']) }, delay || 0); } - var animated = true, + var transform = false, + trs = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'], + i = 0; + for (i = 0; i < trs.length; i++) { + if (trs[i] in historyMessagesEl.style) { + transform = trs[i]; + break; + } + } + + var animated = transform ? true : false, curAnimation = false; + scope.$on('ui_history_append', function (e, options) { if (!atBottom && !options.my) { return; @@ -186,26 +198,29 @@ angular.module('myApp.directives', ['myApp.filters']) $(scrollableWrap).addClass('im_history_to_bottom'); } + var wasH = scrollableWrap.scrollHeight; onContentLoaded(function () { if (animated) { curAnimation = true; - $(scrollableWrap).stop().animate({ - scrollTop: scrollableWrap.scrollHeight - scrollableWrap.clientHeight - }, { - duration: 200, - always: function () { - updateScroller(); + $(historyMessagesEl).removeClass('im_history_appending'); + scrollableWrap.scrollTop = scrollableWrap.scrollHeight; + $(historyMessagesEl).css(transform, 'translate(0px, ' + (scrollableWrap.scrollHeight - wasH) + 'px)'); + setTimeout(function () { + $(historyMessagesEl).addClass('im_history_appending'); + $(historyMessagesEl).css(transform, 'translate(0px, 0px)'); + setTimeout(function () { curAnimation = false; - } - }); - updateScroller(); + $(historyMessagesEl).removeClass('im_history_appending'); + updateBottomizer(); + }, 300); + }, 0); } else { $(scrollableWrap).removeClass('im_history_to_bottom'); $(scrollable).css({bottom: ''}); scrollableWrap.scrollTop = scrollableWrap.scrollHeight; - $(historyWrap).nanoScroller(); + updateBottomizer(); } - + $(historyWrap).nanoScroller(); }); }); @@ -253,6 +268,10 @@ angular.module('myApp.directives', ['myApp.filters']) updateScroller(); moreNotified = false; + + $timeout(function () { + $(scrollableWrap).trigger('scroll'); + }) }); }); @@ -302,6 +321,9 @@ angular.module('myApp.directives', ['myApp.filters']) minHeight: historyH - 44 }); + updateBottomizer(); + + if (heightOnly == true) return; if (atBottom) { onContentLoaded(function () { @@ -312,6 +334,14 @@ angular.module('myApp.directives', ['myApp.filters']) updateScroller(100); } + function updateBottomizer () { + $(historyMessagesEl).css({marginTop: 0}); + if (historyMessagesEl.offsetHeight <= scrollableWrap.offsetHeight) { + $(historyMessagesEl).css({marginTop: (scrollableWrap.offsetHeight - historyMessagesEl.offsetHeight - 20 - 44) + 'px'}); + } + $(historyWrap).nanoScroller(); + } + $($window).on('resize', updateSizes); updateSizes(); diff --git a/app/js/services.js b/app/js/services.js index 91f9fbfc..46e71325 100644 --- a/app/js/services.js +++ b/app/js/services.js @@ -690,19 +690,18 @@ angular.module('myApp.services', []) } } - if (curDialogStorage.count !== null && ( - curDialogStorage.dialogs.length >= offset + limit || - curDialogStorage.dialogs.length == curDialogStorage.count - )) { + if (curDialogStorage.count !== null && curDialogStorage.dialogs.length == curDialogStorage.count || + curDialogStorage.dialogs.length >= offset + (limit || 1) + ) { return $q.when({ count: curDialogStorage.count, - dialogs: curDialogStorage.dialogs.slice(offset, offset + limit) + dialogs: curDialogStorage.dialogs.slice(offset, offset + (limit || 20)) }); } - var deferred = $q.defer(); + limit = limit || 20; - MtpApiManager.invokeApi('messages.getDialogs', { + return MtpApiManager.invokeApi('messages.getDialogs', { offset: offset, limit: limit, max_id: maxID || 0 @@ -735,17 +734,17 @@ angular.module('myApp.services', []) top_message: dialog.top_message, unread_count: dialog.unread_count }); + + if (historiesStorage[peerID] === undefined) { + historiesStorage[peerID] = {count: null, history: [dialog.top_message], pending: []} + } }); - deferred.resolve({ + return { count: curDialogStorage.count, dialogs: curDialogStorage.dialogs.slice(offset, offset + limit) - }); - }, function (error) { - deferred.reject(error); + }; }); - - return deferred.promise; } function fillHistoryStorage (inputPeer, maxID, fullLimit, historyStorage) { @@ -807,12 +806,9 @@ angular.module('myApp.services', []) var foundDialog = getDialogByPeerID(peerID); if (foundDialog && foundDialog[0] && foundDialog[0].unread_count > 1) { unreadLimit = Math.min(1000, foundDialog[0].unread_count); - limit = Math.max(20, unreadLimit + 2); + limit = unreadLimit; } } - if (!limit) { - limit = 20; - } if (maxID > 0) { for (offset = 0; offset < historyStorage.history.length; offset++) { @@ -822,17 +818,22 @@ angular.module('myApp.services', []) } } - if (historyStorage.count !== null && ( - historyStorage.history.length >= offset + limit || - historyStorage.history.length == historyStorage.count - )) { + if (historyStorage.count !== null && historyStorage.history.length == historyStorage.count || + historyStorage.history.length >= offset + (limit || 1) + ) { return $q.when({ count: historyStorage.count, - history: resultPending.concat(historyStorage.history.slice(offset, offset + limit)), + history: resultPending.concat(historyStorage.history.slice(offset, offset + (limit || 20))), unreadLimit: unreadLimit }); } + if (unreadLimit) { + limit = Math.max(20, unreadLimit + 2); + } + + limit = limit || 20; + return fillHistoryStorage(inputPeer, maxID, limit, historyStorage).then(function () { offset = 0; if (maxID > 0) { @@ -858,7 +859,7 @@ angular.module('myApp.services', []) filter: inputFilter || {_: 'inputMessagesFilterEmpty'}, min_date: 0, max_date: 0, - limit: limit, + limit: limit || 20, max_id: maxID || 0 }).then(function (searchResult) { AppUsersManager.saveApiUsers(searchResult.users); @@ -922,7 +923,7 @@ angular.module('myApp.services', []) if (!foundDialog[0] || !foundDialog[0].unread_count) { - if (!historyStorage && !historyStorage.history.length) { + if (!historyStorage || !historyStorage.history.length) { return false; } @@ -2098,18 +2099,10 @@ angular.module('myApp.services', []) return urlPromises[url]; } - var deferred = $q.defer(); - - $http.get(url, {responseType: 'blob', transformRequest: null}) - .then( - function (response) { - deferred.resolve(window.webkitURL.createObjectURL(response.data)); - }, function (error) { - deferred.reject(error); - } - ); - - return urlPromises[url] = deferred.promise; + return urlPromises[url] = $http.get(url, {responseType: 'blob', transformRequest: null}) + .then(function (response) { + return window.webkitURL.createObjectURL(response.data); + }); } return { diff --git a/app/partials/im.html b/app/partials/im.html index 50c516b6..644322f8 100644 --- a/app/partials/im.html +++ b/app/partials/im.html @@ -88,7 +88,9 @@