diff --git a/app/img/Telegram.svg b/app/img/Telegram.svg
new file mode 100644
index 00000000..314eb135
--- /dev/null
+++ b/app/img/Telegram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/js/app.js b/app/js/app.js
index ef8a942f..6f90ca53 100644
--- a/app/js/app.js
+++ b/app/js/app.js
@@ -7,6 +7,12 @@
'use strict';
+var extraModules = [];
+if (Config.Modes.animations) {
+ extraModules.push('ngAnimate');
+}
+
+
// Declare app level module which depends on filters, and services
angular.module('myApp', [
'ngRoute',
@@ -24,7 +30,7 @@ angular.module('myApp', [
PRODUCTION_ONLY_END*/
'myApp.directives',
'myApp.controllers'
-]).
+].concat(extraModules)).
config(['$locationProvider', '$routeProvider', '$compileProvider', 'StorageProvider', function($locationProvider, $routeProvider, $compileProvider, StorageProvider) {
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|blob|filesystem|chrome-extension|app):|data:image\//);
diff --git a/app/js/controllers.js b/app/js/controllers.js
index 24df3fde..55b2d5f4 100644
--- a/app/js/controllers.js
+++ b/app/js/controllers.js
@@ -1058,6 +1058,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.selectedReply = selectedReply;
$scope.selectedCancel = selectedCancel;
$scope.selectedFlush = selectedFlush;
+ $scope.selectInlineBot = selectInlineBot;
$scope.startBot = startBot;
$scope.cancelBot = cancelBot;
@@ -1195,7 +1196,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.historyState.typing.splice(0, $scope.historyState.typing.length);
$scope.$broadcast('ui_peer_change');
$scope.$broadcast('ui_history_change');
- safeReplaceObject($scope.state, {loaded: true, empty: !peerHistory.messages.length});
+ safeReplaceObject($scope.state, {loaded: true, empty: !peerHistory.messages.length, mayBeHasMore: true});
updateBotActions();
updateChannelActions();
@@ -1299,14 +1300,14 @@ angular.module('myApp.controllers', ['myApp.i18n'])
return;
}
lessPending = false;
- lessActive = true;
+ $scope.state.lessActive = lessActive = true;
var curJump = jump,
curLessJump = ++lessJump,
limit = 0,
backLimit = 20;
AppMessagesManager.getHistory($scope.curDialog.peerID, minID, limit, backLimit).then(function (historyResult) {
- lessActive = false;
+ $scope.state.lessActive = lessActive = false;
if (curJump != jump || curLessJump != lessJump) return;
var i, id;
@@ -1347,7 +1348,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
return;
}
morePending = false;
- moreActive = true;
+ $scope.state.moreActive = moreActive = true;
var curJump = jump,
curMoreJump = ++moreJump,
@@ -1358,7 +1359,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
: AppMessagesManager.getHistory($scope.curDialog.peerID, maxID, limit);
getMessagesPromise.then(function (historyResult) {
- moreActive = false;
+ $scope.state.moreActive = moreActive = false;
if (curJump != jump || curMoreJump != moreJump) return;
angular.forEach(historyResult.history, function (id) {
@@ -1405,9 +1406,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
limit = 10;
}
- moreActive = false;
+ $scope.state.moreActive = moreActive = false;
morePending = false;
- lessActive = false;
+ $scope.state.lessActive = lessActive = false;
lessPending = false;
var prerenderedLen = peerHistory.messages.length;
@@ -1550,23 +1551,31 @@ angular.module('myApp.controllers', ['myApp.i18n'])
var target = $event.target;
while (target) {
- if (target.className.indexOf('im_message_outer_wrap') != -1) {
+ if (target instanceof SVGElement) {
+ target = target.parentNode;
+ continue;
+ }
+ if (target.className && target.className.indexOf('im_message_outer_wrap') != -1) {
if (Config.Mobile) {
return false;
}
break;
}
+ if (target.className &&
+ target.className.indexOf('im_message_date') != -1) {
+ if ($scope.historyState.canReply) {
+ selectedReply(messageID);
+ } else {
+ selectedForward(messageID);
+ }
+ return false;
+ }
if (Config.Mobile &&
+ target.className &&
target.className.indexOf('im_message_body') != -1) {
break;
}
- if (target.tagName == 'A' ||
- target.onclick ||
- target.getAttribute('ng-click')) {
- return false;
- }
- var events = $._data(target, 'events');
- if (events && (events.click || events.mousedown)) {
+ if (target.tagName == 'A' || hasOnlick(target)) {
return false;
}
target = target.parentNode;
@@ -1651,6 +1660,11 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.$broadcast('messages_select');
}
+ function selectInlineBot (botID, $event) {
+ $scope.$broadcast('inline_bot_select', botID);
+ return cancelEvent($event);
+ }
+
function selectedCancel (noBroadcast) {
$scope.selectedMsgs = {};
$scope.selectedCount = 0;
@@ -2069,7 +2083,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.$on('user_update', angular.noop);
})
- .controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppProfileManager, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, MtpApiFileManager, RichTextProcessor) {
+ .controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppProfileManager, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, AppInlineBotsManager, MtpApiFileManager, RichTextProcessor) {
$scope.$watch('curDialog.peer', resetDraft);
$scope.$on('user_update', angular.noop);
@@ -2091,6 +2105,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.$watch('draftMessage.files', onFilesSelected);
$scope.$watch('draftMessage.sticker', onStickerSelected);
$scope.$watch('draftMessage.command', onCommandSelected);
+ $scope.$watch('draftMessage.inlineResultID', onInlineResultSelected);
$scope.$on('history_reply_markup', function (e, peerData) {
if (peerData.peerID == $scope.curDialog.peerID) {
@@ -2098,6 +2113,12 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}
});
+ $scope.$on('inline_bot_select', function (e, botID) {
+ var bot = AppUsersManager.getUser(botID);
+ $scope.draftMessage.text = '@' + bot.username + ' ';;
+ $scope.$broadcast('ui_peer_draft', {focus: true});
+ });
+
$scope.replyKeyboardToggle = replyKeyboardToggle;
$scope.toggleSlash = toggleSlash;
@@ -2250,6 +2271,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.draftMessage.text = '';
$scope.$broadcast('ui_peer_draft');
}
+
+ delete $scope.draftMessage.inlineProgress;
+ $scope.$broadcast('inline_results', false);
}
function applyDraftAttachment (e, attachment) {
@@ -2394,6 +2418,60 @@ angular.module('myApp.controllers', ['myApp.i18n'])
Storage.remove('draft' + $scope.curDialog.peerID);
// console.log(dT(), 'draft delete', 'draft' + $scope.curDialog.peerID);
}
+ checkInlinePattern(newVal);
+ }
+
+ var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/;
+ var getInlineResultsTO = false;
+ var jump = 0;
+
+ function checkInlinePattern (message) {
+ if (getInlineResultsTO) {
+ $timeout.cancel(getInlineResultsTO);
+ }
+ var curJump = ++jump;
+ if (!message || !message.length) {
+ delete $scope.draftMessage.inlineProgress;
+ $scope.$broadcast('inline_results', false);
+ return;
+ }
+ var matches = message.match(inlineUsernameRegex);
+ if (!matches) {
+ delete $scope.draftMessage.inlineProgress;
+ $scope.$broadcast('inline_results', false);
+ return;
+ }
+ var username = matches[1];
+ $scope.draftMessage.inlineProgress = true;
+ AppPeersManager.resolveInlineMention(username).then(function (inlineBot) {
+ if (curJump != jump) {
+ return;
+ }
+ $scope.$broadcast('inline_placeholder', {
+ prefix: '@' + username + matches[2],
+ placeholder: inlineBot.placeholder
+ });
+ if (getInlineResultsTO) {
+ $timeout.cancel(getInlineResultsTO);
+ }
+ getInlineResultsTO = $timeout(function () {
+ AppInlineBotsManager.getInlineResults(inlineBot.id, matches[3], '').then(function (botResults) {
+ getInlineResultsTO = false;
+ if (curJump != jump) {
+ return;
+ }
+ botResults.text = message;
+ $scope.$broadcast('inline_results', botResults);
+ delete $scope.draftMessage.inlineProgress;
+ }, function () {
+ $scope.$broadcast('inline_results', false);
+ delete $scope.draftMessage.inlineProgress;
+ });
+ }, 500);
+ }, function () {
+ $scope.$broadcast('inline_results', false);
+ delete $scope.draftMessage.inlineProgress;
+ });
}
function onTyping () {
@@ -2455,7 +2533,6 @@ angular.module('myApp.controllers', ['myApp.i18n'])
fwdsSend();
}
delete $scope.draftMessage.sticker;
- resetDraft();
}
function onCommandSelected (command) {
@@ -2467,6 +2544,25 @@ angular.module('myApp.controllers', ['myApp.i18n'])
delete $scope.draftMessage.sticker;
delete $scope.draftMessage.text;
delete $scope.draftMessage.command;
+ delete $scope.draftMessage.inlineResultID;
+ $scope.$broadcast('ui_message_send');
+ $scope.$broadcast('ui_peer_draft');
+ }
+
+ function onInlineResultSelected (qID) {
+ if (!qID) {
+ return;
+ }
+ var options = {
+ replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.mid
+ };
+ AppInlineBotsManager.sendInlineResult($scope.curDialog.peerID, qID, options);
+ fwdsSend();
+ resetDraft();
+ delete $scope.draftMessage.sticker;
+ delete $scope.draftMessage.text;
+ delete $scope.draftMessage.command;
+ delete $scope.draftMessage.inlineResultID;
$scope.$broadcast('ui_message_send');
$scope.$broadcast('ui_peer_draft');
}
@@ -4654,11 +4750,14 @@ angular.module('myApp.controllers', ['myApp.i18n'])
.controller('StickersetModalController', function ($scope, $rootScope, $modalInstance, MtpApiManager, RichTextProcessor, AppStickersManager, AppDocsManager, AppMessagesManager, LocationParamsService) {
$scope.slice = {limit: 20, limitDelta: 20};
+ var fullSet;
+
AppStickersManager.getStickerset($scope.inputStickerset).then(function (result) {
$scope.$broadcast('ui_height');
$scope.stickersetLoaded = true;
+ fullSet = result;
$scope.stickerset = result.set;
- $scope.stickersetInstalled = result.installed;
+ $scope.stickersetInstalled = result.set.pFlags.installed == true;
$scope.documents = result.documents;
$scope.stickerEmojis = {};
@@ -4673,7 +4772,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
});
$scope.toggleInstalled = function (installed) {
- AppStickersManager.installStickerset($scope.stickerset, !installed).then(function () {
+ AppStickersManager.installStickerset(fullSet, !installed).then(function () {
$scope.stickersetInstalled = installed;
})
};
diff --git a/app/js/directives.js b/app/js/directives.js
index da7388f0..d0082512 100755
--- a/app/js/directives.js
+++ b/app/js/directives.js
@@ -1099,6 +1099,7 @@ angular.module('myApp.directives', ['myApp.filters'])
historyEl = $('.im_history', element)[0],
scrollableWrap = $('.im_history_scrollable_wrap', element)[0],
scrollable = $('.im_history_scrollable', element)[0],
+ emptyWrapEl = $('.im_history_empty_wrap', element)[0],
bottomPanelWrap = $('.im_bottom_panel_wrap', element)[0],
sendFormWrap = $('.im_send_form_wrap', element)[0],
headWrap = $('.tg_page_head')[0],
@@ -1412,7 +1413,7 @@ angular.module('myApp.directives', ['myApp.filters'])
$(historyMessagesEl).css({marginTop: 0});
var marginTop = scrollableWrap.offsetHeight
- historyMessagesEl.offsetHeight
- - 20
+ - emptyWrapEl.offsetHeight
- (Config.Mobile ? 0 : 39);
if (historyMessagesEl.offsetHeight > 0 && marginTop > 0) {
@@ -1429,8 +1430,7 @@ angular.module('myApp.directives', ['myApp.filters'])
})
- .directive('mySendForm', function (_, $window, $compile, $modalStack, $http, $interpolate, Storage, AppStickersManager, AppDocsManager, ErrorService, shouldFocusOnInteraction) {
-
+ .directive('mySendForm', function (_, $timeout, $compile, $modalStack, $http, $interpolate, Storage, AppStickersManager, AppDocsManager, ErrorService, AppInlineBotsManager, shouldFocusOnInteraction) {
return {
link: link,
scope: {
@@ -1497,6 +1497,11 @@ angular.module('myApp.directives', ['myApp.filters'])
}
});
+ $scope.$on('stickers_changed', function () {
+ emojiTooltip.onStickersChanged();
+ });
+
+
var composerEmojiPanel;
if (emojiPanel) {
composerEmojiPanel = new EmojiPanel(emojiPanel, {
@@ -1506,9 +1511,6 @@ angular.module('myApp.directives', ['myApp.filters'])
});
}
- var peerPhotoCompiled = $compile(' ');
- var cachedPeerPhotos = {};
-
var composer = new MessageComposer(messageField, {
onTyping: function () {
$scope.$emit('ui_typing');
@@ -1516,21 +1518,17 @@ angular.module('myApp.directives', ['myApp.filters'])
getSendOnEnter: function () {
return sendOnEnter;
},
- getPeerImage: function (element, peerID, noReplace) {
- if (cachedPeerPhotos[peerID] && !noReplace) {
- element.replaceWith(cachedPeerPhotos[peerID]);
- return;
- }
+ dropdownDirective: function (element, callback) {
var scope = $scope.$new(true);
- scope.peerID = peerID;
- peerPhotoCompiled(scope, function (clonedElement) {
- cachedPeerPhotos[peerID] = clonedElement;
+ var clonedElement = $compile('
').css({
position: 'absolute',
@@ -289,7 +301,21 @@ function scrollToNode (scrollable, node, scroller) {
}
}
+if (Config.Modes.animations &&
+ typeof window.requestAnimationFrame == 'function') {
+ window.onAnimationFrameCallback = function (cb) {
+ return (function () {
+ window.requestAnimationFrame(cb);
+ });
+ };
+} else {
+ window.onAnimationFrameCallback = function (cb) {
+ return cb;
+ };
+}
+
function onContentLoaded (cb) {
+ cb = onAnimationFrameCallback(cb);
setZeroTimeout(cb);
}
diff --git a/app/js/locales/de-de.json b/app/js/locales/de-de.json
index 95e434be..0acd9c0d 100644
--- a/app/js/locales/de-de.json
+++ b/app/js/locales/de-de.json
@@ -253,6 +253,7 @@
"conversation_media_video": "Video",
"conversation_media_document": "Datei",
"conversation_media_sticker": "Sticker",
+ "conversation_media_gif": "GIF",
"conversation_media_audio": "Audio",
"conversation_media_location": "Standort",
"conversation_media_contact": "Kontakt",
@@ -472,7 +473,9 @@
"password_recover_submit": "Absenden",
"login_controller_unknown_country": "Unbekannt",
"message_forwarded_message": "Weitergeleitete Nachricht",
+ "message_via_bot": "via {bot}",
"message_forwarded_message_mobile": "Weitergeleitet von {from}, {date}",
+ "message_forwarded_via_message_mobile": "Weitergeleitet von {from} via {bot}, {date}",
"message_attach_audio_message": "Sprachnachricht",
"message_attach_audio_play": "Abspielen",
"message_attach_document_open": "Öffnen",
diff --git a/app/js/locales/it-it.json b/app/js/locales/it-it.json
index dc00c2d5..a111bb45 100644
--- a/app/js/locales/it-it.json
+++ b/app/js/locales/it-it.json
@@ -253,6 +253,7 @@
"conversation_media_video": "Video",
"conversation_media_document": "File",
"conversation_media_sticker": "Sticker",
+ "conversation_media_gif": "GIF",
"conversation_media_audio": "Audio",
"conversation_media_location": "Posizione",
"conversation_media_contact": "Contatto",
@@ -472,7 +473,9 @@
"password_recover_submit": "Invia",
"login_controller_unknown_country": "Sconosciuto",
"message_forwarded_message": "Messaggio inoltrato",
+ "message_via_bot": "via {bot}",
"message_forwarded_message_mobile": "Inoltrato da {from},{date}",
+ "message_forwarded_via_message_mobile": "Inoltrato da {from} via {bot}, {date}",
"message_attach_audio_message": "Nota vocale",
"message_attach_audio_play": "Riproduci",
"message_attach_document_open": "Apri",
diff --git a/app/js/locales/pt-br.json b/app/js/locales/pt-br.json
index 19080847..f9beec8a 100644
--- a/app/js/locales/pt-br.json
+++ b/app/js/locales/pt-br.json
@@ -253,6 +253,7 @@
"conversation_media_video": "Vídeo",
"conversation_media_document": "Arquivo",
"conversation_media_sticker": "Sticker",
+ "conversation_media_gif": "GIF",
"conversation_media_audio": "Áudio",
"conversation_media_location": "Localização",
"conversation_media_contact": "Contato",
@@ -472,7 +473,9 @@
"password_recover_submit": "Enviar",
"login_controller_unknown_country": "Desconhecido",
"message_forwarded_message": "Encaminhar mensagem",
+ "message_via_bot": "via {bot}",
"message_forwarded_message_mobile": "Encaminhado de {from}, {date}",
+ "message_forwarded_via_message_mobile": "Encaminhado de {from} via {bot}, {date}",
"message_attach_audio_message": "Mensagem de voz",
"message_attach_audio_play": "Tocar",
"message_attach_document_open": "Abrir",
diff --git a/app/js/locales/ru-ru.json b/app/js/locales/ru-ru.json
index fccd9c81..293b7b8f 100644
--- a/app/js/locales/ru-ru.json
+++ b/app/js/locales/ru-ru.json
@@ -251,8 +251,9 @@
"conversation_you": "Вы",
"conversation_media_photo": "Фотография",
"conversation_media_video": "Видео",
- "conversation_media_document": "File",
+ "conversation_media_document": "Файл",
"conversation_media_sticker": "Стикер",
+ "conversation_media_gif": "GIF",
"conversation_media_audio": "Аудио",
"conversation_media_location": "Местоположение",
"conversation_media_contact": "Контакт",
@@ -357,7 +358,7 @@
"head_edit_messages": "Редактировать сообщения",
"head_media_photos": "Фотографии",
"head_media_video": "Видео",
- "head_media_documents": "Files",
+ "head_media_documents": "Файлы",
"head_media_audio": "Голосовые сообщения",
"head_about": "О приложении",
"head_clear_all": "Очистить всё",
@@ -393,7 +394,7 @@
"im_media": "Медиа",
"im_media_photos": "Фотографии",
"im_media_video": "Видео",
- "im_media_documents": "Files",
+ "im_media_documents": "Файлы",
"im_media_audio": "Голосовые сообщения",
"im_pluralize_participants": "{'one': '{} участник', 'few': '{} участника', 'many': '{} участников', 'other': '{} участников'}",
"im_show_recent_messages": "Показать последние сообщения",
@@ -472,7 +473,9 @@
"password_recover_submit": "Отправить",
"login_controller_unknown_country": "Неизвестно",
"message_forwarded_message": "Пересланное сообщение",
+ "message_via_bot": "via {bot}",
"message_forwarded_message_mobile": "Переслано от {from}, {date}",
+ "message_forwarded_via_message_mobile": "Forwarded from {from} via {bot}, {date}",
"message_attach_audio_message": "Запись голоса",
"message_attach_audio_play": "Воспроизвести",
"message_attach_document_open": "Открыть",
diff --git a/app/js/message_composer.js b/app/js/message_composer.js
index 3cbea068..367bd918 100644
--- a/app/js/message_composer.js
+++ b/app/js/message_composer.js
@@ -364,7 +364,7 @@ EmojiTooltip.prototype.createTooltip = function () {
EmojiTooltip.prototype.selectCategory = function (cat, force) {
- if (this.cat === cat && !force) {
+ if (!this.tab && this.cat === cat && !force) {
return false;
}
$('.active', this.categoriesEl).removeClass('active');
@@ -566,6 +566,12 @@ EmojiTooltip.prototype.onStickersScroll = function (scrollable, scrollTop) {
this.activateStickerCategory();
};
+EmojiTooltip.prototype.onStickersChanged = function () {
+ if (this.tab) {
+ this.updateStickersContents(true);
+ }
+};
+
EmojiTooltip.prototype.activateStickerCategory = function () {
var categoriesEl = this.categoriesEl[1];
var categoryEl = categoriesEl.childNodes[this.cat];
@@ -668,38 +674,19 @@ EmojiPanel.prototype.update = function () {
function MessageComposer (textarea, options) {
+ var self = this;
+
this.textareaEl = $(textarea);
this.setUpInput();
this.autoCompleteWrapEl = $('
').appendTo(document.body);
- this.autoCompleteEl = $('').appendTo(this.autoCompleteWrapEl);
+ var autoCompleteEl = $('
').appendTo(this.autoCompleteWrapEl);
- this.scroller = new Scroller(this.autoCompleteEl, {maxHeight: 180});
-
- var self = this;
- this.autoCompleteEl.on('mousedown', function (e) {
- e = e.originalEvent || e;
- var target = $(e.target), mention, code, command;
- if (target[0].tagName != 'A') {
- target = $(target[0].parentNode);
- }
- if (code = target.attr('data-code')) {
- if (self.onEmojiSelected) {
- self.onEmojiSelected(code, true);
- }
- EmojiHelper.pushPopularEmoji(code);
- }
- if (mention = target.attr('data-mention')) {
- self.onMentionSelected(mention);
- }
- if (command = target.attr('data-command')) {
- if (self.onCommandSelected) {
- self.onCommandSelected(command);
- }
- self.hideSuggestions();
- }
- return cancelEvent(e);
+ options.dropdownDirective(autoCompleteEl, function (scope, newAutoCompleteEl) {
+ self.autoCompleteEl = newAutoCompleteEl;
+ self.autoCompleteScope = scope;
+ self.setUpAutoComplete();
});
this.isActive = false;
@@ -708,16 +695,20 @@ function MessageComposer (textarea, options) {
this.onMessageSubmit = options.onMessageSubmit;
this.getSendOnEnter = options.getSendOnEnter;
this.onFilePaste = options.onFilePaste;
+ this.onCommandSend = options.onCommandSend;
+ this.onInlineResultSend = options.onInlineResultSend;
this.mentions = options.mentions;
this.commands = options.commands;
- this.getPeerImage = options.getPeerImage;
- this.onCommandSend = options.onCommandSend;
}
MessageComposer.autoCompleteRegEx = /(\s|^)(:|@|\/)([A-Za-z0-9\-\+\*@_]*)$/;
MessageComposer.prototype.setUpInput = function () {
+ this.inlinePlaceholderWrap = $('
').prependTo(this.textareaEl[0].parentNode);
+ this.inlinePlaceholderPrefixEl = $('
').appendTo(this.inlinePlaceholderWrap);
+ this.inlinePlaceholderEl = $('
').appendTo(this.inlinePlaceholderWrap);
+
if ('contentEditable' in document.body) {
this.setUpRich();
} else {
@@ -732,6 +723,56 @@ MessageComposer.prototype.setUpInput = function () {
}
}
+MessageComposer.prototype.setInlinePlaceholder = function (prefix, placeholder) {
+ this.inlinePlaceholderPrefix = prefix
+ this.inlinePlaceholderPrefixEl.html(encodeEntities(prefix));
+ this.inlinePlaceholderEl.html(encodeEntities(placeholder));
+ this.onChange();
+}
+
+MessageComposer.prototype.updateInlinePlaceholder = function () {
+ var prefix = this.inlinePlaceholderPrefix;
+ if (prefix) {
+ var value = this.textareaEl.val();
+ this.inlinePlaceholderWrap.toggleClass('active', value == prefix);
+ }
+}
+
+MessageComposer.prototype.setUpAutoComplete = function () {
+ this.scroller = new Scroller(this.autoCompleteEl, {maxHeight: 180});
+
+ var self = this;
+ this.autoCompleteEl.on('mousedown', function (e) {
+ e = e.originalEvent || e;
+ var target = $(e.target), mention, code, command, inlineID;
+ if (target[0].tagName != 'A') {
+ target = $(target[0].parentNode);
+ }
+ if (code = target.attr('data-code')) {
+ if (self.onEmojiSelected) {
+ self.onEmojiSelected(code, true);
+ }
+ EmojiHelper.pushPopularEmoji(code);
+ }
+ if (mention = target.attr('data-mention')) {
+ self.onMentionSelected(mention);
+ }
+ if (command = target.attr('data-command')) {
+ if (self.onCommandSelected) {
+ self.onCommandSelected(command);
+ }
+ self.hideSuggestions();
+ }
+ if (inlineID = target.attr('data-inlineid')) {
+ if (self.onInlineResultSend) {
+ self.onInlineResultSend(inlineID);
+ }
+ self.hideSuggestions();
+ }
+ return cancelEvent(e);
+ });
+}
+
MessageComposer.prototype.setUpRich = function () {
this.textareaEl.hide();
this.richTextareaEl = $('
');
@@ -763,7 +804,7 @@ MessageComposer.prototype.onKeyEvent = function (e) {
if (this.keyupStarted === undefined) {
this.keyupStarted = now;
}
- if (now - this.keyupStarted > 10000) {
+ if (now - this.keyupStarted > 3000 || true) {
this.onChange();
}
else {
@@ -771,6 +812,8 @@ MessageComposer.prototype.onKeyEvent = function (e) {
if (this.wasEmpty != !length) {
this.wasEmpty = !this.wasEmpty;
this.onChange();
+ } else if (this.inlinePlaceholderPrefix) {
+ this.onChange();
} else {
this.updateValueTO = setTimeout(this.onChange.bind(this), 1000);
}
@@ -797,48 +840,57 @@ MessageComposer.prototype.onKeyEvent = function (e) {
if (this.autocompleteShown) {
if (e.keyCode == 38 || e.keyCode == 40) { // UP / DOWN
var next = e.keyCode == 40;
- var currentSelected = $(this.autoCompleteEl).find('.composer_autocomplete_option_active');
-
- if (currentSelected.length) {
- var currentSelectedWrap = currentSelected[0].parentNode;
- var nextWrap = currentSelectedWrap[next ? 'nextSibling' : 'previousSibling'];
- currentSelected.removeClass('composer_autocomplete_option_active');
- if (nextWrap) {
- $(nextWrap).find('a').addClass('composer_autocomplete_option_active');
- this.scroller.scrollToNode(nextWrap);
+ var currentSel = $(this.autoCompleteEl).find('li.composer_autocomplete_option_active');
+ var allLIs = Array.prototype.slice.call($(this.autoCompleteEl).find('li'));
+ var nextSel;
+
+ if (currentSel.length) {
+ var pos = allLIs.indexOf(currentSel[0]);
+ var nextPos = pos + (next ? 1 : -1);
+ nextSel = allLIs[nextPos];
+ currentSel.removeClass('composer_autocomplete_option_active');
+ if (nextSel) {
+ $(nextSel).addClass('composer_autocomplete_option_active');
+ this.scroller.scrollToNode(nextSel);
return cancelEvent(e);
}
}
- var childNodes = this.autoCompleteEl[0].childNodes;
- var nextWrap = childNodes[next ? 0 : childNodes.length - 1];
- this.scroller.scrollToNode(nextWrap);
- $(nextWrap).find('a').addClass('composer_autocomplete_option_active');
+ nextSel = allLIs[next ? 0 : allLIs.length - 1];
+ this.scroller.scrollToNode(nextSel);
+ $(nextSel).addClass('composer_autocomplete_option_active');
return cancelEvent(e);
}
if (e.keyCode == 13 || e.keyCode == 9) { // Enter or Tab
- var currentSelected = $(this.autoCompleteEl).find('.composer_autocomplete_option_active');
- if (!currentSelected.length && e.keyCode == 9) {
- currentSelected = $(this.autoCompleteEl[0].childNodes[0]).find('a');
+ var currentSel = $(this.autoCompleteEl).find('li.composer_autocomplete_option_active');
+ if (!currentSel.length && e.keyCode == 9) {
+ currentSel = $(this.autoCompleteEl).find('li:first');
}
- var code, mention, command;
- if (code = currentSelected.attr('data-code')) {
+ currentSel = currentSel.find('a:first');
+ var code, mention, command, inlineID;
+ if (code = currentSel.attr('data-code')) {
this.onEmojiSelected(code, true);
EmojiHelper.pushPopularEmoji(code);
return cancelEvent(e);
}
- if (mention = currentSelected.attr('data-mention')) {
+ if (mention = currentSel.attr('data-mention')) {
this.onMentionSelected(mention);
return cancelEvent(e);
}
- if (command = currentSelected.attr('data-command')) {
+ if (command = currentSel.attr('data-command')) {
if (this.onCommandSelected) {
this.onCommandSelected(command, e.keyCode == 9);
}
return cancelEvent(e);
}
+ if (inlineID = currentSel.attr('data-inlineid')) {
+ if (self.onInlineResultSend) {
+ self.onInlineResultSend(inlineID);
+ }
+ return cancelEvent(e);
+ }
checkSubmit = true;
}
}
@@ -918,6 +970,13 @@ MessageComposer.prototype.checkAutocomplete = function (forceFull) {
var value = textarea.value;
}
+ if (value &&
+ this.curInlineResults &&
+ this.curInlineResults.text == value) {
+ this.showInlineSuggestions(this.curInlineResults);
+ return;
+ };
+
if (!forceFull) {
value = value.substr(0, pos);
}
@@ -1268,6 +1327,7 @@ MessageComposer.prototype.onChange = function (e) {
delete this.keyupStarted;
this.textareaEl.val(getRichValue(this.richTextareaEl[0])).trigger('change');
}
+ this.updateInlinePlaceholder();
}
MessageComposer.prototype.getEmojiHtml = function (code, emoji) {
@@ -1347,8 +1407,7 @@ MessageComposer.prototype.blur = function () {
}
}
-MessageComposer.prototype.renderSuggestions = function (html) {
- this.autoCompleteEl.html(html.join(''));
+MessageComposer.prototype.renderSuggestions = function () {
this.autoCompleteWrapEl.show();
this.scroller.reinit();
this.updatePosition();
@@ -1356,75 +1415,66 @@ MessageComposer.prototype.renderSuggestions = function (html) {
}
MessageComposer.prototype.showEmojiSuggestions = function (codes) {
- var html = [];
- var iconSize = Config.Mobile ? 26 : 20;
-
- var emoticonCode, emoticonData, spritesheet, pos, categoryIndex;
- var count = Math.min(5, codes.length);
- var i, x, y;
-
- for (i = 0; i < count; i++) {
- emoticonCode = codes[i];
- if (emoticonCode.code) {
- emoticonCode = emoticonCode.code;
- }
- if (emoticonData = Config.Emoji[emoticonCode]) {
- spritesheet = EmojiHelper.spritesheetPositions[emoticonCode];
- categoryIndex = spritesheet[0];
- pos = spritesheet[1];
- x = iconSize * spritesheet[3];
- y = iconSize * spritesheet[2];
- html.push('
:' + encodeEntities(emoticonData[1][0]) + ': ');
- }
- }
-
- this.renderSuggestions(html);
+ var self = this;
+ setZeroTimeout(function () {
+ self.autoCompleteScope.$apply(function () {
+ self.autoCompleteScope.type = 'emoji';
+ self.autoCompleteScope.emojiCodes = codes;
+ });
+ onContentLoaded(function () {
+ self.renderSuggestions();
+ });
+ });
}
MessageComposer.prototype.showMentionSuggestions = function (users) {
- var html = [];
- var user;
- var count = users.length;
- var i;
-
- for (i = 0; i < count; i++) {
- user = users[i];
- html.push('
' + user.rFullName + ' @' + user.username + ' ');
- }
-
- this.renderSuggestions(html);
var self = this;
- this.autoCompleteEl.find('.composer_user_photo').each(function (k, element) {
- self.getPeerImage($(element), element.getAttribute('data-user-id'));
+ setZeroTimeout(function () {
+ self.autoCompleteScope.$apply(function () {
+ self.autoCompleteScope.type = 'mentions';
+ self.autoCompleteScope.mentionUsers = users;
+ });
+ onContentLoaded(function () {
+ self.renderSuggestions();
+ });
});
}
MessageComposer.prototype.showCommandsSuggestions = function (commands) {
- var html = [];
- var command;
- var count = Math.min(200, commands.length);
- var i;
+ var self = this;
+ setZeroTimeout(function () {
+ self.autoCompleteScope.$apply(function () {
+ self.autoCompleteScope.type = 'commands';
+ self.autoCompleteScope.commands = commands;
+ });
+ onContentLoaded(function () {
+ self.renderSuggestions();
+ });
+ });
+}
- for (i = 0; i < count; i++) {
- command = commands[i];
- html.push('
' + encodeEntities(command.value) + ' ' + command.rDescription + ' ');
+MessageComposer.prototype.showInlineSuggestions = function (botResults) {
+ if (!botResults || !botResults.results.length) {
+ this.hideSuggestions();
+ return;
}
-
- this.renderSuggestions(html);
-
var self = this;
- var usedImages = {};
- this.autoCompleteEl.find('.composer_user_photo').each(function (k, element) {
- var noReplace = true;
- var botID = element.getAttribute('data-user-id');
- if (!usedImages[botID]) {
- usedImages[botID] = true;
- noReplace = false;
- }
- self.getPeerImage($(element), botID, noReplace);
+ setZeroTimeout(function () {
+ self.autoCompleteScope.$apply(function () {
+ self.autoCompleteScope.type = 'inline';
+ self.autoCompleteScope.botResults = botResults;
+ });
+ onContentLoaded(function () {
+ self.renderSuggestions();
+ });
});
}
+MessageComposer.prototype.setInlineSuggestions = function (botResults) {
+ this.curInlineResults = botResults;
+ this.checkAutocomplete();
+}
+
MessageComposer.prototype.updatePosition = function () {
var offset = (this.richTextareaEl || this.textareaEl).offset();
var height = this.scroller.updateHeight();
@@ -1438,6 +1488,8 @@ MessageComposer.prototype.updatePosition = function () {
}
MessageComposer.prototype.hideSuggestions = function () {
+ // console.trace();
+ // return;
this.autoCompleteWrapEl.hide();
delete this.autocompleteShown;
}
diff --git a/app/js/messages_manager.js b/app/js/messages_manager.js
index 6ddd8272..547bedcd 100644
--- a/app/js/messages_manager.js
+++ b/app/js/messages_manager.js
@@ -181,7 +181,10 @@ angular.module('myApp.services')
}
NotificationsManager.savePeerSettings(peerID, dialog.notify_settings);
- ApiUpdatesManager.addChannelState(channelID, dialog.pts);
+
+ if (dialog.pts) {
+ ApiUpdatesManager.addChannelState(channelID, dialog.pts);
+ }
}
function getTopMessages (limit) {
@@ -1291,10 +1294,12 @@ angular.module('myApp.services')
isChannel = AppPeersManager.isChannel(peerID),
isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID),
asChannel = isChannel && !isMegagroup ? true : false,
- entities = [],
+ entities = options.entities || [],
message;
- text = RichTextProcessor.parseMarkdown(text, entities);
+ if (!options.viaBotID) {
+ text = RichTextProcessor.parseMarkdown(text, entities);
+ }
if (historyStorage === undefined) {
historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
@@ -1328,6 +1333,7 @@ angular.module('myApp.services')
message: text,
random_id: randomIDS,
reply_to_msg_id: replyToMsgID,
+ via_bot_id: options.viaBotID,
entities: entities,
views: asChannel && 1,
pending: true
@@ -1359,21 +1365,34 @@ angular.module('myApp.services')
if (replyToMsgID) {
flags |= 1;
}
- if (entities.length) {
- flags |= 8;
- }
if (asChannel) {
flags |= 16;
}
+ var apiPromise;
+ if (options.viaBotID) {
+ apiPromise = MtpApiManager.invokeApi('messages.sendInlineBotResult', {
+ flags: flags,
+ peer: AppPeersManager.getInputPeerByID(peerID),
+ random_id: randomID,
+ reply_to_msg_id: getMessageLocalID(replyToMsgID),
+ query_id: options.queryID,
+ id: options.resultID
+ }, sentRequestOptions);
+ } else {
+ if (entities.length) {
+ flags |= 8;
+ }
+ apiPromise = MtpApiManager.invokeApi('messages.sendMessage', {
+ flags: flags,
+ peer: AppPeersManager.getInputPeerByID(peerID),
+ message: text,
+ random_id: randomID,
+ reply_to_msg_id: getMessageLocalID(replyToMsgID),
+ entities: entities
+ }, sentRequestOptions)
+ }
// console.log(flags, entities);
- MtpApiManager.invokeApi('messages.sendMessage', {
- flags: flags,
- peer: AppPeersManager.getInputPeerByID(peerID),
- message: text,
- random_id: randomID,
- reply_to_msg_id: getMessageLocalID(replyToMsgID),
- entities: entities
- }, sentRequestOptions).then(function (updates) {
+ apiPromise.then(function (updates) {
if (updates._ == 'updateShortSentMessage') {
message.flags = updates.flags;
message.date = updates.date;
@@ -1637,7 +1656,8 @@ angular.module('myApp.services')
case 'inputMediaPhoto':
media = {
_: 'messageMediaPhoto',
- photo: AppPhotosManager.getPhoto(inputMedia.id.id)
+ photo: AppPhotosManager.getPhoto(inputMedia.id.id),
+ caption: inputMedia.caption || ''
};
break;
@@ -1648,9 +1668,14 @@ angular.module('myApp.services')
};
media = {
_: 'messageMediaDocument',
- 'document': doc
+ 'document': doc,
+ caption: inputMedia.caption || ''
};
break;
+
+ case 'messageMediaPending':
+ media = inputMedia;
+ break;
}
var flags = 0;
@@ -1684,6 +1709,7 @@ angular.module('myApp.services')
media: media,
random_id: randomIDS,
reply_to_msg_id: replyToMsgID,
+ via_bot_id: options.viaBotID,
views: asChannel && 1,
pending: true
};
@@ -1718,13 +1744,26 @@ angular.module('myApp.services')
sentRequestOptions.afterMessageID = pendingAfterMsgs[peerID].messageID;
}
- MtpApiManager.invokeApi('messages.sendMedia', {
- flags: flags,
- peer: AppPeersManager.getInputPeerByID(peerID),
- media: inputMedia,
- random_id: randomID,
- reply_to_msg_id: getMessageLocalID(replyToMsgID)
- }, sentRequestOptions).then(function (updates) {
+ var apiPromise;
+ if (options.viaBotID) {
+ apiPromise = MtpApiManager.invokeApi('messages.sendInlineBotResult', {
+ flags: flags,
+ peer: AppPeersManager.getInputPeerByID(peerID),
+ random_id: randomID,
+ reply_to_msg_id: getMessageLocalID(replyToMsgID),
+ query_id: options.queryID,
+ id: options.resultID
+ }, sentRequestOptions);
+ } else {
+ apiPromise = MtpApiManager.invokeApi('messages.sendMedia', {
+ flags: flags,
+ peer: AppPeersManager.getInputPeerByID(peerID),
+ media: inputMedia,
+ random_id: randomID,
+ reply_to_msg_id: getMessageLocalID(replyToMsgID)
+ }, sentRequestOptions);
+ }
+ apiPromise.then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates);
}, function (error) {
toggleError(true);
@@ -3007,7 +3046,7 @@ angular.module('myApp.services')
};
}
})
- })
+ });
return {
getConversations: getConversations,
diff --git a/app/js/services.js b/app/js/services.js
index dd036724..18f5876c 100755
--- a/app/js/services.js
+++ b/app/js/services.js
@@ -11,7 +11,7 @@
angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
-.service('AppUsersManager', function ($rootScope, $modal, $modalStack, $filter, $q, qSync, MtpApiFileManager, MtpApiManager, RichTextProcessor, ErrorService, Storage, _) {
+.service('AppUsersManager', function ($rootScope, $modal, $modalStack, $filter, $q, qSync, MtpApiManager, RichTextProcessor, ErrorService, Storage, _) {
var users = {},
usernames = {},
userAccess = {},
@@ -575,7 +575,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
})
-.service('AppChatsManager', function ($q, $rootScope, $modal, _, MtpApiFileManager, MtpApiManager, AppUsersManager, AppPhotosManager, RichTextProcessor) {
+.service('AppChatsManager', function ($q, $rootScope, $modal, _, MtpApiManager, AppUsersManager, AppPhotosManager, RichTextProcessor) {
var chats = {},
usernames = {},
channelAccess = {},
@@ -833,7 +833,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}
})
-.service('AppPeersManager', function (qSync, AppUsersManager, AppChatsManager, MtpApiManager) {
+.service('AppPeersManager', function ($q, qSync, AppUsersManager, AppChatsManager, MtpApiManager) {
function getInputPeer (peerString) {
var firstChar = peerString.charAt(0),
@@ -944,6 +944,24 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
});
}
+ function resolveInlineMention (username) {
+ return resolveUsername(username).then(function (peerID) {
+ if (peerID > 0) {
+ var bot = AppUsersManager.getUser(peerID);
+ if (bot.pFlags.bot && bot.bot_inline_placeholder !== undefined) {
+ return qSync.when({
+ id: peerID,
+ placeholder: bot.bot_inline_placeholder
+ });
+ }
+ }
+ return $q.reject();
+ }, function (error) {
+ error.handled = true;
+ return $q.reject(error);
+ });
+ }
+
function getPeerID (peerString) {
if (angular.isObject(peerString)) {
return peerString.user_id
@@ -990,6 +1008,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
getPeer: getPeer,
getPeerPhoto: getPeerPhoto,
resolveUsername: resolveUsername,
+ resolveInlineMention: resolveInlineMention,
isChannel: isChannel,
isMegagroup: isMegagroup,
isBot: isBot
@@ -1222,6 +1241,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
});
break;
}
+ return $q.reject(error);
});
}
@@ -1907,7 +1927,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}
})
-.service('AppDocsManager', function ($sce, $rootScope, $modal, $window, $q, RichTextProcessor, MtpApiFileManager, FileManager, qSync) {
+.service('AppDocsManager', function ($sce, $rootScope, $modal, $window, $q, $timeout, RichTextProcessor, MtpApiFileManager, FileManager, qSync) {
var docs = {},
docsForHistory = {},
windowW = $(window).width(),
@@ -2096,13 +2116,18 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
});
downloadPromise.then(function (blob) {
- delete historyDoc.progress;
if (blob) {
FileManager.getFileCorrectUrl(blob, doc.mime_type).then(function (url) {
- historyDoc.url = $sce.trustAsResourceUrl(url);
+ var trustedUrl = $sce.trustAsResourceUrl(url);
+ historyDoc.url = trustedUrl;
+ doc.url = trustedUrl;
})
historyDoc.downloaded = true;
}
+ historyDoc.progress.percent = 100;
+ $timeout(function () {
+ delete historyDoc.progress;
+ });
console.log('file save done');
}, function (e) {
console.log('document download failed', e);
@@ -2274,24 +2299,81 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}
})
-.service('AppStickersManager', function ($q, $rootScope, $modal, _, FileManager, MtpApiManager, MtpApiFileManager, AppDocsManager, Storage) {
+.service('AppStickersManager', function ($q, $rootScope, $modal, _, FileManager, MtpApiManager, AppDocsManager, Storage, ApiUpdatesManager) {
- var currentStickers = [];
- var currentStickersets = [];
- var installedStickersets = {};
- var stickersetItems = {};
- var applied = false;
var started = false;
+ var applied = false;
+ var currentStickerSets = [];
+
+ $rootScope.$on('apiUpdate', function (e, update) {
+ if (update._ != 'updateStickerSets' &&
+ update._ != 'updateNewStickerSet' &&
+ update._ != 'updateDelStickerSet' &&
+ update._ != 'updateStickerSetsOrder') {
+ return false;
+ }
+
+ return Storage.get('all_stickers').then(function (stickers) {
+ if (!stickers ||
+ stickers.layer != Config.Schema.API.layer) {
+ $rootScope.$broadcast('stickers_changed');
+ }
+ switch (update._) {
+ case 'updateNewStickerSet':
+ var fullSet = update.stickerset;
+ var set = fullSet.set;
+ var pos = false;
+ for (var i = 0, len = stickers.sets.length; i < len; i++) {
+ if (stickers.sets[i].id == set.id) {
+ pos = i;
+ break;
+ }
+ }
+ if (pos !== false) {
+ stickers.sets.splice(pos, 1);
+ }
+ set.pFlags.installed = true;
+ stickers.sets.unshift(set);
+ stickers.fullSets[set.id] = fullSet;
+ break;
+
+ case 'updateDelStickerSet':
+ var set;
+ for (var i = 0, len = stickers.sets.length; i < len; i++) {
+ set = stickers.sets[i];
+ if (set.id == update.id) {
+ set.pFlags.installed = false;
+ stickers.sets.splice(i, 1);
+ break;
+ }
+ }
+ delete stickers.fullSets[update.id];
+ break;
+
+ case 'updateStickerSetsOrder':
+ var order = update.order;
+ stickers.sets.sort(function (a, b) {
+ return order.indexOf(a.id) - order.indexOf(b.id);
+ });
+ break;
+ }
+ stickers.hash = getStickerSetsHash(stickers.sets);
+ stickers.date = 0;
+ Storage.set({all_stickers: stickers}).then(function () {
+ $rootScope.$broadcast('stickers_changed');
+ });
+ });
+
+ });
return {
start: start,
+ getStickers: getStickers,
openStickersetLink: openStickersetLink,
openStickerset: openStickerset,
installStickerset: installStickerset,
pushPopularSticker: pushPopularSticker,
- getStickers: getStickers,
- getStickerset: getStickerset,
- getStickersImages: getStickersImages
+ getStickerset: getStickerset
};
function start () {
@@ -2301,104 +2383,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}
}
- function getPopularStickers () {
- return Storage.get('stickers_popular').then(function (popStickers) {
- var result = [];
- var i, len, docID;
- if (popStickers && popStickers.length) {
- for (i = 0, len = popStickers.length; i < len; i++) {
- docID = popStickers[i][0];
- if (AppDocsManager.hasDoc(docID)) {
- result.push({id: docID, rate: popStickers[i][1]});
- }
- }
- };
- return result;
- });
- }
-
- function pushPopularSticker (id) {
- getPopularStickers().then(function (popularStickers) {
- var exists = false;
- var count = popularStickers.length;
- var result = [];
- for (var i = 0; i < count; i++) {
- if (popularStickers[i].id == id) {
- exists = true;
- popularStickers[i].rate++;
- }
- result.push([popularStickers[i].id, popularStickers[i].rate]);
- }
- if (exists) {
- result.sort(function (a, b) {
- return b[1] - a[1];
- });
- } else {
- if (result.length > 15) {
- result = result.slice(0, 15);
- }
- result.push([id, 1]);
- }
- ConfigStorage.set({stickers_popular: result});
- });
- }
-
- function processRawStickers(stickers) {
- if (applied !== stickers.hash) {
- applied = stickers.hash;
- var i, j, len1, len2, doc, set, setItems, fullSet;
-
- currentStickersets = [];
- currentStickers = [];
- len1 = stickers.sets.length;
- for (i = 0; i < len1; i++) {
- set = stickers.sets[i];
- fullSet = stickers.fullSets[set.id];
- len2 = fullSet.documents.length;
- setItems = [];
- for (j = 0; j < len2; j++) {
- doc = fullSet.documents[j];
- AppDocsManager.saveDoc(doc);
- currentStickers.push(doc.id);
- setItems.push(doc.id);
- }
- currentStickersets.push({
- id: set.id,
- title: set.title,
- short_name: set.short_name,
- installed: (set.flags & (1 << 0)) > 0,
- disabled: (set.flags & (1 << 1)) > 0,
- official: (set.flags & (1 << 2)) > 0,
- docIDs: setItems
- });
- installedStickersets[set.id] = true;
- }
- }
-
- return getPopularStickers().then(function (popularStickers) {
- var resultStickersets = currentStickersets;
- if (popularStickers.length) {
- resultStickersets = currentStickersets.slice();
- var setItems = [];
- var i, len;
- for (i = 0, len = popularStickers.length; i < len; i++) {
- setItems.push(popularStickers[i].id);
- }
- resultStickersets.unshift({
- id: 0,
- title: _('im_stickers_tab_recent_raw'),
- short_name: '',
- installed: true,
- disabled: false,
- official: false,
- docIDs: setItems
- })
- }
-
- return resultStickersets;
- });
- }
-
function getStickers (force) {
return Storage.get('all_stickers').then(function (stickers) {
var layer = Config.Schema.API.layer;
@@ -2424,7 +2408,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return processRawStickers(newStickers);
}
- return getStickerSets(newStickers).then(function () {
+ return getStickerSets(newStickers, stickers && stickers.fullSets).then(function () {
Storage.set({all_stickers: newStickers});
return processRawStickers(newStickers);
});
@@ -2433,9 +2417,54 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
})
}
- function getStickerSets (allStickers) {
+ function processRawStickers(stickers) {
+ if (applied !== stickers.hash) {
+ applied = stickers.hash;
+ var i, j, len1, len2, doc, set, docIDs, documents;
+
+ currentStickerSets = [];
+ len1 = stickers.sets.length;
+ for (i = 0; i < len1; i++) {
+ set = stickers.sets[i];
+ if (set.pFlags.disabled) {
+ continue;
+ }
+ documents = stickers.fullSets[set.id].documents;
+ len2 = documents.length;
+ docIDs = [];
+ for (j = 0; j < len2; j++) {
+ doc = documents[j];
+ AppDocsManager.saveDoc(doc);
+ docIDs.push(doc.id);
+ }
+ set.docIDs = docIDs;
+ currentStickerSets.push(set);
+ }
+ }
+
+ return getPopularStickers().then(function (popularStickers) {
+ var resultStickersets = currentStickerSets;
+ if (popularStickers.length) {
+ resultStickersets = currentStickerSets.slice();
+ var docIDs = [];
+ var i, len;
+ for (i = 0, len = popularStickers.length; i < len; i++) {
+ docIDs.push(popularStickers[i].id);
+ }
+ resultStickersets.unshift({
+ id: 0,
+ title: _('im_stickers_tab_recent_raw'),
+ short_name: '',
+ docIDs: docIDs
+ });
+ }
+ return resultStickersets;
+ });
+ }
+
+ function getStickerSets (allStickers, prevCachedSets) {
var promises = [];
- var cachedSets = allStickers.fullSets || {};
+ var cachedSets = prevCachedSets || allStickers.fullSets || {};
allStickers.fullSets = {};
angular.forEach(allStickers.sets, function (shortSet) {
var fullSet = cachedSets[shortSet.id];
@@ -2457,24 +2486,46 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return $q.all(promises);
}
- function downloadStickerThumb (docID) {
- var doc = AppDocsManager.getDoc(docID);
- var thumbLocation = angular.copy(doc.thumb.location);
- thumbLocation.sticker = true;
- return MtpApiFileManager.downloadSmallFile(thumbLocation).then(function (blob) {
- return {
- id: doc.id,
- src: FileManager.getUrl(blob, 'image/webp')
+ function getPopularStickers () {
+ return Storage.get('stickers_popular').then(function (popStickers) {
+ var result = [];
+ var i, len, docID;
+ if (popStickers && popStickers.length) {
+ for (i = 0, len = popStickers.length; i < len; i++) {
+ docID = popStickers[i][0];
+ if (AppDocsManager.hasDoc(docID)) {
+ result.push({id: docID, rate: popStickers[i][1]});
+ }
+ }
};
+ return result;
});
}
- function getStickersImages () {
- var promises = [];
- angular.forEach(currentStickers, function (docID) {
- promises.push(downloadStickerThumb (docID));
+ function pushPopularSticker (id) {
+ getPopularStickers().then(function (popularStickers) {
+ var exists = false;
+ var count = popularStickers.length;
+ var result = [];
+ for (var i = 0; i < count; i++) {
+ if (popularStickers[i].id == id) {
+ exists = true;
+ popularStickers[i].rate++;
+ }
+ result.push([popularStickers[i].id, popularStickers[i].rate]);
+ }
+ if (exists) {
+ result.sort(function (a, b) {
+ return b[1] - a[1];
+ });
+ } else {
+ if (result.length > 15) {
+ result = result.slice(0, 15);
+ }
+ result.push([id, 1]);
+ }
+ ConfigStorage.set({stickers_popular: result});
});
- return $q.all(promises);
}
function getStickerset (inputStickerset) {
@@ -2484,31 +2535,32 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
for (var i = 0; i < result.documents.length; i++) {
AppDocsManager.saveDoc(result.documents[i]);
}
- result.installed = installedStickersets[result.set.id] !== undefined;
return result;
});
}
- function installStickerset (set, uninstall) {
+ function installStickerset (fullSet, uninstall) {
var method = uninstall
? 'messages.uninstallStickerSet'
: 'messages.installStickerSet';
var inputStickerset = {
_: 'inputStickerSetID',
- id: set.id,
- access_hash: set.access_hash
+ id: fullSet.set.id,
+ access_hash: fullSet.set.access_hash
};
return MtpApiManager.invokeApi(method, {
stickerset: inputStickerset,
disabled: false
}).then(function (result) {
+ var update;
if (uninstall) {
- delete installedStickersets[set.id];
+ update = {_: 'updateDelStickerSet', id: fullSet.set.id};
} else {
- installedStickersets[set.id] = true;
+ update = {_: 'updateNewStickerSet', stickerset: fullSet};
}
- Storage.remove('all_stickers').then(function () {
- getStickers(true);
+ ApiUpdatesManager.processUpdateMessage({
+ _: 'updateShort',
+ update: update
});
});
}
@@ -2530,6 +2582,186 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
windowClass: 'stickerset_modal_window mobile_modal'
});
}
+
+ function getStickerSetsHash (stickerSets) {
+ var acc = 0, set;
+ for (var i = 0; i < stickerSets.length; i++) {
+ set = stickerSets[i];
+ if (set.pFlags.disabled || !set.pFlags.installed) {
+ continue;
+ }
+ acc = ((acc * 20261) + 0x80000000 + set.hash) % 0x80000000;
+ }
+ return acc;
+ }
+})
+
+.service('AppInlineBotsManager', function (MtpApiManager, AppMessagesManager, AppDocsManager, AppPhotosManager, RichTextProcessor, AppUsersManager) {
+
+ var inlineResults = {};
+
+ return {
+ sendInlineResult: sendInlineResult,
+ regroupWrappedResults: regroupWrappedResults,
+ getInlineResults: getInlineResults
+ };
+
+ function getInlineResults (botID, query, offset) {
+ return MtpApiManager.invokeApi('messages.getInlineBotResults', {
+ bot: AppUsersManager.getUserInput(botID),
+ query: query,
+ offset: offset
+ }, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function(botResults) {
+ var queryID = botResults.query_id;
+ delete botResults._;
+ delete botResults.flags;
+ delete botResults.query_id;
+
+ angular.forEach(botResults.results, function (result) {
+ var qID = queryID + '_' + result.id;
+ result.qID = qID;
+ result.botID = botID;
+
+ result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true});
+ result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true});
+ result.initials = (result.url || result.title || result.type || '').substr(0, 1)
+
+ if (result.document) {
+ AppDocsManager.saveDoc(result.document);
+ }
+ if (result.photo) {
+ AppPhotosManager.savePhoto(result.photo);
+ }
+
+ inlineResults[qID] = result;
+ });
+ return botResults;
+ });
+ }
+
+ function regroupWrappedResults (results, rowW, rowH) {
+ if (!results ||
+ !results[0] ||
+ results[0].type != 'photo' && results[0].type != 'gif') {
+ return;
+ }
+ var ratios = [];
+ angular.forEach(results, function (result) {
+ var w, h;
+ if (result._ == 'botInlineMediaResultDocument') {
+ w = result.document.w;
+ h = result.document.h;
+ }
+ else if (result._ == 'botInlineMediaResultPhoto') {
+ var photoSize = (result.photo.sizes || [])[0];
+ w = photoSize && photoSize.w;
+ h = photoSize && photoSize.h;
+ }
+ else {
+ w = result.w;
+ h = result.h;
+ }
+ if (!w || !h) {
+ w = h = 1;
+ }
+ ratios.push(w / h);
+ });
+
+ var rows = [];
+ var curCnt = 0;
+ var curW = 0;
+ angular.forEach(ratios, function (ratio) {
+ var w = ratio * rowH;
+ curW += w;
+ if (!curCnt || curCnt < 4 && curW < (rowW * 1.1)) {
+ curCnt++;
+ } else {
+ rows.push(curCnt);
+ curCnt = 1;
+ curW = w;
+ }
+ });
+ if (curCnt) {
+ rows.push(curCnt);
+ }
+
+ var i = 0;
+ var thumbs = [];
+ var lastRowI = rows.length - 1;
+ angular.forEach(rows, function (rowCnt, rowI) {
+ var lastRow = rowI == lastRowI;
+ var curRatios = ratios.slice(i, i + rowCnt);
+ var sumRatios = 0;
+ angular.forEach(curRatios, function (ratio) {
+ sumRatios += ratio;
+ });
+ angular.forEach(curRatios, function (ratio, j) {
+ var thumbH = rowH;
+ var thumbW = rowW * ratio / sumRatios;
+ var realW = thumbH * ratio;
+ if (lastRow && thumbW > realW) {
+ thumbW = realW;
+ }
+ var result = results[i + j];
+ result.thumbW = Math.floor(thumbW);
+ result.thumbH = Math.floor(thumbH);
+ });
+
+ i += rowCnt;
+ });
+ }
+
+ function sendInlineResult (peerID, qID, options) {
+ var inlineResult = inlineResults[qID];
+ if (inlineResult === undefined) {
+ return false;
+ }
+ var splitted = qID.split('_');
+ var queryID = splitted.shift();
+ var resultID = splitted.join('_');
+ options = options || {};
+ options.viaBotID = inlineResult.botID;
+ options.queryID = queryID;
+ options.resultID = resultID;
+
+ if (inlineResult.send_message._ == 'botInlineMessageText') {
+ options.entities = inlineResult.send_message.entities;
+ AppMessagesManager.sendText(peerID, inlineResult.send_message.message, options);
+ } else {
+ var caption = '';
+ if (inlineResult.send_message._ == 'botInlineMessageMediaAuto') {
+ caption = inlineResult.send_message.caption;
+ }
+ var inputMedia = false;
+ if (inlineResult._ == 'botInlineMediaResultDocument') {
+ var doc = inlineResult.document;
+ inputMedia = {
+ _: 'inputMediaDocument',
+ id: {_: 'inputDocument', id: doc.id, access_hash: doc.access_hash},
+ caption: caption
+ };
+ }
+ else if (inlineResult._ == 'botInlineMediaResultPhoto') {
+ var photo = inlineResult.photo;
+ inputMedia = {
+ _: 'inputMediaPhoto',
+ id: {_: 'inputPhoto', id: photo.id, access_hash: photo.access_hash},
+ caption: caption
+ };
+ }
+ if (!inputMedia) {
+ inputMedia = {
+ _: 'messageMediaPending',
+ type: inlineResult.type,
+ file_name: inlineResult.title || inlineResult.content_url || inlineResult.url,
+ size: 0,
+ progress: {percent: 30, total: 0}
+ };
+ }
+ AppMessagesManager.sendOther(peerID, inputMedia, options);
+ }
+ }
+
})
.service('ApiUpdatesManager', function ($rootScope, MtpNetworkerFactory, AppUsersManager, AppChatsManager, AppPeersManager, MtpApiManager) {
@@ -2828,6 +3060,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}
function addChannelState (channelID, pts) {
+ if (!pts) {
+ throw new Error('Add channel state without pts ' + channelID);
+ }
if (channelStates[channelID] === undefined) {
channelStates[channelID] = {
pts: pts,
@@ -2842,9 +3077,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function getChannelState (channelID, pts) {
if (channelStates[channelID] === undefined) {
- if (!pts) {
- throw new Error('Get channel empty state without pts ' + channelID);
- }
addChannelState(channelID, pts);
}
return channelStates[channelID];
@@ -3997,7 +4229,11 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
type: 'JUMP_EXT_URL',
url: url
}).then(function () {
- window.open(url, '_blank');
+ var target = '_blank';
+ if (url.search('https://telegram.me/') === 0) {
+ target = '_self';
+ }
+ window.open(url, target);
});
return true;
}
@@ -4142,4 +4378,4 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
start: start,
shareUrl: shareUrl
};
-})
+})
\ No newline at end of file
diff --git a/app/less/app.less b/app/less/app.less
index 1fa9862c..f8e43dcd 100644
--- a/app/less/app.less
+++ b/app/less/app.less
@@ -420,20 +420,56 @@ a {
display: block;
border-radius: 100%;
}
-.progress-arc circle {
- stroke-dashoffset: 0;
- stroke: rgba(0,0,0,0.3);
- stroke-width: 3px;
-}
.progress-arc .progress-arc-bar {
- stroke: #FFF;
+ stroke-dashoffset: 0;
transform-origin: center center;
- transition: stroke-dasharray 500ms linear;
+ fill: transparent;
+
+ .progress-arc-intermediate & {
+ stroke: #68a4d1;
+
+ -webkit-animation: infinite_rotation 0.8s linear infinite;
+ -moz-animation: infinite_rotation 0.8s linear infinite;
+ -ms-animation: infinite_rotation 0.8s linear infinite;
+ animation: infinite_rotation 0.8s linear infinite;
+ }
- -webkit-animation: infinite_rotation 2s linear infinite;
- -moz-animation: infinite_rotation 2s linear infinite;
- -ms-animation: infinite_rotation 2s linear infinite;
- animation: infinite_rotation 2s linear infinite;
+ .composer_progress_icon & {
+ stroke: rgba(0,0,0,0.3);
+ }
+
+ .progress-arc-percent & {
+ stroke: #FFF;
+ stroke: rgba(255,255,255,0.95);
+
+ transition: stroke-dasharray 500ms linear;
+
+ -webkit-animation: infinite_rotation 2s linear infinite;
+ -moz-animation: infinite_rotation 2s linear infinite;
+ -ms-animation: infinite_rotation 2s linear infinite;
+ animation: infinite_rotation 2s linear infinite;
+ }
+}
+.stop0 {
+ stop-opacity: 1.0;
+ stop-color: #68a4d1;
+ .composer_progress_icon & {
+ stop-color: rgba(0,0,0,0.3);
+ }
+}
+.stop60 {
+ stop-opacity: 1.0;
+ stop-color: #68a4d1;
+ .composer_progress_icon & {
+ stop-color: rgba(0,0,0,0.3);
+ }
+}
+.stop100 {
+ stop-opacity: 0.0;
+ stop-color: #68a4d1;
+ .composer_progress_icon & {
+ stop-color: rgba(0,0,0,0.3);
+ }
}
/* Infinite rotation */
@@ -926,13 +962,14 @@ a.tg_radio_on:hover i.icon-radio {
background-position: -5px -10px;
}
.icon-tg-title {
- width: 63px;
- height: 16px;
+ width: 62px;
+ height: 14px;
display: inline-block;
vertical-align: middle;
-
- .image-2x('../img/Telegram.png', 63px, 16px);
+ background-image: url('../img/Telegram.svg');
+ background-repeat: no-repeat;
background-position: 0 0;
+ margin-top: 1px;
}
.login_head_submit_wrap,
.login_head_submit_progress {
@@ -1392,7 +1429,8 @@ a.im_dialog_selected {
}
.im_history {
- padding: 20px 0 0 0;
+ // padding: 20px 0 0 0;
+ padding: 0;
position: relative;
}
.im_message_unread_split {
@@ -1403,12 +1441,14 @@ a.im_dialog_selected {
margin: 10px 0;
}
.im_message_author,
-.im_message_fwd_author {
+.im_message_fwd_author,
+.im_message_via_author {
color: #3a6d99;
font-weight: bold;
}
.non_osx .im_message_author,
-.non_osx .im_message_fwd_author {
+.non_osx .im_message_fwd_author,
+.non_osx .im_message_via_author {
font-size: 12px;
}
.im_message_author_via {
@@ -1505,6 +1545,9 @@ div.im_message_video_thumb {
.image-2x('../img/icons/IconsetW.png', 42px, 1171px);
background-position: 0 -590px;
+ .is_2x & {
+ background-position: 0 -591px;
+ }
}
.im_message_geopoint {
@@ -1999,6 +2042,10 @@ img.im_message_document_thumb {
padding: 0 0 20px 10px;
}
+.im_message_date {
+ cursor: pointer;
+}
+
div.im_message_author,
div.im_message_body {
display: block;
@@ -2245,6 +2292,37 @@ a.im_message_fwd_photo {
display: none;
}
}
+.im_history_loading {
+ width: 60px;
+ margin: 0 auto;
+ visibility: hidden;
+
+ &.vertical-aligned {
+ visibility: visible;
+ }
+}
+
+.im_history_loading_more {
+ display: block;
+ width: 26px;
+ margin: 0 auto;
+ padding: 20px 0 0;
+ visibility: hidden;
+
+ &.im_history_loading_more_active {
+ visibility: visible;
+ }
+}
+.im_history_loading_less {
+ display: block;
+ width: 26px;
+ margin: 0 auto;
+ visibility: hidden;
+
+ &.im_history_loading_less_active {
+ visibility: visible;
+ }
+}
.im_send_panel_wrap {
margin: 0 auto;
@@ -2293,6 +2371,22 @@ textarea.im_message_field {
height: 50px;
resize: none;
}
+.im_inline_placeholder_wrap {
+ position: absolute;
+ margin-top: 2px;
+ white-space: nowrap;
+ pointer-events: none;
+ display: none;
+}
+.im_inline_placeholder_wrap.active {
+ display: block;
+}
+.im_inline_placeholder_prefix {
+ visibility: hidden;
+}
+.im_inline_placeholder {
+ color: #9aa2ab;
+}
.icon-online {
background: #6ec26d;
@@ -2423,7 +2517,27 @@ img.img_fullsize {
}
/* Message composer */
+.composer_progress_icon {
+ display: block;
+ opacity: 0;
+ position: absolute;
+ right: 3px;
+ top: 2px;
+ cursor: pointer;
+ padding: 0;
+
+ width: 22px;
+ height: 22px;
+ margin-top: 1px;
+ transition: opacity cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.2s;
+ pointer-events: none;
+
+ .composer_progress_enabled & {
+ opacity: 1;
+ }
+}
.composer_emoji_insert_btn {
+ opacity: 1;
display: block;
position: absolute;
right: 3px;
@@ -2434,7 +2548,13 @@ img.img_fullsize {
width: 22px;
height: 22px;
margin-top: 1px;
+ transition: opacity cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.2s;
+
+ .composer_progress_enabled & {
+ opacity: 0;
+ }
}
+
.icon-emoji {
display: inline-block;
width: 22px;
@@ -2757,6 +2877,7 @@ a.composer_emoji_btn {
border-radius: 0;
margin-top: -5px;
margin-left: -1px;
+ width: 180px;
}
.composer_dropdown {
@@ -2780,9 +2901,10 @@ a.composer_emoji_btn {
}
li a:hover,
- li a.composer_autocomplete_option_active {
+ li.composer_autocomplete_option_active a {
color: #52719a;
background: #f2f6fa;
+ text-decoration: none;
}
}
@@ -2802,7 +2924,7 @@ a.composer_emoji_btn {
.composer_dropdown {
li a:hover .composer_user_mention,
- li a.composer_autocomplete_option_active .composer_user_mention {
+ li.composer_autocomplete_option_active a .composer_user_mention {
color: #698192;
}
}
@@ -2861,7 +2983,7 @@ a.composer_emoji_btn {
text-overflow: ellipsis;
}
a.composer_command_option:hover .composer_command_desc,
-a.composer_command_option.composer_autocomplete_option_active .composer_command_desc {
+.composer_autocomplete_option_active a.composer_command_option .composer_command_desc {
color: #698192;
}
.composer_command_desc .emoji {
@@ -3031,6 +3153,64 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before {
}
}
+.inline_results_wrap {
+ line-height: 0;
+}
+.inline_result_wrap {
+ display: block;
+}
+.inline_result_gif,
+.inline_result_photo {
+ display: inline-block;
+}
+.inline_result_article {
+ display: block;
+}
+.inline_article_thumb_wrap {
+ width: 50px;
+ height: 50px;
+ margin-right: 10px;
+ pointer-events: none;
+}
+.inline_article_thumb {
+ max-width: 50px;
+ max-height: 50px;
+ line-height: 0;
+}
+.inline_article_thumb_initials {
+ background: rgba(0,0,0, 0.05);
+ line-height: 50px;
+ text-align: center;
+ font-size: 25px;
+ text-transform: uppercase;
+}
+.inline_article_content_wrap {
+ overflow: hidden;
+ pointer-events: none;
+}
+.inline_article_title {
+ font-weight: bold;
+}
+
+
+.composer_dropdown > li.inline_result_gif > a,
+.composer_dropdown > li.inline_result_photo > a {
+ padding: 0;
+ line-height: 0;
+ display: block;
+ overflow: hidden;
+}
+.inline_result_gif .img_gif_video,
+.inline_result_photo .inline_result_photo_image {
+ object-fit: cover;
+}
+.inline_result_gif_mtproto,
+.inline_result_gif_http,
+.inline_result_photo_mtproto,
+.inline_result_photo_http {
+ pointer-events: none;
+}
+
.error_modal_window {
.modal-dialog {
@@ -3553,64 +3733,83 @@ h5 {
}
/* Gif documents */
-.img_gif_with_progress_wrap {
+.img_gif_image_wrap {
position: relative;
overflow: hidden;
- float: left;
- margin-top: 3px;
- max-width: 100%;
+}
+.img_gif_meta {
+ background: rgba(0,0,0,0.3);
+ width: 40px;
+ height: 40px;
+ line-height: 0;
+ position: absolute;
+ z-index: 2;
+ border-radius: 50%;
+ overflow: hidden;
+ margin: 0 auto;
+ top: 50%;
+ left: 50%;
+ margin-left: -20px;
+ margin-top: -20px;
+ pointer-events: none;
+}
+.img_gif_label {
+ font-weight: bold;
+ color: #FFF;
+ display: block;
+ line-height: 40px;
+ font-size: 13px;
+ text-align: center;
+}
+.icon-cancel {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin-left: -9px;
+ margin-top: -1px;
+
+ .icon-bar {
+ display: block;
+ width: 18px;
+ height: 2px;
+ background: #FFF;
+ transform-origin: 50% 50%;
+
+ &:first-child {
+ .transform(rotate(-45deg));
+ }
+ &:last-child {
+ .transform(translate3d(0,-2px,0) rotate(45deg));
+ }
+ }
}
.img_gif_thumb {
- -webkit-filter: blur(3px);
- -moz-filter: blur(3px);
- -o-filter: blur(3px);
- -ms-filter: blur(3px);
- filter: blur(3px);
+ -webkit-filter: blur(2px);
+ -moz-filter: blur(2px);
+ -o-filter: blur(2px);
+ -ms-filter: blur(2px);
+ filter: blur(2px);
filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='3');
- margin: -1px;
- padding: 1px;
+ transform-origin: center center;
+ -webkit-transform-origin: center center;
+ -webkit-transform: scale(1.02, 1.02);
+ transform: scale(1.02, 1.02);
+
max-width: 100%;
height: auto;
}
-.img_gif_image {
- max-width: 100%;
-}
-.img_gif_info_wrap {
- color: #fff;
- font-size: 10px;
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- padding: 4px;
+
+.img_gif_meta_contents {
+ transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.2s;
}
-.img_gif_label,
-.img_gif_size {
- padding: 1px 8px;
- background: rgba(0,0,0,0.5);
- border-radius: 3px;
- overflow: hidden;
+.img_gif_meta_contents.ng-leave.ng-leave-active,
+.img_gif_meta_contents.ng-enter {
+ opacity: 0;
}
-
-.img_gif_progress_wrap {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
-
- .tg_progress {
- background: rgba(0,0,0, 0.6);
- border-color: rgba(0,0,0, 0.6);
- border-width: 8px;
- height: 18px;
- border-radius: 0;
- }
-
- .progress-bar {
- background: #fff;
- height: 2px;
- }
+.img_gif_meta_contents.ng-leave,
+.img_gif_meta_contents.ng-enter.ng-enter-active {
+ opacity: 1;
}
.countries_modal_window {
diff --git a/app/less/desktop.less b/app/less/desktop.less
index b0027535..08b6f42e 100644
--- a/app/less/desktop.less
+++ b/app/less/desktop.less
@@ -748,7 +748,6 @@ a.footer_link.active:active {
line-height: 18px;
width: 100%;
height: 39px;
- padding: 13px 0 8px;
overflow: hidden;
-webkit-user-select: none;
}
@@ -758,7 +757,7 @@ a.footer_link.active:active {
color: #999;
max-width: 556px;
margin: 0 auto;
- padding: 0 81px 0 85px;
+ padding: 13px 81px 8px 85px;
a.im_history_typing_author {
color: #999;
@@ -767,6 +766,10 @@ a.footer_link.active:active {
}
}
+.im_history_loading_less {
+ margin-top: 5px;
+}
+
/* Contacts modal */
.contacts_modal {
&_window {
diff --git a/app/partials/desktop/composer_dropdown.html b/app/partials/desktop/composer_dropdown.html
new file mode 100644
index 00000000..f1d5e4ed
--- /dev/null
+++ b/app/partials/desktop/composer_dropdown.html
@@ -0,0 +1,27 @@
+
\ No newline at end of file
diff --git a/app/partials/desktop/full_gif.html b/app/partials/desktop/full_gif.html
index 4c96f20e..ae2f3024 100644
--- a/app/partials/desktop/full_gif.html
+++ b/app/partials/desktop/full_gif.html
@@ -3,11 +3,14 @@