diff --git a/app/img/icons/IconsetSmiles.png b/app/img/icons/IconsetSmiles.png index 128f3608..7ee73406 100644 Binary files a/app/img/icons/IconsetSmiles.png and b/app/img/icons/IconsetSmiles.png differ diff --git a/app/img/icons/IconsetSmiles_2x.png b/app/img/icons/IconsetSmiles_2x.png index d6594207..b05da5ed 100644 Binary files a/app/img/icons/IconsetSmiles_2x.png and b/app/img/icons/IconsetSmiles_2x.png differ diff --git a/app/js/controllers.js b/app/js/controllers.js index 26dd8634..2bdd9460 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -408,11 +408,12 @@ angular.module('myApp.controllers', ['myApp.i18n']) LayoutSwitchService.start(); }) - .controller('AppIMController', function ($scope, $location, $routeParams, $modal, $rootScope, $modalStack, MtpApiManager, AppUsersManager, AppChatsManager, AppPeersManager, ContactsSelectService, ChangelogNotifyService, ErrorService, AppRuntimeManager, HttpsMigrateService, LayoutSwitchService, LocationParamsService, AppStickersManager) { + .controller('AppIMController', function ($q, qSync, $scope, $location, $routeParams, $modal, $rootScope, $modalStack, MtpApiManager, AppUsersManager, AppChatsManager, AppPeersManager, ContactsSelectService, ChangelogNotifyService, ErrorService, AppRuntimeManager, HttpsMigrateService, LayoutSwitchService, LocationParamsService, AppStickersManager) { $scope.$on('$routeUpdate', updateCurDialog); var pendingParams = false; + var pendingShare = false; $scope.$on('history_focus', function (e, peerData) { $modalStack.dismissAll(); if (peerData.peerString == $scope.curDialog.peer && @@ -423,7 +424,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) var peerID = AppPeersManager.getPeerID(peerData.peerString); var username = AppPeersManager.getPeer(peerID).username; var peer = username ? '@' + username : peerData.peerString; - if (peerData.messageID || peerData.startParam) { + if (peerData.messageID || peerData.startParam || peerData.shareUrl) { pendingParams = { messageID: peerData.messageID, startParam: peerData.startParam @@ -431,6 +432,12 @@ angular.module('myApp.controllers', ['myApp.i18n']) } else { pendingParams = false; } + if (peerData.shareUrl) { + pendingShare = { + url: peerData.shareUrl, + text: peerData.shareText + }; + } if ($routeParams.p != peer) { $location.url('/im?p=' + peer); } else { @@ -595,22 +602,28 @@ angular.module('myApp.controllers', ['myApp.i18n']) var addParams = pendingParams || {}; pendingParams = false; addParams.messageID = parseInt(addParams.messageID) || false; - addParams.startParam = addParams.startParam || false; + addParams.startParam = addParams.startParam; + var peerStringPromise; if ($routeParams.p && $routeParams.p.charAt(0) == '@') { if ($scope.curDialog === undefined) { $scope.curDialog = {}; } - AppPeersManager.resolveUsername($routeParams.p.substr(1)).then(function (peerID) { - $scope.curDialog = angular.extend({ - peer: AppPeersManager.getPeerString(peerID) - }, addParams); + peerStringPromise = AppPeersManager.resolveUsername($routeParams.p.substr(1)).then(function (peerID) { + return qSync.when(AppPeersManager.getPeerString(peerID)); }); } else { + peerStringPromise = qSync.when($routeParams.p); + } + peerStringPromise.then(function (peerString) { $scope.curDialog = angular.extend({ - peer: $routeParams.p || false + peer: peerString }, addParams); - } + if (pendingShare) { + $scope.$broadcast('peer_share', pendingShare); + pendingShare = false; + } + }); } ChangelogNotifyService.checkUpdate(); @@ -2010,6 +2023,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.$watch('curDialog.peer', resetDraft); $scope.$on('user_update', angular.noop); + $scope.$on('peer_share', applyShare); $scope.$on('reply_selected', function (e, messageID) { replySelect(messageID); }); @@ -2171,6 +2185,23 @@ angular.module('myApp.controllers', ['myApp.i18n']) } } + function applyShare (e, shareData) { + console.log('apply share', shareData); + var url = shareData.url; + var text = shareData.text || ''; + + $timeout(function () { + $scope.draftMessage.text = url + "\n" + text; + $scope.$broadcast('ui_peer_draft', { + customSelection: [ + url + "\n", + text, + '' + ] + }); + }, 100); + } + function replySelect(messageID) { $scope.draftMessage.replyToMessage = AppMessagesManager.wrapForDialog(messageID); $scope.$broadcast('ui_peer_reply'); @@ -2259,6 +2290,9 @@ angular.module('myApp.controllers', ['myApp.i18n']) } function onTyping () { + if ($scope.curDialog.inputPeer._ == 'inputPeerChannel') { + return false; + } MtpApiManager.invokeApi('messages.setTyping', { peer: $scope.curDialog.inputPeer, action: {_: 'sendMessageTypingAction'} diff --git a/app/js/directives.js b/app/js/directives.js index 3b806509..0488f90f 100755 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -1426,14 +1426,18 @@ angular.module('myApp.directives', ['myApp.filters']) AppStickersManager.getStickers().then(callback); }, getStickerImage: function (element, docID) { - if (cachedStickerImages[docID]) { - element.replaceWith(cachedStickerImages[docID]); + var category = element.attr('data-category'); + var cached = cachedStickerImages[docID]; + if (cached && !isInDOM(cached[0])) { + cached.attr('data-category', category); + element.replaceWith(cached); return; } var scope = $scope.$new(true); scope.document = AppDocsManager.getDoc(docID); stickerImageCompiled(scope, function (clonedElement) { cachedStickerImages[docID] = clonedElement; + clonedElement.attr('data-category', category); element.replaceWith(clonedElement); }); }, @@ -1449,6 +1453,10 @@ angular.module('myApp.directives', ['myApp.filters']) $scope.$apply(function () { $scope.draftMessage.sticker = docID; }); + }, + langpack: { + im_emoji_tab: _('im_emoji_tab'), + im_stickers_tab: _('im_stickers_tab') } }); @@ -1570,15 +1578,21 @@ angular.module('myApp.directives', ['myApp.filters']) $scope.$on('ui_peer_change', composer.resetTyping.bind(composer)); $scope.$on('ui_peer_draft', function (e, options) { + options = options || {}; var isBroadcast = $scope.draftMessage.isBroadcast; composer.setPlaceholder(_(isBroadcast ? 'im_broadcast_field_placeholder_raw' : 'im_message_field_placeholder_raw')); - if (richTextarea) { - composer.setValue($scope.draftMessage.text || ''); + if (options.customSelection) { + composer.setFocusedValue(options.customSelection); updateHeight(); - } - if (!Config.Navigator.touch || options && options.focus) { - composer.focus(); + } else { + if (richTextarea) { + composer.setValue($scope.draftMessage.text || ''); + updateHeight(); + } + if (!Config.Navigator.touch || options && options.focus) { + composer.focus(); + } } onContentLoaded(function () { composer.checkAutocomplete(true); diff --git a/app/js/lib/utils.js b/app/js/lib/utils.js index 7750d429..c8b212b4 100644 --- a/app/js/lib/utils.js +++ b/app/js/lib/utils.js @@ -22,6 +22,17 @@ function checkClick (e, noprevent) { return false; } +function isInDOM (element, parentNode) { + if (!element) { + return false; + } + parentNode = parentNode || document.body; + if (element == parentNode) { + return true; + } + return isInDOM(element.parentNode, parentNode) +} + function checkDragEvent(e) { if (!e || e.target && (e.target.tagName == 'IMG' || e.target.tagName == 'A')) return false; if (e.dataTransfer && e.dataTransfer.types) { @@ -218,9 +229,12 @@ function getRichElementValue(node, lines, line, selNode, selOffset) { } } -function setRichFocus(field, selectNode) { +function setRichFocus(field, selectNode, noCollapse) { field.focus(); - if (selectNode && selectNode.parentNode == field && !selectNode.nextSibling) { + if (selectNode && + selectNode.parentNode == field && + !selectNode.nextSibling && + !noCollapse) { field.removeChild(selectNode); selectNode = null; } @@ -231,7 +245,9 @@ function setRichFocus(field, selectNode) { } else { range.selectNodeContents(field); } - range.collapse(false); + if (!noCollapse) { + range.collapse(false); + } var sel = window.getSelection(); sel.removeAllRanges(); @@ -240,7 +256,9 @@ function setRichFocus(field, selectNode) { else if (document.body.createTextRange !== undefined) { var textRange = document.body.createTextRange(); textRange.moveToElementText(selectNode || field); - textRange.collapse(false); + if (!noCollapse) { + textRange.collapse(false); + } textRange.select(); } } diff --git a/app/js/locales/en-us.json b/app/js/locales/en-us.json index 0ffa1a8b..5723bf44 100644 --- a/app/js/locales/en-us.json +++ b/app/js/locales/en-us.json @@ -444,6 +444,9 @@ "im_photos_drop_text": "Drop photos here to send", "im_message_field_placeholder": "Write a message...", "im_broadcast_field_placeholder": "Broadcast a message...", + "im_emoji_tab": "Emoji", + "im_stickers_tab": "Stickers", + "im_stickers_tab_recent": "Frequently used", "im_media_attach_title": "Send media", "im_attach_file_title": "Send file", "im_emoji_btn_title": "Insert emoticon", diff --git a/app/js/message_composer.js b/app/js/message_composer.js index c53d0469..8e7525e8 100644 --- a/app/js/message_composer.js +++ b/app/js/message_composer.js @@ -140,6 +140,7 @@ function EmojiTooltip (btnEl, options) { this.getStickers = options.getStickers; this.getStickerImage = options.getStickerImage; this.onStickersetSelected = options.onStickersetSelected; + this.langpack = options.langpack || {}; if (!Config.Navigator.touch) { $(this.btnEl).on('mouseenter mouseleave', function (e) { @@ -203,21 +204,59 @@ EmojiTooltip.prototype.createTooltip = function () { return false; } + var html = +'
\ +
\ +
' +this.langpack.im_emoji_tab + '
\ +
' +this.langpack.im_stickers_tab + '
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + \ + \ + \ + \ + \ + \ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
'; + + html = html.replace(/>\s+<'); + var self = this; - this.tooltipEl = $('
').appendTo(document.body); + this.tooltipEl = $(html).appendTo(document.body); this.tabsEl = $('.composer_emoji_tooltip_tabs', this.tooltipEl); + this.categoriesEl = $('.composer_emoji_tooltip_categories', this.tooltipEl); + this.stickersCategoriesEl = $('.composer_emoji_tooltip_tab_stickers_content .composer_emoji_tooltip_categories', this.tooltipEl); + this.contentEl = $('.composer_emoji_tooltip_content', this.tooltipEl); - this.footerEl = $('.composer_emoji_tooltip_footer', this.tooltipEl); - this.settingsEl = $('.composer_emoji_tooltip_settings', this.tooltipEl); + this.emojiContentEl = $('.composer_emoji_tooltip_content_emoji', this.tooltipEl); + this.stickersContentEl = $('.composer_emoji_tooltip_content_stickers', this.tooltipEl); - angular.forEach(['recent', 'smile', 'flower', 'bell', 'car', 'grid', 'stickers'], function (tabName, tabIndex) { - var tab = $('') + // Tabs + angular.forEach(['emoji', 'stickers'], function (tabName, tabIndex) { + var tab = $('.composer_emoji_tooltip_tab_' + tabName, self.tabsEl) .on('mousedown', function (e) { self.selectTab(tabIndex); return cancelEvent(e); - }) - .appendTo(self.tabsEl); + }); if (!Config.Navigator.touch) { tab.on('mouseenter mouseleave', function (e) { @@ -231,7 +270,51 @@ EmojiTooltip.prototype.createTooltip = function () { } }); - this.scroller = new Scroller(this.contentEl, {classPrefix: 'composer_emoji_tooltip'}); + // Categories + var handleEvents = 'mousedown'; + if (!Config.Navigator.touch) { + handleEvents += ' mouseover mouseout'; + } + this.categoriesEl.on(handleEvents, function (e) { + e = e.originalEvent || e; + var target = e.target; + if (target.tagName != 'A') { + target = target.parentNode; + } + if (target.tagName != 'A') { + return; + } + var catIndex = parseInt(target.getAttribute('data-category')); + if (e.type == 'mousedown') { + self.selectCategory(catIndex); + return cancelEvent(e); + } + if (self.tab) { + return; + } + var isOver = e.type == 'mouseover'; + if (isOver && self.selectCategoryIndex == catIndex) { + return; + } + clearTimeout(self.selectCategoryTimeout); + delete self.selectCategoryTimeout; + if (isOver) { + self.selectCategoryIndex = catIndex; + self.selectCategoryTimeout = setTimeout(function () { + delete self.selectCategoryIndex; + delete self.selectCategoryTimeout; + self.selectCategory(catIndex); + }, 300); + } else { + delete self.selectCategoryIndex; + } + }); + + this.emojiScroller = new Scroller(this.emojiContentEl, {classPrefix: 'composer_emoji_tooltip'}); + this.stickersScroller = new Scroller(this.stickersContentEl, {classPrefix: 'composer_emoji_tooltip'}); + this.stickersScroller.onScroll(function (el, st) { + self.onStickersScroll(el, st); + }); this.contentEl.on('mousedown', function (e) { e = e.originalEvent || e; @@ -280,64 +363,48 @@ EmojiTooltip.prototype.createTooltip = function () { } -EmojiTooltip.prototype.selectTab = function (tab) { - if (this.tab === tab && tab != 6) { +EmojiTooltip.prototype.selectCategory = function (cat, force) { + if (this.cat === cat && !force) { + return false; + } + $('.active', this.categoriesEl).removeClass('active'); + this.cat = cat; + + if (this.tab) { + this.activateStickerCategory(); + this.updateStickersContents(force); + } else { + $(this.categoriesEl[this.tab].childNodes[cat]).addClass('active'); + this.updateEmojiContents(); + } +}; + +EmojiTooltip.prototype.selectTab = function (tab, force) { + if (this.tab === tab && !force) { return false; } - $('.active', this.tabsEl).removeClass('active'); + this.tab = tab; - $(this.tabsEl[0].childNodes[tab]).addClass('active'); + this.selectCategory(0, true); - this.updateTabContents(); + var self = this; + setTimeout(function () { + $(self.tooltipEl).toggleClass('composer_emoji_tooltip_tabs_stickers_active', tab == 1); + }, 0); }; -EmojiTooltip.prototype.updateTabContents = function () { +EmojiTooltip.prototype.updateEmojiContents = function () { var html = []; var self = this; - var iconSize = Config.Mobile ? 26 : 20; + var iconSize = 26; var renderContent = function () { - self.contentEl.html(html.join('')); - self.scroller.reinit(); + self.emojiContentEl.html(html.join('')); + self.emojiScroller.reinit(); } - if (this.tab == 6) { // Stickers - var renderStickers = function (stickersets) { - if (self.tab != 6) { - return; - } - var set, docID, i, j, len1, len2; - for (i = 0, len1 = stickersets.length; i < len1; i++) { - set = stickersets[i]; - if (!set.docIDs.length) { - continue; - } - html.push('
'); - if (set.id && set.title) { - html.push( - '', - encodeEntities(set.title), - '' - ); - } - for (j = 0, len2 = set.docIDs.length; j < len2; j++) { - docID = set.docIDs[j]; - html.push(''); - } - html.push('
'); - } - renderContent(); - - self.contentEl.find('.composer_sticker_btn').each(function (k, element) { - self.getStickerImage($(element), element.getAttribute('data-sticker')); - }); - }; - this.getStickers(renderStickers); - } - else if (this.tab > 0) { - var categoryIndex = this.tab - 1; + if (this.cat > 0) { + var categoryIndex = this.cat - 1; var emoticonCodes = Config.EmojiCategories[categoryIndex]; var totalColumns = Config.EmojiCategorySpritesheetDimens[categoryIndex][1]; var count = emoticonCodes.length; @@ -374,6 +441,148 @@ EmojiTooltip.prototype.updateTabContents = function () { } }; +EmojiTooltip.prototype.updateStickersContents = function (force) { + var html = []; + var categoriesHtml = []; + var self = this; + var iconSize = 26; + + var scrollStickers = function () { + var scrollTop = self.cat ? self.stickersetPositions[self.cat][0] : 0; + self.stickersScroller.scrollTo(scrollTop, force ? 0 : 100); + } + + if (!force && self.stickersetPositions.length) { + scrollStickers(); + return; + } + + var renderStickers = function (stickersets) { + var set, docID, i, j, len1, len2; + for (i = 0, len1 = stickersets.length; i < len1; i++) { + set = stickersets[i]; + if (!set.docIDs.length) { + continue; + } + html.push('
'); + if (set.title) { + html.push( + '', + encodeEntities(set.title), + '' + ); + } + if (!set.id) { + categoriesHtml.push(''); + } else { + categoriesHtml.push(''); + } + for (j = 0, len2 = set.docIDs.length; j < len2; j++) { + docID = set.docIDs[j]; + html.push(''); + } + html.push('
'); + } + + self.stickersContentEl.html(html.join('')); + self.stickersCategoriesEl.html(categoriesHtml.join('')); + self.stickersScroller.reinit(); + + var scrollPositions = []; + $('.composer_stickerset_wrap', self.stickersContentEl).each(function (k, stickerSetEl) { + var height = stickerSetEl.offsetHeight; + var top = stickerSetEl.offsetTop; + scrollPositions.push([top, height]); + }); + self.stickersetPositions = scrollPositions; + scrollStickers(); + + var preload = []; + self.contentEl.find('.composer_sticker_btn').each(function (k, element) { + if (k < 12) { + self.replaceStickerImage(element); + } else { + preload.push([element.offsetTop, element]); + } + }); + self.stickersPreload = preload; + + self.stickersCategoriesEl.find('.composer_sticker_btn').each(function (k, element) { + self.replaceStickerImage(element); + }); + }; + this.getStickers(renderStickers); +}; + +EmojiTooltip.prototype.replaceStickerImage = function (element) { + element = $(element); + this.getStickerImage(element, element.attr('data-sticker')); +} + +EmojiTooltip.prototype.onStickersScroll = function (scrollable, scrollTop) { + var ch = scrollable.clientHeight; + var sh = scrollable.scrollHeight; + var len = this.stickersetPositions.length; + var currentCat = false; + var currentPos, i; + + if (scrollTop < 20) { + currentCat = 0; + } else if (scrollTop > sh - ch - 20) { + currentCat = len - 1; + } else { + for (i = 0; i < len; i++) { + currentPos = this.stickersetPositions[i]; + if (scrollTop >= currentPos[0] && + scrollTop < (currentPos[0] + currentPos[1])) { + currentCat = i; + break; + } + } + } + var len = this.stickersPreload.length; + if (len) { + for (i = 0; i < len; i++) { + currentPos = this.stickersPreload[i]; + if (currentPos[0] >= scrollTop && currentPos[0] <= scrollTop + ch) { + // console.log('replace', currentPos[1], i); + this.replaceStickerImage(currentPos[1]); + this.stickersPreload.splice(i, 1); + i--; + len--; + } + } + } + // console.log('on sticker scroll', scrollTop, ch, sh, currentCat, this.stickersetPositions); + if (this.cat === currentCat || currentCat === false) { + return; + } + $('.active', this.categoriesEl).removeClass('active'); + this.cat = currentCat; + this.activateStickerCategory(); +}; + +EmojiTooltip.prototype.activateStickerCategory = function () { + var categoriesEl = this.categoriesEl[1]; + var categoryEl = categoriesEl.childNodes[this.cat]; + if (!categoryEl) { + return; + } + $(categoryEl).addClass('active'); + + var left = categoryEl.offsetLeft; + var width = categoryEl.offsetWidth; + var viewportWidth = categoriesEl.clientWidth; + + // console.log('current cat el', categoryEl, left, width, viewportWidth); + $(categoriesEl).animate({scrollLeft: left - (viewportWidth - width) / 2}, 200); +} + + EmojiTooltip.prototype.updatePosition = function () { var offset = this.btnEl.offset(); this.tooltipEl.css({top: offset.top, left: offset.left}); @@ -381,7 +590,11 @@ EmojiTooltip.prototype.updatePosition = function () { EmojiTooltip.prototype.show = function () { this.updatePosition(); - this.updateTabContents(); + if (this.tab) { + this.updateStickersContents(true); + } else { + this.updateEmojiContents(); + } this.tooltipEl.addClass('composer_emoji_tooltip_shown'); this.btnEl.addClass('composer_emoji_insert_btn_on'); delete this.showTimeout; @@ -1080,6 +1293,31 @@ MessageComposer.prototype.setValue = function (text) { } } +MessageComposer.prototype.setFocusedValue = function (parts) { + var prefix = parts[0]; + var selection = parts[1]; + var suffix = parts[2]; + + if (this.richTextareaEl) { + this.selId = (this.selId || 0) + 1; + var html = + this.getRichHtml(prefix) + + '' + + this.getRichHtml(selection) + + '' + + this.getRichHtml(suffix); + + this.richTextareaEl.html(html); + + setRichFocus(this.richTextareaEl[0], $('#composer_sel' + this.selId)[0], true); + } else { + this.textareaEl.val(prefix + selection + suffix); + setFieldSelection(this.textareaEl[0], prefix.length, prefix.length + selection.length); + } +} + + + MessageComposer.prototype.getRichHtml = function (text) { return $('
').text(text).html().replace(/\n/g, '
').replace(/:([A-Za-z0-9\-\+\*_]+?):/gi, (function (all, shortcut) { var code = EmojiHelper.shortcuts[shortcut]; @@ -1255,6 +1493,18 @@ Scroller.prototype.setUpNative = function () { } } +Scroller.prototype.onScroll = function (cb) { + var self = this; + var scrollable = this.scrollable[0]; + this.scrollable.on('scroll', function (e) { + if (self.isAnimatedScroll) { + return; + } + cb(scrollable, scrollable.scrollTop); + }) + +} + Scroller.prototype.update = function () { if (this.useNano) { $(this.scroller).nanoScroller(); @@ -1293,10 +1543,28 @@ Scroller.prototype.updateHeight = function () { } -Scroller.prototype.scrollTo = function (scrollTop) { - this.scrollable[0].scrollTop = scrollTop; - if (this.useNano) { - $(this.scroller).nanoScroller({flash: true}); +Scroller.prototype.scrollTo = function (scrollTop, animation, cb) { + if (animation > 0) { + var self = this; + this.isAnimatedScroll = true; + this.scrollable.animate({scrollTop: scrollTop}, function () { + delete self.isAnimatedScroll; + if (self.useNano) { + $(self.scroller).nanoScroller({flash: true}); + } + self.scrollable.trigger('scroll'); + if (cb) { + cb(); + } + }); + } else { + this.scrollable[0].scrollTop = scrollTop; + if (this.useNano) { + $(this.scroller).nanoScroller({flash: true}); + } + if (cb) { + cb(); + } } } diff --git a/app/js/messages_manager.js b/app/js/messages_manager.js index 4ca6c046..34ca84e0 100644 --- a/app/js/messages_manager.js +++ b/app/js/messages_manager.js @@ -9,7 +9,7 @@ angular.module('myApp.services') -.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, $timeout, $sce, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, AppWebPagesManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, PeersSelectService, Storage, AppProfileManager, FileManager, TelegramMeWebService, ErrorService, StatusManager, _) { +.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, $timeout, $sce, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppStickersManager, AppAudioManager, AppWebPagesManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, PeersSelectService, Storage, AppProfileManager, FileManager, TelegramMeWebService, ErrorService, StatusManager, _) { var messagesStorage = {}; var messagesForHistory = {}; @@ -1397,9 +1397,13 @@ angular.module('myApp.services') break; case 'inputMediaDocument': + var doc = AppDocsManager.getDoc(inputMedia.id.id); + if (doc.sticker && doc.stickerSetInput) { + AppStickersManager.pushPopularSticker(doc.id); + }; media = { _: 'messageMediaDocument', - 'document': AppDocsManager.getDoc(inputMedia.id.id) + 'document': doc }; break; } diff --git a/app/js/services.js b/app/js/services.js index e5eb7d21..1920fc34 100755 --- a/app/js/services.js +++ b/app/js/services.js @@ -2118,6 +2118,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) openStickersetLink: openStickersetLink, openStickerset: openStickerset, installStickerset: installStickerset, + pushPopularSticker: pushPopularSticker, getStickers: getStickers, getStickerset: getStickerset, getStickersImages: getStickersImages @@ -2130,6 +2131,44 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } } + function getPopularStickers () { + return Storage.get('stickers_popular').then(function (popStickers) { + var result = []; + if (popStickers && popStickers.length) { + for (var i = 0, len = popStickers.length; i < len; i++) { + result.push({id: popStickers[i][0], 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; @@ -2162,7 +2201,28 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } } - return currentStickersets; + 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'), + short_name: '', + installed: true, + disabled: false, + official: false, + docIDs: setItems + }) + } + + return resultStickersets; + }); } function getStickers (force) { @@ -3655,7 +3715,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) var toPeerID = AppPeersManager.getPeerID(toPeerString); var toChatID = toPeerID < 0 ? -toPeerID : 0; AppMessagesManager.startBot(peerID, toChatID, matches[3]).then(function () { - $rootScope.$broadcast('history_focus', {toPeerString: toPeerString}); + $rootScope.$broadcast('history_focus', {peerString: toPeerString}); }); }); return true; @@ -3679,6 +3739,17 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) return true; } + if (matches = url.match(/^msg_url\?url=(.+)(?:&text=(.*))?$/)) { + PeersSelectService.selectPeer({ + confirm_type: 'SHARE_URL' + }).then(function (toPeerString) { + var url = decodeURIComponent(matches[1]); + var text = matches[3] ? decodeURIComponent(matches[3]) : ''; + $rootScope.$broadcast('history_focus', {peerString: toPeerString, shareUrl: url, shareText: text}); + }); + return true; + } + if (inner && (matches = url.match(/^bot_command\?command=(.+?)(?:&bot=(.+))?$/))) { diff --git a/app/less/app.less b/app/less/app.less index 99b15555..73f632df 100644 --- a/app/less/app.less +++ b/app/less/app.less @@ -2370,9 +2370,9 @@ img.img_fullsize { display: none; position: absolute; z-index: 999; - width: 254px; - margin-left: -116px; - margin-top: -245px; + width: 286px; + margin-left: -133px; + margin-top: -330px; border: 1px #dfdfdf solid; @@ -2380,7 +2380,7 @@ img.img_fullsize { .box-shadow(0px 1px 1px rgba(0, 0, 0, 0.1)); background: #fff; - padding: 5px 2px 5px 8px; + padding: 0; &_shown { display: block; @@ -2416,68 +2416,181 @@ img.img_fullsize { } .composer_emoji_tooltip_tabs { + -webkit-box-shadow: 0px 1px 0px 0px rgba(0,0,0,0.1); + -moz-box-shadow: 0px 1px 0px 0px rgba(0,0,0,0.1); + box-shadow: 0px 1px 0px 0px rgba(0,0,0,0.1); + + // border-bottom: 1px solid #e5e5e5; + // border-color: rgba(0,0,0,0.1); +} +.composer_emoji_tooltip_tab { + cursor: pointer; + display: inline-block; + line-height: 35px; + text-align: center; + width: 50%; + text-transform: uppercase; + font-weight: bold; + transition: color ease-in-out 0.2s; + + &:hover, + &:active, + &:focus { + text-decoration: none; + } +} +.composer_emoji_tooltip_tab_emoji, +.composer_emoji_tooltip_tabs_stickers_active .composer_emoji_tooltip_tab_stickers { + color: #53a9ea; +} +.composer_emoji_tooltip_tabs_stickers_active .composer_emoji_tooltip_tab_emoji, +.composer_emoji_tooltip_tab_stickers { + color: #999; +} +.composer_emoji_tooltip_tab_shadow { + width: 50%; + height: 1px; + background: #53a9ea; + -webkit-box-shadow: 0px 1px 0px 0px rgba(83,169,234,1); + -moz-box-shadow: 0px 1px 0px 0px rgba(83,169,234,1); + box-shadow: 0px 1px 0px 0px rgba(83,169,234,1); + transform: translateX(0); + transition: transform ease-in-out 0.2s; + + .composer_emoji_tooltip_tabs_stickers_active & { + transform: translateX(100%); + } +} + +.composer_emoji_tooltip_categories { width: 100%; - margin: 5px 0 2px; + line-height: 0; + + .composer_emoji_tooltip_tab_emoji_content & { + width: 100%; + margin: 9px 0 12px; + padding: 0 5px; + line-height: 0; + } + + .composer_emoji_tooltip_tab_stickers_content & { + vertical-align: top; + padding: 2px 10px 2px; + overflow-x: scroll; + white-space: nowrap; + position: relative; + + &::-webkit-scrollbar { + display: none; + } + + .composer_emoji_tooltip_category_recent { + margin: 7px 10px 7px 7px; + } + .composer_sticker_btn { + width: 42px; + height: 38px; + padding: 3px 5px; + vertical-align: top; + margin-right: 2px; + + &.active { + background: #f2f6fa; + } + } + .composer_sticker_image { + max-width: 32px; + max-height: 32px; + } + } } -.composer_emoji_tooltip_tab { +.composer_emoji_tooltip_category { line-height: 0; color: white; display: inline-block; - width: 24px; - height: 29px; + width: 21px; + height: 21px; cursor: pointer; - opacity: 0.7; - margin: 0 5px 0 4px; + opacity: 0.3; + margin: 0 12px 0 12px; - .image-2x('../img/icons/IconsetSmiles.png', 42px, 470px); + .image-2x('../img/icons/IconsetSmiles.png', 27px, 362px); - &.active { + &:hover { + opacity: 0.4; + } + &.active, + &.active:hover { opacity: 1; } } /* Recent */ -.composer_emoji_tooltip_tab_recent {background-position: -9px -306px; } -.composer_emoji_tooltip_tab_recent.active {background-position: -9px -277px; } +.composer_emoji_tooltip_category_recent {background-position: -3px 0; } +.composer_emoji_tooltip_category_recent.active {background-position: -3px -31px; } /* Smile */ -.composer_emoji_tooltip_tab_smile {background-position: -9px -34px; } -.composer_emoji_tooltip_tab_smile.active {background-position: -9px -5px; } +.composer_emoji_tooltip_category_smile {background-position: -3px -62px; } +.composer_emoji_tooltip_category_smile.active {background-position: -3px -93px; } /* Flower */ -.composer_emoji_tooltip_tab_flower {background-position: -9px -145px; } -.composer_emoji_tooltip_tab_flower.active {background-position: -9px -118px; } +.composer_emoji_tooltip_category_flower {background-position: -3px -124px; } +.composer_emoji_tooltip_category_flower.active {background-position: -3px -155px; } /* Bell */ -.composer_emoji_tooltip_tab_bell {background-position: -9px -89px; } -.composer_emoji_tooltip_tab_bell.active {background-position: -9px -61px; } +.composer_emoji_tooltip_category_bell {background-position: -3px -184px; } +.composer_emoji_tooltip_category_bell.active {background-position: -3px -215px; } /* Car */ -.composer_emoji_tooltip_tab_car {background-position: -9px -196px; } -.composer_emoji_tooltip_tab_car.active {background-position: -9px -170px; } +.composer_emoji_tooltip_category_car {background-position: -3px -245px; } +.composer_emoji_tooltip_category_car.active {background-position: -3px -276px; } /* Grid */ -.composer_emoji_tooltip_tab_grid {background-position: -9px -248px; } -.composer_emoji_tooltip_tab_grid.active {background-position: -9px -222px; } +.composer_emoji_tooltip_category_grid {background-position: -3px -304px; } +.composer_emoji_tooltip_category_grid.active {background-position: -3px -335px; } -/* Stickers */ -.composer_emoji_tooltip_tab_stickers {background-position: -9px -361px; } -.composer_emoji_tooltip_tab_stickers.active {background-position: -9px -333px; } -.composer_emoji_tooltip .scroller_scrollable_container { - height: 174px; +.composer_emoji_tooltip_tabs_wrap { + height: 275px; position: relative; + overflow: hidden; } +.composer_emoji_tooltip_tabs_contents { + position: absolute; + width: 200%; + transform: translateX(0); + transition: transform ease-in-out 0.2s; + .composer_emoji_tooltip_tabs_stickers_active & { + transform: translateX(-284px); + } +} +.composer_emoji_tooltip_tab_emoji_content, +.composer_emoji_tooltip_tab_stickers_content { + width: 284px; + height: 275px; + float: left; +} +.composer_emoji_tooltip_content_stickers { + position: relative; +} +.composer_emoji_tooltip_content_wrap { + padding: 0 2px 0 8px; +} +.composer_emoji_tooltip .scroller_scrollable_container { + height: 233px; + position: relative; +} .composer_emoji_tooltip_content { + padding-top: 10px; padding-right: 8px; outline: 0!important; } a.composer_emoji_btn { - margin: 0 1px 0 0; - padding: 6px; + margin: 0 2px 0 0; + padding: 5px; display: block; float: left; border-radius: 2px; @@ -2684,8 +2797,9 @@ a.composer_command_option.composer_autocomplete_option_active .composer_command_ font-size: 13px; color: #444; margin: 10px 0 3px; + padding: 0 6px; - &:first-child { + .composer_stickerset_wrap:first-child & { margin-top: 0; } &:hover { @@ -2693,12 +2807,12 @@ a.composer_command_option.composer_autocomplete_option_active .composer_command_ } } .composer_sticker_btn { - width: 78px; - height: 78px; - display: block; + width: 66px; + height: 66px; display: inline-block; text-align: center; padding: 3px; + vertical-align: top; &:hover { background: #f2f6fa; @@ -2706,9 +2820,9 @@ a.composer_command_option.composer_autocomplete_option_active .composer_command_ } .composer_sticker_image { - max-width: 72px; - max-height: 72px; - vertical-align: top; + max-width: 60px; + max-height: 60px; + vertical-align: middle; } .composer_rich_textarea { @@ -2758,6 +2872,13 @@ a.composer_command_option.composer_autocomplete_option_active .composer_command_ } } +@-moz-document url-prefix() { + .composer_rich_textarea:empty:active:before, + .composer_rich_textarea:empty:focus:before { + display: none; + } +} + .composer_command_btn { display: block; position: absolute; diff --git a/app/less/desktop.less b/app/less/desktop.less index 492b03f3..2be9acab 100644 --- a/app/less/desktop.less +++ b/app/less/desktop.less @@ -489,6 +489,8 @@ .nano > .nano-pane { background : rgba(255,255,255,0.0); right: -2px; + top: 5px; + bottom: 5px; & > .nano-slider { background: #d1d1d1; diff --git a/app/partials/desktop/confirm_modal.html b/app/partials/desktop/confirm_modal.html index 3af146ab..2e4374cc 100644 --- a/app/partials/desktop/confirm_modal.html +++ b/app/partials/desktop/confirm_modal.html @@ -32,6 +32,7 @@ +