Sticker emoji suggestion

This commit is contained in:
Ilya Laktyushin 2024-03-31 16:24:25 +04:00
parent 977ecf458e
commit 7301013744
5 changed files with 1152 additions and 19 deletions

View File

@ -3,5 +3,5 @@ import Foundation
public struct GlobalExperimentalSettings {
public static var isAppStoreBuild: Bool = false
public static var enableFeed: Bool = false
public static var enableWIPStickers: Bool = false
public static var enableWIPStickers: Bool = true
}

View File

@ -42,10 +42,11 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
let isCreating: Bool
let selectedEmoji: [String]
let selectedEmojiUpdated: ([String]) -> Void
let recommendedEmoji: [String]
let menu: [ContextMenuItem]
let openPremiumIntro: () -> Void
public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, item: StickerPreviewPeekItem, isLocked: Bool = false, isCreating: Bool = false, selectedEmoji: [String] = [], selectedEmojiUpdated: @escaping ([String]) -> Void = { _ in }, menu: [ContextMenuItem], openPremiumIntro: @escaping () -> Void) {
public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, item: StickerPreviewPeekItem, isLocked: Bool = false, isCreating: Bool = false, selectedEmoji: [String] = [], selectedEmojiUpdated: @escaping ([String]) -> Void = { _ in }, recommendedEmoji: [String] = [], menu: [ContextMenuItem], openPremiumIntro: @escaping () -> Void) {
self.context = context
self.theme = theme
self.strings = strings
@ -54,6 +55,7 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
self.isCreating = isCreating
self.selectedEmoji = selectedEmoji
self.selectedEmojiUpdated = selectedEmojiUpdated
self.recommendedEmoji = recommendedEmoji
if isLocked {
self.menu = []
} else {
@ -84,7 +86,7 @@ public final class StickerPreviewPeekContent: PeekControllerContent {
public func fullScreenAccessoryNode(blurView: UIVisualEffectView) -> (PeekControllerAccessoryNode & ASDisplayNode)? {
if self.isCreating {
return EmojiStickerAccessoryNode(context: self.context, theme: self.theme, selectedEmoji: self.selectedEmoji, selectedEmojiUpdated: self.selectedEmojiUpdated)
return EmojiStickerAccessoryNode(context: self.context, theme: self.theme, recommendedEmoji: self.recommendedEmoji, selectedEmoji: self.selectedEmoji, selectedEmojiUpdated: self.selectedEmojiUpdated)
}
if self.isLocked {
return PremiumStickerPackAccessoryNode(theme: self.theme, strings: self.strings, isEmoji: self.item.file?.isCustomEmoji ?? false, proceed: self.openPremiumIntro)
@ -363,10 +365,14 @@ final class PremiumStickerPackAccessoryNode: SparseNode, PeekControllerAccessory
}
}
private func topItems(selectedEmoji: [String] = [], count: Int) -> [String] {
let defaultItems: [String] = [
private func topItems(selectedEmoji: [String] = [], recommendedEmoji: [String], count: Int) -> [String] {
var defaultItems: [String] = [
"👍", "👎", "", "🔥", "🥰", "👏", "😁"
]
if !recommendedEmoji.isEmpty, let firstEmoji = recommendedEmoji.first {
defaultItems.removeLast()
defaultItems.append(firstEmoji)
}
var result = selectedEmoji.filter { !defaultItems.contains($0) }
result.append(contentsOf: defaultItems)
return Array(result.prefix(count))
@ -382,12 +388,12 @@ final class EmojiStickerAccessoryNode: SparseNode, PeekControllerAccessoryNode {
private var scheduledCollapse = false
init(context: AccountContext, theme: PresentationTheme, selectedEmoji: [String], selectedEmojiUpdated: @escaping ([String]) -> Void) {
init(context: AccountContext, theme: PresentationTheme, recommendedEmoji: [String], selectedEmoji: [String], selectedEmojiUpdated: @escaping ([String]) -> Void) {
self.context = context
var layoutImpl: ((ContainedViewLayoutTransition) -> Void)?
let items = topItems(selectedEmoji: selectedEmoji, count: 7)
let items = topItems(selectedEmoji: selectedEmoji, recommendedEmoji: recommendedEmoji, count: 7)
let selectedItems = ValuePromise<[String]>(selectedEmoji)
//TODO:localize
@ -412,7 +418,7 @@ final class EmojiStickerAccessoryNode: SparseNode, PeekControllerAccessoryNode {
subject: .stickerAlt,
hasTrending: false,
topReactionItems: [],
topEmojiItems: topItems(selectedEmoji: selectedItems, count: 7),
topEmojiItems: topItems(selectedEmoji: selectedItems, recommendedEmoji: recommendedEmoji, count: 7),
areUnicodeEmojiEnabled: true,
areCustomEmojiEnabled: false,
chatPeerId: context.account.peerId,
@ -476,7 +482,7 @@ final class EmojiStickerAccessoryNode: SparseNode, PeekControllerAccessoryNode {
return
}
self.reactionContextNode.selectedItems = Set(items)
self.reactionContextNode.items = topItems(selectedEmoji: items, count: 7).map { .staticEmoji($0) }
self.reactionContextNode.items = topItems(selectedEmoji: items, recommendedEmoji: recommendedEmoji, count: 7).map { .staticEmoji($0) }
})
}

View File

@ -196,6 +196,8 @@ public final class MediaEditor {
public var canCutoutUpdated: (Bool) -> Void = { _ in }
public var isCutoutUpdated: (Bool) -> Void = { _ in }
public var classificationUpdated: ([(String, Float)]) -> Void = { _ in }
private var textureCache: CVMetalTextureCache!
public var hasPortraitMask: Bool {
@ -697,8 +699,8 @@ public final class MediaEditor {
textureSource.setMainInput(.image(image))
}
if case .sticker = self.mode, let cgImage = image.cgImage, !imageHasTransparency(cgImage) {
if case .sticker = self.mode, let cgImage = image.cgImage {
if !imageHasTransparency(cgImage) {
let _ = (cutoutStickerImage(from: image, onlyCheck: true)
|> deliverOnMainQueue).start(next: { [weak self] result in
guard let self, result != nil else {
@ -708,7 +710,11 @@ public final class MediaEditor {
self.canCutoutUpdated(true)
})
}
let _ = (classifyImage(image)
|> deliverOnMainQueue).start(next: { [weak self] classes in
self?.classificationUpdated(classes)
})
}
}
if let player, let playerItem = player.currentItem, !textureSourceResult.playerIsReference {
textureSource.setMainInput(.video(playerItem))

View File

@ -2568,6 +2568,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.isCutout = isCutout
self.requestLayout(forceUpdate: true, transition: .immediate)
}
mediaEditor.classificationUpdated = { [weak self] classes in
guard let self else {
return
}
self.controller?.stickerRecommendedEmoji = emojiForClasses(classes.map { $0.0 })
}
if case .message = effectiveSubject {
} else {
@ -5764,6 +5770,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
}
private var stickerRecommendedEmoji: [String] = []
private var stickerSelectedEmoji: [String] = []
private func effectiveStickerEmoji() -> [String] {
guard !self.stickerSelectedEmoji.isEmpty else {
@ -5924,6 +5931,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.stickerSelectedEmoji = selectedEmoji
}
},
recommendedEmoji: stickerRecommendedEmoji,
menu: menuItems,
openPremiumIntro: {}
),