Browse Source

Merge branch 'layer-41'

master
Igor Zhukov 9 years ago
parent
commit
8894ab961f
  1. 64
      app/js/controllers.js
  2. 22
      app/js/directives.js
  3. 2
      app/js/filters.js
  4. 4
      app/js/lib/config.js
  5. 77
      app/js/lib/schema.tl.txt
  6. 31
      app/js/lib/tl_utils.js
  7. 4
      app/js/locales/en-us.json
  8. 445
      app/js/messages_manager.js
  9. 82
      app/js/services.js
  10. 2
      app/less/app.less
  11. 2
      app/partials/desktop/audio_player.html
  12. 2
      app/partials/desktop/chat_modal.html
  13. 8
      app/partials/desktop/dialog.html
  14. 20
      app/partials/desktop/dialog_service.html
  15. 4
      app/partials/desktop/message.html
  16. 18
      app/partials/desktop/message_service.html
  17. 2
      app/partials/desktop/user_modal.html
  18. 2
      app/partials/mobile/audio_player.html
  19. 2
      app/partials/mobile/chat_modal.html
  20. 8
      app/partials/mobile/dialog.html
  21. 4
      app/partials/mobile/message.html
  22. 18
      app/partials/mobile/message_service.html
  23. 2
      app/partials/mobile/user_modal.html

64
app/js/controllers.js

