Browse Source

Supported sticker suggestions by emoji

Also fixed blinking suggestions list
Closes #1409
Closes #1332
Closes #814
master
Igor Zhukov 7 years ago
parent
commit
092685db5a
  1. 57
      app/js/controllers.js
  2. 11
      app/js/lib/ng_utils.js
  3. 37
      app/js/message_composer.js
  4. 76
      app/js/services.js

57
app/js/controllers.js

@ -2288,7 +2288,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.$on('user_update', angular.noop) $scope.$on('user_update', angular.noop)
}) })
.controller('AppImSendController', function ($rootScope, $q, $scope, $timeout, MtpApiManager, Storage, AppProfileManager, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, AppInlineBotsManager, MtpApiFileManager, DraftsManager, RichTextProcessor) { .controller('AppImSendController', function ($rootScope, $q, $scope, $timeout, MtpApiManager, Storage, AppProfileManager, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppStickersManager, AppMessagesManager, AppInlineBotsManager, MtpApiFileManager, DraftsManager, RichTextProcessor) {
$scope.$watch('curDialog.peer', resetDraft) $scope.$watch('curDialog.peer', resetDraft)
$scope.$on('user_update', angular.noop) $scope.$on('user_update', angular.noop)
$scope.$on('peer_draft_attachment', applyDraftAttachment) $scope.$on('peer_draft_attachment', applyDraftAttachment)
@ -2793,6 +2793,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
} }
var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/ var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/
var inlineStickersEmojiRegex = /^\s*:(\S+):\s*$/
var getInlineResultsTO = false var getInlineResultsTO = false
var lastInlineBot = false var lastInlineBot = false
var jump = 0 var jump = 0
@ -2809,6 +2810,39 @@ angular.module('myApp.controllers', ['myApp.i18n'])
} }
var matches = message.match(inlineUsernameRegex) var matches = message.match(inlineUsernameRegex)
if (!matches) { if (!matches) {
matches = message.match(inlineStickersEmojiRegex)
if (matches) {
var emojiCode = EmojiHelper.shortcuts[matches[1]]
if (emojiCode) {
$scope.draftMessage.inlineProgress = true
AppStickersManager.searchStickers(emojiCode).then(function (docs) {
var inlineResults = []
angular.forEach(docs, function (doc) {
inlineResults.push({
_: 'botInlineMediaResult',
qID: '_sticker_' + doc.id,
pFlags: {sticker: true},
id: doc.id,
type: 'sticker',
document: doc,
send_message: {_: 'botInlineMessageMediaAuto'}
})
})
var botResults = {
pFlags: {gallery: true},
query_id: 0,
results: inlineResults
}
botResults.text = message
$scope.$broadcast('inline_results', botResults)
delete $scope.draftMessage.inlineProgress
})
} else {
delete $scope.draftMessage.inlineProgress
$scope.$broadcast('inline_results', false)
return
}
}
delete $scope.draftMessage.inlineProgress delete $scope.draftMessage.inlineProgress
$scope.$broadcast('inline_results', false) $scope.$broadcast('inline_results', false)
return return
@ -2954,7 +2988,26 @@ angular.module('myApp.controllers', ['myApp.i18n'])
replyToMsgID: $scope.draftMessage.replyToMsgID, replyToMsgID: $scope.draftMessage.replyToMsgID,
clearDraft: true clearDraft: true
} }
AppInlineBotsManager.sendInlineResult($scope.curDialog.peerID, qID, options)
if (qID.substr(0, 9) == '_sticker_') {
var docID = qID.substr(9)
var doc = AppDocsManager.getDoc(docID)
if (doc.id && doc.access_hash) {
var inputMedia = {
_: 'inputMediaDocument',
id: {
_: 'inputDocument',
id: doc.id,
access_hash: doc.access_hash
}
}
AppMessagesManager.sendOther($scope.curDialog.peerID, inputMedia, options)
}
}
else {
AppInlineBotsManager.sendInlineResult($scope.curDialog.peerID, qID, options)
}
if (forceDraft == $scope.curDialog.peer) { if (forceDraft == $scope.curDialog.peer) {
forceDraft = false forceDraft = false

11
app/js/lib/ng_utils.js

@ -1160,7 +1160,6 @@ angular.module('izhukov.utils', [])
}) })
.service('RichTextProcessor', function ($sce, $sanitize) { .service('RichTextProcessor', function ($sce, $sanitize) {
var emojiMap = {}
var emojiData = Config.Emoji var emojiData = Config.Emoji
var emojiIconSize = 18 var emojiIconSize = 18
var emojiSupported = navigator.userAgent.search(/OS X|iPhone|iPad|iOS|Android/i) != -1, var emojiSupported = navigator.userAgent.search(/OS X|iPhone|iPad|iOS|Android/i) != -1,
@ -1168,10 +1167,6 @@ angular.module('izhukov.utils', [])
var emojiRegExp = '\\u0023\\u20E3|\\u00a9|\\u00ae|\\u203c|\\u2049|\\u2139|[\\u2194-\\u2199]|\\u21a9|\\u21aa|\\u231a|\\u231b|\\u23e9|[\\u23ea-\\u23ec]|\\u23f0|\\u24c2|\\u25aa|\\u25ab|\\u25b6|\\u2611|\\u2614|\\u26fd|\\u2705|\\u2709|[\\u2795-\\u2797]|\\u27a1|\\u27b0|\\u27bf|\\u2934|\\u2935|[\\u2b05-\\u2b07]|\\u2b1b|\\u2b1c|\\u2b50|\\u2b55|\\u3030|\\u303d|\\u3297|\\u3299|[\\uE000-\\uF8FF\\u270A-\\u2764\\u2122\\u25C0\\u25FB-\\u25FE\\u2615\\u263a\\u2648-\\u2653\\u2660-\\u2668\\u267B\\u267F\\u2693\\u261d\\u26A0-\\u26FA\\u2708\\u2702\\u2601\\u260E]|[\\u2600\\u26C4\\u26BE\\u23F3\\u2764]|\\uD83D[\\uDC00-\\uDFFF]|\\uD83C[\\uDDE8-\\uDDFA\uDDEC]\\uD83C[\\uDDEA-\\uDDFA\uDDE7]|[0-9]\\u20e3|\\uD83C[\\uDC00-\\uDFFF]' var emojiRegExp = '\\u0023\\u20E3|\\u00a9|\\u00ae|\\u203c|\\u2049|\\u2139|[\\u2194-\\u2199]|\\u21a9|\\u21aa|\\u231a|\\u231b|\\u23e9|[\\u23ea-\\u23ec]|\\u23f0|\\u24c2|\\u25aa|\\u25ab|\\u25b6|\\u2611|\\u2614|\\u26fd|\\u2705|\\u2709|[\\u2795-\\u2797]|\\u27a1|\\u27b0|\\u27bf|\\u2934|\\u2935|[\\u2b05-\\u2b07]|\\u2b1b|\\u2b1c|\\u2b50|\\u2b55|\\u3030|\\u303d|\\u3297|\\u3299|[\\uE000-\\uF8FF\\u270A-\\u2764\\u2122\\u25C0\\u25FB-\\u25FE\\u2615\\u263a\\u2648-\\u2653\\u2660-\\u2668\\u267B\\u267F\\u2693\\u261d\\u26A0-\\u26FA\\u2708\\u2702\\u2601\\u260E]|[\\u2600\\u26C4\\u26BE\\u23F3\\u2764]|\\uD83D[\\uDC00-\\uDFFF]|\\uD83C[\\uDDE8-\\uDDFA\uDDEC]\\uD83C[\\uDDEA-\\uDDFA\uDDE7]|[0-9]\\u20e3|\\uD83C[\\uDC00-\\uDFFF]'
for (emojiCode in emojiData) {
emojiMap[emojiData[emojiCode][0]] = emojiCode
}
var alphaCharsRegExp = 'a-z' + var alphaCharsRegExp = 'a-z' +
'\\u00c0-\\u00d6\\u00d8-\\u00f6\\u00f8-\\u00ff' + // Latin-1 '\\u00c0-\\u00d6\\u00d8-\\u00f6\\u00f8-\\u00ff' + // Latin-1
'\\u0100-\\u024f' + // Latin Extended A and B '\\u0100-\\u024f' + // Latin Extended A and B
@ -1363,8 +1358,8 @@ angular.module('izhukov.utils', [])
}) })
} }
else if (match[8]) { // Emoji else if (match[8]) { // Emoji
if ((emojiCode = emojiMap[match[8]]) && if ((emojiCode = EmojiHelper.emojiMap[match[8]]) &&
(emojiCoords = getEmojiSpritesheetCoords(emojiCode))) { (emojiCoords = getEmojiSpritesheetCoords(emojiCode))) {
entities.push({ entities.push({
_: 'messageEntityEmoji', _: 'messageEntityEmoji',
offset: matchIndex, offset: matchIndex,
@ -1906,7 +1901,7 @@ angular.module('izhukov.utils', [])
text.push(raw.substr(0, match.index)) text.push(raw.substr(0, match.index))
if (match[8]) { if (match[8]) {
if ((emojiCode = emojiMap[match[8]]) && if ((emojiCode = EmojiHelper.emojiMap[match[8]]) &&
(emojiTitle = emojiData[emojiCode][1][0])) { (emojiTitle = emojiData[emojiCode][1][0])) {
text.push(':' + emojiTitle + ':') text.push(':' + emojiTitle + ':')
} else { } else {

37
app/js/message_composer.js

@ -9,9 +9,10 @@
/* EmojiHelper */ /* EmojiHelper */
;(function (global, emojis, categories, spritesheets) { ;(function (global, emojiData, categories, spritesheets) {
var emojis = {} var emojis = {}
var shortcuts = {} var shortcuts = {}
var emojiMap = {}
var spritesheetPositions = {} var spritesheetPositions = {}
var index = false var index = false
@ -32,7 +33,7 @@
totalColumns = spritesheets[i][1] totalColumns = spritesheets[i][1]
for (j = 0, len2 = categories[i].length; j < len2; j++) { for (j = 0, len2 = categories[i].length; j < len2; j++) {
code = categories[i][j] code = categories[i][j]
emoji = Config.Emoji[code] emoji = emojiData[code]
shortcut = emoji[1][0] shortcut = emoji[1][0]
emojis[code] = [emoji[0], shortcut] emojis[code] = [emoji[0], shortcut]
shortcuts[shortcut] = code shortcuts[shortcut] = code
@ -40,6 +41,10 @@
} }
} }
angular.forEach(emojiData, function (emoji, emojiCode) {
emojiMap[emoji[0]] = emojiCode
})
function getPopularEmoji (callback) { function getPopularEmoji (callback) {
ConfigStorage.get('emojis_popular', function (popEmojis) { ConfigStorage.get('emojis_popular', function (popEmojis) {
var result = [] var result = []
@ -126,6 +131,7 @@
global.EmojiHelper = { global.EmojiHelper = {
emojis: emojis, emojis: emojis,
emojiMap: emojiMap,
shortcuts: shortcuts, shortcuts: shortcuts,
spritesheetPositions: spritesheetPositions, spritesheetPositions: spritesheetPositions,
getPopularEmoji: getPopularEmoji, getPopularEmoji: getPopularEmoji,
@ -715,6 +721,7 @@ function MessageComposer (textarea, options) {
this.onInlineResultSend = options.onInlineResultSend this.onInlineResultSend = options.onInlineResultSend
this.mentions = options.mentions this.mentions = options.mentions
this.commands = options.commands this.commands = options.commands
this.renderToggleCnt = 0
} }
MessageComposer.autoCompleteRegEx = /(\s|^)(:|@|\/)([\S]*)$/ MessageComposer.autoCompleteRegEx = /(\s|^)(:|@|\/)([\S]*)$/
@ -1096,6 +1103,9 @@ MessageComposer.prototype.checkAutocomplete = function (forceFull) {
} }
} }
else if (matches[2] == ':') { // emoji else if (matches[2] == ':') { // emoji
if (value.match(/^\s*:(.+):\s*$/)) {
return
}
EmojiHelper.getPopularEmoji((function (popular) { EmojiHelper.getPopularEmoji((function (popular) {
if (query.length) { if (query.length) {
var found = EmojiHelper.searchEmojis(query) var found = EmojiHelper.searchEmojis(query)
@ -1497,6 +1507,7 @@ MessageComposer.prototype.renderSuggestions = function () {
} }
MessageComposer.prototype.showEmojiSuggestions = function (codes) { MessageComposer.prototype.showEmojiSuggestions = function (codes) {
var renderCnt = ++this.renderToggleCnt
var self = this var self = this
setZeroTimeout(function () { setZeroTimeout(function () {
self.autoCompleteScope.$apply(function () { self.autoCompleteScope.$apply(function () {
@ -1504,12 +1515,15 @@ MessageComposer.prototype.showEmojiSuggestions = function (codes) {
self.autoCompleteScope.emojiCodes = codes self.autoCompleteScope.emojiCodes = codes
}) })
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions() if (renderCnt == self.renderToggleCnt) {
self.renderSuggestions()
}
}) })
}) })
} }
MessageComposer.prototype.showMentionSuggestions = function (users) { MessageComposer.prototype.showMentionSuggestions = function (users) {
var renderCnt = ++this.renderToggleCnt
var self = this var self = this
setZeroTimeout(function () { setZeroTimeout(function () {
self.autoCompleteScope.$apply(function () { self.autoCompleteScope.$apply(function () {
@ -1517,12 +1531,15 @@ MessageComposer.prototype.showMentionSuggestions = function (users) {
self.autoCompleteScope.mentionUsers = users self.autoCompleteScope.mentionUsers = users
}) })
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions() if (renderCnt == self.renderToggleCnt) {
self.renderSuggestions()
}
}) })
}) })
} }
MessageComposer.prototype.showCommandsSuggestions = function (commands) { MessageComposer.prototype.showCommandsSuggestions = function (commands) {
var renderCnt = ++this.renderToggleCnt
var self = this var self = this
setZeroTimeout(function () { setZeroTimeout(function () {
self.autoCompleteScope.$apply(function () { self.autoCompleteScope.$apply(function () {
@ -1530,7 +1547,9 @@ MessageComposer.prototype.showCommandsSuggestions = function (commands) {
self.autoCompleteScope.commands = commands self.autoCompleteScope.commands = commands
}) })
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions() if (renderCnt == self.renderToggleCnt) {
self.renderSuggestions()
}
}) })
}) })
} }
@ -1540,6 +1559,7 @@ MessageComposer.prototype.showInlineSuggestions = function (botResults) {
this.hideSuggestions() this.hideSuggestions()
return return
} }
var renderCnt = ++this.renderToggleCnt
var self = this var self = this
if (self.autoCompleteScope.type == 'inline' && if (self.autoCompleteScope.type == 'inline' &&
self.autoCompleteScope.botResults == botResults && self.autoCompleteScope.botResults == botResults &&
@ -1552,7 +1572,9 @@ MessageComposer.prototype.showInlineSuggestions = function (botResults) {
self.autoCompleteScope.botResults = botResults self.autoCompleteScope.botResults = botResults
}) })
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions() if (renderCnt == self.renderToggleCnt) {
self.renderSuggestions()
}
}) })
}) })
} }
@ -1575,7 +1597,8 @@ MessageComposer.prototype.updatePosition = function () {
} }
MessageComposer.prototype.hideSuggestions = function () { MessageComposer.prototype.hideSuggestions = function () {
// console.trace() var renderCnt = ++this.renderToggleCnt
// console.trace(dT())
// return // return
this.autoCompleteWrapEl.hide() this.autoCompleteWrapEl.hide()
delete this.autocompleteShown delete this.autocompleteShown

76
app/js/services.js

@ -2209,6 +2209,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
var started = false var started = false
var applied = false var applied = false
var currentStickerSets = [] var currentStickerSets = []
var emojiIndex = {}
$rootScope.$on('apiUpdate', function (e, update) { $rootScope.$on('apiUpdate', function (e, update) {
if (update._ != 'updateStickerSets' && if (update._ != 'updateStickerSets' &&
@ -2220,7 +2221,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
return Storage.get('all_stickers').then(function (stickers) { return Storage.get('all_stickers').then(function (stickers) {
if (!stickers || if (!stickers ||
stickers.layer != Config.Schema.API.layer) { stickers.layer != Config.Schema.API.layer) {
$rootScope.$broadcast('stickers_changed') $rootScope.$broadcast('stickers_changed')
} }
switch (update._) { switch (update._) {
@ -2243,6 +2244,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
set.pFlags.installed = true set.pFlags.installed = true
stickers.sets.unshift(set) stickers.sets.unshift(set)
stickers.fullSets[set.id] = fullSet stickers.fullSets[set.id] = fullSet
indexStickerSetEmoticons(fullSet)
break break
case 'updateDelStickerSet': case 'updateDelStickerSet':
@ -2283,6 +2285,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
openStickerset: openStickerset, openStickerset: openStickerset,
installStickerset: installStickerset, installStickerset: installStickerset,
pushPopularSticker: pushPopularSticker, pushPopularSticker: pushPopularSticker,
searchStickers: searchStickers,
getStickerset: getStickerset getStickerset: getStickerset
} }
@ -2296,10 +2299,12 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function getStickers (force) { function getStickers (force) {
return Storage.get('all_stickers').then(function (stickers) { return Storage.get('all_stickers').then(function (stickers) {
var layer = Config.Schema.API.layer var layer = Config.Schema.API.layer
if (stickers.layer != layer) { if (stickers.layer != layer ||
stickers.emojiIndex === undefined) {
stickers = false stickers = false
} }
if (stickers && stickers.date > tsNow(true) && !force) { if (stickers && stickers.date > tsNow(true) && !force) {
emojiIndex = stickers.emojiIndex
return processRawStickers(stickers) return processRawStickers(stickers)
} }
return MtpApiManager.invokeApi('messages.getAllStickers', { return MtpApiManager.invokeApi('messages.getAllStickers', {
@ -2315,6 +2320,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
if (notModified) { if (notModified) {
Storage.set({all_stickers: newStickers}) Storage.set({all_stickers: newStickers})
emojiIndex = newStickers.emojiIndex
return processRawStickers(newStickers) return processRawStickers(newStickers)
} }
@ -2376,14 +2382,74 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}) })
} }
function indexStickerSetEmoticons(fullSet) {
angular.forEach(fullSet.packs, function (pack) {
var emoji = pack.emoticon
var emojiCode = false
while (emoji.length) {
emojiCode = EmojiHelper.emojiMap[emoji]
if (emojiCode !== undefined) {
break
}
emoji = emoji.substr(0, -1)
}
// console.warn('index', fullSet, pack, emojiCode)
if (emojiCode === undefined) {
return
}
var stickersList = emojiIndex[emojiCode]
if (stickersList === undefined) {
emojiIndex[emojiCode] = stickersList = []
}
angular.forEach(pack.documents, function (docID) {
if (stickersList.indexOf(docID) === -1) {
stickersList.push(docID)
}
})
})
}
function searchStickers(emojiCode) {
return getPopularStickers().then(function () {
// console.warn('search', emojiCode, emojiIndex, emojiIndex[emojiCode])
var stickersList = emojiIndex[emojiCode]
var result = []
if (stickersList === undefined) {
return result
}
var setIDs = []
angular.forEach(currentStickerSets, function (set) {
setIDs.push(set.id)
})
angular.forEach(stickersList, function (docID) {
var doc = AppDocsManager.getDoc(docID)
if (!doc || !doc.stickerSetInput) {
return
}
var setID = doc.stickerSetInput.id
if (setIDs.indexOf(setID) == -1) {
return
}
result.push(doc)
})
result.sort(function (doc1, doc2) {
return setIDs.indexOf(doc1.stickerSetInput.id) - setIDs.indexOf(doc2.stickerSetInput.id)
})
return result
})
}
function getStickerSets (allStickers, prevCachedSets) { function getStickerSets (allStickers, prevCachedSets) {
var promises = [] var promises = []
var cachedSets = prevCachedSets || allStickers.fullSets || {} var cachedSets = prevCachedSets || allStickers.fullSets || {}
allStickers.fullSets = {} allStickers.fullSets = {}
emojiIndex = allStickers.emojiIndex = {}
angular.forEach(allStickers.sets, function (shortSet) { angular.forEach(allStickers.sets, function (shortSet) {
var fullSet = cachedSets[shortSet.id] var fullSet = cachedSets[shortSet.id]
if (fullSet && fullSet.set.hash == shortSet.hash) { if (fullSet && fullSet.set.hash == shortSet.hash) {
allStickers.fullSets[shortSet.id] = fullSet allStickers.fullSets[shortSet.id] = fullSet
indexStickerSetEmoticons(fullSet)
} else { } else {
var promise = MtpApiManager.invokeApi('messages.getStickerSet', { var promise = MtpApiManager.invokeApi('messages.getStickerSet', {
stickerset: { stickerset: {
@ -2393,6 +2459,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
} }
}).then(function (fullSet) { }).then(function (fullSet) {
allStickers.fullSets[shortSet.id] = fullSet allStickers.fullSets[shortSet.id] = fullSet
indexStickerSetEmoticons(fullSet)
}) })
promises.push(promise) promises.push(promise)
} }
@ -2653,8 +2720,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
function regroupWrappedResults (results, rowW, rowH) { function regroupWrappedResults (results, rowW, rowH) {
if (!results || if (!results ||
!results[0] || !results[0] ||
results[0].type != 'photo' && results[0].type != 'gif' && results[0].type != 'sticker') { ['photo', 'gif', 'sticker'].indexOf(results[0].type) == -1) {
return return
} }
var ratios = [] var ratios = []
@ -4768,6 +4835,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
// console.warn(dT(), 'server', draft) // console.warn(dT(), 'server', draft)
} else { } else {
// console.warn(dT(), 'local', draft) // console.warn(dT(), 'local', draft)
console.warn(dT(), 'local', draft)
} }
var replyToMsgID = draft && draft.replyToMsgID var replyToMsgID = draft && draft.replyToMsgID
if (replyToMsgID) { if (replyToMsgID) {

Loading…
Cancel
Save