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 {
|
} else {
|
||||||
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
|
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 {
|
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)"
|
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 {
|
} else {
|
||||||
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
|
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 {
|
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)"
|
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
|
let leftInset: CGFloat = params.leftInset + avatarLeftInset
|
||||||
|
|
||||||
enum ContentData {
|
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])
|
case group(peers: [EngineChatList.GroupItem.Item])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1104,7 +1104,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var hideAuthor = false
|
var hideAuthor = false
|
||||||
switch contentPeer {
|
switch contentPeer {
|
||||||
case let .chat(itemPeer):
|
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 {
|
if case let .psa(_, maybePsaText) = promoInfo, let psaText = maybePsaText {
|
||||||
initialHideAuthor = true
|
initialHideAuthor = true
|
||||||
@ -1125,7 +1125,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
break
|
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
|
hideAuthor = initialHideAuthor
|
||||||
case let .group(groupPeers):
|
case let .group(groupPeers):
|
||||||
contentData = .group(peers: groupPeers)
|
contentData = .group(peers: groupPeers)
|
||||||
@ -1156,7 +1156,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
|
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
|
||||||
|
|
||||||
switch contentData {
|
switch contentData {
|
||||||
case let .chat(itemPeer, _, _, text, spoilers):
|
case let .chat(itemPeer, _, _, text, spoilers, customEmojiRanges):
|
||||||
var isUser = false
|
var isUser = false
|
||||||
if case .user = itemPeer.chatMainPeer {
|
if case .user = itemPeer.chatMainPeer {
|
||||||
isUser = true
|
isUser = true
|
||||||
@ -1185,6 +1185,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else {
|
} else {
|
||||||
if let spoilers = spoilers, !spoilers.isEmpty {
|
if let spoilers = spoilers, !spoilers.isEmpty {
|
||||||
messageText = text
|
messageText = text
|
||||||
|
} else if let customEmojiRanges = customEmojiRanges, !customEmojiRanges.isEmpty {
|
||||||
|
messageText = text
|
||||||
} else {
|
} else {
|
||||||
messageText = foldLineBreaks(text)
|
messageText = foldLineBreaks(text)
|
||||||
}
|
}
|
||||||
@ -1216,10 +1218,17 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let messageString: NSAttributedString
|
let messageString: NSAttributedString
|
||||||
if !message.text.isEmpty && entities.count > 0 {
|
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())
|
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)
|
let mutableString = NSMutableAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
|
||||||
for range in spoilers {
|
if let spoilers = spoilers {
|
||||||
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)
|
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
|
messageString = mutableString
|
||||||
} else {
|
} else {
|
||||||
@ -1268,8 +1277,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
attributedText = composedString
|
attributedText = composedString
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var displayMediaPreviews = true
|
var displayMediaPreviews = true
|
||||||
if message._asMessage().containsSecretMedia {
|
if message._asMessage().containsSecretMedia {
|
||||||
displayMediaPreviews = false
|
displayMediaPreviews = false
|
||||||
@ -1359,7 +1366,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch contentData {
|
switch contentData {
|
||||||
case let .chat(itemPeer, _, _, _, _):
|
case let .chat(itemPeer, _, _, _, _, _):
|
||||||
if let message = messages.last, case let .user(author) = message.author, displayAsMessage {
|
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)
|
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 {
|
} else if isPeerGroup {
|
||||||
|
@ -4,6 +4,7 @@ import TelegramPresentationData
|
|||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
import LocalizedPeerData
|
import LocalizedPeerData
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
private enum MessageGroupType {
|
private enum MessageGroupType {
|
||||||
case photos
|
case photos
|
||||||
@ -44,7 +45,7 @@ private func messageGroupType(messages: [EngineMessage]) -> MessageGroupType {
|
|||||||
return currentType
|
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 peer: EnginePeer?
|
||||||
|
|
||||||
let message = messages.last
|
let message = messages.last
|
||||||
@ -52,6 +53,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
|||||||
var hideAuthor = false
|
var hideAuthor = false
|
||||||
var messageText: String
|
var messageText: String
|
||||||
var spoilers: [NSRange]?
|
var spoilers: [NSRange]?
|
||||||
|
var customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?
|
||||||
if let message = message {
|
if let message = message {
|
||||||
if let messageMain = messageMainPeer(message) {
|
if let messageMain = messageMainPeer(message) {
|
||||||
peer = messageMain
|
peer = messageMain
|
||||||
@ -269,13 +271,14 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
hideAuthor = true
|
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
|
messageText = text
|
||||||
spoilers = textSpoilers
|
spoilers = textSpoilers
|
||||||
|
customEmojiRanges = customEmojiRangesValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case _ as TelegramMediaExpiredContent:
|
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
|
messageText = text
|
||||||
}
|
}
|
||||||
case let poll as TelegramMediaPoll:
|
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 {
|
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 {
|
public func update(component: BlurredBackgroundComponent, availableSize: CGSize, transition: Transition) -> CGSize {
|
||||||
if let tintContainerView = component.tintContainerView {
|
/*if self.tintContainerView !== component.tintContainerView {
|
||||||
self.updateColor(color: .clear, forceKeepBlur: true, transition: transition.containedViewLayoutTransition)
|
if let tintContainerView = self.tintContainerView {
|
||||||
|
self.tintContainerView = nil
|
||||||
|
if tintContainerView.superview === self {
|
||||||
|
tintContainerView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let tintMaskView: UIView
|
self.tintContainerView = component.tintContainerView
|
||||||
if let current = self.tintMaskView {
|
|
||||||
tintMaskView = current
|
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 {
|
} else {
|
||||||
tintMaskView = UIView()
|
if let vibrancyEffectView = self.vibrancyEffectView {
|
||||||
self.tintMaskView = tintMaskView
|
self.vibrancyEffectView = nil
|
||||||
self.addSubview(tintMaskView)
|
vibrancyEffectView.removeFromSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
tintMaskView.backgroundColor = component.color
|
|
||||||
transition.setFrame(view: tintMaskView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
|
||||||
|
|
||||||
if tintMaskView.mask !== tintContainerView {
|
|
||||||
tintMaskView.mask = tintContainerView
|
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
self.updateColor(color: component.color, transition: transition.containedViewLayoutTransition)
|
||||||
|
|
||||||
|
/*if let _ = self.viewWithTag(123) {
|
||||||
} else {
|
} else {
|
||||||
self.updateColor(color: component.color, transition: transition.containedViewLayoutTransition)
|
let blurEffect = UIBlurEffect(style: .extraLight)
|
||||||
|
|
||||||
if let tintMaskView = self.tintMaskView {
|
|
||||||
self.tintMaskView = nil
|
/*let segmentedControl = UISegmentedControl(items: ["First Item", "Second Item"])
|
||||||
tintMaskView.removeFromSuperview()
|
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)
|
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
|
return availableSize
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,10 @@ public protocol PagerPanGestureRecognizer: UIGestureRecognizer {
|
|||||||
open class PagerExternalTopPanelContainer: SparseContainerView {
|
open class PagerExternalTopPanelContainer: SparseContainerView {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public protocol PagerContentViewWithBackground: UIView {
|
||||||
|
func pagerUpdateBackground(backgroundFrame: CGRect, transition: Transition)
|
||||||
|
}
|
||||||
|
|
||||||
public final class PagerComponentChildEnvironment: Equatable {
|
public final class PagerComponentChildEnvironment: Equatable {
|
||||||
public struct ContentScrollingUpdate {
|
public struct ContentScrollingUpdate {
|
||||||
public var relativeOffset: CGFloat
|
public var relativeOffset: CGFloat
|
||||||
@ -292,8 +296,15 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
case .began:
|
case .began:
|
||||||
self.paneTransitionGestureState = PaneTransitionGestureState()
|
self.paneTransitionGestureState = PaneTransitionGestureState()
|
||||||
case .changed:
|
case .changed:
|
||||||
if var paneTransitionGestureState = self.paneTransitionGestureState, self.bounds.width > 0.0 {
|
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 {
|
||||||
paneTransitionGestureState.fraction = recognizer.translation(in: self).x / self.bounds.width
|
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.paneTransitionGestureState = paneTransitionGestureState
|
||||||
self.state?.updated(transition: .immediate)
|
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 {
|
if let contentBackground = component.contentBackground {
|
||||||
let contentBackgroundView: ComponentHostView<Empty>
|
let contentBackgroundView: ComponentHostView<Empty>
|
||||||
var contentBackgroundTransition = panelStateTransition
|
var contentBackgroundTransition = panelStateTransition
|
||||||
@ -565,13 +577,13 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||||||
self.contentBackgroundView = contentBackgroundView
|
self.contentBackgroundView = contentBackgroundView
|
||||||
self.insertSubview(contentBackgroundView, at: 0)
|
self.insertSubview(contentBackgroundView, at: 0)
|
||||||
}
|
}
|
||||||
let contentBackgroundSize = contentBackgroundView.update(
|
let _ = contentBackgroundView.update(
|
||||||
transition: contentBackgroundTransition,
|
transition: contentBackgroundTransition,
|
||||||
component: contentBackground,
|
component: contentBackground,
|
||||||
environment: {},
|
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 {
|
} else {
|
||||||
if let contentBackgroundView = self.contentBackgroundView {
|
if let contentBackgroundView = self.contentBackgroundView {
|
||||||
self.contentBackgroundView = nil
|
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 let color = self._color, self.enableBlur && !sharedIsReduceTransparencyEnabled && ((color.alpha > .ulpOfOne && color.alpha < 0.95) || forceKeepBlur) {
|
||||||
if self.effectView == nil {
|
if self.effectView == nil {
|
||||||
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||||
|
//effectView.isHidden = true
|
||||||
|
|
||||||
for subview in effectView.subviews {
|
for subview in effectView.subviews {
|
||||||
if subview.description.contains("VisualEffectSubview") {
|
if subview.description.contains("VisualEffectSubview") {
|
||||||
|
@ -768,12 +768,13 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
|||||||
strongSelf.animationNode = animationNode
|
strongSelf.animationNode = animationNode
|
||||||
strongSelf.addSubnode(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.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
|
||||||
animationNode.isHidden = !item.playAnimatedStickers
|
animationNode.isHidden = !item.playAnimatedStickers
|
||||||
strongSelf.imageNode.isHidden = item.playAnimatedStickers
|
strongSelf.imageNode.isHidden = item.playAnimatedStickers
|
||||||
if let animationNode = strongSelf.animationNode {
|
if let animationNode = strongSelf.animationNode {
|
||||||
|
animationNode.updateLayout(size: imageFrame.size)
|
||||||
transition.updateFrame(node: animationNode, frame: imageFrame)
|
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
|
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 {
|
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
|
return true
|
||||||
}))
|
}))
|
||||||
|
@ -3,7 +3,7 @@ import Postbox
|
|||||||
import SwiftSignalKit
|
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
|
return postbox.transaction { transaction -> Void in
|
||||||
let namespace: SynchronizeInstalledStickerPacksOperationNamespace?
|
let namespace: SynchronizeInstalledStickerPacksOperationNamespace?
|
||||||
switch info.id.namespace {
|
switch info.id.namespace {
|
||||||
@ -33,7 +33,12 @@ func _internal_addStickerPackInteractively(postbox: Postbox, info: StickerPackCo
|
|||||||
} else {
|
} else {
|
||||||
updatedInfos.insert(mappedInfo, at: 0)
|
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) })
|
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)
|
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)
|
return _internal_addStickerPackInteractively(postbox: self.account.postbox, info: info, items: items, positionInList: positionInList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +276,6 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case chatKeyboardActionButtonProfileIcon
|
case chatKeyboardActionButtonProfileIcon
|
||||||
case chatKeyboardActionButtonAddToChatIcon
|
case chatKeyboardActionButtonAddToChatIcon
|
||||||
case chatKeyboardActionButtonWebAppIcon
|
case chatKeyboardActionButtonWebAppIcon
|
||||||
case chatEntityKeyboardLock
|
|
||||||
|
|
||||||
case uploadToneIcon
|
case uploadToneIcon
|
||||||
}
|
}
|
||||||
@ -313,4 +312,7 @@ public enum PresentationResourceParameterKey: Hashable {
|
|||||||
case chatMessageCommentsArrowIcon(incoming: Bool)
|
case chatMessageCommentsArrowIcon(incoming: Bool)
|
||||||
case chatMessageCommentsUnreadDotIcon(incoming: Bool)
|
case chatMessageCommentsUnreadDotIcon(incoming: Bool)
|
||||||
case chatMessageRepliesIcon(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? {
|
public static func chatInputMediaPanelGridDismissImage(_ theme: PresentationTheme, color: UIColor) -> UIImage? {
|
||||||
return theme.image(PresentationResourceKey.chatInputMediaPanelGridDismissImage.rawValue, { theme in
|
return theme.image(PresentationResourceParameterKey.chatInputMediaPanelGridDismissImage(color: color.argb), { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/GridDismissIcon"), color: theme.chat.inputMediaPanel.stickersSectionTextColor)
|
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? {
|
public static func chatEntityKeyboardLock(_ theme: PresentationTheme, color: UIColor) -> UIImage? {
|
||||||
return theme.image(PresentationResourceKey.chatEntityKeyboardLock.rawValue, { theme in
|
return theme.image(PresentationResourceParameterKey.chatEntityKeyboardLock(color: color.argb), { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.chat.inputMediaPanel.stickersSectionTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: color)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,15 +34,18 @@ private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, E
|
|||||||
return result
|
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) {
|
if let attributedString = universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: forChatList) {
|
||||||
var ranges: [NSRange] = []
|
var ranges: [NSRange] = []
|
||||||
|
var customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)] = []
|
||||||
attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: [], using: { attributes, range, _ in
|
attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: [], using: { attributes, range, _ in
|
||||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)] {
|
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)] {
|
||||||
ranges.append(range)
|
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 {
|
} else {
|
||||||
return nil
|
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 {
|
public final class View: UIView {
|
||||||
|
private let tintContainerView: UIView
|
||||||
|
|
||||||
private let pagerView: ComponentHostView<EntityKeyboardChildEnvironment>
|
private let pagerView: ComponentHostView<EntityKeyboardChildEnvironment>
|
||||||
|
|
||||||
private var component: EntityKeyboardComponent?
|
private var component: EntityKeyboardComponent?
|
||||||
@ -191,6 +193,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
|
self.tintContainerView = UIView()
|
||||||
self.pagerView = ComponentHostView<EntityKeyboardChildEnvironment>()
|
self.pagerView = ComponentHostView<EntityKeyboardChildEnvironment>()
|
||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
@ -392,7 +395,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
maxSize: nil
|
maxSize: nil
|
||||||
)),
|
)),
|
||||||
action: {
|
action: {
|
||||||
stickerContent.inputInteraction.openStickerSettings()
|
stickerContent.inputInteractionHolder.inputInteraction?.openStickerSettings()
|
||||||
}
|
}
|
||||||
).minSize(CGSize(width: 38.0, height: 38.0)))))
|
).minSize(CGSize(width: 38.0, height: 38.0)))))
|
||||||
}
|
}
|
||||||
@ -494,7 +497,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
component.switchToTextInput()
|
component.switchToTextInput()
|
||||||
}
|
}
|
||||||
).minSize(CGSize(width: 38.0, height: 38.0)))))
|
).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(
|
contentAccessoryRightButtons.append(AnyComponentWithIdentity(id: "emoji", component: AnyComponent(Button(
|
||||||
content: AnyComponent(BundleIconComponent(
|
content: AnyComponent(BundleIconComponent(
|
||||||
name: "Chat/Input/Media/EntityInputClearIcon",
|
name: "Chat/Input/Media/EntityInputClearIcon",
|
||||||
@ -502,11 +505,11 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
maxSize: nil
|
maxSize: nil
|
||||||
)),
|
)),
|
||||||
action: {
|
action: {
|
||||||
deleteBackwards()
|
deleteBackwards?()
|
||||||
AudioServicesPlaySystemSound(1155)
|
AudioServicesPlaySystemSound(1155)
|
||||||
}
|
}
|
||||||
).withHoldAction({
|
).withHoldAction({
|
||||||
deleteBackwards()
|
deleteBackwards?()
|
||||||
AudioServicesPlaySystemSound(1155)
|
AudioServicesPlaySystemSound(1155)
|
||||||
}).minSize(CGSize(width: 38.0, height: 38.0)))))
|
}).minSize(CGSize(width: 38.0, height: 38.0)))))
|
||||||
|
|
||||||
@ -529,9 +532,10 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
contentAccessoryLeftButtons: contentAccessoryLeftButtons,
|
contentAccessoryLeftButtons: contentAccessoryLeftButtons,
|
||||||
contentAccessoryRightButtons: contentAccessoryRightButtons,
|
contentAccessoryRightButtons: contentAccessoryRightButtons,
|
||||||
defaultId: component.defaultToEmojiTab ? "emoji" : "stickers",
|
defaultId: component.defaultToEmojiTab ? "emoji" : "stickers",
|
||||||
contentBackground: AnyComponent(BlurredBackgroundComponent(
|
contentBackground: nil/*AnyComponent(BlurredBackgroundComponent(
|
||||||
color: component.theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75)
|
color: component.theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75),
|
||||||
)),
|
tintContainerView: self.tintContainerView
|
||||||
|
))*/,
|
||||||
topPanel: AnyComponent(EntityKeyboardTopContainerPanelComponent(
|
topPanel: AnyComponent(EntityKeyboardTopContainerPanelComponent(
|
||||||
theme: component.theme,
|
theme: component.theme,
|
||||||
overflowHeight: component.hiddenInputHeight,
|
overflowHeight: component.hiddenInputHeight,
|
||||||
@ -542,7 +546,7 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
theme: component.theme,
|
theme: component.theme,
|
||||||
bottomInset: component.bottomInset,
|
bottomInset: component.bottomInset,
|
||||||
deleteBackwards: { [weak self] in
|
deleteBackwards: { [weak self] in
|
||||||
self?.component?.emojiContent.inputInteraction.deleteBackwards()
|
self?.component?.emojiContent.inputInteractionHolder.inputInteraction?.deleteBackwards()
|
||||||
AudioServicesPlaySystemSound(0x451)
|
AudioServicesPlaySystemSound(0x451)
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
|
@ -213,7 +213,7 @@ public final class GifPagerContentComponent: Component {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class View: ContextControllerSourceView, UIScrollViewDelegate {
|
public final class View: ContextControllerSourceView, PagerContentViewWithBackground, UIScrollViewDelegate {
|
||||||
private struct ItemGroupDescription: Equatable {
|
private struct ItemGroupDescription: Equatable {
|
||||||
let hasTitle: Bool
|
let hasTitle: Bool
|
||||||
let itemCount: Int
|
let itemCount: Int
|
||||||
@ -400,6 +400,8 @@ public final class GifPagerContentComponent: Component {
|
|||||||
private final class ContentScrollView: UIScrollView, PagerExpandableScrollView {
|
private final class ContentScrollView: UIScrollView, PagerExpandableScrollView {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let backgroundView: BlurredBackgroundView
|
||||||
|
|
||||||
private let shimmerHostView: PortalSourceView
|
private let shimmerHostView: PortalSourceView
|
||||||
private let standaloneShimmerEffect: StandaloneShimmerEffect
|
private let standaloneShimmerEffect: StandaloneShimmerEffect
|
||||||
|
|
||||||
@ -418,6 +420,8 @@ public final class GifPagerContentComponent: Component {
|
|||||||
private var currentLoadMoreToken: String?
|
private var currentLoadMoreToken: String?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
|
self.backgroundView = BlurredBackgroundView(color: nil)
|
||||||
|
|
||||||
self.shimmerHostView = PortalSourceView()
|
self.shimmerHostView = PortalSourceView()
|
||||||
self.standaloneShimmerEffect = StandaloneShimmerEffect()
|
self.standaloneShimmerEffect = StandaloneShimmerEffect()
|
||||||
|
|
||||||
@ -427,6 +431,8 @@ public final class GifPagerContentComponent: Component {
|
|||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.addSubview(self.backgroundView)
|
||||||
|
|
||||||
self.shimmerHostView.alpha = 0.0
|
self.shimmerHostView.alpha = 0.0
|
||||||
self.addSubview(self.shimmerHostView)
|
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 {
|
func update(component: GifPagerContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||||
var contentReset = false
|
var contentReset = false
|
||||||
if let previousComponent = self.component, previousComponent.subject != component.subject {
|
if let previousComponent = self.component, previousComponent.subject != component.subject {
|
||||||
|
@ -127,14 +127,14 @@ public final class TextNodeWithEntities {
|
|||||||
var found = false
|
var found = false
|
||||||
string.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: fullRange, options: [], using: { value, range, stop in
|
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 {
|
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)
|
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
|
||||||
updatedSubstring.addAttributes(string.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
|
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(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)
|
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(
|
let runDelegateData = RunDelegateData(
|
||||||
ascent: font.ascender,
|
ascent: font.ascender,
|
||||||
@ -230,7 +230,9 @@ public final class TextNodeWithEntities {
|
|||||||
|
|
||||||
let itemSize = floor(stickerItem.fontSize * 24.0 / 17.0)
|
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
|
let itemLayer: InlineStickerItemLayer
|
||||||
if let current = self.inlineStickerItemLayers[id] {
|
if let current = self.inlineStickerItemLayers[id] {
|
||||||
|
@ -1,22 +1,12 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"filename" : "Frame 1.svg",
|
||||||
"scale" : "1x"
|
"idiom" : "universal"
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "StickersGroupCross@2x-1.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "StickersGroupCross@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"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({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -2111,6 +2113,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))).withUpdatedComposeDisableUrlPreview(nil) }
|
$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
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))).withUpdatedComposeDisableUrlPreview(nil) }
|
$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)
|
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -11281,6 +11289,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -11340,6 +11350,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -11363,6 +11375,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -11819,6 +11833,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$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)
|
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -12181,6 +12199,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -12240,6 +12260,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -12258,6 +12280,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -12580,6 +12604,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -12896,6 +12922,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -12967,6 +12995,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -12983,6 +13013,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -13011,6 +13043,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -13156,6 +13190,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -13265,6 +13301,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
@ -13360,6 +13398,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||||
$0.updatedRecordedMediaPreview(nil).updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
$0.updatedRecordedMediaPreview(nil).updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
|
||||||
})
|
})
|
||||||
|
@ -126,6 +126,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
private(set) var accessoryPanelNode: AccessoryPanelNode?
|
private(set) var accessoryPanelNode: AccessoryPanelNode?
|
||||||
private var inputContextPanelNode: ChatInputContextPanelNode?
|
private var inputContextPanelNode: ChatInputContextPanelNode?
|
||||||
private let inputContextPanelContainer: ChatControllerTitlePanelNodeContainer
|
private let inputContextPanelContainer: ChatControllerTitlePanelNodeContainer
|
||||||
|
private let inputContextOverTextPanelContainer: ChatControllerTitlePanelNodeContainer
|
||||||
private var overlayContextPanelNode: ChatInputContextPanelNode?
|
private var overlayContextPanelNode: ChatInputContextPanelNode?
|
||||||
|
|
||||||
private var inputNode: ChatInputNode?
|
private var inputNode: ChatInputNode?
|
||||||
@ -271,6 +272,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.titleAccessoryPanelContainer.clipsToBounds = true
|
self.titleAccessoryPanelContainer.clipsToBounds = true
|
||||||
|
|
||||||
self.inputContextPanelContainer = ChatControllerTitlePanelNodeContainer()
|
self.inputContextPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||||
|
self.inputContextOverTextPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||||
|
|
||||||
var source: ChatHistoryListSource
|
var source: ChatHistoryListSource
|
||||||
if case let .forwardedMessages(messageIds, options) = subject {
|
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.inputContextPanelContainer)
|
||||||
|
self.addSubnode(self.inputPanelContainerNode)
|
||||||
|
self.addSubnode(self.inputContextOverTextPanelContainer)
|
||||||
|
|
||||||
self.inputPanelContainerNode.addSubnode(self.inputPanelClippingNode)
|
self.inputPanelContainerNode.addSubnode(self.inputPanelClippingNode)
|
||||||
self.inputPanelClippingNode.addSubnode(self.inputPanelBackgroundNode)
|
self.inputPanelClippingNode.addSubnode(self.inputPanelBackgroundNode)
|
||||||
@ -1213,7 +1216,18 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self?.updateInputPanelBackgroundExtension(transition: transition)
|
self?.updateInputPanelBackgroundExtension(transition: transition)
|
||||||
}
|
}
|
||||||
inputNode.hideInputUpdated = { [weak self] transition in
|
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
|
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.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.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?
|
var titleAccessoryPanelFrame: CGRect?
|
||||||
if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
|
if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
|
||||||
@ -1355,8 +1370,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if inputContextPanelNode !== self.inputContextPanelNode {
|
if inputContextPanelNode !== self.inputContextPanelNode {
|
||||||
dismissedInputContextPanelNode = self.inputContextPanelNode
|
dismissedInputContextPanelNode = self.inputContextPanelNode
|
||||||
self.inputContextPanelNode = inputContextPanelNode
|
self.inputContextPanelNode = inputContextPanelNode
|
||||||
|
switch inputContextPanelNode.placement {
|
||||||
self.inputContextPanelContainer.addSubnode(inputContextPanelNode)
|
case .overPanels:
|
||||||
|
self.inputContextPanelContainer.addSubnode(inputContextPanelNode)
|
||||||
|
case .overTextInput:
|
||||||
|
self.inputContextOverTextPanelContainer.addSubnode(inputContextPanelNode)
|
||||||
|
}
|
||||||
immediatelyLayoutInputContextPanelAndAnimateAppearance = true
|
immediatelyLayoutInputContextPanelAndAnimateAppearance = true
|
||||||
}
|
}
|
||||||
} else if let inputContextPanelNode = self.inputContextPanelNode {
|
} else if let inputContextPanelNode = self.inputContextPanelNode {
|
||||||
@ -2358,14 +2377,15 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if case let .peer(id) = self.chatPresentationInterfaceState.chatLocation {
|
if case let .peer(id) = self.chatPresentationInterfaceState.chatLocation {
|
||||||
peerId = id
|
peerId = id
|
||||||
}
|
}
|
||||||
let _ = peerId
|
|
||||||
|
|
||||||
let inputNode = ChatEntityKeyboardInputNode(
|
let inputNode = ChatEntityKeyboardInputNode(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
currentInputData: inputMediaNodeData,
|
currentInputData: inputMediaNodeData,
|
||||||
updatedInputData: self.inputMediaNodeDataPromise.get(),
|
updatedInputData: self.inputMediaNodeDataPromise.get(),
|
||||||
defaultToEmojiTab: !self.chatPresentationInterfaceState.interfaceState.effectiveInputState.inputText.string.isEmpty,
|
defaultToEmojiTab: !self.chatPresentationInterfaceState.interfaceState.effectiveInputState.inputText.string.isEmpty,
|
||||||
controllerInteraction: self.controllerInteraction
|
controllerInteraction: self.controllerInteraction,
|
||||||
|
interfaceInteraction: self.interfaceInteraction,
|
||||||
|
chatPeerId: peerId
|
||||||
)
|
)
|
||||||
|
|
||||||
return inputNode
|
return inputNode
|
||||||
@ -2962,6 +2982,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
self.setupSendActionOnViewUpdate({ [weak self] in
|
self.setupSendActionOnViewUpdate({ [weak self] in
|
||||||
if let strongSelf = self, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode {
|
if let strongSelf = self, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode {
|
||||||
|
strongSelf.collapseInput()
|
||||||
|
|
||||||
strongSelf.ignoreUpdateHeight = true
|
strongSelf.ignoreUpdateHeight = true
|
||||||
textInputPanelNode.text = ""
|
textInputPanelNode.text = ""
|
||||||
strongSelf.requestUpdateChatInterfaceState(.immediate, true, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeDisableUrlPreview(nil) })
|
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))
|
let hasPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||||
|> map { peer -> Bool in
|
|> map { peer -> Bool in
|
||||||
guard case let .user(user) = peer else {
|
guard case let .user(user) = peer else {
|
||||||
@ -250,7 +250,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
context: context,
|
context: context,
|
||||||
animationCache: animationCache,
|
animationCache: animationCache,
|
||||||
animationRenderer: animationRenderer,
|
animationRenderer: animationRenderer,
|
||||||
inputInteraction: inputInteraction,
|
inputInteractionHolder: EmojiPagerContentComponent.InputInteractionHolder(),
|
||||||
itemGroups: itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
itemGroups: itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
||||||
var hasClear = false
|
var hasClear = false
|
||||||
if group.id == AnyHashable("recent") {
|
if group.id == AnyHashable("recent") {
|
||||||
@ -291,321 +291,6 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> 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: {
|
let animationCache = AnimationCacheImpl(basePath: context.account.postbox.mediaBox.basePath + "/animation-cache", allocateTempFile: {
|
||||||
return TempBox.shared.tempFile(fileName: "file").path
|
return TempBox.shared.tempFile(fileName: "file").path
|
||||||
})
|
})
|
||||||
@ -616,7 +301,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
animationRenderer = MultiAnimationRendererImpl()
|
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 stickerNamespaces: [ItemCollectionId.Namespace] = [Namespaces.ItemCollection.CloudStickerPacks]
|
||||||
let stickerOrderedItemListCollectionIds: [Int32] = [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers, Namespaces.OrderedItemList.PremiumStickers, Namespaces.OrderedItemList.CloudPremiumStickers]
|
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,
|
context: context,
|
||||||
animationCache: animationCache,
|
animationCache: animationCache,
|
||||||
animationRenderer: animationRenderer,
|
animationRenderer: animationRenderer,
|
||||||
inputInteraction: stickerInputInteraction,
|
inputInteractionHolder: EmojiPagerContentComponent.InputInteractionHolder(),
|
||||||
itemGroups: itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
itemGroups: itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
||||||
var hasClear = false
|
var hasClear = false
|
||||||
var isEmbedded = false
|
var isEmbedded = false
|
||||||
@ -1028,6 +713,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
var switchToTextInput: (() -> Void)?
|
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 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 scheduledInnerTransition: Transition?
|
||||||
|
|
||||||
private var gifMode: GifPagerContentComponent.Subject? {
|
private var gifMode: GifPagerContentComponent.Subject? {
|
||||||
@ -1253,7 +940,10 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
private let gifComponent = Promise<EntityKeyboardGifContent>()
|
private let gifComponent = Promise<EntityKeyboardGifContent>()
|
||||||
private var gifInputInteraction: GifPagerContentComponent.InputInteraction?
|
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.context = context
|
||||||
self.currentInputData = currentInputData
|
self.currentInputData = currentInputData
|
||||||
self.defaultToEmojiTab = defaultToEmojiTab
|
self.defaultToEmojiTab = defaultToEmojiTab
|
||||||
@ -1271,6 +961,331 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
|
|
||||||
self.externalTopPanelContainerImpl = PagerExternalTopPanelContainer()
|
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(),
|
self.inputDataDisposable = (combineLatest(queue: .mainQueue(),
|
||||||
updatedInputData,
|
updatedInputData,
|
||||||
@ -1295,7 +1310,14 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if useAnimation {
|
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.currentInputData = inputData
|
||||||
strongSelf.performLayout(transition: transition)
|
strongSelf.performLayout(transition: transition)
|
||||||
@ -1459,6 +1481,9 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
gifContent = nil
|
gifContent = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stickerContent?.inputInteractionHolder.inputInteraction = self.stickerInputInteraction
|
||||||
|
self.currentInputData.emoji.inputInteractionHolder.inputInteraction = self.emojiInputInteraction
|
||||||
|
|
||||||
let entityKeyboardSize = self.entityKeyboardView.update(
|
let entityKeyboardSize = self.entityKeyboardView.update(
|
||||||
transition: mappedTransition,
|
transition: mappedTransition,
|
||||||
component: AnyComponent(EntityKeyboardComponent(
|
component: AnyComponent(EntityKeyboardComponent(
|
||||||
@ -1824,7 +1849,7 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
|||||||
|
|
||||||
let semaphore = DispatchSemaphore(value: 0)
|
let semaphore = DispatchSemaphore(value: 0)
|
||||||
var emojiComponent: EmojiPagerContentComponent?
|
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
|
emojiComponent = value
|
||||||
semaphore.signal()
|
semaphore.signal()
|
||||||
})
|
})
|
||||||
@ -1841,9 +1866,12 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
|||||||
),
|
),
|
||||||
updatedInputData: .never(),
|
updatedInputData: .never(),
|
||||||
defaultToEmojiTab: true,
|
defaultToEmojiTab: true,
|
||||||
controllerInteraction: nil
|
controllerInteraction: nil,
|
||||||
|
interfaceInteraction: nil,
|
||||||
|
chatPeerId: nil
|
||||||
)
|
)
|
||||||
self.inputNode = inputNode
|
self.inputNode = inputNode
|
||||||
|
inputNode.emojiInputInteraction = inputInteraction
|
||||||
inputNode.externalTopPanelContainerImpl = nil
|
inputNode.externalTopPanelContainerImpl = nil
|
||||||
inputNode.switchToTextInput = { [weak self] in
|
inputNode.switchToTextInput = { [weak self] in
|
||||||
self?.switchToKeyboard?()
|
self?.switchToKeyboard?()
|
||||||
|
@ -74,7 +74,7 @@ final class ChatMediaInputStickerGridSectionNode: ASDisplayNode {
|
|||||||
self.setupNode = setupNode
|
self.setupNode = setupNode
|
||||||
case .clear:
|
case .clear:
|
||||||
let setupNode = HighlightableButtonNode()
|
let setupNode = HighlightableButtonNode()
|
||||||
setupNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme), for: [])
|
setupNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme, color: theme.chat.inputMediaPanel.stickersSectionTextColor), for: [])
|
||||||
self.setupNode = setupNode
|
self.setupNode = setupNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,24 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
|
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
|
||||||
private var absoluteRect: (CGRect, CGSize)?
|
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() {
|
required init() {
|
||||||
self.labelNode = TextNodeWithEntities()
|
self.labelNode = TextNodeWithEntities()
|
||||||
self.labelNode.textNode.isUserInteractionEnabled = false
|
self.labelNode.textNode.isUserInteractionEnabled = false
|
||||||
@ -340,6 +358,18 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
strongSelf.backgroundColorNode.frame = CGRect(origin: CGPoint(), size: image.size)
|
strongSelf.backgroundColorNode.frame = CGRect(origin: CGPoint(), size: image.size)
|
||||||
|
|
||||||
strongSelf.cachedMaskBackgroundImage = (offset, image, labelRects)
|
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] {
|
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 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
|
var text = messageText
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ class StickerPanePeerSpecificSetupGridItemNode: GridItemNode {
|
|||||||
var updateButtonBackgroundImage: UIImage?
|
var updateButtonBackgroundImage: UIImage?
|
||||||
if currentItem?.theme !== item.theme {
|
if currentItem?.theme !== item.theme {
|
||||||
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddPackButtonImage(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
|
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 })
|
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
|
||||||
if currentItem?.theme !== item.theme {
|
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
|
let leftInset: CGFloat = 9.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user