@ -749,7 +749,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
case 'updateUserTyping': case 'updateUserTyping':
case 'updateChatUserTyping': case 'updateChatUserTyping':
if (!AppUsersManager.hasUser(update.user_id)) { if (!AppUsersManager.hasUser(update.user_id)) {
if (update.chat_id) { if (update.chat_id &&
AppChatsManager.hasChat(update.chat_id) &&
!AppChatsManager.isChannel(update.chat_id)) {
AppProfileManager.getChatFull(update.chat_id); AppProfileManager.getChatFull(update.chat_id);
} }
return; return;
@ -1109,9 +1111,10 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$rootScope.selectedPeerID = peerID; $rootScope.selectedPeerID = peerID;
$scope.curDialog.peerID = peerID; $scope.curDialog.peerID = peerID;
$scope.curDialog.inputPeer = AppPeersManager.getInputPeer(newPeer);
$scope.historyFilter.mediaType = false; $scope.historyFilter.mediaType = false;
AppPeersManager.getInputPeer(newPeer);
updateBotActions(); updateBotActions();
selectedCancel(true); selectedCancel(true);
@ -1241,7 +1244,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
AppPeersManager.isChannel(peerID) && AppPeersManager.isChannel(peerID) &&
(channel = AppChatsManager.getChat(-peerID))) { (channel = AppChatsManager.getChat(-peerID))) {
var canSend = channel.pFlags.creator || channel.pFlags.editor; var canSend = AppChatsManager.hasRights(-peerID, 'send');
if (!canSend) { if (!canSend) {
if (channel.pFlags.left) { if (channel.pFlags.left) {
$scope.historyState.channelActions = 'join'; $scope.historyState.channelActions = 'join';
@ -1307,7 +1310,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
curLessJump = ++lessJump, curLessJump = ++lessJump,
limit = 0, limit = 0,
backLimit = 20; backLimit = 20;
AppMessagesManager.getHistory($scope.curDialog.inputPeer, minID, limit, backLimit).then(function (historyResult) { AppMessagesManager.getHistory($scope.curDialog.peerID, minID, limit, backLimit).then(function (historyResult) {
lessActive = false; lessActive = false;
if (curJump != jump || curLessJump != lessJump) return; if (curJump != jump || curLessJump != lessJump) return;
@ -1356,8 +1359,8 @@ angular.module('myApp.controllers', ['myApp.i18n'])
inputMediaFilter = $scope.historyFilter.mediaType && {_: inputMediaFilters[$scope.historyFilter.mediaType]}, inputMediaFilter = $scope.historyFilter.mediaType && {_: inputMediaFilters[$scope.historyFilter.mediaType]},
limit = Config.Mobile ? 20 : 0, limit = Config.Mobile ? 20 : 0,
getMessagesPromise = inputMediaFilter getMessagesPromise = inputMediaFilter
? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, limit) ? AppMessagesManager.getSearch($scope.curDialog.peerID, '', inputMediaFilter, maxID, limit)
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit); : AppMessagesManager.getHistory($scope.curDialog.peerID, maxID, limit);
getMessagesPromise.then(function (historyResult) { getMessagesPromise.then(function (historyResult) {
moreActive = false; moreActive = false;
@ -1423,8 +1426,8 @@ angular.module('myApp.controllers', ['myApp.i18n'])
var curJump = ++jump, var curJump = ++jump,
inputMediaFilter = $scope.historyFilter.mediaType && {_: inputMediaFilters[$scope.historyFilter.mediaType]}, inputMediaFilter = $scope.historyFilter.mediaType && {_: inputMediaFilters[$scope.historyFilter.mediaType]},
getMessagesPromise = inputMediaFilter getMessagesPromise = inputMediaFilter
? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID) ? AppMessagesManager.getSearch($scope.curDialog.peerID, '', inputMediaFilter, maxID)
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit, backLimit, prerenderedLen); : AppMessagesManager.getHistory($scope.curDialog.peerID, maxID, limit, backLimit, prerenderedLen);
$scope.state.mayBeHasMore = true; $scope.state.mayBeHasMore = true;
@ -1452,7 +1455,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
angular.forEach(historyResult.history, function (id) { angular.forEach(historyResult.history, function (id) {
var message = AppMessagesManager.wrapForHistory(id); var message = AppMessagesManager.wrapForHistory(id);
if ($scope.historyState.skipped) { if ($scope.historyState.skipped) {
delete message.unread; delete message.pFlags.unread;
} }
if (historyResult.unreadOffset) { if (historyResult.unreadOffset) {
message.unreadAfter = true; message.unreadAfter = true;
@ -1489,7 +1492,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}, 2800); }, 2800);
} }
AppMessagesManager.readHistory($scope.curDialog.inputPeer); AppMessagesManager.readHistory($scope.curDialog.peerID);
updateBotActions(); updateBotActions();
updateChannelActions(); updateChannelActions();
@ -1664,7 +1667,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
function selectedFlush () { function selectedFlush () {
ErrorService.confirm({type: 'HISTORY_FLUSH'}).then(function () { ErrorService.confirm({type: 'HISTORY_FLUSH'}).then(function () {
AppMessagesManager.flushHistory($scope.curDialog.inputPeer).then(function () { AppMessagesManager.flushHistory($scope.curDialog.peerID).then(function () {
selectedCancel(); selectedCancel();
}); });
}) })
@ -1839,7 +1842,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.historyState.typing.splice(0, $scope.historyState.typing.length); $scope.historyState.typing.splice(0, $scope.historyState.typing.length);
$scope.$broadcast('ui_history_append_new', { $scope.$broadcast('ui_history_append_new', {
my: addedMessage.my, my: addedMessage.my,
idleScroll: unreadAfterIdle && !historyMessage.out && $rootScope.idle.isIDLE idleScroll: unreadAfterIdle && !historyMessage.pFlags.out && $rootScope.idle.isIDLE
}); });
if (addedMessage.my && $scope.historyUnreadAfter) { if (addedMessage.my && $scope.historyUnreadAfter) {
delete $scope.historyUnreadAfter; delete $scope.historyUnreadAfter;
@ -1848,9 +1851,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
// console.log('append check', $rootScope.idle.isIDLE, addedMessage.peerID, $scope.curDialog.peerID, historyMessage, history.messages[history.messages.length - 2]); // console.log('append check', $rootScope.idle.isIDLE, addedMessage.peerID, $scope.curDialog.peerID, historyMessage, history.messages[history.messages.length - 2]);
if ($rootScope.idle.isIDLE) { if ($rootScope.idle.isIDLE) {
if (historyMessage.unread && if (historyMessage.pFlags.unread &&
!historyMessage.out && !historyMessage.pFlags.out &&
!(history.messages[history.messages.length - 2] || {}).unread) { !(history.messages[history.messages.length - 2] || {}).pFlags.unread) {
$scope.historyUnreadAfter = historyMessage.mid; $scope.historyUnreadAfter = historyMessage.mid;
unreadAfterIdle = true; unreadAfterIdle = true;
@ -1858,7 +1861,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
} }
} else { } else {
$timeout(function () { $timeout(function () {
AppMessagesManager.readHistory($scope.curDialog.inputPeer); AppMessagesManager.readHistory($scope.curDialog.peerID);
}); });
} }
@ -1910,7 +1913,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
var hasOut = false; var hasOut = false;
var unreadAfterNew = false; var unreadAfterNew = false;
var historyMessage = history.messages[history.messages.length - 1]; var historyMessage = history.messages[history.messages.length - 1];
var lastIsRead = !historyMessage || !historyMessage.unread; var lastIsRead = !historyMessage || !historyMessage.pFlags.unread;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
messageID = msgs[i]; messageID = msgs[i];
if (messageID < maxID || if (messageID < maxID ||
@ -1921,15 +1924,15 @@ angular.module('myApp.controllers', ['myApp.i18n'])
history.messages.push(historyMessage); history.messages.push(historyMessage);
history.ids.push(messageID); history.ids.push(messageID);
if (!unreadAfterNew && isIDLE) { if (!unreadAfterNew && isIDLE) {
if (historyMessage.unread && if (historyMessage.pFlags.unread &&
!historyMessage.out && !historyMessage.pFlags.out &&
lastIsRead) { lastIsRead) {
unreadAfterNew = messageID; unreadAfterNew = messageID;
} else { } else {
lastIsRead = !historyMessage.unread; lastIsRead = !historyMessage.pFlags.unread;
} }
} }
if (!hasOut && historyMessage.out) { if (!hasOut && historyMessage.pFlags.out) {
hasOut = true; hasOut = true;
} }
} }
@ -1955,7 +1958,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
} }
} else { } else {
$timeout(function () { $timeout(function () {
AppMessagesManager.readHistory($scope.curDialog.inputPeer); AppMessagesManager.readHistory($scope.curDialog.peerID);
}); });
} }
@ -2043,7 +2046,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$rootScope.$watch('idle.isIDLE', function (newVal) { $rootScope.$watch('idle.isIDLE', function (newVal) {
if (!newVal && $scope.curDialog && $scope.curDialog.peerID && !$scope.historyFilter.mediaType && !$scope.historyState.skipped) { if (!newVal && $scope.curDialog && $scope.curDialog.peerID && !$scope.historyFilter.mediaType && !$scope.historyState.skipped) {
AppMessagesManager.readHistory($scope.curDialog.inputPeer); AppMessagesManager.readHistory($scope.curDialog.peerID);
} }
if (!newVal) { if (!newVal) {
unreadAfterIdle = false; unreadAfterIdle = false;
@ -2217,7 +2220,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
// console.log(dT(), 'reset draft', $scope.curDialog.peer, forceDraft); // console.log(dT(), 'reset draft', $scope.curDialog.peer, forceDraft);
if (forceDraft) { if (forceDraft) {
if (forceDraft == $scope.curDialog.peer) { if (forceDraft == $scope.curDialog.peer) {
$scope.draftMessage.isBroadcast = AppPeersManager.isChannel($scope.curDialog.peerID); $scope.draftMessage.isBroadcast = AppPeersManager.isChannel($scope.curDialog.peerID) && !AppPeersManager.isMegagroup($scope.curDialog.peerID);
$scope.$broadcast('ui_peer_draft'); $scope.$broadcast('ui_peer_draft');
return; return;
} else { } else {
@ -2231,7 +2234,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
Storage.get('draft' + $scope.curDialog.peerID).then(function (draftText) { Storage.get('draft' + $scope.curDialog.peerID).then(function (draftText) {
// console.log('Restore draft', 'draft' + $scope.curDialog.peerID, draftText); // console.log('Restore draft', 'draft' + $scope.curDialog.peerID, draftText);
$scope.draftMessage.text = draftText || ''; $scope.draftMessage.text = draftText || '';
$scope.draftMessage.isBroadcast = AppPeersManager.isChannel($scope.curDialog.peerID); $scope.draftMessage.isBroadcast = AppPeersManager.isChannel($scope.curDialog.peerID) && !AppPeersManager.isMegagroup($scope.curDialog.peerID);
// console.log('send broadcast', $scope.draftMessage); // console.log('send broadcast', $scope.draftMessage);
$scope.$broadcast('ui_peer_draft'); $scope.$broadcast('ui_peer_draft');
}); });
@ -2368,7 +2371,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
if (newVal && newVal.length) { if (newVal && newVal.length) {
if (!$scope.historyFilter.mediaType && !$scope.historyState.skipped) { if (!$scope.historyFilter.mediaType && !$scope.historyState.skipped) {
AppMessagesManager.readHistory($scope.curDialog.inputPeer); AppMessagesManager.readHistory($scope.curDialog.peerID);
} }
var backupDraftObj = {}; var backupDraftObj = {};
@ -2382,11 +2385,12 @@ angular.module('myApp.controllers', ['myApp.i18n'])
} }
function onTyping () { function onTyping () {
if ($scope.curDialog.inputPeer._ == 'inputPeerChannel') { if (AppPeersManager.isChannel($scope.curDialog.peerID) &&
!AppPeersManager.isMegagroup($scope.curDialog.peerID)) {
return false; return false;
} }
MtpApiManager.invokeApi('messages.setTyping', { MtpApiManager.invokeApi('messages.setTyping', {
peer: $scope.curDialog.inputPeer, peer: AppPeersManager.getInputPeerByID($scope.curDialog.peerID),
action: {_: 'sendMessageTypingAction'} action: {_: 'sendMessageTypingAction'}
}); });
} }
@ -3076,7 +3080,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.flushHistory = function () { $scope.flushHistory = function () {
ErrorService.confirm({type: 'HISTORY_FLUSH'}).then(function () { ErrorService.confirm({type: 'HISTORY_FLUSH'}).then(function () {
AppMessagesManager.flushHistory(AppPeersManager.getInputPeerByID($scope.userID)).then(function () { AppMessagesManager.flushHistory($scope.userID).then(function () {
$scope.goToHistory(); $scope.goToHistory();
}); });
}); });
@ -3236,7 +3240,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.flushHistory = function () { $scope.flushHistory = function () {
ErrorService.confirm({type: 'HISTORY_FLUSH'}).then(function () { ErrorService.confirm({type: 'HISTORY_FLUSH'}).then(function () {
AppMessagesManager.flushHistory(AppPeersManager.getInputPeerByID(-$scope.chatID)).then(function () { AppMessagesManager.flushHistory(-$scope.chatID).then(function () {
$rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString}); $rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString});
}); });
}); });

22
app/js/directives.js

@ -116,8 +116,8 @@ angular.module('myApp.directives', ['myApp.filters'])
}); });
var deregisterUnreadAfter; var deregisterUnreadAfter;
if (!$scope.historyMessage.out && if (!$scope.historyMessage.pFlags.out &&
($scope.historyMessage.unread || $scope.historyMessage.unreadAfter)) { ($scope.historyMessage.pFlags.unread || $scope.historyMessage.unreadAfter)) {
var applyUnreadAfter = function () { var applyUnreadAfter = function () {
if ($scope.peerHistory.peerID != $scope.historyPeer.id) { if ($scope.peerHistory.peerID != $scope.historyPeer.id) {
return; return;
@ -141,10 +141,10 @@ angular.module('myApp.directives', ['myApp.filters'])
applyUnreadAfter(); applyUnreadAfter();
deregisterUnreadAfter = $scope.$on('messages_unread_after', applyUnreadAfter); deregisterUnreadAfter = $scope.$on('messages_unread_after', applyUnreadAfter);
} }
if ($scope.historyMessage.unread && $scope.historyMessage.out) { if ($scope.historyMessage.pFlags.unread && $scope.historyMessage.pFlags.out) {
element.addClass(unreadClass); element.addClass(unreadClass);
var deregisterUnread = $scope.$on('messages_read', function () { var deregisterUnread = $scope.$on('messages_read', function () {
if (!$scope.historyMessage.unread) { if (!$scope.historyMessage.pFlags.unread) {
element.removeClass(unreadClass); element.removeClass(unreadClass);
deregisterUnread(); deregisterUnread();
if (deregisterUnreadAfter && !unreadAfter) { if (deregisterUnreadAfter && !unreadAfter) {
@ -2519,7 +2519,7 @@ angular.module('myApp.directives', ['myApp.filters'])
}) })
.directive('myUserStatus', function ($filter, AppUsersManager) { .directive('myUserStatus', function ($filter, $rootScope, AppUsersManager) {
var statusFilter = $filter('userStatus'), var statusFilter = $filter('userStatus'),
ind = 0, ind = 0,
@ -2527,6 +2527,13 @@ angular.module('myApp.directives', ['myApp.filters'])
setInterval(updateAll, 90000); setInterval(updateAll, 90000);
$rootScope.$on('stateSynchronized', function () {
setTimeout(function () {
updateAll();
}, 100);
});
return { return {
link: link link: link
}; };
@ -2545,6 +2552,7 @@ angular.module('myApp.directives', ['myApp.filters'])
element element
.html(statusFilter(user, attrs.botChatPrivacy)) .html(statusFilter(user, attrs.botChatPrivacy))
.toggleClass('status_online', user.status && user.status._ == 'userStatusOnline' || false); .toggleClass('status_online', user.status && user.status._ == 'userStatusOnline' || false);
// console.log(dT(), 'update status', element[0], user.status && user.status, tsNow(true), element.html());
}; };
$scope.$watch(attrs.myUserStatus, function (newUserID) { $scope.$watch(attrs.myUserStatus, function (newUserID) {
@ -2947,8 +2955,8 @@ angular.module('myApp.directives', ['myApp.filters'])
$scope.mediaPlayer.player.play(); $scope.mediaPlayer.player.play();
if ($scope.message && if ($scope.message &&
!$scope.message.out && !$scope.message.pFlags.out &&
$scope.message.media_unread) { $scope.message.pFlags.media_unread) {
AppMessagesManager.readMessages([$scope.message.mid]); AppMessagesManager.readMessages([$scope.message.mid]);
} }
}, 300); }, 300);

2
app/js/filters.js

@ -54,7 +54,7 @@ angular.module('myApp.filters', ['myApp.i18n'])
case 'userStatusBot': case 'userStatusBot':
if (botChatPrivacy) { if (botChatPrivacy) {
if (user.pFlags.botNoPrivacy) { if (user.pFlags.bot_chat_history) {
return _('user_status_bot_noprivacy'); return _('user_status_bot_noprivacy');
} else { } else {
return _('user_status_bot_privacy'); return _('user_status_bot_privacy');

4
app/js/lib/config.js

File diff suppressed because one or more lines are too long

77
app/js/lib/schema.tl.txt

@ -1,6 +1,8 @@
boolFalse#bc799737 = Bool; boolFalse#bc799737 = Bool;
boolTrue#997275b5 = Bool; boolTrue#997275b5 = Bool;
true#3fedd339 = True;
vector#1cb5c415 {t:Type} # [ t ] = Vector t; vector#1cb5c415 {t:Type} # [ t ] = Vector t;
error#c4b9f9bb code:int text:string = Error; error#c4b9f9bb code:int text:string = Error;
@ -80,7 +82,7 @@ fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileL
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
userEmpty#200250ba id:int = User; userEmpty#200250ba id:int = User;
user#22e49072 flags:# id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int = User; user#22e49072 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int = User;
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
@ -93,25 +95,27 @@ userStatusLastWeek#7bf09fc = UserStatus;
userStatusLastMonth#77ebc742 = UserStatus; userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat; chatEmpty#9ba2d800 id:int = Chat;
chat#7312bc48 flags:# id:int title:string photo:ChatPhoto participants_count:int date:int version:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chatForbidden#7328bdb id:int title:string = Chat; chatForbidden#7328bdb id:int title:string = Chat;
channel#678e9587 flags:# id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int = Chat; channel#678e9587 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int = Chat;
channelForbidden#2d85832c id:int access_hash:long title:string = Chat; channelForbidden#2d85832c id:int access_hash:long title:string = Chat;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
channelFull#fab31aa3 flags:# id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite = ChatFull; channelFull#9e341ddf flags:# can_view_participants:flags.3?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants;
chatParticipants#7841b415 chat_id:int admin_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
chatPhotoEmpty#37c1011c = ChatPhoto; chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
messageEmpty#83e5de54 id:int = Message; messageEmpty#83e5de54 id:int = Message;
message#5ba66c13 flags:# id:int from_id:flags.8?int to_id:Peer fwd_from_id:flags.2?Peer fwd_date:flags.2?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int = Message; message#5ba66c13 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer fwd_from_id:flags.2?Peer fwd_date:flags.2?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int = Message;
messageService#c06b9607 flags:# id:int from_id:flags.8?int to_id:Peer date:int action:MessageAction = Message; messageService#c06b9607 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia; messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia; messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia;
@ -129,10 +133,12 @@ messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction;
messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction;
messageActionChatAddUser#5e3cfc4b user_id:int = MessageAction; messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction;
messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction;
messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction;
messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog; dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog;
dialogChannel#5b8496b2 peer:Peer top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int notify_settings:PeerNotifySettings pts:int = Dialog; dialogChannel#5b8496b2 peer:Peer top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int notify_settings:PeerNotifySettings pts:int = Dialog;
@ -260,6 +266,8 @@ updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update;
updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update;
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -268,12 +276,12 @@ updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Ve
updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference;
updatesTooLong#e317af7e = Updates; updatesTooLong#e317af7e = Updates;
updateShortMessage#f7d91a46 flags:# id:int user_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShortMessage#f7d91a46 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShortChatMessage#cac7fdd2 flags:# id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates; updateShortChatMessage#cac7fdd2 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShort#78d4dec1 update:Update date:int = Updates; updateShort#78d4dec1 update:Update date:int = Updates;
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates; updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates; updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
updateShortSentMessage#11f1331c flags:# id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates; updateShortSentMessage#11f1331c flags:# unread:flags.0?true out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates;
photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos;
@ -282,9 +290,9 @@ photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
dcOption#5d8c6cc flags:# id:int ip_address:string port:int = DcOption; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true id:int ip_address:string port:int = DcOption;
config#4e32b894 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int broadcast_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int disabled_features:Vector<DisabledFeature> = Config; config#6cb6e65e date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int disabled_features:Vector<DisabledFeature> = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@ -421,13 +429,13 @@ chatInviteEmpty#69df3769 = ExportedChatInvite;
chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#93e99b60 flags:# title:string = ChatInvite; chatInvite#93e99b60 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string = ChatInvite;
inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
stickerSet#cd303b41 flags:# id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true disabled:flags.1?true official:flags.2?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
@ -440,9 +448,9 @@ keyboardButton#a2fa4880 text:string = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow; keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
replyKeyboardHide#a03e5b85 flags:# = ReplyMarkup; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
replyKeyboardForceReply#f4108aa0 flags:# = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup;
replyKeyboardMarkup#3502758c flags:# rows:Vector<KeyboardButtonRow> = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup;
help.appChangelogEmpty#af7e0394 = help.AppChangelog; help.appChangelogEmpty#af7e0394 = help.AppChangelog;
help.appChangelog#4668e6bd text:string = help.AppChangelog; help.appChangelog#4668e6bd text:string = help.AppChangelog;
@ -468,12 +476,12 @@ messageRange#ae30253 min_id:int max_id:int = MessageRange;
messageGroup#e8346f53 min_id:int max_id:int count:int date:int = MessageGroup; messageGroup#e8346f53 min_id:int max_id:int count:int date:int = MessageGroup;
updates.channelDifferenceEmpty#3e11affb flags:# pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference;
updates.channelDifferenceTooLong#5e167646 flags:# pts:int timeout:flags.1?int top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; updates.channelDifferenceTooLong#5e167646 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
updates.channelDifference#2064674e flags:# pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
channelMessagesFilter#cd77d957 flags:# ranges:Vector<MessageRange> = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# important_only:flags.0?true exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter;
channelMessagesFilterCollapsed#fa01232e = ChannelMessagesFilter; channelMessagesFilterCollapsed#fa01232e = ChannelMessagesFilter;
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
@ -486,6 +494,7 @@ channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant;
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter; channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter;
channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
channelRoleEmpty#b285a0c6 = ChannelParticipantRole; channelRoleEmpty#b285a0c6 = ChannelParticipantRole;
channelRoleModerator#9618d975 = ChannelParticipantRole; channelRoleModerator#9618d975 = ChannelParticipantRole;
@ -562,17 +571,17 @@ contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
messages.getMessages#4222fa74 id:Vector<int> = messages.Messages; messages.getMessages#4222fa74 id:Vector<int> = messages.Messages;
messages.getDialogs#859b3d3c offset:int limit:int = messages.Dialogs; messages.getDialogs#6b47f94d offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
messages.getHistory#8a8ec2da peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.getHistory#8a8ec2da peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.search#d4569248 flags:# peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.search#d4569248 flags:# important_only:flags.0?true peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages;
messages.readHistory#b04f2510 peer:InputPeer max_id:int offset:int = messages.AffectedHistory; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#f4f8fb61 peer:InputPeer offset:int = messages.AffectedHistory; messages.deleteHistory#b7c13bd9 peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#a5f18925 id:Vector<int> = messages.AffectedMessages; messages.deleteMessages#a5f18925 id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>; messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.sendMessage#fa88427a flags:# peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.sendMedia#c8f16791 flags:# peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.sendMedia#c8f16791 flags:# broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
messages.forwardMessages#708e0195 flags:# from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates; messages.forwardMessages#708e0195 flags:# broadcast:flags.4?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats; messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
@ -603,8 +612,12 @@ messages.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool; messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#1b3e0ffc bot:InputUser chat_id:int random_id:long start_param:string = Updates; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates;
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
updates.getState#edd4882a = updates.State; updates.getState#edd4882a = updates.State;
updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference;
@ -638,9 +651,9 @@ channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipant
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats; channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#5521d844 flags:# title:string about:string users:Vector<InputUser> = Updates; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates;
channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool;
channels.editAdmin#52b16962 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Bool; channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates;
channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
channels.toggleComments#aaa29e88 channel:InputChannel enabled:Bool = Updates; channels.toggleComments#aaa29e88 channel:InputChannel enabled:Bool = Updates;

31
app/js/lib/tl_utils.js

@ -261,6 +261,7 @@ TLSerialization.prototype.storeObject = function (obj, type, field) {
case 'bytes': return this.storeBytes(obj, field); case 'bytes': return this.storeBytes(obj, field);
case 'double': return this.storeDouble(obj, field); case 'double': return this.storeDouble(obj, field);
case 'Bool': return this.storeBool(obj, field); case 'Bool': return this.storeBool(obj, field);
case 'true': return;
} }
if (angular.isArray(obj)) { if (angular.isArray(obj)) {
@ -510,14 +511,25 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
case 'bytes': return this.fetchBytes(field); case 'bytes': return this.fetchBytes(field);
case 'double': return this.fetchDouble(field); case 'double': return this.fetchDouble(field);
case 'Bool': return this.fetchBool(field); case 'Bool': return this.fetchBool(field);
case 'true': return true;
} }
field = field || type || 'Object'; field = field || type || 'Object';
if (type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') { if (type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') {
if (type.charAt(0) == 'V') { if (type.charAt(0) == 'V') {
var constructor = this.readInt(field + '[id]'); var constructor = this.readInt(field + '[id]'),
if (constructor != 0x1cb5c415) { constructorCmp = uintToInt(constructor);
if (constructorCmp == 0x3072cfa1) { // Gzip packed
var compressed = this.fetchBytes(field + '[packed_string]'),
uncompressed = gzipUncompress(compressed),
buffer = bytesToArrayBuffer(uncompressed),
newDeserializer = (new TLDeserialization(buffer));
return newDeserializer.fetchObject(type, field);
}
if (constructorCmp != 0x1cb5c415) {
throw new Error('Invalid vector constructor ' + constructor); throw new Error('Invalid vector constructor ' + constructor);
} }
} }
@ -613,12 +625,15 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
if (this.override[overrideKey]) { if (this.override[overrideKey]) {
this.override[overrideKey].apply(this, [result, field + '[' + predicate + ']']); this.override[overrideKey].apply(this, [result, field + '[' + predicate + ']']);
} else { } else {
var i, param, type, condType, fieldBit; var i, param, type, isCond, condType, fieldBit, value;
var len = constructorData.params.length; var len = constructorData.params.length;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
param = constructorData.params[i]; param = constructorData.params[i];
type = param.type; type = param.type;
if (type.indexOf('?') !== -1) { if (type == '#' && result.pFlags === undefined) {
result.pFlags = {};
}
if (isCond = (type.indexOf('?') !== -1)) {
condType = type.split('?'); condType = type.split('?');
fieldBit = condType[0].split('.'); fieldBit = condType[0].split('.');
if (!(result[fieldBit[0]] & (1 << fieldBit[1]))) { if (!(result[fieldBit[0]] & (1 << fieldBit[1]))) {
@ -627,7 +642,13 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
type = condType[1]; type = condType[1];
} }
result[param.name] = self.fetchObject(type, field + '[' + predicate + '][' + param.name + ']'); value = self.fetchObject(type, field + '[' + predicate + '][' + param.name + ']');
if (isCond && type === 'true') {
result.pFlags[param.name] = value;
} else {
result[param.name] = value;
}
} }
} }

4
app/js/locales/en-us.json

@ -283,11 +283,13 @@
"conversation_group_photo_removed": "removed group photo", "conversation_group_photo_removed": "removed group photo",
"conversation_returned_to_group": "returned to group", "conversation_returned_to_group": "returned to group",
"conversation_invited_user": "invited {user}", "conversation_invited_user": "invited {user}",
"conversation_invited_users": "{'one': 'invited {} user', 'other': 'invited {} users'}",
"conversation_left_group": "left group", "conversation_left_group": "left group",
"conversation_kicked_user": "removed {user}", "conversation_kicked_user": "removed {user}",
"conversation_invited_user_message": "invited user", "conversation_invited_user_message": "invited user",
"conversation_kicked_user_message": "removed user", "conversation_kicked_user_message": "removed user",
"conversation_joined_by_link": "joined group", "conversation_joined_by_link": "joined group",
"conversation_converted_to_supergroup": "upgraded to a supergroup",
"conversation_created_channel": "Channel created", "conversation_created_channel": "Channel created",
"conversation_changed_channel_name": "Channel renamed", "conversation_changed_channel_name": "Channel renamed",
"conversation_changed_channel_photo": "Channel photo updated", "conversation_changed_channel_photo": "Channel photo updated",
@ -304,12 +306,14 @@
"message_service_changed_group_photo": "changed group photo", "message_service_changed_group_photo": "changed group photo",
"message_service_removed_group_photo": "removed group photo", "message_service_removed_group_photo": "removed group photo",
"message_service_invited_user": "invited {user}", "message_service_invited_user": "invited {user}",
"message_service_invited_users": "invited {user} and {num-more} more",
"message_service_returned_to_group": "returned to group", "message_service_returned_to_group": "returned to group",
"message_service_kicked_user": "removed {user}", "message_service_kicked_user": "removed {user}",
"message_service_left_group": "left group", "message_service_left_group": "left group",
"message_service_joined_by_link": "joined group via invite link", "message_service_joined_by_link": "joined group via invite link",
"message_service_unsupported_action": "unsupported action {action}", "message_service_unsupported_action": "unsupported action {action}",
"message_service_bot_intro_header": "What can this bot do?", "message_service_bot_intro_header": "What can this bot do?",
"message_service_converted_to_supergroup": "upgraded the group to a supergroup",
"message_service_created_channel": "Channel created", "message_service_created_channel": "Channel created",
"message_service_changed_channel_name": "Channel renamed to {channel-name}", "message_service_changed_channel_name": "Channel renamed to {channel-name}",
"message_service_changed_channel_photo": "Channel photo updated", "message_service_changed_channel_photo": "Channel photo updated",

445
app/js/messages_manager.js

@ -65,13 +65,14 @@ angular.module('myApp.services')
NotificationsManager.start(); NotificationsManager.start();
var allChannelsLoaded = false;
var channelsLoadPromise = false;
var allDialogsLoaded = false var allDialogsLoaded = false
var loadedDialogsCount = 0; var loadedDialogsCount = 0;
var dialogsNum = 0; var dialogsNum = 0;
var minDialogsIndex = Math.pow(2, 50); var minDialogsIndex = Math.pow(2, 50);
var migratedFromTo = {};
var migratedToFrom = {};
function getConversations (query, offsetIndex, limit) { function getConversations (query, offsetIndex, limit) {
var curDialogStorage = dialogsStorage; var curDialogStorage = dialogsStorage;
var isSearch = angular.isString(query) && query.length; var isSearch = angular.isString(query) && query.length;
@ -108,7 +109,7 @@ angular.module('myApp.services')
if ( if (
isSearch || isSearch ||
(allChannelsLoaded && allDialogsLoaded) || allDialogsLoaded ||
( (
curDialogStorage.dialogs.length >= offset + limit && curDialogStorage.dialogs.length >= offset + limit &&
curDialogStorage.dialogs[offset + limit - 1].index >= minDialogsIndex curDialogStorage.dialogs[offset + limit - 1].index >= minDialogsIndex
@ -119,7 +120,7 @@ angular.module('myApp.services')
}); });
} }
return $q.all([getAllChannels(), getTopMessages(loadedDialogsCount, limit)]).then(function () { return getTopMessages(limit).then(function () {
offset = 0; offset = 0;
if (offsetIndex > 0) { if (offsetIndex > 0) {
for (offset = 0; offset < curDialogStorage.dialogs.length; offset++) { for (offset = 0; offset < curDialogStorage.dialogs.length; offset++) {
@ -149,9 +150,14 @@ angular.module('myApp.services')
var peerText = AppPeersManager.getPeerSearchText(peerID); var peerText = AppPeersManager.getPeerSearchText(peerID);
SearchIndexManager.indexObject(peerID, peerText, dialogsIndex); SearchIndexManager.indexObject(peerID, peerText, dialogsIndex);
var isMegagroup = AppChatsManager.isMegagroup(channelID);
if (isMegagroup) {
var mid = getFullMessageID(dialog.top_message, channelID);
} else {
var mid = getFullMessageID(dialog.top_important_message, channelID); var mid = getFullMessageID(dialog.top_important_message, channelID);
dialog.top_message = mid;
dialog.unread_count = dialog.unread_important_count; dialog.unread_count = dialog.unread_important_count;
}
dialog.top_message = mid;
dialog.read_inbox_max_id = getFullMessageID(dialog.read_inbox_max_id, channelID); dialog.read_inbox_max_id = getFullMessageID(dialog.read_inbox_max_id, channelID);
var message = getMessage(dialog.top_message); var message = getMessage(dialog.top_message);
@ -168,7 +174,7 @@ angular.module('myApp.services')
// Because we saved message without dialog present // Because we saved message without dialog present
if (message.mid && message.mid > dialog.read_inbox_max_id) { if (message.mid && message.mid > dialog.read_inbox_max_id) {
message.unread = true; message.pFlags.unread = true;
} }
if (historiesStorage[peerID] === undefined) { if (historiesStorage[peerID] === undefined) {
@ -180,46 +186,34 @@ angular.module('myApp.services')
ApiUpdatesManager.addChannelState(channelID, dialog.pts); ApiUpdatesManager.addChannelState(channelID, dialog.pts);
} }
function getAllChannels () { function getTopMessages (limit) {
if (channelsLoadPromise) { var first = true;
return channelsLoadPromise; var dialogs = dialogsStorage.dialogs;
var len = dialogs && dialogs.length;
var offsetDate = 0;
var offsetID = 0;
var offsetPeerID = 0;
if (len) {
var dialog = dialogs[len - 1];
var index = dialog.index;
if (index) {
offsetDate = Math.ceil(index / 0x10000);
offsetID = dialog.top_message;
offsetPeerID = dialog.peerID;
} }
return channelsLoadPromise = MtpApiManager.invokeApi('channels.getDialogs', {
offset: 0,
limit: 100
}, {
timeout: 300
}).then(function (dialogsResult) {
AppUsersManager.saveApiUsers(dialogsResult.users);
AppChatsManager.saveApiChats(dialogsResult.chats);
saveMessages(dialogsResult.messages);
angular.forEach(dialogsResult.dialogs, function (dialog) {
var peerID = AppPeersManager.getPeerID(dialog.peer);
var channelID = -peerID;
saveChannelDialog(channelID, dialog);
ApiUpdatesManager.addChannelState(channelID, dialog.pts);
});
allChannelsLoaded = true;
});
} }
function getTopMessages (offset, limit) {
return MtpApiManager.invokeApi('messages.getDialogs', { return MtpApiManager.invokeApi('messages.getDialogs', {
offset: offset, offset_date: offsetDate,
offset_id: getMessageLocalID(offsetID),
offset_peer: AppPeersManager.getInputPeerByID(offsetPeerID),
limit: limit limit: limit
}, { }, {
timeout: 300 timeout: 300
}).then(function (dialogsResult) { }).then(function (dialogsResult) {
if (!offset) { if (!offsetDate) {
TelegramMeWebService.setAuthorized(true); TelegramMeWebService.setAuthorized(true);
} }
// Server-side bug
if (dialogsResult.count && offset >= dialogsResult.count) {
dialogsResult.dialogs = [];
}
AppUsersManager.saveApiUsers(dialogsResult.users); AppUsersManager.saveApiUsers(dialogsResult.users);
AppChatsManager.saveApiChats(dialogsResult.chats); AppChatsManager.saveApiChats(dialogsResult.chats);
saveMessages(dialogsResult.messages); saveMessages(dialogsResult.messages);
@ -227,12 +221,24 @@ angular.module('myApp.services')
if (!dialogsResult.dialogs.length) { if (!dialogsResult.dialogs.length) {
allDialogsLoaded = true; allDialogsLoaded = true;
} }
else if (!offset) {
incrementMaxSeenID(dialogsResult.dialogs[0].top_message);
}
var maxSeenIdIncremented = offsetDate ? true : false;
angular.forEach(dialogsResult.dialogs, function (dialog) { angular.forEach(dialogsResult.dialogs, function (dialog) {
var peerID = AppPeersManager.getPeerID(dialog.peer); var peerID = AppPeersManager.getPeerID(dialog.peer);
if (dialog._ == 'dialogChannel') {
var channelID = -peerID;
saveChannelDialog(channelID, dialog);
ApiUpdatesManager.addChannelState(channelID, dialog.pts);
} else {
if (peerID < 0) {
var chat = AppChatsManager.getChat(-peerID);
if (chat && chat.migrated_to && chat.pFlags.deactivated) {
var migratedToPeer = AppPeersManager.getPeerID(chat.migrated_to);
migratedFromTo[peerID] = migratedToPeer;
migratedToFrom[migratedToPeer] = peerID;
return;
}
}
var peerText = AppPeersManager.getPeerSearchText(peerID); var peerText = AppPeersManager.getPeerSearchText(peerID);
SearchIndexManager.indexObject(peerID, peerText, dialogsIndex); SearchIndexManager.indexObject(peerID, peerText, dialogsIndex);
@ -243,6 +249,11 @@ angular.module('myApp.services')
pushDialogToStorage(dialog); pushDialogToStorage(dialog);
if (!maxSeenIdIncremented) {
incrementMaxSeenID(dialog.top_message);
maxSeenIdIncremented = true;
}
if (historiesStorage[peerID] === undefined) { if (historiesStorage[peerID] === undefined) {
var historyStorage = {count: null, history: [dialog.top_message], pending: []}; var historyStorage = {count: null, history: [dialog.top_message], pending: []};
historiesStorage[peerID] = historyStorage; historiesStorage[peerID] = historyStorage;
@ -259,7 +270,7 @@ angular.module('myApp.services')
dialog.top_message > maxSeenID dialog.top_message > maxSeenID
) { ) {
var notifyPeer = message.flags & 16 ? message.from_id : peerID; var notifyPeer = message.flags & 16 ? message.from_id : peerID;
if (message.unread && !message.out) { if (message.pFlags.unread && !message.pFlags.out) {
NotificationsManager.getPeerMuted(notifyPeer).then(function (muted) { NotificationsManager.getPeerMuted(notifyPeer).then(function (muted) {
if (!muted) { if (!muted) {
notifyAboutMessage(message); notifyAboutMessage(message);
@ -267,6 +278,7 @@ angular.module('myApp.services')
}); });
} }
} }
}
}); });
}); });
} }
@ -311,11 +323,12 @@ angular.module('myApp.services')
} }
} }
function requestHistory (inputPeer, maxID, limit, offset) { function requestHistory (peerID, maxID, limit, offset) {
var peerID = AppPeersManager.getPeerID(inputPeer);
var isChannel = AppPeersManager.isChannel(peerID); var isChannel = AppPeersManager.isChannel(peerID);
var isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID);
var promise; var promise;
if (isChannel) { if (isChannel && !isMegagroup) {
promise = MtpApiManager.invokeApi('channels.getImportantHistory', { promise = MtpApiManager.invokeApi('channels.getImportantHistory', {
channel: AppChatsManager.getChannelInput(-peerID), channel: AppChatsManager.getChannelInput(-peerID),
offset_id: maxID ? getMessageLocalID(maxID) : 0, offset_id: maxID ? getMessageLocalID(maxID) : 0,
@ -327,7 +340,7 @@ angular.module('myApp.services')
}); });
} else { } else {
promise = MtpApiManager.invokeApi('messages.getHistory', { promise = MtpApiManager.invokeApi('messages.getHistory', {
peer: inputPeer, peer: AppPeersManager.getInputPeerByID(peerID),
offset_id: maxID ? getMessageLocalID(maxID) : 0, offset_id: maxID ? getMessageLocalID(maxID) : 0,
add_offset: offset || 0, add_offset: offset || 0,
limit: limit || 0 limit: limit || 0
@ -364,6 +377,7 @@ angular.module('myApp.services')
from_id: peerID, from_id: peerID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: AppPeersManager.getOutputPeer(peerID),
flags: 0, flags: 0,
pFlags: {},
date: tsNow(true) + serverTimeOffset, date: tsNow(true) + serverTimeOffset,
action: { action: {
_: 'messageActionBotIntro', _: 'messageActionBotIntro',
@ -457,9 +471,13 @@ angular.module('myApp.services')
}; };
} }
function fillHistoryStorage (inputPeer, maxID, fullLimit, historyStorage) { function fillHistoryStorage (peerID, maxID, fullLimit, historyStorage) {
// console.log('fill history storage', inputPeer, maxID, fullLimit, angular.copy(historyStorage)); // console.log('fill history storage', peerID, maxID, fullLimit, angular.copy(historyStorage));
return requestHistory (inputPeer, maxID, fullLimit).then(function (historyResult) { var migratedNextPeer = migratedFromTo[peerID];
var migratedPrevPeer = migratedToFrom[peerID];
var isMigrated = migratedNextPeer !== undefined || migratedPrevPeer !== undefined;
return requestHistory (peerID, maxID, fullLimit).then(function (historyResult) {
historyStorage.count = historyResult.count || historyResult.messages.length; historyStorage.count = historyResult.count || historyResult.messages.length;
var offset = 0; var offset = 0;
@ -474,21 +492,41 @@ angular.module('myApp.services')
} }
} }
var wasTotalCount = historyStorage.history.length;
historyStorage.history.splice(offset, historyStorage.history.length - offset); historyStorage.history.splice(offset, historyStorage.history.length - offset);
angular.forEach(historyResult.messages, function (message) { angular.forEach(historyResult.messages, function (message) {
if (mergeReplyKeyboard(historyStorage, message)) { if (mergeReplyKeyboard(historyStorage, message)) {
$rootScope.$broadcast('history_reply_markup', {peerID: AppPeersManager.getPeerID(inputPeer)}); $rootScope.$broadcast('history_reply_markup', {peerID: peerID});
} }
historyStorage.history.push(message.mid); historyStorage.history.push(message.mid);
}); });
fullLimit -= historyResult.messages.length; var totalCount = historyStorage.history.length;
fullLimit -= (totalCount - wasTotalCount);
if (fullLimit > 0 && historyStorage.history.length < historyStorage.count) { if (isMigrated) {
maxID = historyStorage.history[historyStorage.history.length - 1]; historyStorage.count = Math.max(historyStorage.count, totalCount) + 1;
return fillHistoryStorage(inputPeer, maxID, fullLimit, historyStorage);
} }
if (fullLimit > 0) {
maxID = historyStorage.history[totalCount - 1];
if (isMigrated) {
if (!historyResult.messages.length) {
if (migratedPrevPeer) {
maxID = 0;
peerID = migratedPrevPeer;
} else {
historyStorage.count = totalCount;
return true;
}
}
return fillHistoryStorage(peerID, maxID, fullLimit, historyStorage);
}
else if (totalCount < historyStorage.count) {
return fillHistoryStorage(peerID, maxID, fullLimit, historyStorage);
}
}
return true; return true;
}); });
}; };
@ -499,7 +537,7 @@ angular.module('myApp.services')
var i, message; var i, message;
for (i = result.history.length - 1; i >= 0; i--) { for (i = result.history.length - 1; i >= 0; i--) {
message = messagesStorage[result.history[i]]; message = messagesStorage[result.history[i]];
if (message && !message.out && message.unread) { if (message && !message.pFlags.out && message.pFlags.unread) {
result.unreadOffset = i + 1; result.unreadOffset = i + 1;
break; break;
} }
@ -508,9 +546,11 @@ angular.module('myApp.services')
return $q.when(result); return $q.when(result);
} }
function getHistory (inputPeer, maxID, limit, backLimit, prerendered) { function getHistory (peerID, maxID, limit, backLimit, prerendered) {
var peerID = AppPeersManager.getPeerID(inputPeer), if (migratedFromTo[peerID]) {
historyStorage = historiesStorage[peerID], peerID = migratedFromTo[peerID];
}
var historyStorage = historiesStorage[peerID],
offset = 0, offset = 0,
offsetNotFound = false, offsetNotFound = false,
unreadOffset = false, unreadOffset = false,
@ -522,6 +562,15 @@ angular.module('myApp.services')
historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []}; historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
} }
var isMigrated = false;
var reqPeerID = peerID;
if (migratedToFrom[peerID]) {
isMigrated = true;
if (maxID && maxID < fullMsgIDModulus) {
reqPeerID = migratedToFrom[peerID];
}
}
if (!limit && !maxID) { if (!limit && !maxID) {
var foundDialog = getDialogByPeerID(peerID)[0]; var foundDialog = getDialogByPeerID(peerID)[0];
if (foundDialog && foundDialog.unread_count > 1) { if (foundDialog && foundDialog.unread_count > 1) {
@ -590,8 +639,11 @@ angular.module('myApp.services')
offset = -backLimit; offset = -backLimit;
limit += backLimit; limit += backLimit;
} }
return requestHistory(inputPeer, maxID, limit, offset).then(function (historyResult) { return requestHistory(reqPeerID, maxID, limit, offset).then(function (historyResult) {
historyStorage.count = historyResult.count || historyResult.messages.length; historyStorage.count = historyResult.count || historyResult.messages.length;
if (isMigrated) {
historyStorage.count++;
}
var history = []; var history = [];
angular.forEach(historyResult.messages, function (message) { angular.forEach(historyResult.messages, function (message) {
@ -610,7 +662,7 @@ angular.module('myApp.services')
}) })
} }
return fillHistoryStorage(inputPeer, maxID, limit, historyStorage).then(function () { return fillHistoryStorage(peerID, maxID, limit, historyStorage).then(function () {
offset = 0; offset = 0;
if (maxID > 0) { if (maxID > 0) {
for (offset = 0; offset < historyStorage.history.length; offset++) { for (offset = 0; offset < historyStorage.history.length; offset++) {
@ -641,7 +693,7 @@ angular.module('myApp.services')
function mergeReplyKeyboard (historyStorage, message) { function mergeReplyKeyboard (historyStorage, message) {
// console.log('merge', message.mid, message.reply_markup, historyStorage.reply_markup); // console.log('merge', message.mid, message.reply_markup, historyStorage.reply_markup);
if (!message.reply_markup && if (!message.reply_markup &&
!message.out && !message.pFlags.out &&
!message.action) { !message.action) {
return false; return false;
} }
@ -657,7 +709,7 @@ angular.module('myApp.services')
} }
if (historyStorage.maxOutID && if (historyStorage.maxOutID &&
message.mid < historyStorage.maxOutID && message.mid < historyStorage.maxOutID &&
messageReplyMarkup.pFlags.one_time) { messageReplyMarkup.pFlags.single_use) {
messageReplyMarkup.pFlags.hidden = true; messageReplyMarkup.pFlags.hidden = true;
} }
messageReplyMarkup = angular.extend({ messageReplyMarkup = angular.extend({
@ -671,9 +723,9 @@ angular.module('myApp.services')
return true; return true;
} }
if (message.out) { if (message.pFlags.out) {
if (lastReplyMarkup) { if (lastReplyMarkup) {
if (lastReplyMarkup.pFlags.one_time && if (lastReplyMarkup.pFlags.single_use &&
!lastReplyMarkup.pFlags.hidden && !lastReplyMarkup.pFlags.hidden &&
(message.mid > lastReplyMarkup.mid || message.mid < 0) && (message.mid > lastReplyMarkup.mid || message.mid < 0) &&
message.message) { message.message) {
@ -707,10 +759,9 @@ angular.module('myApp.services')
return false; return false;
} }
function getSearch (inputPeer, query, inputFilter, maxID, limit) { function getSearch (peerID, query, inputFilter, maxID, limit) {
var foundMsgs = [], var foundMsgs = [],
useSearchCache = !query, useSearchCache = !query,
peerID = AppPeersManager.getPeerID(inputPeer),
newSearchFilter = {peer: peerID, filter: inputFilter}, newSearchFilter = {peer: peerID, filter: inputFilter},
sameSearchCache = useSearchCache && angular.equals(lastSearchFilter, newSearchFilter); sameSearchCache = useSearchCache && angular.equals(lastSearchFilter, newSearchFilter);
@ -719,7 +770,7 @@ angular.module('myApp.services')
lastSearchResults = []; lastSearchResults = [];
} }
if (!maxID && !query) { if (peerID && !maxID && !query) {
var historyStorage = historiesStorage[peerID]; var historyStorage = historiesStorage[peerID];
if (historyStorage !== undefined && historyStorage.history.length) { if (historyStorage !== undefined && historyStorage.history.length) {
@ -786,9 +837,17 @@ angular.module('myApp.services')
}); });
} }
return MtpApiManager.invokeApi('messages.search', { var apiPromise;
flags: 0,
peer: inputPeer, if (peerID || !query) {
var flags = 0;
if (AppPeersManager.isChannel(peerID) &&
!AppPeersManager.isMegagroup(peerID)) {
flags |= 1;
}
apiPromise = MtpApiManager.invokeApi('messages.search', {
flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID),
q: query || '', q: query || '',
filter: inputFilter || {_: 'inputMessagesFilterEmpty'}, filter: inputFilter || {_: 'inputMessagesFilterEmpty'},
min_date: 0, min_date: 0,
@ -798,7 +857,30 @@ angular.module('myApp.services')
}, { }, {
timeout: 300, timeout: 300,
noErrorBox: true noErrorBox: true
}).then(function (searchResult) { });
} else {
var offsetDate = 0;
var offsetPeerID = 0;
var offsetID = 0;
var offsetMessage = maxID && getMessage(maxID);
if (offsetMessage && offsetMessage.date) {
offsetDate = offsetMessage.date;
offsetID = offsetMessage.id;
offsetPeerID = getMessagePeer(offsetMessage);
}
apiPromise = MtpApiManager.invokeApi('messages.searchGlobal', {
q: query,
offset_date: offsetDate,
offset_peer: AppPeersManager.getInputPeerByID(offsetPeerID),
offset_id: getMessageLocalID(offsetID),
limit: limit || 20
}, {
timeout: 300,
noErrorBox: true
});
}
return apiPromise.then(function (searchResult) {
AppUsersManager.saveApiUsers(searchResult.users); AppUsersManager.saveApiUsers(searchResult.users);
AppChatsManager.saveApiChats(searchResult.chats); AppChatsManager.saveApiChats(searchResult.chats);
saveMessages(searchResult.messages); saveMessages(searchResult.messages);
@ -832,6 +914,7 @@ angular.module('myApp.services')
function deleteMessages (messageIDs) { function deleteMessages (messageIDs) {
var splitted = splitMessageIDsByChannels(messageIDs); var splitted = splitMessageIDsByChannels(messageIDs);
debugger;
var promises = []; var promises = [];
angular.forEach(splitted.msgIDs, function (msgIDs, channelID) { angular.forEach(splitted.msgIDs, function (msgIDs, channelID) {
var promise; var promise;
@ -842,7 +925,7 @@ angular.module('myApp.services')
if (channel.pFlags.editor) { if (channel.pFlags.editor) {
angular.forEach(msgIDs, function (msgID, i) { angular.forEach(msgIDs, function (msgID, i) {
var message = getMessage(splitted.mids[channelID][i]); var message = getMessage(splitted.mids[channelID][i]);
if (message.out) { if (message.pFlags.out) {
goodMsgIDs.push(msgID); goodMsgIDs.push(msgID);
} }
}); });
@ -888,32 +971,9 @@ angular.module('myApp.services')
return $q.all(promises); return $q.all(promises);
} }
function processAffectedHistory (inputPeer, affectedHistory, method) { function readHistory (peerID) {
ApiUpdatesManager.processUpdateMessage({
_: 'updateShort',
update: {
_: 'updatePts',
pts: affectedHistory.pts,
pts_count: affectedHistory.pts_count
}
});
if (!affectedHistory.offset) {
return $q.when();
}
return MtpApiManager.invokeApi(method, {
peer: inputPeer,
offset: affectedHistory.offset,
max_id: 0
}).then(function (affectedHistory) {
return processAffectedHistory(inputPeer, affectedHistory, method);
});
}
function readHistory (inputPeer) {
// console.trace('start read'); // console.trace('start read');
var peerID = AppPeersManager.getPeerID(inputPeer), var isChannel = AppPeersManager.isChannel(peerID),
isChannel = AppPeersManager.isChannel(peerID),
historyStorage = historiesStorage[peerID], historyStorage = historiesStorage[peerID],
foundDialog = getDialogByPeerID(peerID)[0]; foundDialog = getDialogByPeerID(peerID)[0];
@ -929,7 +989,7 @@ angular.module('myApp.services')
for (i = historyStorage.history.length; i >= 0; i--) { for (i = historyStorage.history.length; i >= 0; i--) {
messageID = historyStorage.history[i]; messageID = historyStorage.history[i];
message = messagesStorage[messageID]; message = messagesStorage[messageID];
if (message && !message.out && message.unread) { if (message && !message.pFlags.out && message.pFlags.unread) {
foundUnread = true; foundUnread = true;
break; break;
} }
@ -951,11 +1011,8 @@ angular.module('myApp.services')
}); });
} else { } else {
apiPromise = MtpApiManager.invokeApi('messages.readHistory', { apiPromise = MtpApiManager.invokeApi('messages.readHistory', {
peer: inputPeer, peer: AppPeersManager.getInputPeerByID(peerID),
offset: 0,
max_id: 0 max_id: 0
}).then(function (affectedHistory) {
return processAffectedHistory(inputPeer, affectedHistory, 'messages.readHistory');
}); });
} }
@ -978,13 +1035,13 @@ angular.module('myApp.services')
for (i = 0; i < historyStorage.history.length; i++) { for (i = 0; i < historyStorage.history.length; i++) {
messageID = historyStorage.history[i]; messageID = historyStorage.history[i];
message = messagesStorage[messageID]; message = messagesStorage[messageID];
if (message && !message.out) { if (message && !message.pFlags.out) {
message.unread = false; message.pFlags.unread = false;
if (messagesForHistory[messageID]) { if (messagesForHistory[messageID]) {
messagesForHistory[messageID].unread = false; messagesForHistory[messageID].pFlags.unread = false;
} }
if (messagesForDialogs[messageID]) { if (messagesForDialogs[messageID]) {
messagesForDialogs[messageID].unread = false; messagesForDialogs[messageID].pFlags.unread = false;
} }
NotificationsManager.cancel('msg' + messageID); NotificationsManager.cancel('msg' + messageID);
} }
@ -1012,17 +1069,28 @@ angular.module('myApp.services')
}); });
} }
function flushHistory (inputPeer) { function doFlushHistory (inputPeer) {
// console.log('start flush');
var peerID = AppPeersManager.getPeerID(inputPeer),
historyStorage = historiesStorage[peerID];
return MtpApiManager.invokeApi('messages.deleteHistory', { return MtpApiManager.invokeApi('messages.deleteHistory', {
peer: inputPeer, peer: inputPeer,
offset: 0 max_id: 0
}).then(function (affectedHistory) { }).then(function (affectedHistory) {
return processAffectedHistory(inputPeer, affectedHistory, 'messages.deleteHistory'); ApiUpdatesManager.processUpdateMessage({
}).then(function () { _: 'updateShort',
update: {
_: 'updatePts',
pts: affectedHistory.pts,
pts_count: affectedHistory.pts_count
}
});
if (!affectedHistory.offset) {
return true;
}
return doFlushHistory(inputPeer);
});
}
function flushHistory (peerID) {
return doFlushHistory(AppPeersManager.getInputPeerByID(peerID)).then(function () {
var foundDialog = getDialogByPeerID(peerID); var foundDialog = getDialogByPeerID(peerID);
if (foundDialog[0]) { if (foundDialog[0]) {
dialogsStorage.dialogs.splice(foundDialog[1], 1); dialogsStorage.dialogs.splice(foundDialog[1], 1);
@ -1034,25 +1102,33 @@ angular.module('myApp.services')
function saveMessages (apiMessages) { function saveMessages (apiMessages) {
angular.forEach(apiMessages, function (apiMessage) { angular.forEach(apiMessages, function (apiMessage) {
if (apiMessage.pFlags === undefined) {
apiMessage.pFlags = {};
}
if (!apiMessage.pFlags.out) {
apiMessage.pFlags.out = false;
}
if (!apiMessage.pFlags.unread) {
apiMessage.pFlags.unread = false;
}
if (apiMessage._ == 'messageEmpty') { if (apiMessage._ == 'messageEmpty') {
return; return;
} }
apiMessage.out = apiMessage.flags & 2 ? true : false;
apiMessage.media_unread = apiMessage.flags & 32 ? true : false;
var toPeerID = AppPeersManager.getPeerID(apiMessage.to_id); var toPeerID = AppPeersManager.getPeerID(apiMessage.to_id);
var isChannel = apiMessage.to_id._ == 'peerChannel'; var isChannel = apiMessage.to_id._ == 'peerChannel';
var channelID = isChannel ? -toPeerID : 0; var channelID = isChannel ? -toPeerID : 0;
var isBroadcast = isChannel && !AppChatsManager.isMegagroup(channelID);
var mid = getFullMessageID(apiMessage.id, channelID); var mid = getFullMessageID(apiMessage.id, channelID);
apiMessage.mid = mid; apiMessage.mid = mid;
messagesStorage[mid] = apiMessage; messagesStorage[mid] = apiMessage;
if (channelID && !apiMessage.out) { if (channelID && !apiMessage.pFlags.out) {
var dialog = getDialogByPeerID(toPeerID)[0]; var dialog = getDialogByPeerID(toPeerID)[0];
apiMessage.unread = dialog ? mid > dialog.read_inbox_max_id : true; apiMessage.pFlags.unread = dialog ? mid > dialog.read_inbox_max_id : true;
} else { } else {
apiMessage.unread = apiMessage.flags & 1 ? true : false; apiMessage.pFlags.unread = apiMessage.flags & 1 ? true : false;
} }
if (apiMessage.reply_to_msg_id) { if (apiMessage.reply_to_msg_id) {
@ -1097,27 +1173,44 @@ angular.module('myApp.services')
} }
} }
if (apiMessage.action) { if (apiMessage.action) {
if (apiMessage.action._ == 'messageActionChatEditPhoto') { switch (apiMessage.action._) {
case 'messageActionChatEditPhoto':
AppPhotosManager.savePhoto(apiMessage.action.photo, mediaContext); AppPhotosManager.savePhoto(apiMessage.action.photo, mediaContext);
if (isChannel) { if (isBroadcast) {
apiMessage.action._ = 'messageActionChannelEditPhoto'; apiMessage.action._ = 'messageActionChannelEditPhoto';
} }
} break;
else if (isChannel) {
if (apiMessage.action._ == 'messageActionChatEditTitle') { case 'messageActionChatEditTitle':
if (isBroadcast) {
apiMessage.action._ = 'messageActionChannelEditTitle'; apiMessage.action._ = 'messageActionChannelEditTitle';
} }
if (apiMessage.action._ == 'messageActionChatDeletePhoto') { break;
case 'messageActionChatDeletePhoto':
if (isBroadcast) {
apiMessage.action._ = 'messageActionChannelDeletePhoto'; apiMessage.action._ = 'messageActionChannelDeletePhoto';
} }
break;
case 'messageActionChatAddUser':
if (apiMessage.action.users.length == 1) {
apiMessage.action.user_id = apiMessage.action.users[0];
if (apiMessage.fromID == apiMessage.action.user_id) {
apiMessage.action._ = 'messageActionChatReturn';
} }
} }
if (apiMessage.reply_markup) { else if (apiMessage.action.users.length > 1) {
apiMessage.reply_markup.pFlags = { apiMessage.action._ = 'messageActionChatAddUsers';
resize: (apiMessage.reply_markup.flags & 1) > 0, }
one_time: (apiMessage.reply_markup.flags & 2) > 0, break;
selective: (apiMessage.reply_markup.flags & 4) > 0
}; case 'messageActionChatDeleteUser':
if (apiMessage.fromID == apiMessage.action.user_id) {
apiMessage.action._ = 'messageActionChatLeave';
}
break;
}
} }
if (apiMessage.message && apiMessage.message.length) { if (apiMessage.message && apiMessage.message.length) {
@ -1137,11 +1230,12 @@ angular.module('myApp.services')
randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)], randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)],
randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(), randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(),
historyStorage = historiesStorage[peerID], historyStorage = historiesStorage[peerID],
inputPeer = AppPeersManager.getInputPeerByID(peerID),
flags = 0, flags = 0,
pFlags = {},
replyToMsgID = options.replyToMsgID, replyToMsgID = options.replyToMsgID,
isChannel = AppPeersManager.isChannel(peerID), isChannel = AppPeersManager.isChannel(peerID),
asChannel = isChannel ? true : false, isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID),
asChannel = isChannel && !isMegagroup ? true : false,
entities = [], entities = [],
message; message;
@ -1154,8 +1248,10 @@ angular.module('myApp.services')
var fromID = AppUsersManager.getSelf().id; var fromID = AppUsersManager.getSelf().id;
if (peerID != fromID) { if (peerID != fromID) {
flags |= 2; flags |= 2;
pFlags.out = true;
if (!isChannel && !AppUsersManager.isBot(peerID)) { if (!isChannel && !AppUsersManager.isBot(peerID)) {
flags |= 1; flags |= 1;
pFlags.unread = true;
} }
} }
if (replyToMsgID) { if (replyToMsgID) {
@ -1172,6 +1268,7 @@ angular.module('myApp.services')
from_id: fromID, from_id: fromID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: AppPeersManager.getOutputPeer(peerID),
flags: flags, flags: flags,
pFlags: pFlags,
date: tsNow(true) + serverTimeOffset, date: tsNow(true) + serverTimeOffset,
message: text, message: text,
random_id: randomIDS, random_id: randomIDS,
@ -1216,7 +1313,7 @@ angular.module('myApp.services')
// console.log(flags, entities); // console.log(flags, entities);
MtpApiManager.invokeApi('messages.sendMessage', { MtpApiManager.invokeApi('messages.sendMessage', {
flags: flags, flags: flags,
peer: inputPeer, peer: AppPeersManager.getInputPeerByID(peerID),
message: text, message: text,
random_id: randomID, random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID), reply_to_msg_id: getMessageLocalID(replyToMsgID),
@ -1274,11 +1371,12 @@ angular.module('myApp.services')
randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)], randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)],
randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(), randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(),
historyStorage = historiesStorage[peerID], historyStorage = historiesStorage[peerID],
inputPeer = AppPeersManager.getInputPeerByID(peerID),
flags = 0, flags = 0,
pFlags = {},
replyToMsgID = options.replyToMsgID, replyToMsgID = options.replyToMsgID,
isChannel = AppPeersManager.isChannel(peerID), isChannel = AppPeersManager.isChannel(peerID),
asChannel = isChannel ? true : false, isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID),
asChannel = isChannel && !isMegagroup ? true : false,
attachType, apiFileName, realFileName; attachType, apiFileName, realFileName;
if (!options.isMedia) { if (!options.isMedia) {
@ -1305,8 +1403,10 @@ angular.module('myApp.services')
var fromID = AppUsersManager.getSelf().id; var fromID = AppUsersManager.getSelf().id;
if (peerID != fromID) { if (peerID != fromID) {
flags |= 2; flags |= 2;
pFlags.out = true;
if (!isChannel && !AppUsersManager.isBot(peerID)) { if (!isChannel && !AppUsersManager.isBot(peerID)) {
flags |= 1; flags |= 1;
pFlags.unread = true;
} }
} }
if (replyToMsgID) { if (replyToMsgID) {
@ -1331,6 +1431,7 @@ angular.module('myApp.services')
from_id: fromID, from_id: fromID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: AppPeersManager.getOutputPeer(peerID),
flags: flags, flags: flags,
pFlags: pFlags,
date: tsNow(true) + serverTimeOffset, date: tsNow(true) + serverTimeOffset,
message: '', message: '',
media: media, media: media,
@ -1400,7 +1501,7 @@ angular.module('myApp.services')
} }
MtpApiManager.invokeApi('messages.sendMedia', { MtpApiManager.invokeApi('messages.sendMedia', {
flags: flags, flags: flags,
peer: inputPeer, peer: AppPeersManager.getInputPeerByID(peerID),
media: inputMedia, media: inputMedia,
random_id: randomID, random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID) reply_to_msg_id: getMessageLocalID(replyToMsgID)
@ -1458,10 +1559,10 @@ angular.module('myApp.services')
randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)], randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)],
randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(), randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(),
historyStorage = historiesStorage[peerID], historyStorage = historiesStorage[peerID],
inputPeer = AppPeersManager.getInputPeerByID(peerID),
replyToMsgID = options.replyToMsgID, replyToMsgID = options.replyToMsgID,
isChannel = AppPeersManager.isChannel(peerID), isChannel = AppPeersManager.isChannel(peerID),
asChannel = isChannel ? true : false; isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID),
asChannel = isChannel && !isMegagroup ? true : false;
if (historyStorage === undefined) { if (historyStorage === undefined) {
historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []}; historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
@ -1494,10 +1595,13 @@ angular.module('myApp.services')
} }
var flags = 0; var flags = 0;
var pFlags = {};
if (peerID != fromID) { if (peerID != fromID) {
flags |= 2; flags |= 2;
pFlags.out = true;
if (!AppUsersManager.isBot(peerID)) { if (!AppUsersManager.isBot(peerID)) {
flags |= 1; flags |= 1;
pFlags.unread = true;
} }
} }
if (replyToMsgID) { if (replyToMsgID) {
@ -1515,6 +1619,7 @@ angular.module('myApp.services')
from_id: fromID, from_id: fromID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: AppPeersManager.getOutputPeer(peerID),
flags: flags, flags: flags,
pFlags: pFlags,
date: tsNow(true) + serverTimeOffset, date: tsNow(true) + serverTimeOffset,
message: '', message: '',
media: media, media: media,
@ -1556,7 +1661,7 @@ angular.module('myApp.services')
MtpApiManager.invokeApi('messages.sendMedia', { MtpApiManager.invokeApi('messages.sendMedia', {
flags: flags, flags: flags,
peer: inputPeer, peer: AppPeersManager.getInputPeerByID(peerID),
media: inputMedia, media: inputMedia,
random_id: randomID, random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID) reply_to_msg_id: getMessageLocalID(replyToMsgID)
@ -1590,7 +1695,8 @@ angular.module('myApp.services')
var i, mid, msgID; var i, mid, msgID;
var fromChannel = getMessageIDInfo(mids[0])[1]; var fromChannel = getMessageIDInfo(mids[0])[1];
var isChannel = AppPeersManager.isChannel(peerID); var isChannel = AppPeersManager.isChannel(peerID);
var asChannel = isChannel ? true : false; var isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID);
var asChannel = isChannel && !isMegagroup ? true : false;
if (asChannel) { if (asChannel) {
flags |= 16; flags |= 16;
@ -1621,36 +1727,37 @@ angular.module('myApp.services')
}; };
function startBot (botID, chatID, startParam) { function startBot (botID, chatID, startParam) {
var peerID = chatID ? -chatID : botID;
if (startParam) { if (startParam) {
var randomID = bigint(nextRandomInt(0xFFFFFFFF)).shiftLeft(32).add(bigint(nextRandomInt(0xFFFFFFFF))).toString(); var randomID = bigint(nextRandomInt(0xFFFFFFFF)).shiftLeft(32).add(bigint(nextRandomInt(0xFFFFFFFF))).toString();
return MtpApiManager.invokeApi('messages.startBot', { return MtpApiManager.invokeApi('messages.startBot', {
bot: AppUsersManager.getUserInput(botID), bot: AppUsersManager.getUserInput(botID),
chat_id: AppChatsManager.getChatInput(chatID), peer: AppPeersManager.getInputPeerByID(peerID),
random_id: randomID, random_id: randomID,
start_param: startParam start_param: startParam
}).then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates);
}); });
} }
var peerID = chatID ? -chatID : botID;
var inputPeer = AppPeersManager.getInputPeerByID(peerID);
if (chatID) { if (chatID) {
return MtpApiManager.invokeApi('messages.addChatUser', { return MtpApiManager.invokeApi('messages.addChatUser', {
chat_id: AppChatsManager.getChatInput(chatID), chat_id: AppChatsManager.getChatInput(chatID),
user_id: AppUsersManager.getUserInput(botID) user_id: AppUsersManager.getUserInput(botID)
}).then(function (updates) { }).then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates); ApiUpdatesManager.processUpdateMessage(updates);
sendText(peerID, '/start@' + bot.username);
}, function (error) { }, function (error) {
if (error && error.type == 'USER_ALREADY_PARTICIPANT') { if (error && error.type == 'USER_ALREADY_PARTICIPANT') {
var bot = AppUsersManager.getUser(botID); var bot = AppUsersManager.getUser(botID);
sendText(-chatID, '/start@' + bot.username); sendText(peerID, '/start@' + bot.username);
error.handled = true; error.handled = true;
} }
}); });
} }
return sendText(botID, '/start'); return sendText(peerID, '/start');
} }
function cancelPendingMessage (randomID) { function cancelPendingMessage (randomID) {
@ -1777,7 +1884,7 @@ angular.module('myApp.services')
if (toID < 0) { if (toID < 0) {
return toID; return toID;
} else if (message.out || message.flags & 2) { } else if (message.pFlags && message.pFlags.out || message.flags & 2) {
return toID; return toID;
} }
return message.from_id; return message.from_id;
@ -1796,7 +1903,7 @@ angular.module('myApp.services')
if (!message || !message.to_id) { if (!message || !message.to_id) {
if (dialog && dialog.peerID) { if (dialog && dialog.peerID) {
message = {_: 'message', to_id: AppPeersManager.getOutputPeer(dialog.peerID), deleted: true, date: tsNow(true)}; message = {_: 'message', to_id: AppPeersManager.getOutputPeer(dialog.peerID), deleted: true, date: tsNow(true), pFlags: {}};
message.deleted = true; message.deleted = true;
} else { } else {
return message; return message;
@ -2316,7 +2423,7 @@ angular.module('myApp.services')
MtpApiFileManager.downloadSmallFile(notificationPhoto.location, notificationPhoto.size).then(function (blob) { MtpApiFileManager.downloadSmallFile(notificationPhoto.location, notificationPhoto.size).then(function (blob) {
notification.image = FileManager.getUrl(blob, 'image/jpeg'); notification.image = FileManager.getUrl(blob, 'image/jpeg');
if (message.unread) { if (message.pFlags.unread) {
NotificationsManager.notify(notification); NotificationsManager.notify(notification);
} }
}); });
@ -2379,11 +2486,11 @@ angular.module('myApp.services')
notifyPeerToHandle.isMutedPromise.then(function (muted) { notifyPeerToHandle.isMutedPromise.then(function (muted) {
var topMessage = notifyPeerToHandle.top_message; var topMessage = notifyPeerToHandle.top_message;
if (muted || if (muted ||
!topMessage.unread) { !topMessage.pFlags.unread) {
return; return;
} }
setTimeout(function () { setTimeout(function () {
if (topMessage.unread) { if (topMessage.pFlags.unread) {
notifyAboutMessage(topMessage, { notifyAboutMessage(topMessage, {
fwd_count: notifyPeerToHandle.fwd_count fwd_count: notifyPeerToHandle.fwd_count
}); });
@ -2451,7 +2558,7 @@ angular.module('myApp.services')
$rootScope.$broadcast('history_reply_markup', {peerID: peerID}) $rootScope.$broadcast('history_reply_markup', {peerID: peerID})
} }
if (!message.out && message.from_id) { if (!message.pFlags.out && message.from_id) {
AppUsersManager.forceUserOnline(message.from_id); AppUsersManager.forceUserOnline(message.from_id);
} }
@ -2477,7 +2584,7 @@ angular.module('myApp.services')
var foundDialog = getDialogByPeerID(peerID); var foundDialog = getDialogByPeerID(peerID);
var dialog; var dialog;
var inboxUnread = !message.out && message.unread; var inboxUnread = !message.pFlags.out && message.pFlags.unread;
if (foundDialog.length) { if (foundDialog.length) {
dialog = foundDialog[0]; dialog = foundDialog[0];
@ -2555,25 +2662,25 @@ angular.module('myApp.services')
} }
message = messagesStorage[messageID]; message = messagesStorage[messageID];
if (message.out != isOut) { if (message.pFlags.out != isOut) {
continue; continue;
} }
if (!message.unread) { if (!message.pFlags.unread) {
break; break;
} }
// console.log('read', messageID, message.unread, message); // console.log('read', messageID, message.pFlags.unread, message);
if (message && message.unread) { if (message && message.pFlags.unread) {
message.unread = false; message.pFlags.unread = false;
if (messagesForHistory[messageID]) { if (messagesForHistory[messageID]) {
messagesForHistory[messageID].unread = false; messagesForHistory[messageID].pFlags.unread = false;
if (!foundAffected) { if (!foundAffected) {
foundAffected = true; foundAffected = true;
} }
} }
if (messagesForDialogs[messageID]) { if (messagesForDialogs[messageID]) {
messagesForDialogs[messageID].unread = false; messagesForDialogs[messageID].pFlags.unread = false;
} }
if (!message.out) { if (!message.pFlags.out) {
if (foundDialog) { if (foundDialog) {
newUnreadCount = --foundDialog[0].unread_count; newUnreadCount = --foundDialog[0].unread_count;
} }
@ -2597,10 +2704,10 @@ angular.module('myApp.services')
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
messageID = messages[i]; messageID = messages[i];
if (message = messagesStorage[messageID]) { if (message = messagesStorage[messageID]) {
delete message.media_unread; delete message.pFlags.media_unread;
} }
if (historyMessage = messagesForHistory[messageID]) { if (historyMessage = messagesForHistory[messageID]) {
delete historyMessage.media_unread; delete historyMessage.pFlags.media_unread;
} }
} }
break; break;
@ -2619,8 +2726,8 @@ angular.module('myApp.services')
peerID = getMessagePeer(message); peerID = getMessagePeer(message);
history = historiesUpdated[peerID] || (historiesUpdated[peerID] = {count: 0, unread: 0, msgs: {}}); history = historiesUpdated[peerID] || (historiesUpdated[peerID] = {count: 0, unread: 0, msgs: {}});
if (!message.out && message.unread) { if (!message.pFlags.out && message.pFlags.unread) {
history.unread++; history.pFlags.unread++;
NotificationsManager.cancel('msg' + messageID); NotificationsManager.cancel('msg' + messageID);
} }
history.count++; history.count++;
@ -2641,8 +2748,7 @@ angular.module('myApp.services')
from_id: message.from_id, from_id: message.from_id,
to_id: message.to_id, to_id: message.to_id,
flags: message.flags, flags: message.flags,
out: message.out, pFlags: message.pFlags,
unread: message.unread,
date: message.date date: message.date
}; };
} }
@ -2651,8 +2757,8 @@ angular.module('myApp.services')
angular.forEach(historiesUpdated, function (updatedData, peerID) { angular.forEach(historiesUpdated, function (updatedData, peerID) {
var foundDialog = getDialogByPeerID(peerID); var foundDialog = getDialogByPeerID(peerID);
if (foundDialog) { if (foundDialog) {
if (updatedData.unread) { if (updatedData.pFlags.unread) {
foundDialog[0].unread_count -= updatedData.unread; foundDialog[0].unread_count -= updatedData.pFlags.unread;
$rootScope.$broadcast('dialog_unread', {peerID: peerID, count: foundDialog[0].unread_count}); $rootScope.$broadcast('dialog_unread', {peerID: peerID, count: foundDialog[0].unread_count});
} }
@ -2747,10 +2853,9 @@ angular.module('myApp.services')
function reloadChannelDialog (channelID) { function reloadChannelDialog (channelID) {
var peerID = -channelID; var peerID = -channelID;
var inputPeer = AppPeersManager.getInputPeerByID(peerID);
return $q.all([ return $q.all([
AppProfileManager.getChannelFull(channelID, true), AppProfileManager.getChannelFull(channelID, true),
getHistory(inputPeer, 0) getHistory(peerID, 0)
]).then(function (results) { ]).then(function (results) {
var channelResult = results[0]; var channelResult = results[0];
var historyResult = results[1]; var historyResult = results[1];

82
app/js/services.js

@ -113,16 +113,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
usernames[searchUsername] = userID; usernames[searchUsername] = userID;
} }
apiUser.pFlags = { if (apiUser.pFlags === undefined) {
self: (apiUser.flags & (1 << 10)) > 0, apiUser.pFlags = {};
contact: (apiUser.flags & (1 << 11)) > 0, }
mutual: (apiUser.flags & (1 << 12)) > 0,
deleted: (apiUser.flags & (1 << 13)) > 0,
bot: (apiUser.flags & (1 << 14)) > 0,
botNoPrivacy: (apiUser.flags & (1 << 15)) > 0,
botNoGroups: (apiUser.flags & (1 << 16)) > 0,
verified: (apiUser.flags & (1 << 17)) > 0
};
apiUser.sortName = apiUser.pFlags.deleted ? '' : SearchIndexManager.cleanSearchText(apiUser.first_name + ' ' + (apiUser.last_name || '')); apiUser.sortName = apiUser.pFlags.deleted ? '' : SearchIndexManager.cleanSearchText(apiUser.first_name + ' ' + (apiUser.last_name || ''));
@ -449,6 +442,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
setInterval(updateUsersStatuses, 60000); setInterval(updateUsersStatuses, 60000);
$rootScope.$on('stateSynchronized', updateUsersStatuses);
return { return {
getContacts: getContacts, getContacts: getContacts,
@ -563,6 +557,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var chats = {}, var chats = {},
usernames = {}, usernames = {},
channelAccess = {}, channelAccess = {},
megagroups = {},
cachedPhotoLocations = {}; cachedPhotoLocations = {};
function saveApiChats (apiChats) { function saveApiChats (apiChats) {
@ -575,23 +570,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
apiChat.rTitle = RichTextProcessor.wrapRichText(apiChat.title, {noLinks: true, noLinebreaks: true}) || _('chat_title_deleted'); apiChat.rTitle = RichTextProcessor.wrapRichText(apiChat.title, {noLinks: true, noLinebreaks: true}) || _('chat_title_deleted');
var flags = apiChat.flags;
apiChat.pFlags = {
creator: (flags & (1 << 0)) > 0,
kicked: (flags & (1 << 1)) > 0,
left: (flags & (1 << 2)) > 0
};
if (apiChat._ == 'channel') {
angular.extend(apiChat.pFlags, {
editor: (apiChat.flags & (1 << 3)) > 0,
moderator: (apiChat.flags & (1 << 4)) > 0,
broadcast: (apiChat.flags & (1 << 5)) > 0,
username: (apiChat.flags & (1 << 6)) > 0,
verified: (apiChat.flags & (1 << 7)) > 0
});
};
var titleWords = SearchIndexManager.cleanSearchText(apiChat.title || '').split(' '); var titleWords = SearchIndexManager.cleanSearchText(apiChat.title || '').split(' ');
var firstWord = titleWords.shift(); var firstWord = titleWords.shift();
var lastWord = titleWords.pop(); var lastWord = titleWords.pop();
@ -599,6 +577,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
apiChat.num = (Math.abs(apiChat.id >> 1) % 8) + 1; apiChat.num = (Math.abs(apiChat.id >> 1) % 8) + 1;
if (apiChat.pFlags === undefined) {
apiChat.pFlags = {};
}
if (apiChat.username) { if (apiChat.username) {
var searchUsername = SearchIndexManager.cleanUsername(apiChat.username); var searchUsername = SearchIndexManager.cleanUsername(apiChat.username);
usernames[searchUsername] = apiChat.id; usernames[searchUsername] = apiChat.id;
@ -617,7 +599,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}; };
function getChat (id) { function getChat (id) {
return chats[id] || {id: id, deleted: true}; return chats[id] || {id: id, deleted: true, access_hash: channelAccess[id]};
} }
function hasRights (id, action) { function hasRights (id, action) {
@ -632,7 +614,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return false; return false;
} }
if (isChannel(id) && action == 'send') { if (isChannel(id) && action == 'send') {
if (!chat.pFlags.creator && !chat.pFlags.editor) { if (!chat.pFlags.megagroup &&
!chat.pFlags.creator &&
!chat.pFlags.editor) {
return false; return false;
} }
} }
@ -647,6 +631,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
channelAccess[id] = accessHash; channelAccess[id] = accessHash;
} }
function saveIsMegagroup (id) {
megagroups[id] = true;
}
function isChannel (id) { function isChannel (id) {
var chat = chats[id]; var chat = chats[id];
if (chat && (chat._ == 'channel' || chat._ == 'channelForbidden') || if (chat && (chat._ == 'channel' || chat._ == 'channelForbidden') ||
@ -656,6 +644,17 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return false; return false;
} }
function isMegagroup (id) {
if (megagroups[id]) {
return true;
}
var chat = chats[id];
if (chat && chat._ == 'channel' && chat.pFlags.megagroup) {
return true;
}
return false;
}
function getChatInput (id) { function getChatInput (id) {
return id || 0; return id || 0;
} }
@ -691,7 +690,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function getChatString (id) { function getChatString (id) {
var chat = getChat(id); var chat = getChat(id);
if (isChannel(id)) { if (isChannel(id)) {
return 'c' + id + '_' + chat.access_hash; return (isMegagroup(id) ? 's' : 'c') + id + '_' + chat.access_hash;
} }
return 'g' + id; return 'g' + id;
} }
@ -702,10 +701,13 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
if (chatFull.participants && chatFull.participants._ == 'chatParticipants') { if (chatFull.participants && chatFull.participants._ == 'chatParticipants') {
MtpApiManager.getUserID().then(function (myID) { MtpApiManager.getUserID().then(function (myID) {
chatFull.isAdmin = (myID == chatFull.participants.admin_id); var isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin;
angular.forEach(chatFull.participants.participants, function(participant){ angular.forEach(chatFull.participants.participants, function(participant){
participant.canLeave = myID == participant.user_id; participant.canLeave = myID == participant.user_id;
participant.canKick = !participant.canLeave && (chatFull.isAdmin || myID == participant.inviter_id); participant.canKick = !participant.canLeave && (
chat.pFlags.creator ||
participant._ == 'chatParticipant' && (isAdmin || myID == participant.inviter_id)
);
// just for order by last seen // just for order by last seen
participant.user = AppUsersManager.getUser(participant.user_id); participant.user = AppUsersManager.getUser(participant.user_id);
@ -769,8 +771,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
saveApiChat: saveApiChat, saveApiChat: saveApiChat,
getChat: getChat, getChat: getChat,
isChannel: isChannel, isChannel: isChannel,
isMegagroup: isMegagroup,
hasRights: hasRights, hasRights: hasRights,
saveChannelAccess: saveChannelAccess, saveChannelAccess: saveChannelAccess,
saveIsMegagroup: saveIsMegagroup,
getChatInput: getChatInput, getChatInput: getChatInput,
getChannelInput: getChannelInput, getChannelInput: getChannelInput,
getChatPhoto: getChatPhoto, getChatPhoto: getChatPhoto,
@ -795,8 +799,11 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
access_hash: peerParams[1] access_hash: peerParams[1]
}; };
} }
else if (firstChar == 'c') { else if (firstChar == 'c' || firstChar == 's') {
AppChatsManager.saveChannelAccess(peerParams[0], peerParams[1]); AppChatsManager.saveChannelAccess(peerParams[0], peerParams[1]);
if (firstChar == 's') {
AppChatsManager.saveIsMegagroup(peerParams[0]);
}
return { return {
_: 'inputPeerChannel', _: 'inputPeerChannel',
channel_id: peerParams[0], channel_id: peerParams[0],
@ -917,6 +924,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return (peerID < 0) && AppChatsManager.isChannel(-peerID); return (peerID < 0) && AppChatsManager.isChannel(-peerID);
} }
function isMegagroup (peerID) {
return (peerID < 0) && AppChatsManager.isMegagroup(-peerID);
}
function isBot (peerID) { function isBot (peerID) {
return (peerID > 0) && AppUsersManager.isBot(peerID); return (peerID > 0) && AppUsersManager.isBot(peerID);
} }
@ -932,6 +943,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
getPeerPhoto: getPeerPhoto, getPeerPhoto: getPeerPhoto,
resolveUsername: resolveUsername, resolveUsername: resolveUsername,
isChannel: isChannel, isChannel: isChannel,
isMegagroup: isMegagroup,
isBot: isBot isBot: isBot
} }
}) })
@ -2526,6 +2538,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
message: { message: {
_: 'message', _: 'message',
flags: updateMessage.flags, flags: updateMessage.flags,
pFlags: updateMessage.pFlags,
id: updateMessage.id, id: updateMessage.id,
from_id: fromID, from_id: fromID,
to_id: AppPeersManager.getOutputPeer(toID), to_id: AppPeersManager.getOutputPeer(toID),
@ -2672,7 +2685,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
console.log(dT(), 'apply channel diff', channelState.pts); console.log(dT(), 'apply channel diff', channelState.pts);
if (differenceResult._ == 'updates.channelDifference' && !(differenceResult.flags & 1)) { if (differenceResult._ == 'updates.channelDifference' &&
!differenceResult.pFlags['final']) {
getChannelDifference(channelID); getChannelDifference(channelID);
} else { } else {
console.log(dT(), 'finished channel get diff'); console.log(dT(), 'finished channel get diff');

2
app/less/app.less

@ -43,6 +43,7 @@ pre {
overflow: auto; overflow: auto;
padding: 3px; padding: 3px;
border: 1px solid #dedede; border: 1px solid #dedede;
font-size: inherit;
} }
a { a {
@ -3011,6 +3012,7 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before {
padding: 20px 0; padding: 20px 0;
font-size: 14px; font-size: 14px;
line-height: 160%; line-height: 160%;
word-break: break-all;
} }
.confirm_phone_number { .confirm_phone_number {
font-weight: bold; font-weight: bold;

2
app/partials/desktop/audio_player.html

@ -15,7 +15,7 @@
<span ng-switch-when="1" ng-bind="::audio.file_name"></span> <span ng-switch-when="1" ng-bind="::audio.file_name"></span>
<span ng-switch-default my-i18n="message_attach_audio_message"></span> <span ng-switch-default my-i18n="message_attach_audio_message"></span>
</a> </a>
<i ng-if="::message.media_unread || false" ng-show="message.media_unread" class="icon icon-audio-unread"></i> <i ng-if="::message.pFlags.media_unread || false" ng-show="message.pFlags.media_unread" class="icon icon-audio-unread"></i>
<div class="audio_player_meta" ng-if="!audio.downloaded || !(mediaPlayer.player.duration || audio.duration)" ng-switch="audio.progress.enabled"> <div class="audio_player_meta" ng-if="!audio.downloaded || !(mediaPlayer.player.duration || audio.duration)" ng-switch="audio.progress.enabled">
<span ng-switch-when="true" class="audio_player_size" ng-bind="audio.progress | formatSizeProgress"></span> <span ng-switch-when="true" class="audio_player_size" ng-bind="audio.progress | formatSizeProgress"></span>
<span ng-switch-default class="audio_player_size" ng-bind="audio.size | formatSize"></span> <span ng-switch-default class="audio_player_size" ng-bind="audio.size | formatSize"></span>

2
app/partials/desktop/chat_modal.html

@ -51,7 +51,7 @@
</div> </div>
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_link" ng-if="chatFull.chat._ != 'chatForbidden' && !chatFull.chat.pFlags.left && chatFull.isAdmin"> <div class="md_modal_iconed_section_wrap md_modal_iconed_section_link" ng-if="chatFull.chat._ != 'chatForbidden' && !chatFull.chat.pFlags.left && chatFull.chat.pFlags.creator">
<!-- <i class="md_modal_section_icon md_modal_section_icon_more"></i> --> <!-- <i class="md_modal_section_icon md_modal_section_icon_more"></i> -->
<div class="md_modal_section_link_wrap"> <div class="md_modal_section_link_wrap">

8
app/partials/desktop/dialog.html

@ -4,12 +4,12 @@
<div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div> <div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div>
<span <span
class="im_dialog_badge badge" class="im_dialog_badge badge"
ng-show="dialogMessage.unreadCount > 0 && !dialogMessage.out" ng-show="dialogMessage.unreadCount > 0 && !dialogMessage.pFlags.out"
ng-bind="dialogMessage.unreadCount" ng-bind="dialogMessage.unreadCount"
></span> ></span>
<i <i
class="im_dialog_unread" class="im_dialog_unread"
ng-show="dialogMessage.out && dialogMessage.unread" ng-show="dialogMessage.pFlags.out && dialogMessage.pFlags.unread"
></i> ></i>
</div> </div>
@ -34,7 +34,7 @@
<div ng-switch-default class="im_dialog_message"> <div ng-switch-default class="im_dialog_message">
<span ng-switch="dialogMessage.peerID > 0 || dialogMessage.fromID < 0"> <span ng-switch="dialogMessage.peerID > 0 || dialogMessage.fromID < 0">
<span ng-switch-when="true"> <span ng-switch-when="true">
<span class="im_dialog_chat_from_wrap" ng-if="dialogMessage.out"> <span class="im_dialog_chat_from_wrap" ng-if="dialogMessage.pFlags.out">
<span <span
class="im_dialog_chat_from" class="im_dialog_chat_from"
my-i18n="conversation_you" my-i18n="conversation_you"
@ -42,7 +42,7 @@
</span> </span>
</span> </span>
<span ng-switch-default> <span ng-switch-default>
<span class="im_dialog_chat_from_wrap" ng-switch="dialogMessage.out && dialogMessage._ != 'messageService'"> <span class="im_dialog_chat_from_wrap" ng-switch="dialogMessage.pFlags.out && dialogMessage._ != 'messageService'">
<span <span
ng-switch-when="false" ng-switch-when="false"
class="im_dialog_chat_from" class="im_dialog_chat_from"

20
app/partials/desktop/dialog_service.html

@ -3,20 +3,22 @@
<span ng-switch-when="messageActionChatEditTitle" my-i18n="conversation_group_renamed"></span> <span ng-switch-when="messageActionChatEditTitle" my-i18n="conversation_group_renamed"></span>
<span ng-switch-when="messageActionChatEditPhoto" my-i18n="conversation_group_photo_updated"></span> <span ng-switch-when="messageActionChatEditPhoto" my-i18n="conversation_group_photo_updated"></span>
<span ng-switch-when="messageActionChatDeletePhoto" my-i18n="conversation_group_photo_removed"></span> <span ng-switch-when="messageActionChatDeletePhoto" my-i18n="conversation_group_photo_removed"></span>
<span ng-switch-when="messageActionChatAddUser" ng-switch="::message.fromID != message.action.user_id"> <span ng-switch-when="messageActionChatJoinedByLink" my-i18n="conversation_joined_by_link"></span>
<span ng-switch-when="true" my-i18n="conversation_invited_user"> <span ng-switch-when="messageActionChatReturn" my-i18n="conversation_returned_to_group"></span>
<span ng-switch-when="messageActionChatAddUser" my-i18n="conversation_invited_user">
<my-i18n-param name="user"><span my-peer-link="message.action.user_id"></span></my-i18n-param> <my-i18n-param name="user"><span my-peer-link="message.action.user_id"></span></my-i18n-param>
</span> </span>
<span ng-switch-default my-i18n="conversation_returned_to_group"></span> <span ng-switch-when="messageActionChatAddUsers" my-i18n="">
<ng-pluralize count="message.action.users.length"
when="conversation_invited_users">
</ng-pluralize>
</span> </span>
<span ng-switch-when="messageActionChatDeleteUser" ng-switch="::message.fromID != message.action.user_id"> <span ng-switch-when="messageActionChatLeave" my-i18n="conversation_left_group"></span>
<span ng-switch-when="true" my-i18n="conversation_kicked_user"> <span ng-switch-when="messageActionChatDeleteUser" my-i18n="conversation_kicked_user">
<my-i18n-param name="user"><span my-peer-link="message.action.user_id"></span></my-i18n-param> <my-i18n-param name="user"><span my-peer-link="message.action.user_id"></span></my-i18n-param>
</span> </span>
<span ng-switch-default my-i18n="conversation_left_group"></span> <span ng-switch-when="messageActionChatMigrateTo" my-i18n="conversation_converted_to_supergroup"></span>
</span> <span ng-switch-when="messageActionChannelMigrateFrom" my-i18n="conversation_converted_to_supergroup"></span>
<span ng-switch-when="messageActionChatJoinedByLink" my-i18n="conversation_joined_by_link"></span>
<span ng-switch-when="messageActionChannelCreate" my-i18n="conversation_created_channel"></span> <span ng-switch-when="messageActionChannelCreate" my-i18n="conversation_created_channel"></span>
<span ng-switch-when="messageActionChannelEditTitle" my-i18n="conversation_changed_channel_name"></span> <span ng-switch-when="messageActionChannelEditTitle" my-i18n="conversation_changed_channel_name"></span>
<span ng-switch-when="messageActionChannelEditPhoto" my-i18n="conversation_changed_channel_photo"></span> <span ng-switch-when="messageActionChannelEditPhoto" my-i18n="conversation_changed_channel_photo"></span>

4
app/partials/desktop/message.html

@ -23,13 +23,13 @@
</div> </div>
<div ng-switch-default class="im_content_message_wrap" ng-class="::[historyMessage.out ? 'im_message_out' : 'im_message_in', historyMessage.fwdFromID ? 'im_message_fwd' : '']"> <div ng-switch-default class="im_content_message_wrap" ng-class="::[historyMessage.pFlags.out ? 'im_message_out' : 'im_message_in', historyMessage.fwdFromID ? 'im_message_fwd' : '']">
<i class="icon icon-select-tick"></i> <i class="icon icon-select-tick"></i>
<a class="im_message_error_btn" ng-if="::historyMessage.pending || historyMessage.error || false" ng-click="historyMessage.send()"> <a class="im_message_error_btn" ng-if="::historyMessage.pending || historyMessage.error || false" ng-click="historyMessage.send()">
<i class="icon-message-status" tooltip="Try again"></i> <i class="icon-message-status" tooltip="Try again"></i>
</a> </a>
<i ng-if="::historyMessage.unread &amp;&amp; historyMessage.out || historyMessage.pending || false" class="icon-message-status" ng-show="!historyMessage.error"></i> <i ng-if="::historyMessage.pFlags.unread &amp;&amp; historyMessage.pFlags.out || historyMessage.pending || false" class="icon-message-status" ng-show="!historyMessage.error"></i>
<a class="im_message_from_photo pull-left" my-peer-photolink="::historyMessage.fromID" img-class="im_message_from_photo"></a> <a class="im_message_from_photo pull-left" my-peer-photolink="::historyMessage.fromID" img-class="im_message_from_photo"></a>

18
app/partials/desktop/message_service.html

@ -6,20 +6,22 @@
</my-i18n> </my-i18n>
<span ng-switch-when="messageActionChatEditPhoto" my-i18n="message_service_changed_group_photo"></span> <span ng-switch-when="messageActionChatEditPhoto" my-i18n="message_service_changed_group_photo"></span>
<span ng-switch-when="messageActionChatDeletePhoto" my-i18n="message_service_removed_group_photo"></span> <span ng-switch-when="messageActionChatDeletePhoto" my-i18n="message_service_removed_group_photo"></span>
<span ng-switch-when="messageActionChatAddUser" ng-switch="::historyMessage.fromID != historyMessage.action.user_id"> <span ng-switch-when="messageActionChatJoinedByLink" my-i18n="message_service_joined_by_link"></span>
<span ng-switch-when="true" my-i18n="message_service_invited_user"> <span ng-switch-when="messageActionChatReturn" my-i18n="message_service_returned_to_group"></span>
<span ng-switch-when="messageActionChatAddUser" my-i18n="message_service_invited_user">
<my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param> <my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param>
</span> </span>
<span ng-switch-default my-i18n="message_service_returned_to_group"></span> <span ng-switch-when="messageActionChatAddUsers" my-i18n="message_service_invited_users">
</span>
<span ng-switch-when="messageActionChatDeleteUser" ng-switch="::historyMessage.fromID != historyMessage.action.user_id">
<span ng-switch-when="true" my-i18n="message_service_kicked_user">
<my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param> <my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param>
<my-i18n-param name="num-more"><span ng-bind="historyMessage.action.users.length - 1"></span></my-i18n-param>
</span> </span>
<span ng-switch-default my-i18n="message_service_left_group"></span> <span ng-switch-when="messageActionChatLeave" my-i18n="message_service_left_group"></span>
<span ng-switch-when="messageActionChatDeleteUser" my-i18n="message_service_kicked_user">
<my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param>
</span> </span>
<span ng-switch-when="messageActionChatJoinedByLink" my-i18n="message_service_joined_by_link"></span>
<span ng-switch-when="messageActionChatMigrateTo" my-i18n="message_service_converted_to_supergroup"></span>
<span ng-switch-when="messageActionChannelMigrateFrom" my-i18n="message_service_converted_to_supergroup"></span>
<span ng-switch-when="messageActionChannelCreate" my-i18n="message_service_created_channel"></span> <span ng-switch-when="messageActionChannelCreate" my-i18n="message_service_created_channel"></span>
<span ng-switch-when="messageActionChannelEditTitle" my-i18n="message_service_changed_channel_name"> <span ng-switch-when="messageActionChannelEditTitle" my-i18n="message_service_changed_channel_name">
<my-i18n-param name="channel-name">&laquo;<strong ng-bind-html="::historyMessage.action.rTitle"></strong>&raquo;</my-i18n-param> <my-i18n-param name="channel-name">&laquo;<strong ng-bind-html="::historyMessage.action.rTitle"></strong>&raquo;</my-i18n-param>

2
app/partials/desktop/user_modal.html

@ -69,7 +69,7 @@
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_link" ng-init="f.showMoreActions = !user.phone.length"> <div class="md_modal_iconed_section_wrap md_modal_iconed_section_link" ng-init="f.showMoreActions = !user.phone.length">
<i class="md_modal_section_icon md_modal_section_icon_more"></i> <i class="md_modal_section_icon md_modal_section_icon_more"></i>
<div class="md_modal_section_link_wrap" ng-if="user.pFlags.bot &amp;&amp; !user.pFlags.botNoGroups"> <div class="md_modal_section_link_wrap" ng-if="user.pFlags.bot &amp;&amp; !user.pFlags.bot_nochats">
<a class="md_modal_section_link" ng-click="inviteToGroup()" my-i18n="user_modal_add_to_group"></a> <a class="md_modal_section_link" ng-click="inviteToGroup()" my-i18n="user_modal_add_to_group"></a>
</div> </div>

2
app/partials/mobile/audio_player.html

@ -15,7 +15,7 @@
<span ng-switch-when="1" ng-bind="::audio.file_name"></span> <span ng-switch-when="1" ng-bind="::audio.file_name"></span>
<span ng-switch-default my-i18n="message_attach_audio_message"></span> <span ng-switch-default my-i18n="message_attach_audio_message"></span>
</a> </a>
<i ng-if="::message.media_unread || false" ng-show="message.media_unread" class="icon icon-audio-unread"></i> <i ng-if="::message.pFlags.media_unread || false" ng-show="message.pFlags.media_unread" class="icon icon-audio-unread"></i>
<div class="audio_player_meta" ng-if="!audio.downloaded || !(mediaPlayer.player.duration || audio.duration)" ng-switch="audio.progress.enabled"> <div class="audio_player_meta" ng-if="!audio.downloaded || !(mediaPlayer.player.duration || audio.duration)" ng-switch="audio.progress.enabled">
<span ng-switch-when="true" class="audio_player_size" ng-bind="audio.progress | formatSizeProgress"></span> <span ng-switch-when="true" class="audio_player_size" ng-bind="audio.progress | formatSizeProgress"></span>
<span ng-switch-default class="audio_player_size" ng-bind="audio.size | formatSize"></span> <span ng-switch-default class="audio_player_size" ng-bind="audio.size | formatSize"></span>

2
app/partials/mobile/chat_modal.html

@ -62,7 +62,7 @@
<div class="mobile_modal_action_wrap" ng-if="!chatFull.chat.pFlags.left &amp;&amp; chatFull.participants.participants.length"> <div class="mobile_modal_action_wrap" ng-if="!chatFull.chat.pFlags.left &amp;&amp; chatFull.participants.participants.length">
<a class="mobile_modal_action" ng-click="inviteToGroup()" my-i18n="group_modal_add_member"></a> <a class="mobile_modal_action" ng-click="inviteToGroup()" my-i18n="group_modal_add_member"></a>
</div> </div>
<div class="mobile_modal_action_wrap" ng-if="chatFull.chat._ != 'chatForbidden' && !chatFull.chat.pFlags.left && chatFull.isAdmin"> <div class="mobile_modal_action_wrap" ng-if="chatFull.chat._ != 'chatForbidden' && !chatFull.chat.pFlags.left && chatFull.chat.pFlags.creator">
<a class="mobile_modal_action" ng-click="inviteViaLink()" my-i18n="group_modal_menu_share_link"></a> <a class="mobile_modal_action" ng-click="inviteViaLink()" my-i18n="group_modal_menu_share_link"></a>
</div> </div>

8
app/partials/mobile/dialog.html

@ -4,12 +4,12 @@
<div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div> <div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div>
<span <span
class="im_dialog_badge badge" class="im_dialog_badge badge"
ng-show="dialogMessage.unreadCount > 0 && !dialogMessage.out" ng-show="dialogMessage.unreadCount > 0 && !dialogMessage.pFlags.out"
ng-bind="dialogMessage.unreadCount" ng-bind="dialogMessage.unreadCount"
></span> ></span>
<i <i
class="im_dialog_unread" class="im_dialog_unread"
ng-show="dialogMessage.out && dialogMessage.unread" ng-show="dialogMessage.pFlags.out && dialogMessage.pFlags.unread"
></i> ></i>
</div> </div>
@ -34,7 +34,7 @@
<div ng-switch-default class="im_dialog_message"> <div ng-switch-default class="im_dialog_message">
<span ng-switch="dialogMessage.peerID > 0 || dialogMessage.fromID < 0"> <span ng-switch="dialogMessage.peerID > 0 || dialogMessage.fromID < 0">
<span ng-switch-when="true"> <span ng-switch-when="true">
<span class="im_dialog_chat_from_wrap" ng-if="dialogMessage.out"> <span class="im_dialog_chat_from_wrap" ng-if="dialogMessage.pFlags.out">
<span <span
class="im_dialog_chat_from" class="im_dialog_chat_from"
my-i18n="conversation_you" my-i18n="conversation_you"
@ -42,7 +42,7 @@
</span> </span>
</span> </span>
<span ng-switch-default> <span ng-switch-default>
<span class="im_dialog_chat_from_wrap" ng-switch="dialogMessage.out && dialogMessage._ != 'messageService'"> <span class="im_dialog_chat_from_wrap" ng-switch="dialogMessage.pFlags.out && dialogMessage._ != 'messageService'">
<span <span
ng-switch-when="false" ng-switch-when="false"
class="im_dialog_chat_from" class="im_dialog_chat_from"

4
app/partials/mobile/message.html

@ -23,7 +23,7 @@
</div> </div>
<div ng-switch-default class="im_content_message_wrap" ng-class="::[historyMessage.out ? 'im_message_out' : 'im_message_in', historyMessage.fwdFromID ? 'im_message_fwd' : '']"> <div ng-switch-default class="im_content_message_wrap" ng-class="::[historyMessage.pFlags.out ? 'im_message_out' : 'im_message_in', historyMessage.fwdFromID ? 'im_message_fwd' : '']">
<a class="im_message_from_photo pull-left" my-peer-photolink="::historyMessage.fromID" img-class="im_message_from_photo"></a> <a class="im_message_from_photo pull-left" my-peer-photolink="::historyMessage.fromID" img-class="im_message_from_photo"></a>
@ -36,7 +36,7 @@
<a class="im_message_error_btn" ng-if="::historyMessage.pending || historyMessage.error || false" ng-click="historyMessage.send()"> <a class="im_message_error_btn" ng-if="::historyMessage.pending || historyMessage.error || false" ng-click="historyMessage.send()">
<i class="icon-message-status" tooltip="Try again"></i> <i class="icon-message-status" tooltip="Try again"></i>
</a> </a>
<i ng-if="::historyMessage.unread &amp;&amp; historyMessage.out || historyMessage.pending || false" class="icon-message-status" ng-show="!historyMessage.error"></i> <i ng-if="::historyMessage.pFlags.unread &amp;&amp; historyMessage.pFlags.out || historyMessage.pending || false" class="icon-message-status" ng-show="!historyMessage.error"></i>
<span class="im_message_date" ng-bind="::historyMessage.date | time"></span> <span class="im_message_date" ng-bind="::historyMessage.date | time"></span>
</div> </div>

18
app/partials/mobile/message_service.html

@ -6,20 +6,22 @@
</my-i18n> </my-i18n>
<span ng-switch-when="messageActionChatEditPhoto" my-i18n="message_service_changed_group_photo"></span> <span ng-switch-when="messageActionChatEditPhoto" my-i18n="message_service_changed_group_photo"></span>
<span ng-switch-when="messageActionChatDeletePhoto" my-i18n="message_service_removed_group_photo"></span> <span ng-switch-when="messageActionChatDeletePhoto" my-i18n="message_service_removed_group_photo"></span>
<span ng-switch-when="messageActionChatAddUser" ng-switch="::historyMessage.fromID != historyMessage.action.user_id"> <span ng-switch-when="messageActionChatJoinedByLink" my-i18n="message_service_joined_by_link"></span>
<span ng-switch-when="true" my-i18n="message_service_invited_user"> <span ng-switch-when="messageActionChatReturn" my-i18n="message_service_returned_to_group"></span>
<span ng-switch-when="messageActionChatAddUser" my-i18n="message_service_invited_user">
<my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param> <my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param>
</span> </span>
<span ng-switch-default my-i18n="message_service_returned_to_group"></span> <span ng-switch-when="messageActionChatAddUsers" my-i18n="message_service_invited_users">
</span>
<span ng-switch-when="messageActionChatDeleteUser" ng-switch="::historyMessage.fromID != historyMessage.action.user_id">
<span ng-switch-when="true" my-i18n="message_service_kicked_user">
<my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param> <my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param>
<my-i18n-param name="num-more"><span ng-bind="historyMessage.action.users.length - 1"></span></my-i18n-param>
</span> </span>
<span ng-switch-default my-i18n="message_service_left_group"></span> <span ng-switch-when="messageActionChatLeave" my-i18n="message_service_left_group"></span>
<span ng-switch-when="messageActionChatDeleteUser" my-i18n="message_service_kicked_user">
<my-i18n-param name="user"><a my-peer-link="historyMessage.action.user_id" color="true"></a></my-i18n-param>
</span> </span>
<span ng-switch-when="messageActionChatJoinedByLink" my-i18n="message_service_joined_by_link"></span>
<span ng-switch-when="messageActionChatMigrateTo" my-i18n="message_service_converted_to_supergroup"></span>
<span ng-switch-when="messageActionChannelMigrateFrom" my-i18n="message_service_converted_to_supergroup"></span>
<span ng-switch-when="messageActionChannelCreate" my-i18n="message_service_created_channel"></span> <span ng-switch-when="messageActionChannelCreate" my-i18n="message_service_created_channel"></span>
<span ng-switch-when="messageActionChannelEditTitle" my-i18n="message_service_changed_channel_name"> <span ng-switch-when="messageActionChannelEditTitle" my-i18n="message_service_changed_channel_name">
<my-i18n-param name="channel-name">&laquo;<strong ng-bind-html="::historyMessage.action.rTitle"></strong>&raquo;</my-i18n-param> <my-i18n-param name="channel-name">&laquo;<strong ng-bind-html="::historyMessage.action.rTitle"></strong>&raquo;</my-i18n-param>

2
app/partials/mobile/user_modal.html

@ -71,7 +71,7 @@
<a class="mobile_modal_action" ng-click="shareContact()" my-i18n="user_modal_share_contact"></a> <a class="mobile_modal_action" ng-click="shareContact()" my-i18n="user_modal_share_contact"></a>
</div> </div>
<div class="mobile_modal_action_wrap" ng-if="user.pFlags.bot &amp;&amp; !user.pFlags.botNoGroups"> <div class="mobile_modal_action_wrap" ng-if="user.pFlags.bot &amp;&amp; !user.pFlags.bot_nochats">
<a class="mobile_modal_action" ng-click="inviteToGroup()" my-i18n="user_modal_add_to_group"></a> <a class="mobile_modal_action" ng-click="inviteToGroup()" my-i18n="user_modal_add_to_group"></a>
</div> </div>

Loading…
Cancel
Save