diff --git a/app/js/controllers.js b/app/js/controllers.js
index eaaf15f0..b7ffc75d 100644
--- a/app/js/controllers.js
+++ b/app/js/controllers.js
@@ -3848,6 +3848,13 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.$broadcast('ui_height');
$scope.stickersetLoaded = true;
$scope.stickerset = result.set;
+ $scope.stickersetInstalled = result.installed;
$scope.documents = result.documents;
});
+
+ $scope.toggleInstalled = function (installed) {
+ AppStickersManager.installStickerset($scope.stickerset, !installed).then(function () {
+ $scope.stickersetInstalled = installed;
+ })
+ }
})
diff --git a/app/js/directives.js b/app/js/directives.js
index 5066c9bc..1b6ba3a0 100755
--- a/app/js/directives.js
+++ b/app/js/directives.js
@@ -925,6 +925,33 @@ angular.module('myApp.directives', ['myApp.filters'])
})
+ .directive('myStickersList', function($window, $timeout) {
+
+ return {
+ link: link
+ };
+
+ function link ($scope, element, attrs) {
+ var stickersWrap = $('.stickerset_wrap', element)[0];
+
+ onContentLoaded(function () {
+ $(stickersWrap).nanoScroller({preventPageScrolling: true, tabIndex: -1, iOSNativeScrolling: true});
+ updateSizes();
+ });
+
+ function updateSizes () {
+ $(element).css({
+ height: Math.min(500, $($window).height()
+ - (Config.Mobile ? 46 + 18 : 200))
+ });
+ $(stickersWrap).nanoScroller();
+ }
+
+ $($window).on('resize', updateSizes);
+ };
+
+ })
+
.directive('myHistory', function ($window, $timeout, $rootScope, $transition) {
return {
@@ -1249,7 +1276,7 @@ angular.module('myApp.directives', ['myApp.filters'])
})
- .directive('mySendForm', function ($timeout, $compile, $modalStack, $http, $interpolate, Storage, AppStickersManager, ErrorService) {
+ .directive('mySendForm', function ($timeout, $compile, $modalStack, $http, $interpolate, Storage, AppStickersManager, AppDocsManager, ErrorService) {
return {
link: link,
@@ -1270,14 +1297,28 @@ angular.module('myApp.directives', ['myApp.filters'])
var dragStarted, dragTimeout;
var submitBtn = $('.im_submit', element)[0];
+ var stickerImageCompiled = $compile('');
+ var cachedStickerImages = {};
+
var emojiTooltip = new EmojiTooltip(emojiButton, {
getStickers: function (callback) {
- AppStickersManager.getStickers().then(function () {
- AppStickersManager.getStickersImages().then(function (stickersData) {
- callback(stickersData);
- });
+ AppStickersManager.getStickers().then(callback);
+ },
+ getStickerImage: function (element, docID) {
+ if (cachedStickerImages[docID]) {
+ element.replaceWith(cachedStickerImages[docID]);
+ return;
+ }
+ var scope = $scope.$new(true);
+ scope.document = AppDocsManager.getDoc(docID);
+ stickerImageCompiled(scope, function (clonedElement) {
+ cachedStickerImages[docID] = clonedElement;
+ element.replaceWith(clonedElement);
});
},
+ onStickersetSelected: function (stickerset) {
+ AppStickersManager.openStickersetLink(stickerset);
+ },
onEmojiSelected: function (code) {
$scope.$apply(function () {
composer.onEmojiSelected(code);
@@ -1817,7 +1858,9 @@ angular.module('myApp.directives', ['myApp.filters'])
};
function link ($scope, element, attrs) {
- var imgElement = $('').appendTo(element);
+ var imgElement = $('
')
+ .appendTo(element)
+ .addClass(attrs.imgClass);
var setSrc = function (blob) {
if (WebpManager.isWebpSupported()) {
@@ -1863,11 +1906,19 @@ angular.module('myApp.directives', ['myApp.filters'])
imgElement.attr('src', emptySrc);
}
- MtpApiFileManager.downloadFile($scope.document.dc_id, fullLocation, $scope.document.size).then(function (blob) {
- setSrc(blob);
- }, function (e) {
- console.log('Download sticker failed', e, fullLocation);
- });
+ if (attrs.thumb) {
+ MtpApiFileManager.downloadSmallFile(smallLocation).then(function (blob) {
+ setSrc(blob);
+ }, function (e) {
+ console.log('Download sticker failed', e, fullLocation);
+ });
+ } else {
+ MtpApiFileManager.downloadFile($scope.document.dc_id, fullLocation, $scope.document.size).then(function (blob) {
+ setSrc(blob);
+ }, function (e) {
+ console.log('Download sticker failed', e, fullLocation);
+ });
+ }
}
})
diff --git a/app/js/locales/en-us.json b/app/js/locales/en-us.json
index f9e9f910..02d81eaf 100644
--- a/app/js/locales/en-us.json
+++ b/app/js/locales/en-us.json
@@ -86,6 +86,11 @@
"sessions_modal_terminate_all": "Terminate all other sessions",
"sessions_modal_active_sessions": "Active sessions",
+ "stickerset_modal_title_loading": "Stickerset",
+ "stickerset_modal_install": "Add stickers",
+ "stickerset_modal_uninstall": "Remove stickers",
+ "stickerset_modal_loading": "Loading{dots}",
+
"page_title_pluralize_notifications": "{'0': 'No notifications', 'one': '1 notification', 'other': '{} notifications'}",
"profile_edit_modal_title": "Edit profile",
diff --git a/app/js/message_composer.js b/app/js/message_composer.js
index e03a07b9..b6ed70c6 100644
--- a/app/js/message_composer.js
+++ b/app/js/message_composer.js
@@ -138,6 +138,8 @@ function EmojiTooltip (btnEl, options) {
this.onEmojiSelected = options.onEmojiSelected;
this.onStickerSelected = options.onStickerSelected;
this.getStickers = options.getStickers;
+ this.getStickerImage = options.getStickerImage;
+ this.onStickersetSelected = options.onStickersetSelected;
if (!Config.Navigator.touch) {
$(this.btnEl).on('mouseenter mouseleave', function (e) {
@@ -258,7 +260,7 @@ EmojiTooltip.prototype.createTooltip = function () {
this.contentEl.on('mousedown', function (e) {
e = e.originalEvent || e;
- var target = $(e.target), code, sticker;
+ var target = $(e.target), code, sticker, stickerset;
if (target[0].tagName != 'A') {
target = $(target[0].parentNode);
}
@@ -276,6 +278,12 @@ EmojiTooltip.prototype.createTooltip = function () {
self.hide();
}
}
+ if (stickerset = target.attr('data-stickerset')) {
+ if (self.onStickersetSelected) {
+ self.onStickersetSelected(stickerset);
+ }
+ self.hide();
+ }
return cancelEvent(e);
});
@@ -298,7 +306,7 @@ EmojiTooltip.prototype.createTooltip = function () {
EmojiTooltip.prototype.selectTab = function (tab) {
- if (this.tab === tab) {
+ if (this.tab === tab && tab != 6) {
return false;
}
$('.active', this.tabsEl).removeClass('active');
@@ -308,7 +316,7 @@ EmojiTooltip.prototype.selectTab = function (tab) {
this.updateTabContents();
};
-EmojiTooltip.prototype.updateTabContents = function (tab) {
+EmojiTooltip.prototype.updateTabContents = function () {
var html = [];
var self = this;
var iconSize = Config.Mobile ? 26 : 20;
@@ -325,14 +333,32 @@ EmojiTooltip.prototype.updateTabContents = function (tab) {
}
if (this.tab == 6) { // Stickers
- var renderStickers = function (stickers) {
- var sticker, i;
- var count = stickers.length;
- for (i = 0; i < count; i++) {
- sticker = stickers[i];
- html.push('
');
+ 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;
+ }
+ 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('');
+ }
}
renderContent();
+
+ self.contentEl.find('.composer_sticker_btn').each(function (k, element) {
+ self.getStickerImage($(element), element.getAttribute('data-sticker'));
+ });
};
this.getStickers(renderStickers);
}
@@ -381,6 +407,7 @@ EmojiTooltip.prototype.updatePosition = function () {
EmojiTooltip.prototype.show = function () {
this.updatePosition();
+ this.updateTabContents();
this.tooltipEl.addClass('composer_emoji_tooltip_shown');
this.btnEl.addClass('composer_emoji_insert_btn_on');
delete this.showTimeout;
diff --git a/app/js/services.js b/app/js/services.js
index bf678957..fa3bcbf6 100755
--- a/app/js/services.js
+++ b/app/js/services.js
@@ -3348,6 +3348,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
apiDoc.stickerEmojiRaw = attribute.alt;
apiDoc.stickerEmoji = RichTextProcessor.wrapRichText(apiDoc.stickerEmojiRaw, {noLinks: true, noLinebreaks: true});
}
+ if (attribute.stickerset &&
+ attribute.stickerset._ == 'inputStickerSetID') {
+ apiDoc.stickerSetID = attribute.stickerset.id;
+ }
break;
case 'documentAttributeImageSize':
apiDoc.w = attribute.w;
@@ -3640,16 +3644,19 @@ 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, MtpApiFileManager, AppDocsManager, Storage) {
var currentStickers = [];
+ var currentStickersets = [];
var installedStickersets = {};
+ var stickersetItems = {};
var applied = false;
var started = false;
return {
start: start,
openStickersetLink: openStickersetLink,
+ installStickerset: installStickerset,
getStickers: getStickers,
getStickerset: getStickerset,
getStickersImages: getStickersImages
@@ -3670,26 +3677,49 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function processRawStickers(stickers) {
if (applied !== stickers.hash) {
applied = stickers.hash;
- var i, j, len1, len2, doc;
+ var i, j, len1, len2, doc, setID, set;
len1 = stickers.documents.length;
currentStickers = [];
+ stickersetItems = {};
for (i = 0; i < len1; i++) {
doc = stickers.documents[i];
AppDocsManager.saveDoc(doc);
currentStickers.push(doc.id);
+ setID = doc.stickerSetID || 0;
+ if (stickersetItems[setID] === undefined) {
+ stickersetItems[setID] = [];
+ }
+ stickersetItems[setID].push(doc.id);
+ }
+
+ if (stickersetItems[0] !== undefined) {
+ currentStickersets.push({
+ _: 'stickerSetDefault',
+ id: 0,
+ docIDs: stickersetItems[0]
+ });
}
+ len1 = stickers.sets.length;
+ for (i = 0; i < len1; i++) {
+ set = stickers.sets[i];
+ installedStickersets[set.id] = true;
+ set.docIDs = stickersetItems[set.id] || [];
+ currentStickersets.push(set);
+ }
+
}
- return currentStickers;
+
+ return currentStickersets;
}
- function getStickers () {
+ function getStickers (force) {
return Storage.get('all_stickers').then(function (stickers) {
var layer = Config.Schema.API.layer;
if (stickers.layer != layer) {
stickers = false;
}
- if (stickers && stickers.date > tsNow(true)) {
+ if (stickers && stickers.date > tsNow(true) && !force) {
return processRawStickers(stickers);
}
return MtpApiManager.invokeApi('messages.getAllStickers', {
@@ -3742,10 +3772,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) {
+ var method = uninstall
+ ? 'messages.uninstallStickerSet'
+ : 'messages.installStickerSet';
+ var inputStickerset = {
+ _: 'inputStickerSetID',
+ id: set.id,
+ access_hash: set.access_hash
+ };
+ return MtpApiManager.invokeApi(method, {
+ stickerset: inputStickerset
+ }).then(function (result) {
+ if (uninstall) {
+ delete installedStickersets[set.id];
+ } else {
+ installedStickersets[set.id] = true;
+ }
+ getStickers(true);
+ });
+ }
+
function openStickersetLink (shortName) {
var scope = $rootScope.$new(true);
scope.inputStickerset = {
@@ -3755,8 +3807,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var modal = $modal.open({
templateUrl: templateUrl('stickerset_modal'),
controller: 'StickersetModalController',
- scope: scope/*,
- windowClass: 'error_modal_window'*/
+ scope: scope,
+ windowClass: 'stickerset_modal_window'
});
}
})
diff --git a/app/less/app.less b/app/less/app.less
index e359c45b..9be84bb6 100644
--- a/app/less/app.less
+++ b/app/less/app.less
@@ -2474,6 +2474,20 @@ a.composer_emoji_btn {
vertical-align: top;
}
+.composer_stickerset_title {
+ display: block;
+ clear: both;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ font-weight: bold;
+ font-size: 13px;
+ color: #444;
+ margin: 10px 0 3px;
+}
+.composer_stickerset_title:hover {
+ color: #444;
+}
.composer_sticker_btn {
width: 78px;
height: 78px;
@@ -2917,6 +2931,49 @@ a.contacts_modal_contact:hover .md_modal_list_peer_description,
margin: 15px 0 20px 24px;
}
+
+.stickerset_modal_window .modal-dialog {
+ max-width: 474px;
+}
+.stickerset_modal_stickers_list {
+ padding: 25px;
+}
+.stickerset_modal_sticker_wrap {
+ list-style: none;
+ margin: 0 10px 10px 0;
+ padding: 0;
+ position: relative;
+ display: block;
+ width: 96px;
+ height: 96px;
+ float: left;
+}
+.stickerset_modal_sticker {
+ width: 96px;
+ height: 96px;
+}
+.stickerset_modal_sticker img {
+ width: 96px;
+ height: 96px;
+}
+.stickerset_modal_sticker_alt {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+}
+.stickerset_actions {
+ padding: 10px 20px;
+ text-align: center;
+}
+.stickerset_modal_loading {
+ text-align: center;
+ color: #999;
+ font-size: 16px;
+ line-height: 18px;
+ padding: 1px 50px;
+ margin: 0;
+}
+
.modal-dialog {
.md_simple_modal_window &,
.confirm_modal_window &,
diff --git a/app/less/desktop.less b/app/less/desktop.less
index 781b5807..d00863ac 100644
--- a/app/less/desktop.less
+++ b/app/less/desktop.less
@@ -646,6 +646,7 @@ a.footer_link.active:active {
.im_history_col .nano > &,
.contacts_modal_col .nano > &,
.sessions_modal_col .nano > &,
+ .stickerset_modal_col .nano > &,
.im_dialogs_modal_col .nano > & {
background : rgba(216,223,225,0.45); /*45% d8dfe5*/
width : 9px;
@@ -661,7 +662,8 @@ a.footer_link.active:active {
right: 4px;
}
- .sessions_modal_col .nano > & {
+ .sessions_modal_col .nano > &,
+ .stickerset_modal_col .nano > & {
top: 4px;
bottom: 4px;
width: 5px;
@@ -681,6 +683,7 @@ a.footer_link.active:active {
.im_history_col .nano > &,
.contacts_modal_col .nano > &,
.sessions_modal_col .nano > &,
+ .stickerset_modal_col .nano > &,
.im_dialogs_modal_col .nano > & {
& > .nano-slider {
background : rgba(137,160,179,0.50); /*50% 89a0b3*/
diff --git a/app/partials/desktop/stickerset_modal.html b/app/partials/desktop/stickerset_modal.html
index 445ea124..09065913 100644
--- a/app/partials/desktop/stickerset_modal.html
+++ b/app/partials/desktop/stickerset_modal.html
@@ -6,12 +6,15 @@
-