mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Emoji input improvements
This commit is contained in:
parent
3384d86415
commit
7b663a3445
@ -556,7 +556,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} else {
|
||||
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
|
||||
}
|
||||
let (_, initialHideAuthor, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
|
||||
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
|
||||
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
|
||||
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
|
||||
}
|
||||
@ -590,7 +590,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} else {
|
||||
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
|
||||
}
|
||||
let (_, initialHideAuthor, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
|
||||
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
|
||||
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
|
||||
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
|
||||
}
|
||||
@ -1095,7 +1095,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
let leftInset: CGFloat = params.leftInset + avatarLeftInset
|
||||
|
||||
enum ContentData {
|
||||
case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?)
|
||||
case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?)
|
||||
case group(peers: [EngineChatList.GroupItem.Item])
|
||||
}
|
||||
|
||||
@ -1104,7 +1104,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
var hideAuthor = false
|
||||
switch contentPeer {
|
||||
case let .chat(itemPeer):
|
||||
var (peer, initialHideAuthor, messageText, spoilers) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
|
||||
var (peer, initialHideAuthor, messageText, spoilers, customEmojiRanges) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
|
||||
|
||||
if case let .psa(_, maybePsaText) = promoInfo, let psaText = maybePsaText {
|
||||
initialHideAuthor = true
|
||||
@ -1125,7 +1125,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
break
|
||||
}
|
||||
|
||||
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers)
|
||||
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers, customEmojiRanges: customEmojiRanges)
|
||||
hideAuthor = initialHideAuthor
|
||||
case let .group(groupPeers):
|
||||
contentData = .group(peers: groupPeers)
|
||||
@ -1156,7 +1156,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
|
||||
|
||||
switch contentData {
|
||||
case let .chat(itemPeer, _, _, text, spoilers):
|
||||
case let .chat(itemPeer, _, _, text, spoilers, customEmojiRanges):
|
||||
var isUser = false
|
||||
if case .user = itemPeer.chatMainPeer {
|
||||
isUser = true
|
||||
@ -1185,6 +1185,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} else {
|
||||
if let spoilers = spoilers, !spoilers.isEmpty {
|
||||
messageText = text
|
||||
} else if let customEmojiRanges = customEmojiRanges, !customEmojiRanges.isEmpty {
|
||||
messageText = text
|
||||
} else {
|
||||
messageText = foldLineBreaks(text)
|
||||
}
|
||||
@ -1216,10 +1218,17 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
let messageString: NSAttributedString
|
||||
if !message.text.isEmpty && entities.count > 0 {
|
||||
messageString = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: authorAttributedString == nil ? 2 : 1), entities: entities, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: message._asMessage())
|
||||
} else if let spoilers = spoilers {
|
||||
} else if spoilers != nil || customEmojiRanges != nil {
|
||||
let mutableString = NSMutableAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
|
||||
for range in spoilers {
|
||||
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)
|
||||
if let spoilers = spoilers {
|
||||
for range in spoilers {
|
||||
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)
|
||||
}
|
||||
}
|
||||
if let customEmojiRanges = customEmojiRanges {
|
||||
for (range, attribute) in customEmojiRanges {
|
||||
mutableString.addAttribute(ChatTextInputAttributes.customEmoji, value: attribute, range: range)
|
||||
}
|
||||
}
|
||||
messageString = mutableString
|
||||
} else {
|
||||
@ -1268,8 +1277,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
attributedText = composedString
|
||||
|
||||
|
||||
|
||||
var displayMediaPreviews = true
|
||||
if message._asMessage().containsSecretMedia {
|
||||
displayMediaPreviews = false
|
||||
@ -1359,7 +1366,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
|
||||
switch contentData {
|
||||
case let .chat(itemPeer, _, _, _, _):
|
||||
case let .chat(itemPeer, _, _, _, _, _):
|
||||
if let message = messages.last, case let .user(author) = message.author, displayAsMessage {
|
||||
titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer.user(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor)
|
||||
} else if isPeerGroup {
|
||||
|
@ -4,6 +4,7 @@ import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import TelegramStringFormatting
|
||||
import LocalizedPeerData
|
||||
import TextFormat
|
||||
|
||||
private enum MessageGroupType {
|
||||
case photos
|
||||
@ -44,7 +45,7 @@ private func messageGroupType(messages: [EngineMessage]) -> MessageGroupType {
|
||||
return currentType
|
||||
}
|
||||
|
||||
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?) {
|
||||
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?) {
|
||||
let peer: EnginePeer?
|
||||
|
||||
let message = messages.last
|
||||
@ -52,6 +53,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
||||
var hideAuthor = false
|
||||
var messageText: String
|
||||
var spoilers: [NSRange]?
|
||||
var customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?
|
||||
if let message = message {
|
||||
if let messageMain = messageMainPeer(message) {
|
||||
peer = messageMain
|
||||
@ -269,13 +271,14 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
||||
}
|
||||
default:
|
||||
hideAuthor = true
|
||||
if let (text, textSpoilers) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
|
||||
if let (text, textSpoilers, customEmojiRangesValue) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
|
||||
messageText = text
|
||||
spoilers = textSpoilers
|
||||
customEmojiRanges = customEmojiRangesValue
|
||||
}
|
||||
}
|
||||
case _ as TelegramMediaExpiredContent:
|
||||
if let (text, _) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
|
||||
if let (text, _, _) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
|
||||
messageText = text
|
||||
}
|
||||
case let poll as TelegramMediaPoll:
|
||||
@ -314,5 +317,5 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
||||
}
|
||||
}
|
||||
|
||||
return (peer, hideAuthor, messageText, spoilers)
|
||||
return (peer, hideAuthor, messageText, spoilers, customEmojiRanges)
|
||||
}
|
||||
|
@ -27,36 +27,93 @@ public final class BlurredBackgroundComponent: Component {
|
||||
}
|
||||
|
||||
public final class View: BlurredBackgroundView {
|
||||
private var tintMaskView: UIView?
|
||||
private var tintContainerView: UIView?
|
||||
private var vibrancyEffectView: UIVisualEffectView?
|
||||
|
||||
public func update(component: BlurredBackgroundComponent, availableSize: CGSize, transition: Transition) -> CGSize {
|
||||
if let tintContainerView = component.tintContainerView {
|
||||
self.updateColor(color: .clear, forceKeepBlur: true, transition: transition.containedViewLayoutTransition)
|
||||
/*if self.tintContainerView !== component.tintContainerView {
|
||||
if let tintContainerView = self.tintContainerView {
|
||||
self.tintContainerView = nil
|
||||
if tintContainerView.superview === self {
|
||||
tintContainerView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
let tintMaskView: UIView
|
||||
if let current = self.tintMaskView {
|
||||
tintMaskView = current
|
||||
self.tintContainerView = component.tintContainerView
|
||||
|
||||
if let tintContainerView = self.tintContainerView {
|
||||
let vibrancyEffectView: UIVisualEffectView
|
||||
if let current = self.vibrancyEffectView {
|
||||
vibrancyEffectView = current
|
||||
} else {
|
||||
let blurEffect = UIBlurEffect(style: .extraLight)
|
||||
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
|
||||
vibrancyEffectView = UIVisualEffectView(effect: vibrancyEffect)
|
||||
self.vibrancyEffectView = vibrancyEffectView
|
||||
self.addSubview(vibrancyEffectView)
|
||||
}
|
||||
tintContainerView.backgroundColor = .white
|
||||
vibrancyEffectView.contentView.addSubview(tintContainerView)
|
||||
} else {
|
||||
tintMaskView = UIView()
|
||||
self.tintMaskView = tintMaskView
|
||||
self.addSubview(tintMaskView)
|
||||
}
|
||||
|
||||
tintMaskView.backgroundColor = component.color
|
||||
transition.setFrame(view: tintMaskView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||
|
||||
if tintMaskView.mask !== tintContainerView {
|
||||
tintMaskView.mask = tintContainerView
|
||||
if let vibrancyEffectView = self.vibrancyEffectView {
|
||||
self.vibrancyEffectView = nil
|
||||
vibrancyEffectView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
self.updateColor(color: component.color, transition: transition.containedViewLayoutTransition)
|
||||
|
||||
/*if let _ = self.viewWithTag(123) {
|
||||
} else {
|
||||
self.updateColor(color: component.color, transition: transition.containedViewLayoutTransition)
|
||||
let blurEffect = UIBlurEffect(style: .extraLight)
|
||||
|
||||
if let tintMaskView = self.tintMaskView {
|
||||
self.tintMaskView = nil
|
||||
tintMaskView.removeFromSuperview()
|
||||
}
|
||||
|
||||
/*let segmentedControl = UISegmentedControl(items: ["First Item", "Second Item"])
|
||||
segmentedControl.sizeToFit()
|
||||
segmentedControl.center = CGPoint(x: 250.0, y: 250.0)*/
|
||||
let testView = UIView(frame: CGRect(origin: CGPoint(x: 50.0, y: 100.0), size: CGSize(width: 250.0, height: 50.0)))
|
||||
testView.backgroundColor = .white
|
||||
|
||||
let testView2 = UILabel()
|
||||
testView2.text = "Test 13245"
|
||||
testView2.font = Font.semibold(17.0)
|
||||
testView2.textColor = .black
|
||||
testView2.sizeToFit()
|
||||
|
||||
testView2.center = CGPoint(x: 250.0 - testView.frame.minX, y: 490.0 - testView.frame.minY)
|
||||
|
||||
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
|
||||
let vibrancyEffectView = UIVisualEffectView(effect: vibrancyEffect)
|
||||
//vibrancyEffectView.frame = CGRect(origin: CGPoint(), size: CGSize(width: 400.0, height: 300.0))
|
||||
vibrancyEffectView.tag = 123
|
||||
|
||||
vibrancyEffectView.contentView.addSubview(testView)
|
||||
testView.addSubview(testView2)
|
||||
//vibrancyEffectView.contentView.addSubview(testView2)
|
||||
|
||||
self.addSubview(vibrancyEffectView)
|
||||
|
||||
/*let view = UIView()
|
||||
view.tag = 123
|
||||
view.layer.compositingFilter = "sourceOverCompositing"
|
||||
view.backgroundColor = .white
|
||||
view.frame = CGRect(origin: CGPoint(), size: CGSize(width: 100.0, height: 200.0))
|
||||
self.addSubview(view)*/
|
||||
}
|
||||
|
||||
if let view = self.viewWithTag(123) {
|
||||
view.frame = CGRect(origin: CGPoint(), size: availableSize)
|
||||
}*/
|
||||
|
||||
self.update(size: availableSize, transition: transition.containedViewLayoutTransition)
|
||||
|
||||
if let tintContainerView = self.tintContainerView {
|
||||
transition.setFrame(view: tintContainerView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||
}
|
||||
if let vibrancyEffectView = self.vibrancyEffectView {
|
||||
transition.setFrame(view: vibrancyEffectView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||
}
|
||||
|
||||
return availableSize
|
||||
}
|
||||
|
@ -12,6 +12,10 @@ public protocol PagerPanGestureRecognizer: UIGestureRecognizer {
|
||||
open class PagerExternalTopPanelContainer: SparseContainerView {
|
||||
}
|
||||
|
||||
public protocol PagerContentViewWithBackground: UIView {
|
||||
func pagerUpdateBackground(backgroundFrame: CGRect, transition: Transition)
|
||||
}
|
||||
|
||||
public final class PagerComponentChildEnvironment: Equatable {
|
||||
public struct ContentScrollingUpdate {
|
||||
public var relativeOffset: CGFloat
|
||||
@ -292,8 +296,15 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
case .began:
|
||||
self.paneTransitionGestureState = PaneTransitionGestureState()
|
||||
case .changed:
|
||||
if var paneTransitionGestureState = self.paneTransitionGestureState, self.bounds.width > 0.0 {
|
||||
paneTransitionGestureState.fraction = recognizer.translation(in: self).x / self.bounds.width
|
||||
if let centralId = self.centralId, let component = self.component, let centralIndex = component.contents.firstIndex(where: { $0.id == centralId }), var paneTransitionGestureState = self.paneTransitionGestureState, self.bounds.width > 0.0 {
|
||||
var fraction = recognizer.translation(in: self).x / self.bounds.width
|
||||
if centralIndex <= 0 {
|
||||
fraction = min(0.0, fraction)
|
||||
}
|
||||
if centralIndex >= component.contents.count - 1 {
|
||||
fraction = max(0.0, fraction)
|
||||
}
|
||||
paneTransitionGestureState.fraction = fraction
|
||||
|
||||
self.paneTransitionGestureState = paneTransitionGestureState
|
||||
self.state?.updated(transition: .immediate)
|
||||
@ -554,6 +565,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
}
|
||||
}
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: effectiveTopPanelHeight), size: CGSize(width: availableSize.width, height: availableSize.height - effectiveTopPanelHeight - contentInsets.bottom + bottomPanelOffset))
|
||||
if let contentBackground = component.contentBackground {
|
||||
let contentBackgroundView: ComponentHostView<Empty>
|
||||
var contentBackgroundTransition = panelStateTransition
|
||||
@ -565,13 +577,13 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
self.contentBackgroundView = contentBackgroundView
|
||||
self.insertSubview(contentBackgroundView, at: 0)
|
||||
}
|
||||
let contentBackgroundSize = contentBackgroundView.update(
|
||||
let _ = contentBackgroundView.update(
|
||||
transition: contentBackgroundTransition,
|
||||
component: contentBackground,
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width, height: availableSize.height - effectiveTopPanelHeight - contentInsets.bottom + bottomPanelOffset)
|
||||
containerSize: backgroundFrame.size
|
||||
)
|
||||
contentBackgroundTransition.setFrame(view: contentBackgroundView, frame: CGRect(origin: CGPoint(x: 0.0, y: effectiveTopPanelHeight), size: contentBackgroundSize))
|
||||
contentBackgroundTransition.setFrame(view: contentBackgroundView, frame: backgroundFrame)
|
||||
} else {
|
||||
if let contentBackgroundView = self.contentBackgroundView {
|
||||
self.contentBackgroundView = nil
|
||||
@ -691,6 +703,10 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if let contentViewWithBackground = contentView.view.componentView as? PagerContentViewWithBackground {
|
||||
contentViewWithBackground.pagerUpdateBackground(backgroundFrame: backgroundFrame, transition: contentTransition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,6 +327,7 @@ open class BlurredBackgroundView: UIView {
|
||||
if let color = self._color, self.enableBlur && !sharedIsReduceTransparencyEnabled && ((color.alpha > .ulpOfOne && color.alpha < 0.95) || forceKeepBlur) {
|
||||
if self.effectView == nil {
|
||||
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
//effectView.isHidden = true
|
||||
|
||||
for subview in effectView.subviews {
|
||||
if subview.description.contains("VisualEffectSubview") {
|
||||
|
@ -768,12 +768,13 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.animationNode = animationNode
|
||||
strongSelf.addSubnode(animationNode)
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .cached)
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
}
|
||||
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
|
||||
animationNode.isHidden = !item.playAnimatedStickers
|
||||
strongSelf.imageNode.isHidden = item.playAnimatedStickers
|
||||
if let animationNode = strongSelf.animationNode {
|
||||
animationNode.updateLayout(size: imageFrame.size)
|
||||
transition.updateFrame(node: animationNode, frame: imageFrame)
|
||||
}
|
||||
}
|
||||
|
@ -729,7 +729,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
|
||||
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: action == .archive ? presentationData.strings.StickerPackActionInfo_ArchivedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(archivedItem.info.title).string, undo: true, info: archivedItem.info, topItem: archivedItem.topItems.first, context: context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { action in
|
||||
if case .undo = action {
|
||||
let _ = context.engine.stickers.addStickerPackInteractively(info: archivedItem.info, items: items, positionInList: positionInList).start()
|
||||
let _ = context.engine.stickers.addStickerPackInteractively(info: archivedItem.info, items: items.compactMap({ $0 as? StickerPackItem }), positionInList: positionInList).start()
|
||||
}
|
||||
return true
|
||||
}))
|
||||
|
@ -3,7 +3,7 @@ import Postbox
|
||||
import SwiftSignalKit
|
||||
|
||||
|
||||
func _internal_addStickerPackInteractively(postbox: Postbox, info: StickerPackCollectionInfo, items: [ItemCollectionItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
|
||||
func _internal_addStickerPackInteractively(postbox: Postbox, info: StickerPackCollectionInfo, items: [StickerPackItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
|
||||
return postbox.transaction { transaction -> Void in
|
||||
let namespace: SynchronizeInstalledStickerPacksOperationNamespace?
|
||||
switch info.id.namespace {
|
||||
@ -33,7 +33,12 @@ func _internal_addStickerPackInteractively(postbox: Postbox, info: StickerPackCo
|
||||
} else {
|
||||
updatedInfos.insert(mappedInfo, at: 0)
|
||||
}
|
||||
transaction.replaceItemCollectionItems(collectionId: mappedInfo.id, items: items)
|
||||
|
||||
var indexedItems: [ItemCollectionItem] = []
|
||||
for item in items {
|
||||
indexedItems.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(indexedItems.count), id: item.index.id), file: item.file, indexKeys: item.indexKeys))
|
||||
}
|
||||
transaction.replaceItemCollectionItems(collectionId: mappedInfo.id, items: indexedItems)
|
||||
}
|
||||
transaction.replaceItemCollectionInfos(namespace: mappedInfo.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) })
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public extension TelegramEngine {
|
||||
return _internal_searchGifs(account: self.account, query: query, nextOffset: nextOffset)
|
||||
}
|
||||
|
||||
public func addStickerPackInteractively(info: StickerPackCollectionInfo, items: [ItemCollectionItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
|
||||
public func addStickerPackInteractively(info: StickerPackCollectionInfo, items: [StickerPackItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
|
||||
return _internal_addStickerPackInteractively(postbox: self.account.postbox, info: info, items: items, positionInList: positionInList)
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,6 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatKeyboardActionButtonProfileIcon
|
||||
case chatKeyboardActionButtonAddToChatIcon
|
||||
case chatKeyboardActionButtonWebAppIcon
|
||||
case chatEntityKeyboardLock
|
||||
|
||||
case uploadToneIcon
|
||||
}
|
||||
@ -313,4 +312,7 @@ public enum PresentationResourceParameterKey: Hashable {
|
||||
case chatMessageCommentsArrowIcon(incoming: Bool)
|
||||
case chatMessageCommentsUnreadDotIcon(incoming: Bool)
|
||||
case chatMessageRepliesIcon(incoming: Bool)
|
||||
|
||||
case chatEntityKeyboardLock(color: UInt32)
|
||||
case chatInputMediaPanelGridDismissImage(color: UInt32)
|
||||
}
|
||||
|
@ -371,9 +371,9 @@ public struct PresentationResourcesChat {
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatInputMediaPanelGridDismissImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatInputMediaPanelGridDismissImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/GridDismissIcon"), color: theme.chat.inputMediaPanel.stickersSectionTextColor)
|
||||
public static func chatInputMediaPanelGridDismissImage(_ theme: PresentationTheme, color: UIColor) -> UIImage? {
|
||||
return theme.image(PresentationResourceParameterKey.chatInputMediaPanelGridDismissImage(color: color.argb), { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/GridDismissIcon"), color: color)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1282,9 +1282,9 @@ public struct PresentationResourcesChat {
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatEntityKeyboardLock(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatEntityKeyboardLock.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.chat.inputMediaPanel.stickersSectionTextColor)
|
||||
public static func chatEntityKeyboardLock(_ theme: PresentationTheme, color: UIColor) -> UIImage? {
|
||||
return theme.image(PresentationResourceParameterKey.chatEntityKeyboardLock(color: color.argb), { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: color)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -34,15 +34,18 @@ private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, E
|
||||
return result
|
||||
}
|
||||
|
||||
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> (String, [NSRange])? {
|
||||
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> (text: String, spoilerRanges: [NSRange], customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)])? {
|
||||
if let attributedString = universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: forChatList) {
|
||||
var ranges: [NSRange] = []
|
||||
var customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)] = []
|
||||
attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: [], using: { attributes, range, _ in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)] {
|
||||
ranges.append(range)
|
||||
} else if let value = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute {
|
||||
customEmojiRanges.append((range, value))
|
||||
}
|
||||
})
|
||||
return (attributedString.string, ranges)
|
||||
return (attributedString.string, ranges, customEmojiRanges)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -171,6 +171,8 @@ public final class EntityKeyboardComponent: Component {
|
||||
}
|
||||
|
||||
public final class View: UIView {
|
||||
private let tintContainerView: UIView
|
||||
|
||||
private let pagerView: ComponentHostView<EntityKeyboardChildEnvironment>
|
||||
|
||||
private var component: EntityKeyboardComponent?
|
||||
@ -191,6 +193,7 @@ public final class EntityKeyboardComponent: Component {
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.tintContainerView = UIView()
|
||||
self.pagerView = ComponentHostView<EntityKeyboardChildEnvironment>()
|
||||
|
||||
super.init(frame: frame)
|
||||
@ -392,7 +395,7 @@ public final class EntityKeyboardComponent: Component {
|
||||
maxSize: nil
|
||||
)),
|
||||
action: {
|
||||
stickerContent.inputInteraction.openStickerSettings()
|
||||
stickerContent.inputInteractionHolder.inputInteraction?.openStickerSettings()
|
||||
}
|
||||
).minSize(CGSize(width: 38.0, height: 38.0)))))
|
||||
}
|
||||
@ -494,7 +497,7 @@ public final class EntityKeyboardComponent: Component {
|
||||
component.switchToTextInput()
|
||||
}
|
||||
).minSize(CGSize(width: 38.0, height: 38.0)))))
|
||||
let deleteBackwards = component.emojiContent.inputInteraction.deleteBackwards
|
||||
let deleteBackwards = component.emojiContent.inputInteractionHolder.inputInteraction?.deleteBackwards
|
||||
contentAccessoryRightButtons.append(AnyComponentWithIdentity(id: "emoji", component: AnyComponent(Button(
|
||||
content: AnyComponent(BundleIconComponent(
|
||||
name: "Chat/Input/Media/EntityInputClearIcon",
|
||||
@ -502,11 +505,11 @@ public final class EntityKeyboardComponent: Component {
|
||||
maxSize: nil
|
||||
)),
|
||||
action: {
|
||||
deleteBackwards()
|
||||
deleteBackwards?()
|
||||
AudioServicesPlaySystemSound(1155)
|
||||
}
|
||||
).withHoldAction({
|
||||
deleteBackwards()
|
||||
deleteBackwards?()
|
||||
AudioServicesPlaySystemSound(1155)
|
||||
}).minSize(CGSize(width: 38.0, height: 38.0)))))
|
||||
|
||||
@ -529,9 +532,10 @@ public final class EntityKeyboardComponent: Component {
|
||||
contentAccessoryLeftButtons: contentAccessoryLeftButtons,
|
||||
contentAccessoryRightButtons: contentAccessoryRightButtons,
|
||||
defaultId: component.defaultToEmojiTab ? "emoji" : "stickers",
|
||||
contentBackground: AnyComponent(BlurredBackgroundComponent(
|
||||
color: component.theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75)
|
||||
)),
|
||||
contentBackground: nil/*AnyComponent(BlurredBackgroundComponent(
|
||||
color: component.theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75),
|
||||
tintContainerView: self.tintContainerView
|
||||
))*/,
|
||||
topPanel: AnyComponent(EntityKeyboardTopContainerPanelComponent(
|
||||
theme: component.theme,
|
||||
overflowHeight: component.hiddenInputHeight,
|
||||
@ -542,7 +546,7 @@ public final class EntityKeyboardComponent: Component {
|
||||
theme: component.theme,
|
||||
bottomInset: component.bottomInset,
|
||||
deleteBackwards: { [weak self] in
|
||||
self?.component?.emojiContent.inputInteraction.deleteBackwards()
|
||||
self?.component?.emojiContent.inputInteractionHolder.inputInteraction?.deleteBackwards()
|
||||
AudioServicesPlaySystemSound(0x451)
|
||||
}
|
||||
)),
|
||||
|
@ -213,7 +213,7 @@ public final class GifPagerContentComponent: Component {
|
||||
return true
|
||||
}
|
||||
|
||||
public final class View: ContextControllerSourceView, UIScrollViewDelegate {
|
||||
public final class View: ContextControllerSourceView, PagerContentViewWithBackground, UIScrollViewDelegate {
|
||||
private struct ItemGroupDescription: Equatable {
|
||||
let hasTitle: Bool
|
||||
let itemCount: Int
|
||||
@ -400,6 +400,8 @@ public final class GifPagerContentComponent: Component {
|
||||
private final class ContentScrollView: UIScrollView, PagerExpandableScrollView {
|
||||
}
|
||||
|
||||
private let backgroundView: BlurredBackgroundView
|
||||
|
||||
private let shimmerHostView: PortalSourceView
|
||||
private let standaloneShimmerEffect: StandaloneShimmerEffect
|
||||
|
||||
@ -418,6 +420,8 @@ public final class GifPagerContentComponent: Component {
|
||||
private var currentLoadMoreToken: String?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.backgroundView = BlurredBackgroundView(color: nil)
|
||||
|
||||
self.shimmerHostView = PortalSourceView()
|
||||
self.standaloneShimmerEffect = StandaloneShimmerEffect()
|
||||
|
||||
@ -427,6 +431,8 @@ public final class GifPagerContentComponent: Component {
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
|
||||
self.shimmerHostView.alpha = 0.0
|
||||
self.addSubview(self.shimmerHostView)
|
||||
|
||||
@ -745,6 +751,15 @@ public final class GifPagerContentComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
public func pagerUpdateBackground(backgroundFrame: CGRect, transition: Transition) {
|
||||
guard let theme = self.theme else {
|
||||
return
|
||||
}
|
||||
self.backgroundView.updateColor(color: theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75), enableBlur: true, forceKeepBlur: false, transition: transition.containedViewLayoutTransition)
|
||||
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
|
||||
self.backgroundView.update(size: backgroundFrame.size, transition: transition.containedViewLayoutTransition)
|
||||
}
|
||||
|
||||
func update(component: GifPagerContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||
var contentReset = false
|
||||
if let previousComponent = self.component, previousComponent.subject != component.subject {
|
||||
|
@ -127,14 +127,14 @@ public final class TextNodeWithEntities {
|
||||
var found = false
|
||||
string.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: fullRange, options: [], using: { value, range, stop in
|
||||
if let value = value as? ChatTextInputTextCustomEmojiAttribute, let font = string.attribute(.font, at: range.location, effectiveRange: nil) as? UIFont {
|
||||
let updatedSubstring = NSMutableAttributedString(string: ".")
|
||||
let updatedSubstring = NSMutableAttributedString(string: "😀")
|
||||
|
||||
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
|
||||
updatedSubstring.addAttributes(string.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
|
||||
updatedSubstring.addAttribute(NSAttributedString.Key("Attribute__EmbeddedItem"), value: InlineStickerItem(emoji: value, file: value.file, fontSize: font.pointSize), range: replacementRange)
|
||||
updatedSubstring.addAttribute(originalTextAttributeKey, value: string.attributedSubstring(from: range).string, range: replacementRange)
|
||||
|
||||
let itemSize = font.pointSize * 24.0 / 17.0
|
||||
let itemSize = (font.pointSize * 24.0 / 17.0) * 0.5
|
||||
|
||||
let runDelegateData = RunDelegateData(
|
||||
ascent: font.ascender,
|
||||
@ -230,7 +230,9 @@ public final class TextNodeWithEntities {
|
||||
|
||||
let itemSize = floor(stickerItem.fontSize * 24.0 / 17.0)
|
||||
|
||||
let itemFrame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left, dy: textLayout.insets.top + 0.0).center, size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0)
|
||||
var itemFrame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left, dy: textLayout.insets.top + 1.0).center, size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0)
|
||||
itemFrame.origin.x = floorToScreenPixels(itemFrame.origin.x)
|
||||
itemFrame.origin.y = floorToScreenPixels(itemFrame.origin.y)
|
||||
|
||||
let itemLayer: InlineStickerItemLayer
|
||||
if let current = self.inlineStickerItemLayers[id] {
|
||||
|
@ -1,22 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "StickersGroupCross@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "StickersGroupCross@3x.png",
|
||||
"scale" : "3x"
|
||||
"filename" : "Frame 1.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/GridDismissIcon.imageset/Frame 1.svg
vendored
Normal file
4
submodules/TelegramUI/Images.xcassets/Chat/Input/Media/GridDismissIcon.imageset/Frame 1.svg
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.4131 0.413101C8.73724 0.0889662 9.26276 0.0889662 9.5869 0.413101C9.91103 0.737236 9.91103 1.26276 9.5869 1.5869L6.1738 5L9.5869 8.4131C9.91103 8.73724 9.91103 9.26276 9.5869 9.5869C9.26276 9.91103 8.73724 9.91103 8.4131 9.5869L5 6.1738L1.5869 9.5869C1.26276 9.91103 0.737237 9.91103 0.413101 9.5869C0.0889663 9.26276 0.0889663 8.73724 0.413101 8.4131L3.8262 5L0.413101 1.5869C0.0889662 1.26276 0.0889662 0.737237 0.413101 0.413101C0.737237 0.0889663 1.26276 0.0889663 1.5869 0.413101L5 3.8262L8.4131 0.413101Z" fill="black" style="mix-blend-mode:overlay"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.4131 0.413101C8.73724 0.0889662 9.26276 0.0889662 9.5869 0.413101C9.91103 0.737236 9.91103 1.26276 9.5869 1.5869L6.1738 5L9.5869 8.4131C9.91103 8.73724 9.91103 9.26276 9.5869 9.5869C9.26276 9.91103 8.73724 9.91103 8.4131 9.5869L5 6.1738L1.5869 9.5869C1.26276 9.91103 0.737237 9.91103 0.413101 9.5869C0.0889663 9.26276 0.0889663 8.73724 0.413101 8.4131L3.8262 5L0.413101 1.5869C0.0889662 1.26276 0.0889662 0.737237 0.413101 0.413101C0.737237 0.0889663 1.26276 0.0889663 1.5869 0.413101L5 3.8262L8.4131 0.413101Z" fill="black" fill-opacity="0.2"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 508 B |
Binary file not shown.
Before Width: | Height: | Size: 576 B |
@ -1576,6 +1576,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -2111,6 +2113,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))).withUpdatedComposeDisableUrlPreview(nil) }
|
||||
})
|
||||
@ -7342,6 +7346,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))).withUpdatedComposeDisableUrlPreview(nil) }
|
||||
})
|
||||
@ -11219,6 +11225,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -11281,6 +11289,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -11340,6 +11350,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -11363,6 +11375,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -11819,6 +11833,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
} else {
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12134,6 +12150,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12181,6 +12199,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12240,6 +12260,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12258,6 +12280,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12580,6 +12604,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12896,6 +12922,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12967,6 +12995,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -12983,6 +13013,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -13011,6 +13043,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -13156,6 +13190,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -13265,6 +13301,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
@ -13360,6 +13398,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedRecordedMediaPreview(nil).updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||
})
|
||||
|
@ -126,6 +126,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private(set) var accessoryPanelNode: AccessoryPanelNode?
|
||||
private var inputContextPanelNode: ChatInputContextPanelNode?
|
||||
private let inputContextPanelContainer: ChatControllerTitlePanelNodeContainer
|
||||
private let inputContextOverTextPanelContainer: ChatControllerTitlePanelNodeContainer
|
||||
private var overlayContextPanelNode: ChatInputContextPanelNode?
|
||||
|
||||
private var inputNode: ChatInputNode?
|
||||
@ -271,6 +272,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.titleAccessoryPanelContainer.clipsToBounds = true
|
||||
|
||||
self.inputContextPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||
self.inputContextOverTextPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||
|
||||
var source: ChatHistoryListSource
|
||||
if case let .forwardedMessages(messageIds, options) = subject {
|
||||
@ -540,8 +542,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
self.addSubnode(self.inputPanelContainerNode)
|
||||
self.addSubnode(self.inputContextPanelContainer)
|
||||
self.addSubnode(self.inputPanelContainerNode)
|
||||
self.addSubnode(self.inputContextOverTextPanelContainer)
|
||||
|
||||
self.inputPanelContainerNode.addSubnode(self.inputPanelClippingNode)
|
||||
self.inputPanelClippingNode.addSubnode(self.inputPanelBackgroundNode)
|
||||
@ -1213,7 +1216,18 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self?.updateInputPanelBackgroundExtension(transition: transition)
|
||||
}
|
||||
inputNode.hideInputUpdated = { [weak self] transition in
|
||||
self?.updateInputPanelBackgroundExpansion(transition: transition)
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let applyAutocorrection = strongSelf.inputNode?.hideInput ?? false
|
||||
|
||||
strongSelf.updateInputPanelBackgroundExpansion(transition: transition)
|
||||
|
||||
if applyAutocorrection, let textInputPanelNode = strongSelf.textInputPanelNode {
|
||||
if let textInputNode = textInputPanelNode.textInputNode, textInputNode.isFirstResponder() {
|
||||
Keyboard.applyAutocorrection(textView: textInputNode.textView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dismissedInputNode = self.inputNode
|
||||
@ -1308,6 +1322,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
transition.updateFrame(node: self.titleAccessoryPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: 66.0)))
|
||||
|
||||
transition.updateFrame(node: self.inputContextPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height)))
|
||||
transition.updateFrame(node: self.inputContextOverTextPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height)))
|
||||
|
||||
var titleAccessoryPanelFrame: CGRect?
|
||||
if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
|
||||
@ -1355,8 +1370,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
if inputContextPanelNode !== self.inputContextPanelNode {
|
||||
dismissedInputContextPanelNode = self.inputContextPanelNode
|
||||
self.inputContextPanelNode = inputContextPanelNode
|
||||
|
||||
self.inputContextPanelContainer.addSubnode(inputContextPanelNode)
|
||||
switch inputContextPanelNode.placement {
|
||||
case .overPanels:
|
||||
self.inputContextPanelContainer.addSubnode(inputContextPanelNode)
|
||||
case .overTextInput:
|
||||
self.inputContextOverTextPanelContainer.addSubnode(inputContextPanelNode)
|
||||
}
|
||||
immediatelyLayoutInputContextPanelAndAnimateAppearance = true
|
||||
}
|
||||
} else if let inputContextPanelNode = self.inputContextPanelNode {
|
||||
@ -2358,14 +2377,15 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
if case let .peer(id) = self.chatPresentationInterfaceState.chatLocation {
|
||||
peerId = id
|
||||
}
|
||||
let _ = peerId
|
||||
|
||||
let inputNode = ChatEntityKeyboardInputNode(
|
||||
context: self.context,
|
||||
currentInputData: inputMediaNodeData,
|
||||
updatedInputData: self.inputMediaNodeDataPromise.get(),
|
||||
defaultToEmojiTab: !self.chatPresentationInterfaceState.interfaceState.effectiveInputState.inputText.string.isEmpty,
|
||||
controllerInteraction: self.controllerInteraction
|
||||
controllerInteraction: self.controllerInteraction,
|
||||
interfaceInteraction: self.interfaceInteraction,
|
||||
chatPeerId: peerId
|
||||
)
|
||||
|
||||
return inputNode
|
||||
@ -2962,6 +2982,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
self.setupSendActionOnViewUpdate({ [weak self] in
|
||||
if let strongSelf = self, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode {
|
||||
strongSelf.collapseInput()
|
||||
|
||||
strongSelf.ignoreUpdateHeight = true
|
||||
textInputPanelNode.text = ""
|
||||
strongSelf.requestUpdateChatInterfaceState(.immediate, true, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeDisableUrlPreview(nil) })
|
||||
|
@ -86,7 +86,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
}
|
||||
}
|
||||
|
||||
static func emojiInputData(context: AccountContext, inputInteraction: EmojiPagerContentComponent.InputInteraction, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError> {
|
||||
static func emojiInputData(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer) -> Signal<EmojiPagerContentComponent, NoError> {
|
||||
let hasPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> map { peer -> Bool in
|
||||
guard case let .user(user) = peer else {
|
||||
@ -250,7 +250,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
context: context,
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer,
|
||||
inputInteraction: inputInteraction,
|
||||
inputInteractionHolder: EmojiPagerContentComponent.InputInteractionHolder(),
|
||||
itemGroups: itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
||||
var hasClear = false
|
||||
if group.id == AnyHashable("recent") {
|
||||
@ -291,321 +291,6 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let emojiInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
performItemAction: { [weak interfaceInteraction, weak controllerInteraction] _, item, _, _, _ in
|
||||
let _ = (hasPremium |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
||||
guard let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
|
||||
if let file = item.file {
|
||||
var text = "."
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, packReference):
|
||||
text = displayText
|
||||
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(stickerPack: packReference, fileId: file.fileId.id, file: file)
|
||||
break loop
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if file.isPremiumEmoji && !hasPremium {
|
||||
//TODO:localize
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
controllerInteraction.presentController(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Subscribe to Telegram Premium to unlock this emoji.", undoText: "More", customAction: { [weak controllerInteraction] in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = PremiumDemoScreen(context: context, subject: .animatedEmoji, action: {
|
||||
let controller = PremiumIntroScreen(context: context, source: .animatedEmoji)
|
||||
replaceImpl?(controller)
|
||||
})
|
||||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
/*let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)*/
|
||||
}), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
return
|
||||
}
|
||||
|
||||
if let emojiAttribute = emojiAttribute {
|
||||
AudioServicesPlaySystemSound(0x450)
|
||||
interfaceInteraction.insertText(NSAttributedString(string: text, attributes: [ChatTextInputAttributes.customEmoji: emojiAttribute]))
|
||||
}
|
||||
} else if let staticEmoji = item.staticEmoji {
|
||||
AudioServicesPlaySystemSound(0x450)
|
||||
interfaceInteraction.insertText(NSAttributedString(string: staticEmoji, attributes: [:]))
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteBackwards: { [weak interfaceInteraction] in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
interfaceInteraction.backwardsDeleteText()
|
||||
},
|
||||
openStickerSettings: {
|
||||
},
|
||||
addGroupAction: { [weak controllerInteraction] groupId, isPremiumLocked in
|
||||
guard let controllerInteraction = controllerInteraction, let collectionId = groupId.base as? ItemCollectionId else {
|
||||
return
|
||||
}
|
||||
|
||||
if isPremiumLocked {
|
||||
let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { views in
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
for featuredEmojiPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
if featuredEmojiPack.info.id == collectionId {
|
||||
let _ = context.engine.stickers.addStickerPackInteractively(info: featuredEmojiPack.info, items: featuredEmojiPack.topItems).start()
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
clearGroup: { [weak controllerInteraction] groupId in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
if groupId == AnyHashable("recent") {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let actionSheet = ActionSheetController(theme: ActionSheetControllerTheme(presentationTheme: presentationData.theme, fontSize: presentationData.listsFontSize))
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Emoji_ClearRecent, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
let _ = context.engine.stickers.clearRecentlyUsedEmoji().start()
|
||||
}))
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
controllerInteraction.presentController(actionSheet, nil)
|
||||
}
|
||||
},
|
||||
pushController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
},
|
||||
presentController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentController(controller, nil)
|
||||
},
|
||||
presentGlobalOverlayController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentGlobalOverlayController(controller, nil)
|
||||
},
|
||||
navigationController: { [weak controllerInteraction] in
|
||||
return controllerInteraction?.navigationController()
|
||||
},
|
||||
sendSticker: { [weak controllerInteraction] fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
let _ = controllerInteraction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer)
|
||||
},
|
||||
chatPeerId: chatPeerId
|
||||
)
|
||||
let stickerInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
performItemAction: { [weak controllerInteraction, weak interfaceInteraction] groupId, item, view, rect, layer in
|
||||
let _ = (hasPremium |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
||||
guard let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
guard let file = item.file else {
|
||||
return
|
||||
}
|
||||
|
||||
if groupId == AnyHashable("featuredTop") {
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak controllerInteraction] views in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
if featuredStickerPack.topItems.contains(where: { $0.file.fileId == file.fileId }) {
|
||||
controllerInteraction.navigationController()?.pushViewController(FeaturedStickersScreen(
|
||||
context: context,
|
||||
highlightedPackId: featuredStickerPack.info.id,
|
||||
sendSticker: { [weak controllerInteraction] fileReference, sourceNode, sourceRect in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return false
|
||||
}
|
||||
return controllerInteraction.sendSticker(fileReference, false, false, nil, false, sourceNode, sourceRect, nil)
|
||||
}
|
||||
))
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if file.isPremiumSticker && !hasPremium {
|
||||
let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
return
|
||||
}
|
||||
let _ = interfaceInteraction.sendSticker(.standalone(media: file), false, view, rect, layer)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteBackwards: { [weak interfaceInteraction] in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
interfaceInteraction.backwardsDeleteText()
|
||||
},
|
||||
openStickerSettings: { [weak controllerInteraction] in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
let controller = installedStickerPacksController(context: context, mode: .modal)
|
||||
controller.navigationPresentation = .modal
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
},
|
||||
addGroupAction: { groupId, isPremiumLocked in
|
||||
guard let controllerInteraction = controllerInteraction, let collectionId = groupId.base as? ItemCollectionId else {
|
||||
return
|
||||
}
|
||||
|
||||
if isPremiumLocked {
|
||||
let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { views in
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
if featuredStickerPack.info.id == collectionId {
|
||||
//let _ = context.engine.stickers.addStickerPackInteractively(info: featuredEmojiPack.info, items: featuredEmojiPack.topItems).start()
|
||||
|
||||
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: featuredStickerPack.info.id.id, accessHash: featuredStickerPack.info.accessHash), forceActualized: false)
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
switch result {
|
||||
case let .result(info, items, installed):
|
||||
if installed {
|
||||
return .complete()
|
||||
} else {
|
||||
return context.engine.stickers.addStickerPackInteractively(info: info, items: items)
|
||||
}
|
||||
case .fetching:
|
||||
break
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
clearGroup: { [weak controllerInteraction] groupId in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
if groupId == AnyHashable("recent") {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let actionSheet = ActionSheetController(theme: ActionSheetControllerTheme(presentationTheme: presentationData.theme, fontSize: presentationData.listsFontSize))
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Stickers_ClearRecent, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
let _ = context.engine.stickers.clearRecentlyUsedStickers().start()
|
||||
}))
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
controllerInteraction.presentController(actionSheet, nil)
|
||||
} else if groupId == AnyHashable("featuredTop") {
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { views in
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
var stickerPackIds: [Int64] = []
|
||||
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
stickerPackIds.append(featuredStickerPack.info.id.id)
|
||||
}
|
||||
let _ = ApplicationSpecificNotice.setDismissedTrendingStickerPacks(accountManager: context.sharedContext.accountManager, values: stickerPackIds).start()
|
||||
})
|
||||
}
|
||||
},
|
||||
pushController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
},
|
||||
presentController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentController(controller, nil)
|
||||
},
|
||||
presentGlobalOverlayController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentGlobalOverlayController(controller, nil)
|
||||
},
|
||||
navigationController: { [weak controllerInteraction] in
|
||||
return controllerInteraction?.navigationController()
|
||||
},
|
||||
sendSticker: { [weak controllerInteraction] fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
let _ = controllerInteraction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer)
|
||||
},
|
||||
chatPeerId: chatPeerId
|
||||
)
|
||||
|
||||
let animationCache = AnimationCacheImpl(basePath: context.account.postbox.mediaBox.basePath + "/animation-cache", allocateTempFile: {
|
||||
return TempBox.shared.tempFile(fileName: "file").path
|
||||
})
|
||||
@ -616,7 +301,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
animationRenderer = MultiAnimationRendererImpl()
|
||||
//}
|
||||
|
||||
let emojiItems = emojiInputData(context: context, inputInteraction: emojiInputInteraction, animationCache: animationCache, animationRenderer: animationRenderer)
|
||||
let emojiItems = emojiInputData(context: context, animationCache: animationCache, animationRenderer: animationRenderer)
|
||||
|
||||
let stickerNamespaces: [ItemCollectionId.Namespace] = [Namespaces.ItemCollection.CloudStickerPacks]
|
||||
let stickerOrderedItemListCollectionIds: [Int32] = [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers, Namespaces.OrderedItemList.PremiumStickers, Namespaces.OrderedItemList.CloudPremiumStickers]
|
||||
@ -863,7 +548,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
context: context,
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer,
|
||||
inputInteraction: stickerInputInteraction,
|
||||
inputInteractionHolder: EmojiPagerContentComponent.InputInteractionHolder(),
|
||||
itemGroups: itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
||||
var hasClear = false
|
||||
var isEmbedded = false
|
||||
@ -1028,6 +713,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
var switchToTextInput: (() -> Void)?
|
||||
|
||||
private var currentState: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, interfaceState: ChatPresentationInterfaceState, deviceMetrics: DeviceMetrics, isVisible: Bool, isExpanded: Bool)?
|
||||
|
||||
private var scheduledContentAnimationHint: EmojiPagerContentComponent.ContentAnimation?
|
||||
private var scheduledInnerTransition: Transition?
|
||||
|
||||
private var gifMode: GifPagerContentComponent.Subject? {
|
||||
@ -1253,7 +940,10 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
private let gifComponent = Promise<EntityKeyboardGifContent>()
|
||||
private var gifInputInteraction: GifPagerContentComponent.InputInteraction?
|
||||
|
||||
init(context: AccountContext, currentInputData: InputData, updatedInputData: Signal<InputData, NoError>, defaultToEmojiTab: Bool, controllerInteraction: ChatControllerInteraction?) {
|
||||
fileprivate var emojiInputInteraction: EmojiPagerContentComponent.InputInteraction?
|
||||
private var stickerInputInteraction: EmojiPagerContentComponent.InputInteraction?
|
||||
|
||||
init(context: AccountContext, currentInputData: InputData, updatedInputData: Signal<InputData, NoError>, defaultToEmojiTab: Bool, controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, chatPeerId: PeerId?) {
|
||||
self.context = context
|
||||
self.currentInputData = currentInputData
|
||||
self.defaultToEmojiTab = defaultToEmojiTab
|
||||
@ -1271,6 +961,331 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
|
||||
self.externalTopPanelContainerImpl = PagerExternalTopPanelContainer()
|
||||
|
||||
let hasPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> map { peer -> Bool in
|
||||
guard case let .user(user) = peer else {
|
||||
return false
|
||||
}
|
||||
return user.isPremium
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
self.emojiInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
performItemAction: { [weak interfaceInteraction, weak controllerInteraction] _, item, _, _, _ in
|
||||
let _ = (hasPremium |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
||||
guard let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
|
||||
if let file = item.file {
|
||||
var text = "."
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, packReference):
|
||||
text = displayText
|
||||
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(stickerPack: packReference, fileId: file.fileId.id, file: file)
|
||||
break loop
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if file.isPremiumEmoji && !hasPremium {
|
||||
//TODO:localize
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
controllerInteraction.presentController(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Subscribe to Telegram Premium to unlock this emoji.", undoText: "More", customAction: { [weak controllerInteraction] in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = PremiumDemoScreen(context: context, subject: .animatedEmoji, action: {
|
||||
let controller = PremiumIntroScreen(context: context, source: .animatedEmoji)
|
||||
replaceImpl?(controller)
|
||||
})
|
||||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
/*let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)*/
|
||||
}), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
return
|
||||
}
|
||||
|
||||
if let emojiAttribute = emojiAttribute {
|
||||
AudioServicesPlaySystemSound(0x450)
|
||||
interfaceInteraction.insertText(NSAttributedString(string: text, attributes: [ChatTextInputAttributes.customEmoji: emojiAttribute]))
|
||||
}
|
||||
} else if let staticEmoji = item.staticEmoji {
|
||||
AudioServicesPlaySystemSound(0x450)
|
||||
interfaceInteraction.insertText(NSAttributedString(string: staticEmoji, attributes: [:]))
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteBackwards: { [weak interfaceInteraction] in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
interfaceInteraction.backwardsDeleteText()
|
||||
},
|
||||
openStickerSettings: {
|
||||
},
|
||||
addGroupAction: { [weak self, weak controllerInteraction] groupId, isPremiumLocked in
|
||||
guard let controllerInteraction = controllerInteraction, let collectionId = groupId.base as? ItemCollectionId else {
|
||||
return
|
||||
}
|
||||
|
||||
if isPremiumLocked {
|
||||
let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { views in
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
for featuredEmojiPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
if featuredEmojiPack.info.id == collectionId {
|
||||
if let strongSelf = self {
|
||||
strongSelf.scheduledContentAnimationHint = EmojiPagerContentComponent.ContentAnimation(type: .groupInstalled(id: collectionId))
|
||||
}
|
||||
let _ = context.engine.stickers.addStickerPackInteractively(info: featuredEmojiPack.info, items: featuredEmojiPack.topItems).start()
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
clearGroup: { [weak controllerInteraction] groupId in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
if groupId == AnyHashable("recent") {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let actionSheet = ActionSheetController(theme: ActionSheetControllerTheme(presentationTheme: presentationData.theme, fontSize: presentationData.listsFontSize))
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Emoji_ClearRecent, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
let _ = context.engine.stickers.clearRecentlyUsedEmoji().start()
|
||||
}))
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
controllerInteraction.presentController(actionSheet, nil)
|
||||
}
|
||||
},
|
||||
pushController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
},
|
||||
presentController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentController(controller, nil)
|
||||
},
|
||||
presentGlobalOverlayController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentGlobalOverlayController(controller, nil)
|
||||
},
|
||||
navigationController: { [weak controllerInteraction] in
|
||||
return controllerInteraction?.navigationController()
|
||||
},
|
||||
sendSticker: { [weak controllerInteraction] fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
let _ = controllerInteraction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer)
|
||||
},
|
||||
chatPeerId: chatPeerId
|
||||
)
|
||||
|
||||
self.stickerInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
performItemAction: { [weak controllerInteraction, weak interfaceInteraction] groupId, item, view, rect, layer in
|
||||
let _ = (hasPremium |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
|
||||
guard let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
guard let file = item.file else {
|
||||
return
|
||||
}
|
||||
|
||||
if groupId == AnyHashable("featuredTop") {
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak controllerInteraction] views in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
if featuredStickerPack.topItems.contains(where: { $0.file.fileId == file.fileId }) {
|
||||
controllerInteraction.navigationController()?.pushViewController(FeaturedStickersScreen(
|
||||
context: context,
|
||||
highlightedPackId: featuredStickerPack.info.id,
|
||||
sendSticker: { [weak controllerInteraction] fileReference, sourceNode, sourceRect in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return false
|
||||
}
|
||||
return controllerInteraction.sendSticker(fileReference, false, false, nil, false, sourceNode, sourceRect, nil)
|
||||
}
|
||||
))
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if file.isPremiumSticker && !hasPremium {
|
||||
let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
return
|
||||
}
|
||||
let _ = interfaceInteraction.sendSticker(.standalone(media: file), false, view, rect, layer)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteBackwards: { [weak interfaceInteraction] in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
interfaceInteraction.backwardsDeleteText()
|
||||
},
|
||||
openStickerSettings: { [weak controllerInteraction] in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
let controller = installedStickerPacksController(context: context, mode: .modal)
|
||||
controller.navigationPresentation = .modal
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
},
|
||||
addGroupAction: { groupId, isPremiumLocked in
|
||||
guard let controllerInteraction = controllerInteraction, let collectionId = groupId.base as? ItemCollectionId else {
|
||||
return
|
||||
}
|
||||
|
||||
if isPremiumLocked {
|
||||
let controller = PremiumIntroScreen(context: context, source: .stickers)
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { views in
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
if featuredStickerPack.info.id == collectionId {
|
||||
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: featuredStickerPack.info.id.id, accessHash: featuredStickerPack.info.accessHash), forceActualized: false)
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
switch result {
|
||||
case let .result(info, items, installed):
|
||||
if installed {
|
||||
return .complete()
|
||||
} else {
|
||||
return context.engine.stickers.addStickerPackInteractively(info: info, items: items)
|
||||
}
|
||||
case .fetching:
|
||||
break
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
clearGroup: { [weak controllerInteraction] groupId in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
if groupId == AnyHashable("recent") {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let actionSheet = ActionSheetController(theme: ActionSheetControllerTheme(presentationTheme: presentationData.theme, fontSize: presentationData.listsFontSize))
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Stickers_ClearRecent, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
let _ = context.engine.stickers.clearRecentlyUsedStickers().start()
|
||||
}))
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
controllerInteraction.presentController(actionSheet, nil)
|
||||
} else if groupId == AnyHashable("featuredTop") {
|
||||
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)
|
||||
let _ = (context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { views in
|
||||
guard let view = views.views[viewKey] as? OrderedItemListView else {
|
||||
return
|
||||
}
|
||||
var stickerPackIds: [Int64] = []
|
||||
for featuredStickerPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
|
||||
stickerPackIds.append(featuredStickerPack.info.id.id)
|
||||
}
|
||||
let _ = ApplicationSpecificNotice.setDismissedTrendingStickerPacks(accountManager: context.sharedContext.accountManager, values: stickerPackIds).start()
|
||||
})
|
||||
}
|
||||
},
|
||||
pushController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.navigationController()?.pushViewController(controller)
|
||||
},
|
||||
presentController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentController(controller, nil)
|
||||
},
|
||||
presentGlobalOverlayController: { [weak controllerInteraction] controller in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
controllerInteraction.presentGlobalOverlayController(controller, nil)
|
||||
},
|
||||
navigationController: { [weak controllerInteraction] in
|
||||
return controllerInteraction?.navigationController()
|
||||
},
|
||||
sendSticker: { [weak controllerInteraction] fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer in
|
||||
guard let controllerInteraction = controllerInteraction else {
|
||||
return
|
||||
}
|
||||
let _ = controllerInteraction.sendSticker(fileReference, silentPosting, schedule, query, clearInput, sourceView, sourceRect, sourceLayer)
|
||||
},
|
||||
chatPeerId: chatPeerId
|
||||
)
|
||||
|
||||
self.inputDataDisposable = (combineLatest(queue: .mainQueue(),
|
||||
updatedInputData,
|
||||
@ -1295,7 +1310,14 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
}
|
||||
|
||||
if useAnimation {
|
||||
transition = Transition(animation: .curve(duration: 0.4, curve: .spring)).withUserData(EmojiPagerContentComponent.ContentAnimation(type: .generic))
|
||||
let contentAnimation: EmojiPagerContentComponent.ContentAnimation
|
||||
if let scheduledContentAnimationHint = strongSelf.scheduledContentAnimationHint {
|
||||
strongSelf.scheduledContentAnimationHint = nil
|
||||
contentAnimation = scheduledContentAnimationHint
|
||||
} else {
|
||||
contentAnimation = EmojiPagerContentComponent.ContentAnimation(type: .generic)
|
||||
}
|
||||
transition = Transition(animation: .curve(duration: 0.4, curve: .spring)).withUserData(contentAnimation)
|
||||
}
|
||||
strongSelf.currentInputData = inputData
|
||||
strongSelf.performLayout(transition: transition)
|
||||
@ -1459,6 +1481,9 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
gifContent = nil
|
||||
}
|
||||
|
||||
stickerContent?.inputInteractionHolder.inputInteraction = self.stickerInputInteraction
|
||||
self.currentInputData.emoji.inputInteractionHolder.inputInteraction = self.emojiInputInteraction
|
||||
|
||||
let entityKeyboardSize = self.entityKeyboardView.update(
|
||||
transition: mappedTransition,
|
||||
component: AnyComponent(EntityKeyboardComponent(
|
||||
@ -1824,7 +1849,7 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
var emojiComponent: EmojiPagerContentComponent?
|
||||
let _ = ChatEntityKeyboardInputNode.emojiInputData(context: context, inputInteraction: inputInteraction, animationCache: self.animationCache, animationRenderer: self.animationRenderer).start(next: { value in
|
||||
let _ = ChatEntityKeyboardInputNode.emojiInputData(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer).start(next: { value in
|
||||
emojiComponent = value
|
||||
semaphore.signal()
|
||||
})
|
||||
@ -1841,9 +1866,12 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
||||
),
|
||||
updatedInputData: .never(),
|
||||
defaultToEmojiTab: true,
|
||||
controllerInteraction: nil
|
||||
controllerInteraction: nil,
|
||||
interfaceInteraction: nil,
|
||||
chatPeerId: nil
|
||||
)
|
||||
self.inputNode = inputNode
|
||||
inputNode.emojiInputInteraction = inputInteraction
|
||||
inputNode.externalTopPanelContainerImpl = nil
|
||||
inputNode.switchToTextInput = { [weak self] in
|
||||
self?.switchToKeyboard?()
|
||||
|
@ -74,7 +74,7 @@ final class ChatMediaInputStickerGridSectionNode: ASDisplayNode {
|
||||
self.setupNode = setupNode
|
||||
case .clear:
|
||||
let setupNode = HighlightableButtonNode()
|
||||
setupNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme), for: [])
|
||||
setupNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme, color: theme.chat.inputMediaPanel.stickersSectionTextColor), for: [])
|
||||
self.setupNode = setupNode
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,24 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
|
||||
private var absoluteRect: (CGRect, CGSize)?
|
||||
|
||||
override var visibility: ListViewItemNodeVisibility {
|
||||
didSet {
|
||||
if oldValue != self.visibility {
|
||||
switch self.visibility {
|
||||
case .none:
|
||||
self.labelNode.visibilityRect = nil
|
||||
//self.spoilerTextNode?.visibilityRect = nil
|
||||
case let .visible(_, subRect):
|
||||
var subRect = subRect
|
||||
subRect.origin.x = 0.0
|
||||
subRect.size.width = 10000.0
|
||||
self.labelNode.visibilityRect = subRect
|
||||
//self.spoilerTextNode?.visibilityRect = subRect
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required init() {
|
||||
self.labelNode = TextNodeWithEntities()
|
||||
self.labelNode.textNode.isUserInteractionEnabled = false
|
||||
@ -340,6 +358,18 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.backgroundColorNode.frame = CGRect(origin: CGPoint(), size: image.size)
|
||||
|
||||
strongSelf.cachedMaskBackgroundImage = (offset, image, labelRects)
|
||||
|
||||
switch strongSelf.visibility {
|
||||
case .none:
|
||||
strongSelf.labelNode.visibilityRect = nil
|
||||
//strongSelf.spoilerTextNode?.visibilityRect = nil
|
||||
case let .visible(_, subRect):
|
||||
var subRect = subRect
|
||||
subRect.origin.x = 0.0
|
||||
subRect.size.width = 10000.0
|
||||
strongSelf.labelNode.visibilityRect = subRect
|
||||
//strongSelf.spoilerTextNode?.visibilityRect = subRect
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -206,7 +206,7 @@ final class ChatMessageAccessibilityData {
|
||||
if let chatPeer = message.peers[item.message.id.peerId] {
|
||||
let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
||||
|
||||
let (_, _, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
|
||||
let (_, _, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
|
||||
|
||||
var text = messageText
|
||||
|
||||
|
@ -138,7 +138,7 @@ class StickerPanePeerSpecificSetupGridItemNode: GridItemNode {
|
||||
var updateButtonBackgroundImage: UIImage?
|
||||
if currentItem?.theme !== item.theme {
|
||||
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddPackButtonImage(item.theme)
|
||||
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme), for: [])
|
||||
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme, color: item.theme.chat.inputMediaPanel.stickersSectionTextColor), for: [])
|
||||
}
|
||||
|
||||
let leftInset: CGFloat = 12.0
|
||||
|
@ -525,7 +525,7 @@ class StickerPaneTrendingListGridItemNode: GridItemNode {
|
||||
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
if currentItem?.theme !== item.theme {
|
||||
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme), for: [])
|
||||
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme, color: item.theme.chat.inputMediaPanel.stickersSectionTextColor), for: [])
|
||||
}
|
||||
|
||||
let leftInset: CGFloat = 9.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user