Channels improvements

Supported load important history
Added channel profile
This commit is contained in:
Igor Zhukov 2015-09-28 23:25:55 +03:00
parent 5aa5a1d9a2
commit b0b5e2c75c
18 changed files with 800 additions and 161 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -706,7 +706,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.$on('history_delete', function (e, historyUpdate) { $scope.$on('history_delete', function (e, historyUpdate) {
for (var i = 0; i < $scope.dialogs.length; i++) { for (var i = 0; i < $scope.dialogs.length; i++) {
if ($scope.dialogs[i].peerID == historyUpdate.peerID) { if ($scope.dialogs[i].peerID == historyUpdate.peerID) {
if (historyUpdate.msgs[$scope.dialogs[i].id]) { if (historyUpdate.msgs[$scope.dialogs[i].mid]) {
$scope.dialogs[i].deleted = true; $scope.dialogs[i].deleted = true;
} }
break; break;
@ -1490,7 +1490,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
i, startPos, curMessageID; i, startPos, curMessageID;
for (i = 0; i < peerHistory.messages.length; i++) { for (i = 0; i < peerHistory.messages.length; i++) {
if (peerHistory.messages[i].id == lastSelectID) { if (peerHistory.messages[i].mid == lastSelectID) {
startPos = i; startPos = i;
break; break;
} }
@ -1498,7 +1498,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
i = startPos; i = startPos;
while (peerHistory.messages[i] && while (peerHistory.messages[i] &&
(curMessageID = peerHistory.messages[i].id) != messageID) { (curMessageID = peerHistory.messages[i].mid) != messageID) {
if (!$scope.selectedMsgs[curMessageID]) { if (!$scope.selectedMsgs[curMessageID]) {
$scope.selectedMsgs[curMessageID] = true; $scope.selectedMsgs[curMessageID] = true;
$scope.selectedCount++; $scope.selectedCount++;
@ -1646,7 +1646,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
return; return;
} }
AppMessagesManager.sendText(peerID, button.text, { AppMessagesManager.sendText(peerID, button.text, {
replyToMsgID: peerID < 0 && replyKeyboard.id replyToMsgID: peerID < 0 && replyKeyboard.mid
}); });
}); });
@ -1700,7 +1700,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
!historyMessage.out && !historyMessage.out &&
!(history.messages[history.messages.length - 2] || {}).unread) { !(history.messages[history.messages.length - 2] || {}).unread) {
$scope.historyUnreadAfter = historyMessage.id; $scope.historyUnreadAfter = historyMessage.mid;
unreadAfterIdle = true; unreadAfterIdle = true;
$scope.$broadcast('messages_unread_after'); $scope.$broadcast('messages_unread_after');
} }
@ -1740,7 +1740,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
if (len > 10) { if (len > 10) {
if (curPeer) { if (curPeer) {
if (exlen > 10) { if (exlen > 10) {
minID = history.messages[exlen - 1].id; minID = history.messages[exlen - 1].mid;
$scope.historyState.skipped = hasLess = minID > 0; $scope.historyState.skipped = hasLess = minID > 0;
if (hasLess) { if (hasLess) {
loadAfterSync = peerID; loadAfterSync = peerID;
@ -1825,7 +1825,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
i; i;
for (i = 0; i < history.messages.length; i++) { for (i = 0; i < history.messages.length; i++) {
if (!historyUpdate.msgs[history.messages[i].id]) { if (!historyUpdate.msgs[history.messages[i].mid]) {
newMessages.push(history.messages[i]); newMessages.push(history.messages[i]);
} }
}; };
@ -1949,7 +1949,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
var timeout = 0; var timeout = 0;
var options = { var options = {
replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.id replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.mid
}; };
do { do {
@ -2074,7 +2074,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
var message = $scope.draftMessage.replyToMessage; var message = $scope.draftMessage.replyToMessage;
if (message && if (message &&
$scope.historyState.replyKeyboard && $scope.historyState.replyKeyboard &&
$scope.historyState.replyKeyboard.id == message.id && $scope.historyState.replyKeyboard.mid == message.mid &&
!$scope.historyState.replyKeyboard.pFlags.hidden) { !$scope.historyState.replyKeyboard.pFlags.hidden) {
$scope.historyState.replyKeyboard.pFlags.hidden = true; $scope.historyState.replyKeyboard.pFlags.hidden = true;
$scope.$broadcast('ui_keyboard_update'); $scope.$broadcast('ui_keyboard_update');
@ -2110,7 +2110,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
(replyKeyboard._ == 'replyKeyboardMarkup' && peerID < 0)); (replyKeyboard._ == 'replyKeyboardMarkup' && peerID < 0));
if (addReplyMessage) { if (addReplyMessage) {
replySelect(replyKeyboard.id); replySelect(replyKeyboard.mid);
replyToMarkup = true; replyToMarkup = true;
} }
else if (replyToMarkup) { else if (replyToMarkup) {
@ -2162,7 +2162,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
return; return;
} }
var options = { var options = {
replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.id, replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.mid,
isMedia: $scope.draftMessage.isMedia isMedia: $scope.draftMessage.isMedia
}; };
@ -2196,7 +2196,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
} }
} }
var options = { var options = {
replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.id replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.mid
}; };
AppMessagesManager.sendOther($scope.curDialog.peerID, inputMedia, options); AppMessagesManager.sendOther($scope.curDialog.peerID, inputMedia, options);
$scope.$broadcast('ui_message_send'); $scope.$broadcast('ui_message_send');
@ -2647,15 +2647,18 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}) })
.controller('ChatpicModalController', function ($q, $scope, $rootScope, $modalInstance, MtpApiManager, AppPhotosManager, AppChatsManager, AppPeersManager, AppMessagesManager, PeersSelectService, ErrorService) { .controller('ChatpicModalController', function ($q, $scope, $rootScope, $modalInstance, MtpApiManager, AppPhotosManager, AppChatsManager, AppPeersManager, AppMessagesManager, ApiUpdatesManager, PeersSelectService, ErrorService) {
$scope.photo = AppPhotosManager.wrapForFull($scope.photoID); $scope.photo = AppPhotosManager.wrapForFull($scope.photoID);
$scope.photo.thumb = { $scope.photo.thumb = {
location: AppPhotosManager.choosePhotoSize($scope.photo, 0, 0).location location: AppPhotosManager.choosePhotoSize($scope.photo, 0, 0).location
}; };
var chat = AppChatsManager.getChat($scope.chatID);
var isChannel = AppChatsManager.isChannel($scope.chatID);
$scope.canForward = true; $scope.canForward = true;
$scope.canDelete = true; $scope.canDelete = isChannel ? chat.pFlags.creator : true;
$scope.forward = function () { $scope.forward = function () {
PeersSelectService.selectPeers({confirm_type: 'FORWARD_PEER'}).then(function (peerStrings) { PeersSelectService.selectPeers({confirm_type: 'FORWARD_PEER'}).then(function (peerStrings) {
@ -2679,10 +2682,19 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope['delete'] = function () { $scope['delete'] = function () {
ErrorService.confirm({type: 'PHOTO_DELETE'}).then(function () { ErrorService.confirm({type: 'PHOTO_DELETE'}).then(function () {
$scope.photo.updating = true; $scope.photo.updating = true;
MtpApiManager.invokeApi('messages.editChatPhoto', { var apiPromise;
if (AppChatsManager.isChannel($scope.chatID)) {
apiPromise = MtpApiManager.invokeApi('channels.editPhoto', {
channel: AppChatsManager.getChannelInput($scope.chatID),
photo: {_: 'inputChatPhotoEmpty'}
});
} else {
apiPromise = MtpApiManager.invokeApi('messages.editChatPhoto', {
chat_id: AppChatsManager.getChatInput($scope.chatID), chat_id: AppChatsManager.getChatInput($scope.chatID),
photo: {_: 'inputChatPhotoEmpty'} photo: {_: 'inputChatPhotoEmpty'}
}).then(function (updates) { });
}
apiPromise.then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates); ApiUpdatesManager.processUpdateMessage(updates);
$modalInstance.dismiss(); $modalInstance.dismiss();
$rootScope.$broadcast('history_focus', {peerString: AppChatsManager.getChatString($scope.chatID)}); $rootScope.$broadcast('history_focus', {peerString: AppChatsManager.getChatString($scope.chatID)});
@ -3069,6 +3081,150 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}) })
.controller('ChannelModalController', function ($scope, $timeout, $rootScope, $modal, AppUsersManager, AppChatsManager, AppPhotosManager, MtpApiManager, MtpApiFileManager, NotificationsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, ContactsSelectService, ErrorService) {
$scope.chatFull = AppChatsManager.wrapForFull($scope.chatID, {});
$scope.settings = {notifications: true};
AppChatsManager.getChannelFull($scope.chatID, true).then(function (chatFull) {
$scope.chatFull = AppChatsManager.wrapForFull($scope.chatID, chatFull);
$scope.$broadcast('ui_height');
NotificationsManager.savePeerSettings(-$scope.chatID, chatFull.notify_settings);
NotificationsManager.getPeerMuted(-$scope.chatID).then(function (muted) {
$scope.settings.notifications = !muted;
$scope.$watch('settings.notifications', function(newValue, oldValue) {
if (newValue === oldValue) {
return false;
}
NotificationsManager.getPeerSettings(-$scope.chatID).then(function (settings) {
if (newValue) {
settings.mute_until = 0;
} else {
settings.mute_until = 2000000000;
}
NotificationsManager.updatePeerSettings(-$scope.chatID, settings);
});
});
});
});
function onChatUpdated (updates) {
ApiUpdatesManager.processUpdateMessage(updates);
$rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString});
}
$scope.leaveChannel = function () {
MtpApiManager.invokeApi('channels.leaveChannel', {
channel: AppChatsManager.getChannelInput($scope.chatID)
}).then(onChatUpdated);
};
$scope.deleteChannel = function () {
return ErrorService.confirm({type: 'CHANNEL_DELETE'}).then(function () {
MtpApiManager.invokeApi('channels.deleteChannel', {
channel: AppChatsManager.getChannelInput($scope.chatID)
}).then(onChatUpdated);
});
}
$scope.joinChannel = function () {
MtpApiManager.invokeApi('channels.joinChannel', {
channel: AppChatsManager.getChannelInput($scope.chatID)
}).then(onChatUpdated);
};
$scope.inviteToChannel = function () {
var disabled = [];
angular.forEach(($scope.chatFull.participants || {}).participants || [], function(participant){
disabled.push(participant.user_id);
});
ContactsSelectService.selectContacts({disabled: disabled}).then(function (userIDs) {
var inputUsers = [];
angular.forEach(userIDs, function (userID) {
inputUsers.push(AppUsersManager.getUserInput(userID));
});
MtpApiManager.invokeApi('channels.inviteToChannel', {
channel: AppChatsManager.getChannelInput($scope.chatID),
users: inputUsers
}).then(onChatUpdated);
});
};
$scope.kickFromChannel = function (userID) {
MtpApiManager.invokeApi('channels.kickFromChannel', {
channel: AppChatsManager.getChannelInput($scope.chatID),
user_id: AppUsersManager.getUserInput(userID),
kicked: true
}).then(onChatUpdated);
};
$scope.shareLink = function ($event) {
var scope = $rootScope.$new();
scope.chatID = $scope.chatID;
$modal.open({
templateUrl: templateUrl('chat_invite_link_modal'),
controller: 'ChatInviteLinkModalController',
scope: scope,
windowClass: 'md_simple_modal_window'
});
return cancelEvent($event);
}
$scope.photo = {};
$scope.$watch('photo.file', onPhotoSelected);
function onPhotoSelected (photo) {
if (!photo || !photo.type || photo.type.indexOf('image') !== 0) {
return;
}
$scope.photo.updating = true;
MtpApiFileManager.uploadFile(photo).then(function (inputFile) {
return MtpApiManager.invokeApi('channels.editPhoto', {
channel: AppChatsManager.getChannelInput($scope.chatID),
photo: {
_: 'inputChatUploadedPhoto',
file: inputFile,
crop: {_: 'inputPhotoCropAuto'}
}
}).then(onChatUpdated);
})['finally'](function () {
$scope.photo.updating = false;
});
};
$scope.deletePhoto = function () {
$scope.photo.updating = true;
MtpApiManager.invokeApi('messages.editChatPhoto', {
channel: AppChatsManager.getChannelInput($scope.chatID),
photo: {_: 'inputChatPhotoEmpty'}
}).then(onChatUpdated)['finally'](function () {
$scope.photo.updating = false;
});
};
$scope.editChannel = function () {
var scope = $rootScope.$new();
scope.chatID = $scope.chatID;
$modal.open({
templateUrl: templateUrl('channel_edit_modal'),
controller: 'ChannelEditModalController',
scope: scope,
windowClass: 'md_simple_modal_window mobile_modal'
});
}
})
.controller('SettingsModalController', function ($rootScope, $scope, $timeout, $modal, AppUsersManager, AppChatsManager, AppPhotosManager, MtpApiManager, Storage, NotificationsManager, MtpApiFileManager, PasswordManager, ApiUpdatesManager, ChangelogNotifyService, LayoutSwitchService, AppRuntimeManager, ErrorService, _) { .controller('SettingsModalController', function ($rootScope, $scope, $timeout, $modal, AppUsersManager, AppChatsManager, AppPhotosManager, MtpApiManager, Storage, NotificationsManager, MtpApiFileManager, PasswordManager, ApiUpdatesManager, ChangelogNotifyService, LayoutSwitchService, AppRuntimeManager, ErrorService, _) {
$scope.profile = {}; $scope.profile = {};
@ -3911,12 +4067,21 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.group.updating = true; $scope.group.updating = true;
return MtpApiManager.invokeApi('messages.editChatTitle', { var apiPromise;
if (AppChatsManager.isChannel($scope.chatID)) {
apiPromise = MtpApiManager.invokeApi('channels.editTitle', {
channel: AppChatsManager.getChannelInput($scope.chatID),
title: $scope.group.name
});
} else {
apiPromise = MtpApiManager.invokeApi('messages.editChatTitle', {
chat_id: AppChatsManager.getChatInput($scope.chatID), chat_id: AppChatsManager.getChatInput($scope.chatID),
title: $scope.group.name title: $scope.group.name
}).then(function (updates) { });
ApiUpdatesManager.processUpdateMessage(updates); }
return apiPromise.then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates);
var peerString = AppChatsManager.getChatString($scope.chatID); var peerString = AppChatsManager.getChatString($scope.chatID);
$rootScope.$broadcast('history_focus', {peerString: peerString}); $rootScope.$broadcast('history_focus', {peerString: peerString});
})['finally'](function () { })['finally'](function () {
@ -3925,19 +4090,80 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}; };
}) })
.controller('ChannelEditModalController', function ($q, $scope, $modalInstance, $rootScope, MtpApiManager, AppUsersManager, AppChatsManager, ApiUpdatesManager) {
var channel = AppChatsManager.getChat($scope.chatID);
var initial = {title: channel.title};
$scope.channel = {title: channel.title};
AppChatsManager.getChannelFull($scope.chatID).then(function (channelFull) {
initial.about = channelFull.about;
$scope.channel.about = channelFull.about;
});
$scope.updateChannel = function () {
if (!$scope.channel.title.length) {
return;
}
var promises = [];
if ($scope.channel.title != initial.title) {
promises.push(editTitle());
}
if ($scope.channel.about != initial.about) {
promises.push(editAbout());
}
return $q.all(promises).then(function () {
var peerString = AppChatsManager.getChatString($scope.chatID);
$rootScope.$broadcast('history_focus', {peerString: peerString});
})['finally'](function () {
delete $scope.channel.updating;
});
};
function editTitle () {
return MtpApiManager.invokeApi('channels.editTitle', {
channel: AppChatsManager.getChannelInput($scope.chatID),
title: $scope.channel.title
}).then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates);
});
}
function editAbout () {
return MtpApiManager.invokeApi('channels.editAbout', {
channel: AppChatsManager.getChannelInput($scope.chatID),
about: $scope.channel.about
});
}
})
.controller('ChatInviteLinkModalController', function (_, $scope, $timeout, $modalInstance, AppChatsManager, ErrorService) { .controller('ChatInviteLinkModalController', function (_, $scope, $timeout, $modalInstance, AppChatsManager, ErrorService) {
$scope.exportedInvite = {link: _('group_invite_link_loading_raw')}; $scope.exportedInvite = {link: _('group_invite_link_loading_raw')};
var isChannel = AppChatsManager.isChannel($scope.chatID);
function selectLink () {
$timeout(function () {
$scope.$broadcast('ui_invite_select');
}, 100);
}
function updateLink (force) { function updateLink (force) {
var chat = AppChatsManager.getChat($scope.chatID);
if (chat.username) {
$scope.exportedInvite = {link: 'https://telegram.me/' + chat.username, short: true};
selectLink();
return;
}
if (force) { if (force) {
$scope.exportedInvite.revoking = true; $scope.exportedInvite.revoking = true;
} }
AppChatsManager.getChatInviteLink($scope.chatID, force).then(function (link) { AppChatsManager.getChatInviteLink($scope.chatID, force).then(function (link) {
$scope.exportedInvite = {link: link}; $scope.exportedInvite = {link: link, canRevoke: true};
$timeout(function () { selectLink();
$scope.$broadcast('ui_invite_select');
}, 100);
})['finally'](function () { })['finally'](function () {
delete $scope.exportedInvite.revoking; delete $scope.exportedInvite.revoking;
}); });
@ -3945,7 +4171,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.revokeLink = function () { $scope.revokeLink = function () {
ErrorService.confirm({ ErrorService.confirm({
type: 'REVOKE_GROUP_INVITE_LINK' type: isChannel ? 'REVOKE_CHANNEL_INVITE_LINK' : 'REVOKE_GROUP_INVITE_LINK'
}).then(function () { }).then(function () {
updateLink(true); updateLink(true);
}) })

View File

@ -65,7 +65,7 @@ angular.module('myApp.directives', ['myApp.filters'])
needDate = false, needDate = false,
unreadAfter = false, unreadAfter = false,
applySelected = function () { applySelected = function () {
if (selected != ($scope.selectedMsgs[$scope.historyMessage.id] || false)) { if (selected != ($scope.selectedMsgs[$scope.historyMessage.mid] || false)) {
selected = !selected; selected = !selected;
element.toggleClass(selectedClass, selected); element.toggleClass(selectedClass, selected);
} }
@ -109,7 +109,7 @@ angular.module('myApp.directives', ['myApp.filters'])
$scope.$on('messages_regroup', applyGrouped); $scope.$on('messages_regroup', applyGrouped);
$scope.$on('messages_focus', function (e, focusedMsgID) { $scope.$on('messages_focus', function (e, focusedMsgID) {
if ((focusedMsgID == $scope.historyMessage.id) != focused) { if ((focusedMsgID == $scope.historyMessage.mid) != focused) {
focused = !focused; focused = !focused;
element.toggleClass(focusClass, focused); element.toggleClass(focusClass, focused);
} }
@ -122,7 +122,7 @@ angular.module('myApp.directives', ['myApp.filters'])
if ($scope.peerHistory.peerID != $scope.historyPeer.id) { if ($scope.peerHistory.peerID != $scope.historyPeer.id) {
return; return;
} }
if (unreadAfter != ($scope.historyUnreadAfter == $scope.historyMessage.id)) { if (unreadAfter != ($scope.historyUnreadAfter == $scope.historyMessage.mid)) {
unreadAfter = !unreadAfter; unreadAfter = !unreadAfter;
if (unreadAfter) { if (unreadAfter) {
if (unreadAfterSplit) { if (unreadAfterSplit) {
@ -362,10 +362,10 @@ angular.module('myApp.directives', ['myApp.filters'])
if (!message.loading) { if (!message.loading) {
updateMessage($scope, element); updateMessage($scope, element);
} else { } else {
var messageID = message.id; var mid = message.mid;
var stopWaiting = $scope.$on('messages_downloaded', function (e, msgIDs) { var stopWaiting = $scope.$on('messages_downloaded', function (e, mids) {
if (msgIDs.indexOf(messageID) != -1) { if (mids.indexOf(mid) != -1) {
$scope.replyMessage = AppMessagesManager.wrapForDialog(messageID); $scope.replyMessage = AppMessagesManager.wrapForDialog(mid);
updateMessage($scope, element); updateMessage($scope, element);
stopWaiting(); stopWaiting();
} }
@ -379,6 +379,7 @@ angular.module('myApp.directives', ['myApp.filters'])
$(element).remove(); $(element).remove();
return; return;
} }
console.log(element[0], message, AppPeersManager.getPeer(message.fromID));
var thumbWidth = 42; var thumbWidth = 42;
var thumbHeight = 42; var thumbHeight = 42;
var thumbPhotoSize; var thumbPhotoSize;
@ -421,10 +422,14 @@ angular.module('myApp.directives', ['myApp.filters'])
var peerID = AppMessagesManager.getMessagePeer(message); var peerID = AppMessagesManager.getMessagePeer(message);
var peerString = AppPeersManager.getPeerString(peerID); var peerString = AppPeersManager.getPeerString(peerID);
$rootScope.$broadcast('history_focus', {peerString: peerString, messageID: message.id}); $rootScope.$broadcast('history_focus', {peerString: peerString, messageID: message.mid});
}) })
} }
onContentLoaded(function () {
$scope.$emit('ui_height');
})
} }
}) })
@ -465,7 +470,7 @@ angular.module('myApp.directives', ['myApp.filters'])
function link ($scope, element, attrs) { function link ($scope, element, attrs) {
var message = $scope.message; var message = $scope.message;
var msgID = message.id; var msgID = message.mid;
// var msgID = $scope.$eval(attrs.myMessageText); // var msgID = $scope.$eval(attrs.myMessageText);
// var message = AppMessagesManager.getMessage(msgID); // var message = AppMessagesManager.getMessage(msgID);
@ -473,7 +478,7 @@ angular.module('myApp.directives', ['myApp.filters'])
if (message.pending) { if (message.pending) {
var unlink = $scope.$on('messages_pending', function () { var unlink = $scope.$on('messages_pending', function () {
if (message.id != msgID) { if (message.mid != msgID) {
updateHtml(message, element); updateHtml(message, element);
unlink(); unlink();
} }
@ -2546,6 +2551,9 @@ angular.module('myApp.directives', ['myApp.filters'])
return; return;
} }
AppChatsManager.getChatFull(chatID).then(function (chatFull) { AppChatsManager.getChatFull(chatID).then(function (chatFull) {
if (chatFull.participants_count) {
participantsCount = chatFull.participants_count;
}
var participantsVector = (chatFull.participants || {}).participants || []; var participantsVector = (chatFull.participants || {}).participants || [];
participantsCount = participantsVector.length; participantsCount = participantsVector.length;
angular.forEach(participantsVector, function (participant) { angular.forEach(participantsVector, function (participant) {
@ -2920,7 +2928,7 @@ angular.module('myApp.directives', ['myApp.filters'])
if ($scope.message && if ($scope.message &&
!$scope.message.out && !$scope.message.out &&
$scope.message.media_unread) { $scope.message.media_unread) {
AppMessagesManager.readMessages([$scope.message.id]); AppMessagesManager.readMessages([$scope.message.mid]);
} }
}, 300); }, 300);
}); });

View File

@ -27,6 +27,14 @@
"group_modal_members": "Members", "group_modal_members": "Members",
"group_modal_members_kick": "Remove", "group_modal_members_kick": "Remove",
"channel_modal_info": "Channel info",
"channel_modal_share_link": "Share link",
"channel_modal_share_loading": "Loading{dots}",
"channel_modal_join": "Join channel",
"channel_modal_add_member": "Invite members",
"channel_modal_leave_channel": "Leave channel",
"channel_modal_delete_channel": "Delete channel",
"country_select_modal_title": "Country", "country_select_modal_title": "Country",
"settings_modal_title": "Settings", "settings_modal_title": "Settings",
@ -173,6 +181,12 @@
"group_edit_submit": "Save", "group_edit_submit": "Save",
"group_edit_submit_active": "Saving...", "group_edit_submit_active": "Saving...",
"channel_edit_modal_title": "Edit channel",
"channel_edit_name": "Channel name",
"channel_edit_about": "Channel description",
"channel_edit_submit": "Save",
"channel_edit_submit_active": "Saving...",
"group_invite_link_modal_title": "Invite link", "group_invite_link_modal_title": "Invite link",
"group_invite_link_link_label": "Copy link", "group_invite_link_link_label": "Copy link",
"group_invite_link_loading": "Loading...", "group_invite_link_loading": "Loading...",
@ -204,6 +218,9 @@
"confirm_modal_reset_account_md": "Are you sure?\nThis action can not be undone.\n\nYou will lose all your chats and messages, along with any media and files you shared, if you proceed with resetting your account.", "confirm_modal_reset_account_md": "Are you sure?\nThis action can not be undone.\n\nYou will lose all your chats and messages, along with any media and files you shared, if you proceed with resetting your account.",
"confirm_modal_join_group_link": "Do you want to join the group «{title}»?", "confirm_modal_join_group_link": "Do you want to join the group «{title}»?",
"confirm_modal_revoke_group_link": "Are you sure you want to revoke this link? Once you do, no one will be able to join the group using it.", "confirm_modal_revoke_group_link": "Are you sure you want to revoke this link? Once you do, no one will be able to join the group using it.",
"confirm_modal_revoke_channel_link": "Are you sure you want to revoke this link? Once you do, no one will be able to join the channel using it.",
"confirm_modal_delete_channel_md": "Are you sure you want to delete this channel?\n\nAll messages will be removed and all messages will be lost.",
"confirm_modal_are_u_sure": "Are you sure?", "confirm_modal_are_u_sure": "Are you sure?",
"confirm_modal_logout_submit": "Log out", "confirm_modal_logout_submit": "Log out",

View File

@ -113,8 +113,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
usernames[searchUsername] = userID; usernames[searchUsername] = userID;
} }
apiUser.sortName = SearchIndexManager.cleanSearchText(apiUser.first_name + ' ' + (apiUser.last_name || ''));
apiUser.pFlags = { apiUser.pFlags = {
self: (apiUser.flags & (1 << 10)) > 0, self: (apiUser.flags & (1 << 10)) > 0,
contact: (apiUser.flags & (1 << 11)) > 0, contact: (apiUser.flags & (1 << 11)) > 0,
@ -125,6 +123,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
botNoGroups: (apiUser.flags & (1 << 16)) > 0 botNoGroups: (apiUser.flags & (1 << 16)) > 0
}; };
apiUser.sortName = apiUser.pFlags.deleted ? '' : SearchIndexManager.cleanSearchText(apiUser.first_name + ' ' + (apiUser.last_name || ''));
var nameWords = apiUser.sortName.split(' '); var nameWords = apiUser.sortName.split(' ');
var firstWord = nameWords.shift(); var firstWord = nameWords.shift();
var lastWord = nameWords.pop(); var lastWord = nameWords.pop();
@ -553,6 +553,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
usernames = {}, usernames = {},
chatsFull = {}, chatsFull = {},
chatFullPromises = {}, chatFullPromises = {},
channelAccess = {},
cachedPhotoLocations = {}; cachedPhotoLocations = {};
function saveApiChats (apiChats) { function saveApiChats (apiChats) {
@ -565,6 +566,23 @@ 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();
@ -597,8 +615,17 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return usernames[username] || 0; return usernames[username] || 0;
} }
function saveChannelAccess (id, accessHash) {
channelAccess[id] = accessHash;
}
function isChannel (id) { function isChannel (id) {
return (chats[id] || {})._ == 'channel'; var chat = chats[id];
if (chat && chat._ == 'channel' ||
channelAccess[id]) {
return true;
}
return false;
} }
function getChatInput (id) { function getChatInput (id) {
@ -612,11 +639,14 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return { return {
_: 'inputChannel', _: 'inputChannel',
channel_id: id, channel_id: id,
access_hash: getChat(id).access_hash || 0 access_hash: getChat(id).access_hash || channelAccess[id] || 0
} }
} }
function getChatFull(id) { function getChatFull(id) {
if (isChannel(id)) {
return getChannelFull(id);
}
if (chatsFull[id] !== undefined) { if (chatsFull[id] !== undefined) {
if (chats[id].version == chatsFull[id].participants.version || if (chats[id].version == chatsFull[id].participants.version ||
chats[id].left) { chats[id].left) {
@ -631,13 +661,72 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}).then(function (result) { }).then(function (result) {
saveApiChats(result.chats); saveApiChats(result.chats);
AppUsersManager.saveApiUsers(result.users); AppUsersManager.saveApiUsers(result.users);
if (result.full_chat && result.full_chat.chat_photo.id) { var fullChat = result.full_chat;
AppPhotosManager.savePhoto(result.full_chat.chat_photo); if (fullChat && fullChat.chat_photo.id) {
AppPhotosManager.savePhoto(fullChat.chat_photo);
} }
delete chatFullPromises[id]; delete chatFullPromises[id];
chatsFull[id] = fullChat;
$rootScope.$broadcast('chat_full_update', id); $rootScope.$broadcast('chat_full_update', id);
return chatsFull[id] = result.full_chat; return fullChat;
});
}
function getChannelFull (id, force) {
if (chatsFull[id] !== undefined && !force) {
return $q.when(chatsFull[id]);
}
if (chatFullPromises[id] !== undefined) {
return chatFullPromises[id];
}
return chatFullPromises[id] = MtpApiManager.invokeApi('channels.getFullChannel', {
channel: getChannelInput(id)
}).then(function (result) {
saveApiChats(result.chats);
AppUsersManager.saveApiUsers(result.users);
var fullChannel = result.full_chat;
var chat = getChat(id);
if (fullChannel && fullChannel.chat_photo.id) {
AppPhotosManager.savePhoto(fullChannel.chat_photo);
}
var participantsPromise;
if ((fullChannel.flags & 8) ||
chat.pFlags.creator ||
chat.pFlags.editor ||
chat.pFlags.moderator) {
participantsPromise = getChannelParticipants(id).then(function (participants) {
delete chatFullPromises[id];
fullChannel.participants = {
_: 'channelParticipants',
participants: participants
};
}, function (error) {
error.handled = true;
});
} else {
participantsPromise = $q.when();
}
return participantsPromise.then(function () {
delete chatFullPromises[id];
chatsFull[id] = fullChannel;
$rootScope.$broadcast('chat_full_update', id);
return fullChannel;
});
});
}
function getChannelParticipants (id) {
return MtpApiManager.invokeApi('channels.getParticipants', {
channel: getChannelInput(id),
filter: {_: 'channelParticipantsRecent'},
offset: 0,
limit: 200
}).then(function (result) {
AppUsersManager.saveApiUsers(result.users);
return result.participants;
}); });
} }
@ -688,25 +777,33 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var chatFull = angular.copy(fullChat), var chatFull = angular.copy(fullChat),
chat = getChat(id); chat = getChat(id);
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); chatFull.isAdmin = (myID == chatFull.participants.admin_id);
angular.forEach(chatFull.participants.participants, function(participant){ angular.forEach(chatFull.participants.participants, function(participant){
participant.user = AppUsersManager.getUser(participant.user_id);
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 && (chatFull.isAdmin || myID == participant.inviter_id);
// just for order by last seen
participant.user = AppUsersManager.getUser(participant.user_id);
}); });
}); });
} }
if (chatFull.participants && chatFull.participants._ == 'channelParticipants') {
var isAdmin = chat.pFlags.creator || chat.pFlags.editor || chat.pFlags.moderator;
angular.forEach(chatFull.participants.participants, function(participant) {
participant.canLeave = !chat.pFlags.creator && participant._ == 'channelParticipantSelf';
participant.canKick = isAdmin && participant._ == 'channelParticipant';
// just for order by last seen
participant.user = AppUsersManager.getUser(participant.user_id);
});
}
if (chatFull.about) {
chatFull.rAbout = RichTextProcessor.wrapRichText(chatFull.about, {noLinebreaks: true});
}
chatFull.thumb = {
placeholder: 'img/placeholders/GroupAvatar'+(Config.Mobile ? chat.num : Math.ceil(chat.num / 2))+'@2x.png',
location: chat && chat.photo && chat.photo.photo_small,
width: 72,
height: 72,
size: 0
};
chatFull.peerString = getChatString(id); chatFull.peerString = getChatString(id);
chatFull.chat = chat; chatFull.chat = chat;
@ -717,6 +814,14 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var scope = $rootScope.$new(); var scope = $rootScope.$new();
scope.chatID = chatID; scope.chatID = chatID;
if (isChannel(chatID)) {
var modalInstance = $modal.open({
templateUrl: templateUrl('channel_modal'),
controller: 'ChannelModalController',
scope: scope,
windowClass: 'chat_modal_window channel_modal_window mobile_modal'
});
} else {
var modalInstance = $modal.open({ var modalInstance = $modal.open({
templateUrl: templateUrl('chat_modal'), templateUrl: templateUrl('chat_modal'),
controller: 'ChatModalController', controller: 'ChatModalController',
@ -724,6 +829,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
windowClass: 'chat_modal_window mobile_modal' windowClass: 'chat_modal_window mobile_modal'
}); });
} }
}
$rootScope.$on('apiUpdate', function (e, update) { $rootScope.$on('apiUpdate', function (e, update) {
// console.log('on apiUpdate', update); // console.log('on apiUpdate', update);
@ -779,9 +885,11 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
saveApiChat: saveApiChat, saveApiChat: saveApiChat,
getChat: getChat, getChat: getChat,
isChannel: isChannel, isChannel: isChannel,
saveChannelAccess: saveChannelAccess,
getChatInput: getChatInput, getChatInput: getChatInput,
getChannelInput: getChannelInput, getChannelInput: getChannelInput,
getChatFull: getChatFull, getChatFull: getChatFull,
getChannelFull: getChannelFull,
getChatPhoto: getChatPhoto, getChatPhoto: getChatPhoto,
getChatString: getChatString, getChatString: getChatString,
getChatInviteLink: getChatInviteLink, getChatInviteLink: getChatInviteLink,
@ -806,6 +914,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}; };
} }
else if (firstChar == 'c') { else if (firstChar == 'c') {
AppChatsManager.saveChannelAccess(peerParams[0], peerParams[1]);
return { return {
_: 'inputPeerChannel', _: 'inputPeerChannel',
channel_id: peerParams[0], channel_id: peerParams[0],
@ -875,13 +984,13 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function resolveUsername (username) { function resolveUsername (username) {
var searchUserName = SearchIndexManager.cleanUsername(username); var searchUserName = SearchIndexManager.cleanUsername(username);
var foundUserID, foundChatID, foundPeerID, foundUsername; var foundUserID, foundChatID, foundPeerID, foundUsername;
if (foundUserID == AppUsersManager.resolveUsername(searchUserName)) { if (foundUserID = AppUsersManager.resolveUsername(searchUserName)) {
foundUsername = AppUsersManager.getUser(foundUserID).username; foundUsername = AppUsersManager.getUser(foundUserID).username;
if (SearchIndexManager.cleanUsername(foundUsername) == searchUserName) { if (SearchIndexManager.cleanUsername(foundUsername) == searchUserName) {
return qSync.when(foundUserID); return qSync.when(foundUserID);
} }
} }
if (foundChatID == AppChatsManager.resolveUsername(searchUserName)) { if (foundChatID = AppChatsManager.resolveUsername(searchUserName)) {
foundUsername = AppChatsManager.getChat(foundChatID).username; foundUsername = AppChatsManager.getChat(foundChatID).username;
if (SearchIndexManager.cleanUsername(foundUsername) == searchUserName) { if (SearchIndexManager.cleanUsername(foundUsername) == searchUserName) {
return qSync.when(-foundChatID); return qSync.when(-foundChatID);
@ -1171,8 +1280,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var peerText = AppPeersManager.getPeerSearchText(peerID); var peerText = AppPeersManager.getPeerSearchText(peerID);
SearchIndexManager.indexObject(peerID, peerText, dialogsIndex); SearchIndexManager.indexObject(peerID, peerText, dialogsIndex);
var messageID = dialog.top_important_message; var mid = getFullMessageID(dialog.top_important_message, -peerID);
dialog.top_message = peerID + '_' + messageID; dialog.top_message = mid;
var message = getMessage(dialog.top_message); var message = getMessage(dialog.top_message);
var topDate = message.date; var topDate = message.date;
@ -1187,7 +1296,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
pushDialogToStorage(dialog); pushDialogToStorage(dialog);
if (historiesStorage[peerID] === undefined) { if (historiesStorage[peerID] === undefined) {
var historyStorage = {count: null, history: [messageID], pending: []}; var historyStorage = {count: null, history: [mid], pending: []};
historiesStorage[peerID] = historyStorage; historiesStorage[peerID] = historyStorage;
} }
@ -1305,15 +1414,15 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var promise; var promise;
if (AppPeersManager.isChannel(peerID)) { if (AppPeersManager.isChannel(peerID)) {
promise = MtpApiManager.invokeApi('channels.getImportantHistory', { promise = MtpApiManager.invokeApi('channels.getImportantHistory', {
peer: inputPeer, channel: AppChatsManager.getChannelInput(-peerID),
offset_id: maxID || 0, offset_id: maxID ? getMessageLocalID(maxID) : 0,
add_offset: offset || 0, add_offset: offset || 0,
limit: limit || 0 limit: limit || 0
}, {noErrorBox: true}); }, {noErrorBox: true});
} else { } else {
promise = MtpApiManager.invokeApi('messages.getHistory', { promise = MtpApiManager.invokeApi('messages.getHistory', {
peer: inputPeer, peer: inputPeer,
offset_id: maxID || 0, offset_id: maxID ? getMessageLocalID(maxID) : 0,
add_offset: offset || 0, add_offset: offset || 0,
limit: limit || 0 limit: limit || 0
}, {noErrorBox: true}); }, {noErrorBox: true});
@ -1359,6 +1468,40 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}); });
} }
var channelLocals = {};
var channelsByLocals = {};
var channelCurLocal = 0;
var fullMsgIDModulus = 4294967296;
function getFullMessageID (msgID, channelID) {
if (!channelID) {
return msgID;
}
msgID = getMessageLocalID(msgID);
var localStart = channelLocals[channelID];
if (!localStart) {
localStart = (++channelCurLocal) * fullMsgIDModulus;
channelsByLocals[localStart] = channelID;
channelLocals[channelID] = localStart;
}
return localStart + msgID;
}
function getMessageIDInfo (fullMsgID) {
if (fullMsgID < fullMsgIDModulus) {
return [fullMsgID, 0];
}
var msgID = fullMsgID % fullMsgIDModulus;
var channelID = channelsByLocals[fullMsgID - msgID];
return [msgID, channelID];
}
function getMessageLocalID (fullMsgID) {
return fullMsgID % fullMsgIDModulus;
}
function fillHistoryStorage (inputPeer, maxID, fullLimit, historyStorage) { function fillHistoryStorage (inputPeer, maxID, fullLimit, historyStorage) {
// console.log('fill history storage', inputPeer, maxID, fullLimit, angular.copy(historyStorage)); // console.log('fill history storage', inputPeer, maxID, fullLimit, angular.copy(historyStorage));
return requestHistory (inputPeer, maxID, fullLimit).then(function (historyResult) { return requestHistory (inputPeer, maxID, fullLimit).then(function (historyResult) {
@ -1366,7 +1509,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var offset = 0; var offset = 0;
if (!maxID && historyResult.messages.length) { if (!maxID && historyResult.messages.length) {
maxID = historyResult.messages[0].id + 1; maxID = historyResult.messages[0].mid + 1;
} }
if (maxID > 0) { if (maxID > 0) {
for (offset = 0; offset < historyStorage.history.length; offset++) { for (offset = 0; offset < historyStorage.history.length; offset++) {
@ -1381,7 +1524,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
if (mergeReplyKeyboard(historyStorage, message)) { if (mergeReplyKeyboard(historyStorage, message)) {
$rootScope.$broadcast('history_reply_markup', {peerID: AppPeersManager.getPeerID(inputPeer)}); $rootScope.$broadcast('history_reply_markup', {peerID: AppPeersManager.getPeerID(inputPeer)});
} }
historyStorage.history.push(message.id); historyStorage.history.push(message.mid);
}); });
fullLimit -= historyResult.messages.length; fullLimit -= historyResult.messages.length;
@ -1479,7 +1622,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var history = []; var history = [];
angular.forEach(historyResult.messages, function (message) { angular.forEach(historyResult.messages, function (message) {
history.push(message.id); history.push(message.mid);
}); });
if (!maxID && historyStorage.pending.length) { if (!maxID && historyStorage.pending.length) {
history = historyStorage.pending.slice().concat(history); history = historyStorage.pending.slice().concat(history);
@ -1523,7 +1666,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
function mergeReplyKeyboard (historyStorage, message) { function mergeReplyKeyboard (historyStorage, message) {
// console.log('merge', message.id, 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.out &&
!message.action) { !message.action) {
@ -1532,7 +1675,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var messageReplyMarkup = message.reply_markup; var messageReplyMarkup = message.reply_markup;
var lastReplyMarkup = historyStorage.reply_markup; var lastReplyMarkup = historyStorage.reply_markup;
if (messageReplyMarkup) { if (messageReplyMarkup) {
if (lastReplyMarkup && lastReplyMarkup.id >= message.id) { if (lastReplyMarkup && lastReplyMarkup.mid >= message.mid) {
return false; return false;
} }
if (messageReplyMarkup.pFlags.selective && if (messageReplyMarkup.pFlags.selective &&
@ -1540,12 +1683,12 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return false; return false;
} }
if (historyStorage.maxOutID && if (historyStorage.maxOutID &&
message.id < historyStorage.maxOutID && message.mid < historyStorage.maxOutID &&
messageReplyMarkup.pFlags.one_time) { messageReplyMarkup.pFlags.one_time) {
messageReplyMarkup.pFlags.hidden = true; messageReplyMarkup.pFlags.hidden = true;
} }
messageReplyMarkup = angular.extend({ messageReplyMarkup = angular.extend({
id: message.id id: message.mid
}, messageReplyMarkup); }, messageReplyMarkup);
if (messageReplyMarkup._ != 'replyKeyboardHide') { if (messageReplyMarkup._ != 'replyKeyboardHide') {
messageReplyMarkup.fromID = message.from_id; messageReplyMarkup.fromID = message.from_id;
@ -1559,15 +1702,15 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
if (lastReplyMarkup) { if (lastReplyMarkup) {
if (lastReplyMarkup.pFlags.one_time && if (lastReplyMarkup.pFlags.one_time &&
!lastReplyMarkup.pFlags.hidden && !lastReplyMarkup.pFlags.hidden &&
(message.id > lastReplyMarkup.id || message.id < 0) && (message.mid > lastReplyMarkup.mid || message.mid < 0) &&
message.message) { message.message) {
lastReplyMarkup.pFlags.hidden = true; lastReplyMarkup.pFlags.hidden = true;
// console.log('set', historyStorage.reply_markup); // console.log('set', historyStorage.reply_markup);
return true; return true;
} }
} else if (!historyStorage.maxOutID || } else if (!historyStorage.maxOutID ||
message.id > historyStorage.maxOutID) { message.mid > historyStorage.maxOutID) {
historyStorage.maxOutID = message.id; historyStorage.maxOutID = message.mid;
} }
} }
@ -1580,7 +1723,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
) { ) {
historyStorage.reply_markup = { historyStorage.reply_markup = {
_: 'replyKeyboardHide', _: 'replyKeyboardHide',
id: message.id, mid: message.mid,
flags: 0, flags: 0,
pFlags: {} pFlags: {}
}; };
@ -1636,7 +1779,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
for (i = 0; i < historyStorage.history.length; i++) { for (i = 0; i < historyStorage.history.length; i++) {
message = messagesStorage[historyStorage.history[i]]; message = messagesStorage[historyStorage.history[i]];
if (message.media && neededContents[message.media._]) { if (message.media && neededContents[message.media._]) {
foundMsgs.push(message.id); foundMsgs.push(message.mid);
if (foundMsgs.length >= neededLimit) { if (foundMsgs.length >= neededLimit) {
break; break;
} }
@ -1688,7 +1831,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
foundMsgs = []; foundMsgs = [];
angular.forEach(searchResult.messages, function (message) { angular.forEach(searchResult.messages, function (message) {
foundMsgs.push(message.id); foundMsgs.push(message.mid);
}); });
if (useSearchCache) { if (useSearchCache) {
@ -1753,6 +1896,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function readHistory (inputPeer) { function readHistory (inputPeer) {
// console.trace('start read'); // console.trace('start read');
var peerID = AppPeersManager.getPeerID(inputPeer), var peerID = AppPeersManager.getPeerID(inputPeer),
isChannel = AppPeersManager.isChannel(peerID),
historyStorage = historiesStorage[peerID], historyStorage = historiesStorage[peerID],
foundDialog = getDialogByPeerID(peerID); foundDialog = getDialogByPeerID(peerID);
@ -1783,13 +1927,23 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return historyStorage.readPromise; return historyStorage.readPromise;
} }
historyStorage.readPromise = MtpApiManager.invokeApi('messages.readHistory', { var apiPromise;
if (isChannel) {
apiPromise = MtpApiManager.invokeApi('channels.readHistory', {
channel: AppChatsManager.getChannelInput(-peerID),
max_id: 0
});
} else {
apiPromise = MtpApiManager.invokeApi('messages.readHistory', {
peer: inputPeer, peer: inputPeer,
offset: 0, offset: 0,
max_id: 0 max_id: 0
}).then(function (affectedHistory) { }).then(function (affectedHistory) {
return processAffectedHistory(inputPeer, affectedHistory, 'messages.readHistory'); return processAffectedHistory(inputPeer, affectedHistory, 'messages.readHistory');
}).then(function () { });
}
historyStorage.readPromise = apiPromise.then(function () {
if (foundDialog[0]) { if (foundDialog[0]) {
// console.log('done read history', peerID); // console.log('done read history', peerID);
foundDialog[0].unread_count = 0; foundDialog[0].unread_count = 0;
@ -1861,17 +2015,25 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function saveMessages (apiMessages) { function saveMessages (apiMessages) {
angular.forEach(apiMessages, function (apiMessage) { angular.forEach(apiMessages, function (apiMessage) {
if (apiMessage._ == 'messageEmpty') {
return;
}
apiMessage.unread = apiMessage.flags & 1 ? true : false; apiMessage.unread = apiMessage.flags & 1 ? true : false;
apiMessage.out = apiMessage.flags & 2 ? true : false; apiMessage.out = apiMessage.flags & 2 ? true : false;
apiMessage.media_unread = apiMessage.flags & 32 ? 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 mid = isChannel ? toPeerID + '_' + apiMessage.id : apiMessage.id; var channelID = isChannel ? -toPeerID : 0;
apiMessage.mid = mid;
var mid = getFullMessageID(apiMessage.id, channelID);
apiMessage.mid = mid;
messagesStorage[mid] = apiMessage; messagesStorage[mid] = apiMessage;
if (apiMessage.reply_to_msg_id) {
apiMessage.reply_to_mid = getFullMessageID(apiMessage.reply_to_msg_id, channelID);
}
apiMessage.date -= serverTimeOffset; apiMessage.date -= serverTimeOffset;
apiMessage.toID = toPeerID; apiMessage.toID = toPeerID;
apiMessage.fromID = apiMessage.from_id || toPeerID; apiMessage.fromID = apiMessage.from_id || toPeerID;
@ -1902,7 +2064,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
AppAudioManager.saveAudio(apiMessage.media.audio); AppAudioManager.saveAudio(apiMessage.media.audio);
break; break;
case 'messageMediaWebPage': case 'messageMediaWebPage':
AppWebPagesManager.saveWebPage(apiMessage.media.webpage, apiMessage.id, mediaContext); AppWebPagesManager.saveWebPage(apiMessage.media.webpage, apiMessage.mid, mediaContext);
break; break;
} }
} }
@ -1913,9 +2075,14 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
apiMessage.action._ = 'messageActionChannelEditPhoto'; apiMessage.action._ = 'messageActionChannelEditPhoto';
} }
} }
if (apiMessage.action._ == 'messageActionChatEditTitle' && isChannel) { else if (isChannel) {
if (apiMessage.action._ == 'messageActionChatEditTitle') {
apiMessage.action._ = 'messageActionChannelEditTitle'; apiMessage.action._ = 'messageActionChannelEditTitle';
} }
if (apiMessage.action._ == 'messageActionChatDeletePhoto') {
apiMessage.action._ = 'messageActionChannelDeletePhoto';
}
}
} }
if (apiMessage.reply_markup) { if (apiMessage.reply_markup) {
apiMessage.reply_markup.pFlags = { apiMessage.reply_markup.pFlags = {
@ -2013,7 +2180,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
peer: inputPeer, peer: inputPeer,
message: text, message: text,
random_id: randomID, random_id: randomID,
reply_to_msg_id: replyToMsgID, reply_to_msg_id: getMessageLocalID(replyToMsgID),
entities: entities entities: entities
}, sentRequestOptions).then(function (updates) { }, sentRequestOptions).then(function (updates) {
if (updates._ == 'updateShortSentMessage') { if (updates._ == 'updateShortSentMessage') {
@ -2187,7 +2354,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
peer: inputPeer, peer: inputPeer,
media: inputMedia, media: inputMedia,
random_id: randomID, random_id: randomID,
reply_to_msg_id: replyToMsgID reply_to_msg_id: getMessageLocalID(replyToMsgID)
}).then(function (updates) { }).then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates); ApiUpdatesManager.processUpdateMessage(updates);
}, function (error) { }, function (error) {
@ -2319,7 +2486,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
peer: inputPeer, peer: inputPeer,
media: inputMedia, media: inputMedia,
random_id: randomID, random_id: randomID,
reply_to_msg_id: replyToMsgID reply_to_msg_id: getMessageLocalID(replyToMsgID)
}).then(function (updates) { }).then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates); ApiUpdatesManager.processUpdateMessage(updates);
}, function (error) { }, function (error) {
@ -2337,20 +2504,26 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
pendingByRandomID[randomIDS] = [peerID, messageID]; pendingByRandomID[randomIDS] = [peerID, messageID];
} }
function forwardMessages (peerID, msgIDs) { function forwardMessages (peerID, mids) {
msgIDs = msgIDs.sort(); mids = mids.sort();
var flags = 0;
var msgIDs = [];
var randomIDs = []; var randomIDs = [];
var i; var len = mids.length;
var len = msgIDs.length; var i, mid, msgID;
for (var i = 0; i < msgIDs.length; i++) { var fromChannel = getMessageIDInfo(mids[0])[1];
for (i = 0; i < len; i++) {
msgIDs.push(getMessageLocalID(mids[i]));
randomIDs.push([nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]); randomIDs.push([nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]);
} }
return MtpApiManager.invokeApi('messages.forwardMessages', { return MtpApiManager.invokeApi('messages.forwardMessages', {
peer: AppPeersManager.getInputPeerByID(peerID), flags: flags,
from_peer: AppPeersManager.getInputPeerByID(-fromChannel),
id: msgIDs, id: msgIDs,
random_id: randomIDs random_id: randomIDs,
to_peer: AppPeersManager.getInputPeerByID(peerID),
}).then(function (updates) { }).then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates); ApiUpdatesManager.processUpdateMessage(updates);
}); });
@ -2446,7 +2619,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
if (historyMessage = messagesForHistory[tempID]) { if (historyMessage = messagesForHistory[tempID]) {
messagesForHistory[finalMessage.id] = angular.extend(historyMessage, wrapForHistory(finalMessage.id)); messagesForHistory[finalMessage.mid] = angular.extend(historyMessage, wrapForHistory(finalMessage.mid));
delete historyMessage.pending; delete historyMessage.pending;
delete historyMessage.error; delete historyMessage.error;
delete historyMessage.random_id; delete historyMessage.random_id;
@ -2654,12 +2827,12 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
} }
var replyToMsgID = message.reply_to_msg_id; var replyToMsgID = message.reply_to_mid;
if (replyToMsgID) { if (replyToMsgID) {
if (messagesStorage[replyToMsgID] && false) { if (messagesStorage[replyToMsgID]) {
message.reply_to_msg = wrapForDialog(replyToMsgID); message.reply_to_msg = wrapForDialog(replyToMsgID);
} else { } else {
message.reply_to_msg = {id: replyToMsgID, loading: true}; message.reply_to_msg = {mid: replyToMsgID, loading: true};
if (needSingleMessages.indexOf(replyToMsgID) == -1) { if (needSingleMessages.indexOf(replyToMsgID) == -1) {
needSingleMessages.push(replyToMsgID); needSingleMessages.push(replyToMsgID);
if (fetchSingleMessagesTimeout === false) { if (fetchSingleMessagesTimeout === false) {
@ -2705,16 +2878,43 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
if (!needSingleMessages.length) { if (!needSingleMessages.length) {
return; return;
} }
var msgIDs = needSingleMessages.slice(); var mids = needSingleMessages.slice();
needSingleMessages = []; needSingleMessages = [];
MtpApiManager.invokeApi('messages.getMessages', {
var msgIDsByChannels = {};
var midsByChannels = {};
var i, mid, msgChannel, channelID;
for (i = 0; i < mids.length; i++) {
mid = mids[i];
msgChannel = getMessageIDInfo(mid);
channelID = msgChannel[1];
if (msgIDsByChannels[channelID] === undefined) {
msgIDsByChannels[channelID] = [];
midsByChannels[channelID] = [];
}
msgIDsByChannels[channelID].push(msgChannel[0]);
midsByChannels[channelID].push(mid);
}
angular.forEach(msgIDsByChannels, function (msgIDs, channelID) {
var promise;
if (channelID > 0) {
promise = MtpApiManager.invokeApi('channels.getMessages', {
channel: AppChatsManager.getChannelInput(channelID),
id: msgIDs id: msgIDs
}).then(function (getMessagesResult) { });
} else {
promise = MtpApiManager.invokeApi('messages.getMessages', {
id: msgIDs
});
}
promise.then(function (getMessagesResult) {
AppUsersManager.saveApiUsers(getMessagesResult.users); AppUsersManager.saveApiUsers(getMessagesResult.users);
AppChatsManager.saveApiChats(getMessagesResult.chats); AppChatsManager.saveApiChats(getMessagesResult.chats);
saveMessages(getMessagesResult.messages); saveMessages(getMessagesResult.messages);
$rootScope.$broadcast('messages_downloaded', msgIDs); $rootScope.$broadcast('messages_downloaded', midsByChannels[channelID]);
})
}) })
} }
@ -2757,20 +2957,20 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
if (curMessage.fwdFromID && if (curMessage.fwdFromID &&
curMessage.media && curMessage.media &&
curMessage.media.document && curMessage.media.document &&
curMessage.media.document.sticker && (curMessage.media.document.sticker || curMessage.media.document.audioTitle) &&
(curMessage.from_id != (prevMessage || {}).from_id || !(prevMessage || {}).fwdFromID)) { (curMessage.fromID != (prevMessage || {}).fromID || !(prevMessage || {}).fwdFromID)) {
delete curMessage.fwdFromID; delete curMessage.fwdFromID;
curMessage._ = 'message'; curMessage._ = 'message';
} }
if (prevMessage && if (prevMessage &&
curMessage.from_id == prevMessage.from_id && curMessage.fromID == prevMessage.fromID &&
!prevMessage.fwdFromID == !curMessage.fwdFromID && !prevMessage.fwdFromID == !curMessage.fwdFromID &&
!prevMessage.action && !prevMessage.action &&
!curMessage.action && !curMessage.action &&
curMessage.date < prevMessage.date + 900) { curMessage.date < prevMessage.date + 900) {
var singleLine = curMessage.message && curMessage.message.length < 70 && curMessage.message.indexOf("\n") == -1 && !curMessage.reply_to_msg_id; var singleLine = curMessage.message && curMessage.message.length < 70 && curMessage.message.indexOf("\n") == -1 && !curMessage.reply_to_mid;
if (groupFwd && curMessage.fwdFromID && curMessage.fwdFromID == prevMessage.fwdFromID) { if (groupFwd && curMessage.fwdFromID && curMessage.fwdFromID == prevMessage.fwdFromID) {
curMessage.grouped = singleLine ? 'im_grouped_fwd_short' : 'im_grouped_fwd'; curMessage.grouped = singleLine ? 'im_grouped_fwd_short' : 'im_grouped_fwd';
} else { } else {
@ -2922,13 +3122,13 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
notification.onclick = function () { notification.onclick = function () {
$rootScope.$broadcast('history_focus', { $rootScope.$broadcast('history_focus', {
peerString: peerString, peerString: peerString,
messageID: message.flags & 16 ? message.id : 0, messageID: message.flags & 16 ? message.mid : 0,
}); });
}; };
notification.message = notificationMessage; notification.message = notificationMessage;
notification.image = notificationPhoto.placeholder; notification.image = notificationPhoto.placeholder;
notification.key = 'msg' + message.id; notification.key = 'msg' + message.mid;
notification.tag = peerString; notification.tag = peerString;
if (notificationPhoto.location && !notificationPhoto.location.empty) { if (notificationPhoto.location && !notificationPhoto.location.empty) {
@ -3025,14 +3225,16 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
peerID = getMessagePeer(message), peerID = getMessagePeer(message),
historyStorage = historiesStorage[peerID]; historyStorage = historiesStorage[peerID];
saveMessages([message]);
if (historyStorage !== undefined) { if (historyStorage !== undefined) {
var history = historyStorage.history; var history = historyStorage.history;
if (history.indexOf(message.id) != -1) { if (history.indexOf(message.mid) != -1) {
return false; return false;
} }
var topMsgID = history[0]; var topMsgID = history[0];
history.unshift(message.id); history.unshift(message.mid);
if (message.id > 0 && message.id < topMsgID) { if (message.mid > 0 && message.mid < topMsgID) {
history.sort(function (a, b) { history.sort(function (a, b) {
return b - a; return b - a;
}); });
@ -3043,12 +3245,11 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} else { } else {
historyStorage = historiesStorage[peerID] = { historyStorage = historiesStorage[peerID] = {
count: null, count: null,
history: [message.id], history: [message.mid],
pending: [] pending: []
}; };
} }
saveMessages([message]);
if (mergeReplyKeyboard(historyStorage, message)) { if (mergeReplyKeyboard(historyStorage, message)) {
$rootScope.$broadcast('history_reply_markup', {peerID: peerID}) $rootScope.$broadcast('history_reply_markup', {peerID: peerID})
@ -3058,21 +3259,21 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
AppUsersManager.forceUserOnline(message.from_id); AppUsersManager.forceUserOnline(message.from_id);
} }
var randomID = pendingByMessageID[message.id], var randomID = pendingByMessageID[message.mid],
pendingMessage; pendingMessage;
if (randomID) { if (randomID) {
if (pendingMessage = finalizePendingMessage(randomID, message)) { if (pendingMessage = finalizePendingMessage(randomID, message)) {
$rootScope.$broadcast('history_update', {peerID: peerID}); $rootScope.$broadcast('history_update', {peerID: peerID});
} }
delete pendingByMessageID[message.id]; delete pendingByMessageID[message.mid];
} }
if (!pendingMessage) { if (!pendingMessage) {
if (newMessagesToHandle[peerID] === undefined) { if (newMessagesToHandle[peerID] === undefined) {
newMessagesToHandle[peerID] = []; newMessagesToHandle[peerID] = [];
} }
newMessagesToHandle[peerID].push(message.id); newMessagesToHandle[peerID].push(message.mid);
if (!newMessagesHandlePromise) { if (!newMessagesHandlePromise) {
newMessagesHandlePromise = $timeout(handleNewMessages, 0); newMessagesHandlePromise = $timeout(handleNewMessages, 0);
} }
@ -3088,7 +3289,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
dialogsStorage.dialogs.splice(foundDialog[1], 1); dialogsStorage.dialogs.splice(foundDialog[1], 1);
dialogsStorage.dialogs.unshift(dialog); dialogsStorage.dialogs.unshift(dialog);
} }
dialog.top_message = message.id; dialog.top_message = message.mid;
if (inboxUnread) { if (inboxUnread) {
dialog.unread_count++; dialog.unread_count++;
} }
@ -3098,7 +3299,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
dialog = { dialog = {
peerID: peerID, peerID: peerID,
unread_count: inboxUnread ? 1 : 0, unread_count: inboxUnread ? 1 : 0,
top_message: message.id top_message: message.mid
}; };
dialogsStorage.dialogs.unshift(dialog); dialogsStorage.dialogs.unshift(dialog);
} }
@ -4586,7 +4787,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
message: updateMessage.message, message: updateMessage.message,
fwd_from_id: updateMessage.fwd_from_id, fwd_from_id: updateMessage.fwd_from_id,
fwd_date: updateMessage.fwd_date, fwd_date: updateMessage.fwd_date,
reply_to_msg_id: updateMessage.reply_to_msg_id, reply_to_msg_id: updateMessage.reply_to_msg_id
}, },
pts: updateMessage.pts, pts: updateMessage.pts,
pts_count: updateMessage.pts_count pts_count: updateMessage.pts_count

View File

@ -3652,7 +3652,7 @@ a.countries_modal_search_clear {
height: 18px; height: 18px;
margin: 17px 0 0 16px; margin: 17px 0 0 16px;
.image-2x('../img/icons/ProfileIcons.png', 40px, 360px); .image-2x('../img/icons/ProfileIcons.png', 40px, 420px);
background-position: -10px -164px; background-position: -10px -164px;
} }
@ -3667,7 +3667,7 @@ a.countries_modal_search_clear {
height: 22px; height: 22px;
margin: 17px 0 0 13px; margin: 17px 0 0 13px;
.image-2x('../img/icons/ProfileIcons.png', 40px, 360px); .image-2x('../img/icons/ProfileIcons.png', 40px, 420px);
background-position: -7px -280px; background-position: -7px -280px;
} }
@ -3682,7 +3682,7 @@ a.countries_modal_search_clear {
height: 20px; height: 20px;
margin: 18px 0 0 16px; margin: 18px 0 0 16px;
.image-2x('../img/icons/ProfileIcons.png', 40px, 360px); .image-2x('../img/icons/ProfileIcons.png', 40px, 420px);
background-position: -10px -220px; background-position: -10px -220px;
} }
@ -3728,7 +3728,7 @@ a.countries_modal_search_clear {
margin-top: 5px; margin-top: 5px;
position: absolute; position: absolute;
.image-2x('../img/icons/ProfileIcons.png', 40px, 360px); .image-2x('../img/icons/ProfileIcons.png', 40px, 420px);
background-position: 0 0; background-position: 0 0;
.md_modal_iconed_section_toggle & { .md_modal_iconed_section_toggle & {
@ -3748,6 +3748,13 @@ a.countries_modal_search_clear {
margin-top: 3px; margin-top: 3px;
} }
&_about {
width: 20px;
height: 20px;
background-position: -10px -344px;
margin-top: 0px;
}
&_notification { &_notification {
width: 17px; width: 17px;
height: 20px; height: 20px;

View File

@ -0,0 +1,28 @@
<div class="md_simple_modal_wrap" my-modal-position>
<div class="md_simple_modal_body">
<form class="modal_simple_form" ng-submit="updateChannel()">
<h4 my-i18n="channel_edit_modal_title"></h4>
<div class="md-input-group" my-labeled-input>
<label class="md-input-label" my-i18n="channel_edit_name"></label>
<input class="md-input" my-focused type="text" ng-model="channel.title" />
</div>
<div class="md-input-group" my-labeled-input>
<label class="md-input-label" my-i18n="channel_edit_about"></label>
<input class="md-input" type="text" ng-model="channel.about" />
</div>
</form>
</div>
<div class="md_simple_modal_footer">
<button class="btn btn-md" ng-click="$dismiss()" my-i18n="modal_cancel"></button>
<button class="btn btn-md btn-md-primary" ng-class="{disabled: channel.updating}" ng-click="updateChannel()" ng-bind="channel.updating ? 'channel_edit_submit_active' : 'channel_edit_submit' | i18n" ng-disabled="channel.updating"></button>
</div>
</div>

View File

@ -0,0 +1,136 @@
<div class="chat_modal_wrap md_modal_wrap" my-modal-position>
<div class="md_modal_head">
<div class="md_modal_title_wrap">
<div class="md_modal_actions_wrap clearfix">
<a class="md_modal_action md_modal_action_close" ng-click="$close()" my-i18n="modal_close"></a>
<a class="md_modal_action" ng-if="chatFull.chat.pFlags.creator" ng-click="editChannel()" my-i18n="modal_edit"></a>
</div>
<div class="md_modal_title" my-i18n="channel_modal_info"></div>
</div>
<div class="peer_modal_profile_wrap clearfix">
<div class="peer_modal_photo_wrap pull-left" ng-switch="photo.updating">
<div ng-switch-when="true" class="peer_modal_photo md_photo_loading loading_dots">
<i></i><i></i><i></i>
</div>
<a ng-switch-default ng-click="openPhoto(chatFull.chat_photo.id, {p: -chatFull.chat.id})" class="peer_modal_photo" my-peer-photolink="::-chatFull.chat.id" img-class="peer_modal_photo" no-open="true" watch="true" ng-class="{disabled: !chatFull.chat.photo.photo_small}" ng-disabled="!chatFull.chat.photo.photo_small"></a>
</div>
<div class="peer_modal_profile">
<div class="peer_modal_profile_name" my-peer-link="-chatFull.chat.id"></div>
<div class="peer_modal_profile_description" ng-if="chatFull.participants_count > 0">
<ng-pluralize count="chatFull.participants_count"
when="group_modal_pluralize_participants">
</ng-pluralize>
</div>
</div>
</div>
</div>
<div class="md_modal_split_actions_wrap" ng-if="chatFull.chat.pFlags.creator">
<div class="md_modal_split_actions">
<div class="md_modal_split_action">
<input my-file-upload type="file" multiple="false" class="im_attach_input" size="120" multiple="false" accept="image/x-png, image/png, image/gif, image/jpeg" title="{{'group_modal_update_photo' | i18n}}" />
<i class="md_modal_split_action_camera"></i>
</div>
</div>
</div>
<div class="md_modal_body">
<div class="md_modal_sections">
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_number" ng-if="chatFull.rAbout || chatFull.chat.username || chatFull.chat.pFlags.creator">
<i class="md_modal_section_icon md_modal_section_icon_about"></i>
<div class="md_modal_section_param_wrap" ng-if="chatFull.about.length > 0">
<div class="md_modal_section_param_value">
<span ng-bind-html="chatFull.rAbout"></span>
</div>
<div class="md_modal_section_param_name" my-i18n="user_modal_about"></div>
</div>
<div class="md_modal_section_param_wrap" ng-if="chatFull.chat.username">
<div class="md_modal_section_param_value">
<a class="settings_modal_username_link" ng-click="shareLink($event)" ng-bind="'https://telegram.me/' + chatFull.chat.username" ng-href="https://telegram.me/{{chatFull.chat.username}}" target="_blank"></a>
</div>
<div class="md_modal_section_param_name" my-i18n="channel_modal_share_link"></div>
</div>
<div class="md_modal_section_param_wrap" ng-if="!chatFull.chat.username &amp;&amp; chatFull.chat.pFlags.creator">
<div class="md_modal_section_param_value" ng-switch="chatFull.exported_invite._">
<a ng-switch-when="chatInviteExported" class="settings_modal_username_link" ng-click="shareLink($event)" ng-bind="chatFull.exported_invite.link" ng-href="{{chatFull.exported_invite.link}}" target="_blank"></a>
<span ng-switch-default my-i18n="channel_modal_share_loading">
<my-i18n-param name="dots"><span my-loading-dots></span></my-i18n-param>
</span>
</div>
<div class="md_modal_section_param_name" my-i18n="channel_modal_share_link"></div>
</div>
</div>
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_link" ng-if="chatFull.chat.pFlags.creator || chatFull.chat.pFlags.left">
<i class="md_modal_section_icon md_modal_section_icon_person"></i>
<div class="md_modal_section_link_wrap" ng-switch="chatFull.chat.pFlags.left">
<a ng-switch-when="true" class="md_modal_section_link" ng-click="joinChannel()" my-i18n="channel_modal_join"></a>
<a ng-switch-default class="md_modal_section_link" ng-click="inviteToChannel()" my-i18n="channel_modal_add_member"></a>
</div>
</div>
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_toggle">
<i class="md_modal_section_icon md_modal_section_icon_notification"></i>
<a class="md_modal_section_toggle_wrap tg_checkbox" ng-click="settings.notifications = !settings.notifications" ng-class="settings.notifications ? 'tg_checkbox_on' : ''">
<span class="icon icon-checkbox-outer"><i class="icon-checkbox-inner"></i></span>
<span class="tg_checkbox_label" my-i18n="group_modal_notifications"></span>
</a>
</div>
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_link" ng-if="chatFull.chat.pFlags.creator || !chatFull.chat.pFlags.left && !chatFull.chat.pFlags.kicked">
<i class="md_modal_section_icon md_modal_section_icon_more"></i>
<div class="md_modal_section_link_wrap" ng-if="!chatFull.chat.pFlags.creator && !chatFull.chat.pFlags.left && !chatFull.chat.pFlags.kicked">
<a class="md_modal_section_link" ng-click="leaveChannel()" my-i18n="channel_modal_leave_channel"></a>
</div>
<div class="md_modal_section_link_wrap" ng-if="chatFull.chat.pFlags.creator">
<a class="md_modal_section_link md_modal_section_link_danger" ng-click="deleteChannel()" my-i18n="channel_modal_delete_channel"></a>
</div>
</div>
</div>
<div ng-if="chatFull.participants.participants.length > 0">
<div class="md_modal_section_splitter"></div>
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_peers">
<i class="md_modal_section_icon md_modal_section_icon_people"></i>
<div class="md_modal_section_peers_wrap">
<div class="md_modal_list_peer_wrap clearfix" ng-repeat="participant in chatFull.participants.participants | orderBy:'-user.sortStatus'">
<a ng-if="participant.canLeave" ng-click="leaveChannel()" class="md_modal_list_peer_action pull-right" my-i18n="group_modal_menu_leave"></a>
<a ng-if="participant.canKick" ng-click="kickFromChannel(participant.user_id)" class="md_modal_list_peer_action pull-right" my-i18n="group_modal_members_kick"></a>
<a class="md_modal_list_peer_photo pull-left" my-peer-photolink="::participant.user_id" img-class="md_modal_list_peer_photo"></a>
<div class="md_modal_list_peer_name">
<a class="md_modal_list_peer_name" my-peer-link="participant.user_id"></a>
</div>
<div class="md_modal_list_peer_description" my-user-status="::participant.user_id" bot-chat-privacy="true"></div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -6,18 +6,32 @@
<h4 my-i18n="group_invite_link_modal_title"></h4> <h4 my-i18n="group_invite_link_modal_title"></h4>
<div ng-switch="exportedInvite.canRevoke">
<div ng-switch-when="true">
<div class="md-input-group md-textarea-group" my-labeled-input> <div class="md-input-group md-textarea-group" my-labeled-input>
<label class="md-input-label" my-i18n="group_invite_link_link_label"></label> <label class="md-input-label" my-i18n="group_invite_link_link_label"></label>
<textarea class="md-input" ng-model="exportedInvite.link" rows="2" my-copy-field="'ui_invite_select'"></textarea> <textarea class="md-input" ng-model="exportedInvite.link" rows="2" my-copy-field="'ui_invite_select'"></textarea>
</div> </div>
</div>
<div ng-switch-default>
<div class="md-input-group" my-labeled-input>
<label class="md-input-label" my-i18n="group_invite_link_link_label"></label>
<input class="md-input" type="text" ng-model="exportedInvite.link" my-copy-field="'ui_invite_select'" />
</div>
</div>
</div>
</div> </div>
</div> </div>
<div class="md_simple_modal_footer"> <div class="md_simple_modal_footer" ng-switch="exportedInvite.canRevoke">
<div ng-switch-when="true">
<button class="btn btn-md" ng-click="$dismiss()" my-i18n="modal_cancel"></button> <button class="btn btn-md" ng-click="$dismiss()" my-i18n="modal_cancel"></button>
<button class="btn btn-md btn-md-primary" ng-class="{disabled: exportedInvite.revoking}" ng-click="revokeLink()" ng-bind="exportedInvite.revoking ? 'group_invite_revoke_active' : 'group_invite_revoke' | i18n" ng-disabled="exportedInvite.revoking"></button> <button class="btn btn-md btn-md-primary" ng-class="{disabled: exportedInvite.revoking}" ng-click="revokeLink()" ng-bind="exportedInvite.revoking ? 'group_invite_revoke_active' : 'group_invite_revoke' | i18n" ng-disabled="exportedInvite.revoking"></button>
</div> </div>
</div>
</div> </div>

View File

@ -49,6 +49,8 @@
<my-i18n-param name="title"><strong ng-bind="title"></strong></my-i18n-param> <my-i18n-param name="title"><strong ng-bind="title"></strong></my-i18n-param>
</div> </div>
<div ng-switch-when="REVOKE_GROUP_INVITE_LINK" my-i18n="confirm_modal_revoke_group_link"></div> <div ng-switch-when="REVOKE_GROUP_INVITE_LINK" my-i18n="confirm_modal_revoke_group_link"></div>
<div ng-switch-when="REVOKE_CHANNEL_INVITE_LINK" my-i18n="confirm_modal_revoke_channel_link"></div>
<div ng-switch-when="CHANNEL_DELETE" my-i18n="confirm_modal_delete_channel_md"></div>
<span ng-switch-default ng-switch="message.length > 0"> <span ng-switch-default ng-switch="message.length > 0">

View File

@ -1,4 +1,4 @@
<a class="im_dialog" ng-mousedown="dialogSelect(dialogMessage.peerString, dialogMessage.unreadCount == -1 && dialogMessage.id)"> <a class="im_dialog" ng-mousedown="dialogSelect(dialogMessage.peerString, dialogMessage.unreadCount == -1 && dialogMessage.mid)">
<div class="im_dialog_meta pull-right text-right"> <div class="im_dialog_meta pull-right text-right">
<div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div> <div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div>

View File

@ -71,7 +71,7 @@
<div class="im_dialogs_messages_wrap" ng-show="foundMessages.length > 0"> <div class="im_dialogs_messages_wrap" ng-show="foundMessages.length > 0">
<h5 my-i18n="im_messages"></h5> <h5 my-i18n="im_messages"></h5>
<ul class="nav nav-pills nav-stacked"> <ul class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in foundMessages track by dialogMessage.id" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.id}"></li> <li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in foundMessages track by dialogMessage.mid" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.id}"></li>
</ul> </ul>
</div> </div>

View File

@ -1,4 +1,4 @@
<div class="im_message_outer_wrap" ng-click="toggleMessage(historyMessage.id, $event)"> <div class="im_message_outer_wrap" ng-click="toggleMessage(historyMessage.mid, $event)">
<div class="im_message_wrap clearfix" ng-switch="::historyMessage._ == 'messageService'"> <div class="im_message_wrap clearfix" ng-switch="::historyMessage._ == 'messageService'">
@ -43,7 +43,7 @@
<a class="im_message_author" my-peer-link="historyMessage.fromID" short="historyMessage.toID > 0" color="historyMessage.toID < 0" no-watch="true"></a> <a class="im_message_author" my-peer-link="historyMessage.fromID" short="historyMessage.toID > 0" color="historyMessage.toID < 0" no-watch="true"></a>
<a class="im_message_reply_wrap" my-reply-message="historyMessage.reply_to_msg" ng-if="::historyMessage.reply_to_msg_id"></a> <a class="im_message_reply_wrap" my-reply-message="historyMessage.reply_to_msg" ng-if="::historyMessage.reply_to_mid"></a>
<div ng-if="::historyMessage.fwdFromID || false" class="im_message_fwd_from"> <div ng-if="::historyMessage.fwdFromID || false" class="im_message_fwd_from">
<a class="im_message_fwd_photo pull-left" my-peer-photolink="::historyMessage.fwdFromID" img-class="im_message_fwd_photo"></a> <a class="im_message_fwd_photo pull-left" my-peer-photolink="::historyMessage.fwdFromID" img-class="im_message_fwd_photo"></a>
@ -54,16 +54,16 @@
<div class="im_message_text" ng-if="::historyMessage.message.length || false" my-message-text="::historyMessage" dir="auto"></div> <div class="im_message_text" ng-if="::historyMessage.message.length || false" my-message-text="::historyMessage" dir="auto"></div>
<div ng-if="::historyMessage.media || historyMessage.id < 0 ? true : false" class="im_message_media" ng-switch="historyMessage.media._"> <div ng-if="::historyMessage.media || historyMessage.mid < 0 ? true : false" class="im_message_media" ng-switch="historyMessage.media._">
<div ng-switch-when="messageMediaPhoto" my-message-photo="historyMessage.media" message-id="historyMessage.id"></div> <div ng-switch-when="messageMediaPhoto" my-message-photo="historyMessage.media" message-id="historyMessage.mid"></div>
<div ng-switch-when="messageMediaVideo" my-message-video="historyMessage.media" message-id="historyMessage.id"></div> <div ng-switch-when="messageMediaVideo" my-message-video="historyMessage.media" message-id="historyMessage.mid"></div>
<div ng-switch-when="messageMediaDocument" my-message-document="historyMessage.media.document" message-id="historyMessage.id"></div> <div ng-switch-when="messageMediaDocument" my-message-document="historyMessage.media.document" message-id="historyMessage.mid"></div>
<div ng-switch-when="messageMediaAudio" class="im_message_audio" my-audio-player audio="historyMessage.media.audio" message="historyMessage"></div> <div ng-switch-when="messageMediaAudio" class="im_message_audio" my-audio-player audio="historyMessage.media.audio" message="historyMessage"></div>
<div ng-switch-when="messageMediaGeo" my-message-geo="historyMessage.media"></div> <div ng-switch-when="messageMediaGeo" my-message-geo="historyMessage.media"></div>
<div ng-switch-when="messageMediaVenue" my-message-venue="historyMessage.media"></div> <div ng-switch-when="messageMediaVenue" my-message-venue="historyMessage.media"></div>
<div ng-switch-when="messageMediaContact" class="im_message_contact" my-message-contact></div> <div ng-switch-when="messageMediaContact" class="im_message_contact" my-message-contact></div>
<div ng-switch-when="messageMediaWebPage" class="im_message_webpage" my-message-webpage="historyMessage.media.webpage" message-id="historyMessage.id"></div> <div ng-switch-when="messageMediaWebPage" class="im_message_webpage" my-message-webpage="historyMessage.media.webpage" message-id="historyMessage.mid"></div>
<div ng-switch-when="messageMediaPending" my-message-pending></div> <div ng-switch-when="messageMediaPending" my-message-pending></div>
<div ng-switch-when="messageMediaUnsupported"> <div ng-switch-when="messageMediaUnsupported">
<div class="im_message_text"> <div class="im_message_text">

View File

@ -12,7 +12,7 @@
/> />
</div> </div>
<div class="im_message_reply_author" ng-switch-default> <div class="im_message_reply_author" ng-switch-default>
<span my-peer-link="replyMessage.from_id"></span> <span my-peer-link="replyMessage.fromID" peer-watch="true"></span>
</div> </div>
<div class="im_message_reply_body" ng-switch-default> <div class="im_message_reply_body" ng-switch-default>
<span class="im_reply_message_media" ng-if="replyMessage.media" ng-switch="replyMessage.media._"> <span class="im_reply_message_media" ng-if="replyMessage.media" ng-switch="replyMessage.media._">

View File

@ -1,4 +1,4 @@
<a class="im_dialog" ng-mousedown="dialogSelect(dialogMessage.peerString, dialogMessage.unreadCount == -1 && dialogMessage.id)"> <a class="im_dialog" ng-mousedown="dialogSelect(dialogMessage.peerString, dialogMessage.unreadCount == -1 && dialogMessage.mid)">
<div class="im_dialog_meta pull-right text-right"> <div class="im_dialog_meta pull-right text-right">
<div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div> <div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div>

View File

@ -69,7 +69,7 @@
<div class="im_dialogs_messages_wrap" ng-show="foundMessages.length > 0"> <div class="im_dialogs_messages_wrap" ng-show="foundMessages.length > 0">
<h5 my-i18n="im_messages"></h5> <h5 my-i18n="im_messages"></h5>
<ul class="nav nav-pills nav-stacked"> <ul class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in foundMessages track by dialogMessage.id" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.id}"></li> <li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in foundMessages track by dialogMessage.mid" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.mid}"></li>
</ul> </ul>
</div> </div>

View File

@ -1,4 +1,4 @@
<div class="im_message_outer_wrap" ng-click="toggleMessage(historyMessage.id, $event)"> <div class="im_message_outer_wrap" ng-click="toggleMessage(historyMessage.mid, $event)">
<div class="im_message_wrap clearfix" ng-switch="::historyMessage._ == 'messageService'"> <div class="im_message_wrap clearfix" ng-switch="::historyMessage._ == 'messageService'">
@ -30,14 +30,14 @@
<div class="im_message_meta"> <div class="im_message_meta">
<i class="icon-message-status-tick"></i> <i class="icon-message-status-tick"></i>
<span class="im_message_date" ng-bind="::historyMessage.date | time"></span> <span class="im_message_date" ng-bind="::mhistoryMessage.date | time"></span>
</div> </div>
<div class="im_message_body" ng-class="::{im_message_body_media: !!historyMessage.media && !historyMessage.media.rCaption}"> <div class="im_message_body" ng-class="::{im_message_body_media: !!historyMessage.media && !historyMessage.media.rCaption}">
<a class="im_message_author" my-peer-link="historyMessage.from_id" short="!historyMessage.to_id.chat_id" color="historyMessage.to_id.chat_id > 0" no-watch="true"></a> <a class="im_message_author" my-peer-link="historyMessage.from_id" short="!historyMessage.to_id.chat_id" color="historyMessage.to_id.chat_id > 0" no-watch="true"></a>
<a class="im_message_reply_wrap" my-reply-message="historyMessage.reply_to_msg" ng-if="::historyMessage.reply_to_msg_id"></a> <a class="im_message_reply_wrap" my-reply-message="historyMessage.reply_to_msg" ng-if="::historyMessage.reply_to_mid"></a>
<div ng-if="::historyMessage.fwd_from_id > 0 &amp;&amp; !historyMessage.media" class="im_message_fwd_header" my-i18n="message_forwarded_message_mobile"> <div ng-if="::historyMessage.fwd_from_id > 0 &amp;&amp; !historyMessage.media" class="im_message_fwd_header" my-i18n="message_forwarded_message_mobile">
<a my-i18n-param="from" class="im_message_fwd_author" my-peer-link="historyMessage.fwd_from_id" no-watch="true"></a> <a my-i18n-param="from" class="im_message_fwd_author" my-peer-link="historyMessage.fwd_from_id" no-watch="true"></a>
@ -46,9 +46,9 @@
<div ng-if="::historyMessage.media || false" class="im_message_media" ng-switch="historyMessage.media._"> <div ng-if="::historyMessage.media || false" class="im_message_media" ng-switch="historyMessage.media._">
<div ng-switch-when="messageMediaPhoto" my-message-photo="historyMessage.media" message-id="historyMessage.id"></div> <div ng-switch-when="messageMediaPhoto" my-message-photo="historyMessage.media" message-id="historyMessage.mid"></div>
<div ng-switch-when="messageMediaVideo" my-message-video="historyMessage.media" message-id="historyMessage.id"></div> <div ng-switch-when="messageMediaVideo" my-message-video="historyMessage.media" message-id="historyMessage.mid"></div>
<div ng-switch-when="messageMediaDocument" my-message-document="historyMessage.media.document" message-id="historyMessage.id"></div> <div ng-switch-when="messageMediaDocument" my-message-document="historyMessage.media.document" message-id="historyMessage.mid"></div>
<div ng-switch-when="messageMediaAudio" class="im_message_audio" my-audio-player audio="historyMessage.media.audio" message="historyMessage"></div> <div ng-switch-when="messageMediaAudio" class="im_message_audio" my-audio-player audio="historyMessage.media.audio" message="historyMessage"></div>
<div ng-switch-when="messageMediaGeo" my-message-geo="historyMessage.media"></div> <div ng-switch-when="messageMediaGeo" my-message-geo="historyMessage.media"></div>
<div ng-switch-when="messageMediaVenue" my-message-geo="historyMessage.media"></div> <div ng-switch-when="messageMediaVenue" my-message-geo="historyMessage.media"></div>