Browse Source

Implemented history search

History search: added 2 tabs while searching, scroll to found message
in history
Move to 15th layer
Improve typing event (now only on value change)
Fixed styles from
https://github.com/zhukov/webogram/issues/286#issuecomment-45406436
Closes #137
master
Igor Zhukov 10 years ago
parent
commit
8556d03d9f
  1. 53
      app/css/app.css
  2. 268
      app/js/controllers.js
  3. 84
      app/js/directives.js
  4. 2
      app/js/init.js
  5. 11
      app/js/lib/config.js
  6. 2
      app/js/lib/mtproto.js
  7. 76
      app/js/services.js
  8. 4
      app/partials/dialog.html
  9. 19
      app/partials/im.html
  10. 2
      app/partials/message.html

53
app/css/app.css

@ -910,7 +910,7 @@ a.tg_radio_on:hover i.icon-radio { @@ -910,7 +910,7 @@ a.tg_radio_on:hover i.icon-radio {
}
.im_dialogs_panel {
padding: 14px 12px;
padding: 12px 12px 6px;
position: relative;
}
.im_dialogs_search {
@ -927,8 +927,7 @@ a.tg_radio_on:hover i.icon-radio { @@ -927,8 +927,7 @@ a.tg_radio_on:hover i.icon-radio {
border: 1px solid #F2F2F2;
border-radius: 3px;
padding: 6px 20px 6px 30px;
margin-bottom: 0;
margin: 0;
margin: 0 0 6px;
}
.is_1x .im_dialogs_search_field {
background-image: url(../img/icons/IconsetW_1x.png);
@ -941,7 +940,7 @@ a.tg_radio_on:hover i.icon-radio { @@ -941,7 +940,7 @@ a.tg_radio_on:hover i.icon-radio {
.im_dialogs_search_clear {
position: absolute;
right: 9px;
margin-top: -23px;
margin-top: -30px;
color: #999;
width: 13px;
height: 13px;
@ -957,6 +956,37 @@ a.tg_radio_on:hover i.icon-radio { @@ -957,6 +956,37 @@ a.tg_radio_on:hover i.icon-radio {
opacity: 1;
}
.im_dialogs_tabs {
padding: 4px 0;
position: relative;
}
.im_dialogs_tab {
color: #8c8c8c;
background: #f2f2f2;
height: 30px;
text-align: center;
overflow: hidden;
width: 50%;
float: left;
padding: 7px 0;
}
.im_dialogs_tab:hover,
.im_dialogs_tab:active {
color: #8c8c8c;
text-decoration: none;
}
.im_dialogs_tab.active {
color: #FFF;
background: #6490b1;
}
.im_dialogs_tab:first-child {
border-radius: 2px 0 0 2px;
}
.im_dialogs_tab:last-child {
border-radius: 0 2px 2px 0;
}
.im_dialogs_panel_dropdown {
position: absolute;
right: 12px;
@ -1499,7 +1529,8 @@ div.im_message_video_thumb { @@ -1499,7 +1529,8 @@ div.im_message_video_thumb {
overflow: hidden;
margin-top: 5px;
}
.im_message_iframe_video iframe {
.im_message_iframe_video iframe,
.im_message_iframe_video webview {
position: absolute;
top: 0;
left: 0;
@ -2937,6 +2968,15 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status { @@ -2937,6 +2968,15 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status {
.im_message_selected {
background: #f2f6fa;
}
.im_message_focus {
background-color: #f2f6fa;
-webkit-transition: background-color linear 1s;
transition: background-color linear 1s;
}
/*.im_message_focus.inactive {
background-color: none;
}*/
.im_history_selectable .im_message_outer_wrap {
cursor: pointer;
}
@ -3103,7 +3143,8 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status { @@ -3103,7 +3143,8 @@ a.contacts_modal_contact:hover .contacts_modal_contact_status {
margin-top: 1px;
border: 0;
}
.im_message_grouped .icon-message-status {
.im_message_grouped1 .icon-message-status,
.im_message_grouped2 .icon-message-status {
margin-top: -8px;
}
}

268
app/js/controllers.js

@ -216,10 +216,10 @@ angular.module('myApp.controllers', []) @@ -216,10 +216,10 @@ angular.module('myApp.controllers', [])
$scope.$on('history_focus', function (e, peerData) {
$modalStack.dismissAll();
if (peerData.peerString == $scope.curDialog.peer) {
if (peerData.peerString == $scope.curDialog.peer && !peerData.messageID) {
$scope.$broadcast('ui_history_focus');
} else {
$location.url('/im?p=' + peerData.peerString);
$location.url('/im?p=' + peerData.peerString + (peerData.messageID ? '&m=' + peerData.messageID : ''));
}
});
@ -261,8 +261,12 @@ angular.module('myApp.controllers', []) @@ -261,8 +261,12 @@ angular.module('myApp.controllers', [])
});
}
$scope.dialogSelect = function (peerString) {
$rootScope.$broadcast('history_focus', {peerString: peerString});
$scope.dialogSelect = function (peerString, messageID) {
var params = {peerString: peerString};
if (messageID) {
params.messageID = messageID;
}
$rootScope.$broadcast('history_focus', params);
};
$scope.logOut = function () {
@ -278,16 +282,15 @@ angular.module('myApp.controllers', []) @@ -278,16 +282,15 @@ angular.module('myApp.controllers', [])
function updateCurDialog() {
$scope.curDialog = {
peer: $routeParams.p || false
peer: $routeParams.p || false,
messageID: $routeParams.m || false
};
}
ChangelogNotifyService.checkUpdate();
})
.controller('AppImDialogsController', function ($scope, $location, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, PhonebookContactsService, ErrorService) {
// console.log('init controller');
.controller('AppImDialogsController', function ($scope, $location, $q, $timeout, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, PhonebookContactsService, ErrorService) {
$scope.dialogs = [];
$scope.contacts = [];
@ -298,6 +301,7 @@ angular.module('myApp.controllers', []) @@ -298,6 +301,7 @@ angular.module('myApp.controllers', [])
var offset = 0,
maxID = 0,
hasMore = false,
jump = 0,
peersInDialogs = {},
contactsShown;
@ -345,7 +349,84 @@ angular.module('myApp.controllers', []) @@ -345,7 +349,84 @@ angular.module('myApp.controllers', [])
}
});
$scope.$watch('search.query', loadDialogs);
$scope.$watchCollection('search', loadDialogs);
$scope.importContact = function () {
AppUsersManager.openImportContact().then(function (foundContact) {
if (contactsShown && foundContact) {
loadDialogs();
}
});
};
$scope.importPhonebook = function () {
PhonebookContactsService.openPhonebookImport().result.then(function (foundContacts) {
if (contactsShown && foundContacts.length) {
loadDialogs();
}
})
};
var searchTimeoutPromise;
function getDialogs() {
var searchMessages = $scope.search.messages && $scope.search.query.length > 0,
curJump = ++jump,
promise;
$timeout.cancel(searchTimeoutPromise);
if (searchMessages) {
searchTimeoutPromise = $timeout(angular.noop, 500);
promise = searchTimeoutPromise.then(function () {
return AppMessagesManager.getSearch({_: 'inputPeerEmpty'}, $scope.search.query, {_: 'inputMessagesFilterEmpty'}, maxID)
});
} else {
promise = AppMessagesManager.getDialogs($scope.search.query, maxID);
}
return promise.then(function (result) {
if (curJump != jump) {
return $q.reject();
}
if (searchMessages) {
var dialogs = [];
angular.forEach(result.history, function (messageID) {
var message = AppMessagesManager.getMessage(messageID),
peerID = AppMessagesManager.getMessagePeer(message);
dialogs.push({
peerID: peerID,
top_message: messageID,
unread_count: 0
});
});
result = {
count: result.count,
dialogs: dialogs
};
}
return result;
}, function (error) {
if (error.type == 'NETWORK_BAD_REQUEST') {
if (location.protocol == 'https:') {
ErrorService.confirm({type: 'HTTPS_MIXED_FAIL'}).then(function () {
location = location.toString().replace(/^https:/, 'http:');
});
error.handled = true;
}
}
if (error.code == 401) {
MtpApiManager.logOut()['finally'](function () {
$location.url('/login');
});
error.handled = true;
}
return $q.reject();
});
};
$scope.importContact = function () {
AppUsersManager.openImportContact().then(function (foundContact) {
@ -370,7 +451,7 @@ angular.module('myApp.controllers', []) @@ -370,7 +451,7 @@ angular.module('myApp.controllers', [])
peersInDialogs = {};
contactsShown = false;
AppMessagesManager.getDialogs($scope.search.query, maxID).then(function (dialogsResult) {
getDialogs().then(function (dialogsResult) {
$scope.dialogs = [];
$scope.contacts = [];
@ -398,22 +479,6 @@ angular.module('myApp.controllers', []) @@ -398,22 +479,6 @@ angular.module('myApp.controllers', [])
showMoreDialogs();
}
}, function (error) {
if (error.type == 'NETWORK_BAD_REQUEST') {
if (location.protocol == 'https:') {
ErrorService.confirm({type: 'HTTPS_MIXED_FAIL'}).then(function () {
location = location.toString().replace(/^https:/, 'http:');
});
error.handled = true;
}
}
if (error.code == 401) {
MtpApiManager.logOut()['finally'](function () {
$location.url('/login');
});
error.handled = true;
}
});
}
@ -422,10 +487,12 @@ angular.module('myApp.controllers', []) @@ -422,10 +487,12 @@ angular.module('myApp.controllers', [])
return;
}
if (!hasMore && ($scope.search.query || !$scope.dialogs.length)) {
if (!hasMore && !$scope.search.messages && ($scope.search.query || !$scope.dialogs.length)) {
contactsShown = true;
var curJump = ++jump;
AppUsersManager.getContacts($scope.search.query).then(function (contactsList) {
if (curJump != jump) return;
$scope.contacts = [];
angular.forEach(contactsList, function(userID) {
if (peersInDialogs[userID] === undefined) {
@ -448,7 +515,7 @@ angular.module('myApp.controllers', []) @@ -448,7 +515,7 @@ angular.module('myApp.controllers', [])
return;
}
AppMessagesManager.getDialogs($scope.search.query, maxID).then(function (dialogsResult) {
getDialogs().then(function (dialogsResult) {
if (dialogsResult.dialogs.length) {
offset += dialogsResult.dialogs.length;
maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message;
@ -468,10 +535,9 @@ angular.module('myApp.controllers', []) @@ -468,10 +535,9 @@ angular.module('myApp.controllers', [])
.controller('AppImHistoryController', function ($scope, $location, $timeout, $rootScope, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, PeersSelectService, IdleManager, StatusManager, ErrorService) {
$scope.$watch('curDialog.peer', applyDialogSelect);
$scope.$watch('curDialog', applyDialogSelect);
ApiUpdatesManager.attach();
IdleManager.start();
StatusManager.start();
@ -494,9 +560,10 @@ angular.module('myApp.controllers', []) @@ -494,9 +560,10 @@ angular.module('myApp.controllers', [])
$scope.showPeerInfo = showPeerInfo;
var peerID,
offset = 0,
hasMore = false,
hasLess = false,
maxID = 0,
minID = 0,
lastSelectID = false,
inputMediaFilters = {
photos: 'inputMessagesFilterPhotos',
@ -504,22 +571,32 @@ angular.module('myApp.controllers', []) @@ -504,22 +571,32 @@ angular.module('myApp.controllers', [])
documents: 'inputMessagesFilterDocument',
audio: 'inputMessagesFilterAudio'
},
jump = 0;
function applyDialogSelect (newPeer) {
selectedCancel(true);
newPeer = newPeer || $scope.curDialog.peer || '';
jump = 0,
moreJump = 0,
lessJump = 0;
function applyDialogSelect (newDialog, oldDialog) {
var newPeer = newDialog.peer || $scope.curDialog.peer || '';
peerID = AppPeersManager.getPeerID(newPeer);
if (peerID == $scope.curDialog.peerID && oldDialog.messageID == newDialog.messageID) {
return false;
}
$scope.curDialog.peerID = peerID;
$scope.curDialog.inputPeer = AppPeersManager.getInputPeer(newPeer);
$scope.mediaType = false;
if (peerID) {
selectedCancel(true);
if (oldDialog.peer && oldDialog.peer == newDialog.peer && newDialog.messageID) {
messageFocusHistory();
}
else if (peerID) {
updateHistoryPeer(true);
loadHistory();
} else {
}
else {
showEmptyHistory();
}
}
@ -581,56 +658,119 @@ angular.module('myApp.controllers', []) @@ -581,56 +658,119 @@ angular.module('myApp.controllers', [])
}
}
function messageFocusHistory () {
var i, found = false;
for (i = 0; i < $scope.history.length; i++) {
if ($scope.curDialog.messageID == $scope.history[i].id) {
found = true;
break;
}
}
if (found) {
$scope.historyUnread = {};
$scope.historyFocus = $scope.curDialog.messageID;
$scope.$broadcast('ui_history_change_scroll');
} else {
loadHistory();
}
}
function showLessHistory () {
if (!hasLess) {
return;
}
var curJump = jump,
curLessJump = ++lessJump,
limit = 0,
backLimit = 20;
AppMessagesManager.getHistory($scope.curDialog.inputPeer, minID, limit, backLimit).then(function (historyResult) {
if (curJump != jump || curLessJump != lessJump) return;
angular.forEach(historyResult.history, function (id) {
if (id > minID) {
$scope.history.push(AppMessagesManager.wrapForHistory(id));
}
});
if (historyResult.history.length) {
minID = historyResult.history.length >= backLimit
? historyResult.history[0]
: 0;
updateHistoryGroups(-backLimit);
$scope.$broadcast('ui_history_append');
} else {
minID = 0;
}
hasLess = minID > 0;
});
}
function showMoreHistory () {
if (!hasMore || !offset) {
if (!hasMore) {
return;
}
// console.trace('load history');
var curJump = ++jump,
var curJump = jump,
curMoreJump = moreJump,
inputMediaFilter = $scope.mediaType && {_: inputMediaFilters[$scope.mediaType]},
getMessagesPromise = inputMediaFilter
? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID)
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID);
getMessagesPromise.then(function (historyResult) {
if (curJump != jump) return;
offset += historyResult.history.length;
hasMore = historyResult.count === null || offset < historyResult.count;
maxID = historyResult.history[historyResult.history.length - 1];
if (curJump != jump || curMoreJump != moreJump) return;
angular.forEach(historyResult.history, function (id) {
$scope.history.unshift(AppMessagesManager.wrapForHistory(id));
});
updateHistoryGroups(historyResult.history.length + 1);
hasMore = historyResult.count === null ||
historyResult.history.length && $scope.history.length < historyResult.count;
$scope.$broadcast('ui_history_prepend');
if (historyResult.history.length) {
maxID = historyResult.history[historyResult.history.length - 1];
updateHistoryGroups(historyResult.history.length + 1);
$scope.$broadcast('ui_history_prepend');
}
});
}
};
function loadHistory () {
hasMore = false;
offset = 0;
hasLess = false;
maxID = 0;
minID = 0;
var limit = 0, backLimit = 0;
if ($scope.curDialog.messageID) {
maxID = parseInt($scope.curDialog.messageID);
limit = 5;
backLimit = 5;
}
var curJump = ++jump,
inputMediaFilter = $scope.mediaType && {_: inputMediaFilters[$scope.mediaType]},
getMessagesPromise = inputMediaFilter
? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID)
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID);
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit, backLimit);
$scope.state.mayBeHasMore = true;
getMessagesPromise.then(function (historyResult) {
if (curJump != jump) return;
offset += historyResult.history.length;
hasMore = historyResult.count === null || offset < historyResult.count;
minID = maxID && historyResult.history.indexOf(maxID)>= backLimit - 1
? historyResult.history[0]
: 0;
maxID = historyResult.history[historyResult.history.length - 1];
hasLess = minID > 0;
hasMore = historyResult.count === null ||
historyResult.history.length && historyResult.history.length < historyResult.count;
updateHistoryPeer();
safeReplaceObject($scope.state, {loaded: true});
@ -651,6 +791,8 @@ angular.module('myApp.controllers', []) @@ -651,6 +791,8 @@ angular.module('myApp.controllers', [])
$scope.historyUnread = {};
}
$scope.historyFocus = $scope.curDialog.messageID || 0;
$scope.$broadcast('ui_history_change');
AppMessagesManager.readHistory($scope.curDialog.inputPeer);
@ -805,6 +947,14 @@ angular.module('myApp.controllers', []) @@ -805,6 +947,14 @@ angular.module('myApp.controllers', [])
$scope.$on('history_append', function (e, addedMessage) {
if (addedMessage.peerID == $scope.curDialog.peerID) {
if (minID) {
if (addedMessage.my) {
$rootScope.$broadcast('history_focus', {peerString: $scope.curDialog.peer});
} else {
$scope.missedCount++;
}
return;
}
if ($scope.mediaType) {
if (addedMessage.my) {
toggleMedia();
@ -818,7 +968,7 @@ angular.module('myApp.controllers', []) @@ -818,7 +968,7 @@ angular.module('myApp.controllers', [])
$scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID));
updateHistoryGroups(-3);
$scope.typing = {};
$scope.$broadcast('ui_history_append', {my: addedMessage.my});
$scope.$broadcast('ui_history_append_new', {my: addedMessage.my});
if (addedMessage.my) {
$scope.historyUnread = {};
}
@ -889,9 +1039,8 @@ angular.module('myApp.controllers', []) @@ -889,9 +1039,8 @@ angular.module('myApp.controllers', [])
}
});
$scope.$on('history_need_more', function () {
showMoreHistory();
});
$scope.$on('history_need_less', showLessHistory);
$scope.$on('history_need_more', showMoreHistory);
$rootScope.$watch('idle.isIDLE', function (newVal) {
if (!newVal && $scope.curDialog && $scope.curDialog.peerID) {
@ -976,9 +1125,10 @@ angular.module('myApp.controllers', []) @@ -976,9 +1125,10 @@ angular.module('myApp.controllers', [])
function onMessageChange(newVal) {
// console.log('ctrl text changed', newVal);
// console.trace('ctrl text changed', newVal);
AppMessagesManager.readHistory($scope.curDialog.inputPeer);
if (newVal && newVal.length) {
AppMessagesManager.readHistory($scope.curDialog.inputPeer);
var backupDraftObj = {};
backupDraftObj['draft' + $scope.curDialog.peerID] = newVal;
AppConfigManager.set(backupDraftObj);

84
app/js/directives.js

@ -329,7 +329,8 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -329,7 +329,8 @@ angular.module('myApp.directives', ['myApp.filters'])
headWrap = $('.tg_page_head')[0],
footer = $('.im_page_footer')[0],
sendForm = $('.im_send_form', element)[0],
moreNotified = false;
moreNotified = false,
lessNotified = false;
onContentLoaded(function () {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
@ -337,6 +338,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -337,6 +338,7 @@ angular.module('myApp.directives', ['myApp.filters'])
});
var updateScroller = function (delay) {
// console.trace('scroller update', delay);
$timeout(function () {
if (!$(scrollableWrap).hasClass('im_history_to_bottom')) {
$(historyWrap).nanoScroller();
@ -357,7 +359,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -357,7 +359,7 @@ angular.module('myApp.directives', ['myApp.filters'])
var animated = transform ? true : false,
curAnimation = false;
$scope.$on('ui_history_append', function (e, options) {
$scope.$on('ui_history_append_new', function (e, options) {
if (!atBottom && !options.my) {
return;
}
@ -392,6 +394,24 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -392,6 +394,24 @@ angular.module('myApp.directives', ['myApp.filters'])
});
});
function changeScroll () {
var unreadSplit, focusMessage;
if (focusMessage = $('.im_message_focus', scrollableWrap)[0]) {
scrollableWrap.scrollTop = Math.max(0, focusMessage.offsetTop - 52);
atBottom = false;
} else if (unreadSplit = $('.im_message_unread_split', scrollableWrap)[0]) {
scrollableWrap.scrollTop = Math.max(0, unreadSplit.offsetTop - 52);
atBottom = false;
} else {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
}
updateScroller();
$timeout(function () {
$(scrollableWrap).trigger('scroll');
});
};
$scope.$on('ui_history_change', function () {
$(scrollableWrap).addClass('im_history_to_bottom');
$(scrollable).css({bottom: 0});
@ -399,24 +419,16 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -399,24 +419,16 @@ angular.module('myApp.directives', ['myApp.filters'])
$(scrollableWrap).removeClass('im_history_to_bottom');
$(scrollable).css({bottom: ''});
updateSizes(true);
var unreadSplit = $('.im_message_unread_split', scrollableWrap);
if (unreadSplit[0]) {
scrollableWrap.scrollTop = Math.max(0, unreadSplit[0].offsetTop - 52);
atBottom = false;
} else {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
}
updateScroller();
moreNotified = false;
$timeout(function () {
$(scrollableWrap).trigger('scroll');
});
lessNotified = false;
changeScroll();
});
});
$scope.$on('ui_history_change_scroll', function () {
onContentLoaded(changeScroll)
});
$scope.$on('ui_history_focus', function () {
if (!atBottom) {
scrollableWrap.scrollTop = scrollableWrap.scrollHeight;
@ -450,6 +462,20 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -450,6 +462,20 @@ angular.module('myApp.directives', ['myApp.filters'])
});
});
$scope.$on('ui_history_append', function () {
var sh = scrollableWrap.scrollHeight;
onContentLoaded(function () {
updateBottomizer();
lessNotified = false;
$timeout(function () {
if (scrollableWrap.scrollHeight != sh) {
$(scrollableWrap).trigger('scroll');
}
});
});
});
$scope.$on('ui_panel_update', function () {
onContentLoaded(function () {
updateSizes();
@ -493,6 +519,10 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -493,6 +519,10 @@ angular.module('myApp.directives', ['myApp.filters'])
moreNotified = true;
$scope.$emit('history_need_more');
}
else if (!lessNotified && scrollableWrap.scrollTop >= scrollableWrap.scrollHeight - scrollableWrap.clientHeight - 300) {
lessNotified = true;
$scope.$emit('history_need_less');
}
});
function updateSizes (heightOnly) {
@ -623,6 +653,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -623,6 +653,7 @@ angular.module('myApp.directives', ['myApp.filters'])
if (submit) {
$(element).trigger('submit');
$(element).trigger('message_send');
resetAfterSubmit();
return cancelEvent(e);
}
}
@ -632,19 +663,28 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -632,19 +663,28 @@ angular.module('myApp.directives', ['myApp.filters'])
$('.im_submit', element).on('mousedown', function (e) {
$(element).trigger('submit');
$(element).trigger('message_send');
resetAfterSubmit();
return cancelEvent(e);
});
var lastTyping = 0;
var lastTyping = 0,
lastLength;
$(editorElement).on('keyup', function (e) {
var now = tsNow();
if (now - lastTyping < 5000) {
return;
var now = tsNow(),
length = (editorElement[richTextarea ? 'innerText' : 'value']).length;
if (now - lastTyping > 5000 && length != lastLength) {
lastTyping = now;
lastLength = length;
$scope.$emit('ui_typing');
}
lastTyping = now;
$scope.$emit('ui_typing');
});
function resetAfterSubmit () {
lastTyping = 0;
lastLength = 0;
};
function updateField () {
if (richTextarea) {
$timeout.cancel(updatePromise);

2
app/js/init.js

@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
setTimeout(function () {callback(result)}, 10);
};
if (!window.applicationCache || Config.App.packaged || !window.addEventListener) {
if (!window.applicationCache || Config.Modes.packed || !window.addEventListener) {
return;
}

11
app/js/lib/config.js

File diff suppressed because one or more lines are too long

2
app/js/lib/mtproto.js

@ -1785,7 +1785,7 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato @@ -1785,7 +1785,7 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato
var serializer = new TLSerialization(options);
if (!this.connectionInited) {
serializer.storeInt(0x2b9b08fa, 'invokeWithLayer14');
serializer.storeInt(0xb4418b64, 'invokeWithLayer15');
serializer.storeInt(0x69796de9, 'initConnection');
serializer.storeInt(Config.App.id, 'api_id');
serializer.storeString(navigator.userAgent || 'Unknown UserAgent', 'device_model');

76
app/js/services.js

@ -750,7 +750,6 @@ angular.module('myApp.services', []) @@ -750,7 +750,6 @@ angular.module('myApp.services', [])
}
function search (query, searchIndex) {
console.time('search');
var shortIndexes = searchIndex.shortIndexes,
fullTexts = searchIndex.fullTexts;
@ -787,7 +786,6 @@ angular.module('myApp.services', []) @@ -787,7 +786,6 @@ angular.module('myApp.services', [])
}
}
console.timeEnd('search');
return newFoundObjs;
}
})
@ -873,9 +871,7 @@ angular.module('myApp.services', []) @@ -873,9 +871,7 @@ angular.module('myApp.services', [])
}
}
curDialogStorage.count = dialogsResult._ == 'messages.dialogsSlice'
? dialogsResult.count
: dialogsResult.dialogs.length;
curDialogStorage.count = dialogsResult.count || dialogsResult.dialogs.length;
curDialogStorage.dialogs.splice(offset, curDialogStorage.dialogs.length - offset);
angular.forEach(dialogsResult.dialogs, function (dialog) {
@ -904,21 +900,29 @@ angular.module('myApp.services', []) @@ -904,21 +900,29 @@ angular.module('myApp.services', [])
});
}
function fillHistoryStorage (inputPeer, maxID, fullLimit, historyStorage) {
console.log('fill history storage', inputPeer, maxID, fullLimit, angular.copy(historyStorage));
function requestHistory (inputPeer, maxID, limit, backLimit) {
maxID = maxID || 0;
limit = limit || 0;
backLimit = backLimit || 0;
return MtpApiManager.invokeApi('messages.getHistory', {
peer: inputPeer,
offset: 0,
limit: fullLimit,
offset: -backLimit,
limit: limit + backLimit,
max_id: maxID || 0
}).then(function (historyResult) {
AppUsersManager.saveApiUsers(historyResult.users);
AppChatsManager.saveApiChats(historyResult.chats);
saveMessages(historyResult.messages);
historyStorage.count = historyResult._ == 'messages.messagesSlice'
? historyResult.count
: historyResult.messages.length;
return historyResult;
});
}
function fillHistoryStorage (inputPeer, maxID, fullLimit, historyStorage) {
console.log('fill history storage', inputPeer, maxID, fullLimit, angular.copy(historyStorage));
return requestHistory (inputPeer, maxID, fullLimit).then(function (historyResult) {
historyStorage.count = historyResult.count || historyResult.messages.length;
var offset = 0;
if (maxID > 0) {
@ -945,8 +949,7 @@ angular.module('myApp.services', []) @@ -945,8 +949,7 @@ angular.module('myApp.services', [])
});
};
function getHistory (inputPeer, maxID, limit) {
function getHistory (inputPeer, maxID, limit, backLimit) {
var peerID = AppPeersManager.getPeerID(inputPeer),
historyStorage = historiesStorage[peerID],
offset = 0,
@ -979,9 +982,17 @@ angular.module('myApp.services', []) @@ -979,9 +982,17 @@ angular.module('myApp.services', [])
if (historyStorage.count !== null && historyStorage.history.length == historyStorage.count ||
historyStorage.history.length >= offset + (limit || 1)
) {
if (backLimit) {
backLimit = Math.min(offset, backLimit);
offset = Math.max(0, offset - backLimit);
limit += backLimit;
} else {
limit = limit || 20;
}
return $q.when({
count: historyStorage.count,
history: resultPending.concat(historyStorage.history.slice(offset, offset + (limit || 20))),
history: resultPending.concat(historyStorage.history.slice(offset, offset + limit)),
unreadLimit: unreadLimit
});
}
@ -989,8 +1000,26 @@ angular.module('myApp.services', []) @@ -989,8 +1000,26 @@ angular.module('myApp.services', [])
if (unreadLimit) {
limit = Math.max(20, unreadLimit + 2);
}
else if (!backLimit && !limit) {
limit = 20;
}
limit = limit || 20;
if (backLimit || maxID && historyStorage.history.indexOf(maxID) == -1) {
return requestHistory(inputPeer, maxID, limit, backLimit).then(function (historyResult) {
historyStorage.count = historyResult.count || historyResult.messages.length;
var history = [];
angular.forEach(historyResult.messages, function (message) {
history.push(message.id);
});
return {
count: historyStorage.count,
history: resultPending.concat(history),
unreadLimit: unreadLimit
};
})
}
return fillHistoryStorage(inputPeer, maxID, limit, historyStorage).then(function () {
offset = 0;
@ -1102,9 +1131,7 @@ angular.module('myApp.services', []) @@ -1102,9 +1131,7 @@ angular.module('myApp.services', [])
AppChatsManager.saveApiChats(searchResult.chats);
saveMessages(searchResult.messages);
var foundCount = searchResult._ == 'messages.messagesSlice'
? searchResult.count
: searchResult.messages.length;
var foundCount = searchResult.count || searchResult.messages.length;
foundMsgs = [];
angular.forEach(searchResult.messages, function (message) {
@ -1186,6 +1213,10 @@ angular.module('myApp.services', []) @@ -1186,6 +1213,10 @@ angular.module('myApp.services', [])
}
}
if (historyStorage.readPromise) {
return historyStorage.readPromise;
}
var promise = MtpApiManager.invokeApi('messages.readHistory', {
peer: inputPeer,
offset: 0,
@ -1198,6 +1229,8 @@ angular.module('myApp.services', []) @@ -1198,6 +1229,8 @@ angular.module('myApp.services', [])
foundDialog[0].unread_count = 0;
$rootScope.$broadcast('dialog_unread', {peerID: peerID, count: 0});
}
})['finally'](function () {
delete historyStorage.readPromise;
});
@ -3125,9 +3158,10 @@ angular.module('myApp.services', []) @@ -3125,9 +3158,10 @@ angular.module('myApp.services', [])
videoID = youtubeMatches && youtubeMatches[1];
if (videoID) {
text = text + '<div class="im_message_iframe_video"><iframe type="text/html" frameborder="0" ' +
var tag = Config.Modes.chrome_packed ? 'webview' : 'iframe';
text = text + '<div class="im_message_iframe_video"><' + tag + ' type="text/html" frameborder="0" ' +
'src="http://www.youtube.com/embed/' + videoID +
'?autoplay=0&amp;controls=2"></iframe></div>'
'?autoplay=0&amp;controls=2"></' + tag + '></div>'
}
}

4
app/partials/dialog.html

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<a class="im_dialog" ng-click="dialogSelect(dialogMessage.peerString)">
<a class="im_dialog" ng-click="dialogSelect(dialogMessage.peerString, search.messages &amp;&amp; dialogMessage.id)">
<div class="im_dialog_meta pull-right text-right">
<div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div>
@ -52,7 +52,7 @@ @@ -52,7 +52,7 @@
</span>
<span class="im_dialog_message_service" ng-if="dialogMessage._ == 'messageService'" ng-switch="dialogMessage.action._">
<span ng-switch-when="messageActionChatCreate"> created the group </span>
<span ng-switch-when="messageActionChatCreate">created the group</span>
<span ng-switch-when="messageActionChatEditTitle">changed group name</span>
<span ng-switch-when="messageActionChatEditPhoto">changed group photo</span>
<span ng-switch-when="messageActionChatDeletePhoto">removed group photo</span>

19
app/partials/im.html

@ -23,7 +23,15 @@ @@ -23,7 +23,15 @@
<input class="form-control im_dialogs_search_field" type="search" placeholder="Search" ng-model="search.query"/>
<a class="im_dialogs_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a>
</div>
<div class="im_dialogs_tabs_wrap" ng-show="search.query.length">
<div class="im_dialogs_tabs clearfix">
<a href="" class="im_dialogs_tab" ng-class="{active: !search.messages}" ng-click="search.messages = false">Conversations</a>
<a href="" class="im_dialogs_tab" ng-class="{active: search.messages}" ng-click="search.messages = true">Messages</a>
</div>
</div>
</div>
<div my-dialogs-list class="im_dialogs_col">
<div class="im_dialogs_wrap nano">
<div class="im_dialogs_scrollable_wrap content">
@ -35,9 +43,14 @@ @@ -35,9 +43,14 @@
<button ng-if="phonebookAvailable" type="button" class="btn btn-primary btn-sm im_dialogs_import_phonebook" ng-click="importPhonebook()">Import phonebook</button>
</div>
<ul class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.peerID" ng-class="{active: curDialog.peerID == dialogMessage.peerID}"></li>
</ul>
<div ng-switch="search.messages">
<ul ng-switch-when="true" class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.id" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.id}"></li>
</ul>
<ul ng-switch-default class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.peerID" ng-class="{active: curDialog.peerID == dialogMessage.peerID}"></li>
</ul>
</div>
<div class="im_dialogs_contacts_wrap" ng-show="contacts.length > 0">
<h5>Contacts</h5>

2
app/partials/message.html

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
</ng-pluralize>
</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) ]" 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)">
<div class="im_message_wrap clearfix" bindonce>

Loading…
Cancel
Save