Merge branches 'master' and 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin
2022-07-22 17:46:14 +03:00
39 changed files with 3135 additions and 996 deletions
@@ -107,6 +107,7 @@
"PUSH_MESSAGE_THEME" = "%1$@|changed chat theme to %2$@";
"PUSH_MESSAGE_NOTHEME" = "%1$@|disabled chat theme";
"PUSH_MESSAGE_RECURRING_PAY" = "%1$@|You were charged %2$@";
"CHAT_MESSAGE_RECURRING_PAY" = "%1$@|You were charged %2$@";
"PUSH_CHANNEL_MESSAGE_TEXT" = "%1$@|%2$@";
"PUSH_CHANNEL_MESSAGE_NOTEXT" = "%1$@|posted a message";
@@ -556,7 +556,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else {
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
}
let (_, initialHideAuthor, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
}
@@ -590,7 +590,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else {
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
}
let (_, initialHideAuthor, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
}
@@ -1095,7 +1095,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let leftInset: CGFloat = params.leftInset + avatarLeftInset
enum ContentData {
case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?)
case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?)
case group(peers: [EngineChatList.GroupItem.Item])
}
@@ -1104,7 +1104,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
var hideAuthor = false
switch contentPeer {
case let .chat(itemPeer):
var (peer, initialHideAuthor, messageText, spoilers) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
var (peer, initialHideAuthor, messageText, spoilers, customEmojiRanges) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
if case let .psa(_, maybePsaText) = promoInfo, let psaText = maybePsaText {
initialHideAuthor = true
@@ -1125,7 +1125,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
break
}
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers)
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers, customEmojiRanges: customEmojiRanges)
hideAuthor = initialHideAuthor
case let .group(groupPeers):
contentData = .group(peers: groupPeers)
@@ -1156,7 +1156,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
switch contentData {
case let .chat(itemPeer, _, _, text, spoilers):
case let .chat(itemPeer, _, _, text, spoilers, customEmojiRanges):
var isUser = false
if case .user = itemPeer.chatMainPeer {
isUser = true
@@ -1185,6 +1185,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else {
if let spoilers = spoilers, !spoilers.isEmpty {
messageText = text
} else if let customEmojiRanges = customEmojiRanges, !customEmojiRanges.isEmpty {
messageText = text
} else {
messageText = foldLineBreaks(text)
}
@@ -1216,10 +1218,17 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let messageString: NSAttributedString
if !message.text.isEmpty && entities.count > 0 {
messageString = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: authorAttributedString == nil ? 2 : 1), entities: entities, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: message._asMessage())
} else if let spoilers = spoilers {
} else if spoilers != nil || customEmojiRanges != nil {
let mutableString = NSMutableAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
for range in spoilers {
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)
if let spoilers = spoilers {
for range in spoilers {
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)
}
}
if let customEmojiRanges = customEmojiRanges {
for (range, attribute) in customEmojiRanges {
mutableString.addAttribute(ChatTextInputAttributes.customEmoji, value: attribute, range: range)
}
}
messageString = mutableString
} else {
@@ -1268,8 +1277,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
attributedText = composedString
var displayMediaPreviews = true
if message._asMessage().containsSecretMedia {
displayMediaPreviews = false
@@ -1359,7 +1366,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
}
switch contentData {
case let .chat(itemPeer, _, _, _, _):
case let .chat(itemPeer, _, _, _, _, _):
if let message = messages.last, case let .user(author) = message.author, displayAsMessage {
titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer.user(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor)
} else if isPeerGroup {
@@ -4,6 +4,7 @@ import TelegramPresentationData
import TelegramUIPreferences
import TelegramStringFormatting
import LocalizedPeerData
import TextFormat
private enum MessageGroupType {
case photos
@@ -44,7 +45,7 @@ private func messageGroupType(messages: [EngineMessage]) -> MessageGroupType {
return currentType
}
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?) {
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?) {
let peer: EnginePeer?
let message = messages.last
@@ -52,6 +53,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
var hideAuthor = false
var messageText: String
var spoilers: [NSRange]?
var customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?
if let message = message {
if let messageMain = messageMainPeer(message) {
peer = messageMain
@@ -269,13 +271,14 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
}
default:
hideAuthor = true
if let (text, textSpoilers) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
if let (text, textSpoilers, customEmojiRangesValue) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
messageText = text
spoilers = textSpoilers
customEmojiRanges = customEmojiRangesValue
}
}
case _ as TelegramMediaExpiredContent:
if let (text, _) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
if let (text, _, _) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
messageText = text
}
case let poll as TelegramMediaPoll:
@@ -314,5 +317,5 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
}
}
return (peer, hideAuthor, messageText, spoilers)
return (peer, hideAuthor, messageText, spoilers, customEmojiRanges)
}
@@ -27,36 +27,93 @@ public final class BlurredBackgroundComponent: Component {
}
public final class View: BlurredBackgroundView {
private var tintMaskView: UIView?
private var tintContainerView: UIView?
private var vibrancyEffectView: UIVisualEffectView?
public func update(component: BlurredBackgroundComponent, availableSize: CGSize, transition: Transition) -> CGSize {
if let tintContainerView = component.tintContainerView {
self.updateColor(color: .clear, forceKeepBlur: true, transition: transition.containedViewLayoutTransition)
/*if self.tintContainerView !== component.tintContainerView {
if let tintContainerView = self.tintContainerView {
self.tintContainerView = nil
if tintContainerView.superview === self {
tintContainerView.removeFromSuperview()
}
}
let tintMaskView: UIView
if let current = self.tintMaskView {
tintMaskView = current
self.tintContainerView = component.tintContainerView
if let tintContainerView = self.tintContainerView {
let vibrancyEffectView: UIVisualEffectView
if let current = self.vibrancyEffectView {
vibrancyEffectView = current
} else {
let blurEffect = UIBlurEffect(style: .extraLight)
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
vibrancyEffectView = UIVisualEffectView(effect: vibrancyEffect)
self.vibrancyEffectView = vibrancyEffectView
self.addSubview(vibrancyEffectView)
}
tintContainerView.backgroundColor = .white
vibrancyEffectView.contentView.addSubview(tintContainerView)
} else {
tintMaskView = UIView()
self.tintMaskView = tintMaskView
self.addSubview(tintMaskView)
}
tintMaskView.backgroundColor = component.color
transition.setFrame(view: tintMaskView, frame: CGRect(origin: CGPoint(), size: availableSize))
if tintMaskView.mask !== tintContainerView {
tintMaskView.mask = tintContainerView
if let vibrancyEffectView = self.vibrancyEffectView {
self.vibrancyEffectView = nil
vibrancyEffectView.removeFromSuperview()
}
}
}*/
self.updateColor(color: component.color, transition: transition.containedViewLayoutTransition)
/*if let _ = self.viewWithTag(123) {
} else {
self.updateColor(color: component.color, transition: transition.containedViewLayoutTransition)
let blurEffect = UIBlurEffect(style: .extraLight)
if let tintMaskView = self.tintMaskView {
self.tintMaskView = nil
tintMaskView.removeFromSuperview()
}
/*let segmentedControl = UISegmentedControl(items: ["First Item", "Second Item"])
segmentedControl.sizeToFit()
segmentedControl.center = CGPoint(x: 250.0, y: 250.0)*/
let testView = UIView(frame: CGRect(origin: CGPoint(x: 50.0, y: 100.0), size: CGSize(width: 250.0, height: 50.0)))
testView.backgroundColor = .white
let testView2 = UILabel()
testView2.text = "Test 13245"
testView2.font = Font.semibold(17.0)
testView2.textColor = .black
testView2.sizeToFit()
testView2.center = CGPoint(x: 250.0 - testView.frame.minX, y: 490.0 - testView.frame.minY)
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
let vibrancyEffectView = UIVisualEffectView(effect: vibrancyEffect)
//vibrancyEffectView.frame = CGRect(origin: CGPoint(), size: CGSize(width: 400.0, height: 300.0))
vibrancyEffectView.tag = 123
vibrancyEffectView.contentView.addSubview(testView)
testView.addSubview(testView2)
//vibrancyEffectView.contentView.addSubview(testView2)
self.addSubview(vibrancyEffectView)
/*let view = UIView()
view.tag = 123
view.layer.compositingFilter = "sourceOverCompositing"
view.backgroundColor = .white
view.frame = CGRect(origin: CGPoint(), size: CGSize(width: 100.0, height: 200.0))
self.addSubview(view)*/
}
if let view = self.viewWithTag(123) {
view.frame = CGRect(origin: CGPoint(), size: availableSize)
}*/
self.update(size: availableSize, transition: transition.containedViewLayoutTransition)
if let tintContainerView = self.tintContainerView {
transition.setFrame(view: tintContainerView, frame: CGRect(origin: CGPoint(), size: availableSize))
}
if let vibrancyEffectView = self.vibrancyEffectView {
transition.setFrame(view: vibrancyEffectView, frame: CGRect(origin: CGPoint(), size: availableSize))
}
return availableSize
}
@@ -12,6 +12,10 @@ public protocol PagerPanGestureRecognizer: UIGestureRecognizer {
open class PagerExternalTopPanelContainer: SparseContainerView {
}
public protocol PagerContentViewWithBackground: UIView {
func pagerUpdateBackground(backgroundFrame: CGRect, transition: Transition)
}
public final class PagerComponentChildEnvironment: Equatable {
public struct ContentScrollingUpdate {
public var relativeOffset: CGFloat
@@ -292,8 +296,15 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
case .began:
self.paneTransitionGestureState = PaneTransitionGestureState()
case .changed:
if var paneTransitionGestureState = self.paneTransitionGestureState, self.bounds.width > 0.0 {
paneTransitionGestureState.fraction = recognizer.translation(in: self).x / self.bounds.width
if let centralId = self.centralId, let component = self.component, let centralIndex = component.contents.firstIndex(where: { $0.id == centralId }), var paneTransitionGestureState = self.paneTransitionGestureState, self.bounds.width > 0.0 {
var fraction = recognizer.translation(in: self).x / self.bounds.width
if centralIndex <= 0 {
fraction = min(0.0, fraction)
}
if centralIndex >= component.contents.count - 1 {
fraction = max(0.0, fraction)
}
paneTransitionGestureState.fraction = fraction
self.paneTransitionGestureState = paneTransitionGestureState
self.state?.updated(transition: .immediate)
@@ -554,6 +565,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
}
}
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: effectiveTopPanelHeight), size: CGSize(width: availableSize.width, height: availableSize.height - effectiveTopPanelHeight - contentInsets.bottom + bottomPanelOffset))
if let contentBackground = component.contentBackground {
let contentBackgroundView: ComponentHostView<Empty>
var contentBackgroundTransition = panelStateTransition
@@ -565,13 +577,13 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
self.contentBackgroundView = contentBackgroundView
self.insertSubview(contentBackgroundView, at: 0)
}
let contentBackgroundSize = contentBackgroundView.update(
let _ = contentBackgroundView.update(
transition: contentBackgroundTransition,
component: contentBackground,
environment: {},
containerSize: CGSize(width: availableSize.width, height: availableSize.height - effectiveTopPanelHeight - contentInsets.bottom + bottomPanelOffset)
containerSize: backgroundFrame.size
)
contentBackgroundTransition.setFrame(view: contentBackgroundView, frame: CGRect(origin: CGPoint(x: 0.0, y: effectiveTopPanelHeight), size: contentBackgroundSize))
contentBackgroundTransition.setFrame(view: contentBackgroundView, frame: backgroundFrame)
} else {
if let contentBackgroundView = self.contentBackgroundView {
self.contentBackgroundView = nil
@@ -691,6 +703,10 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
}
})
}
if let contentViewWithBackground = contentView.view.componentView as? PagerContentViewWithBackground {
contentViewWithBackground.pagerUpdateBackground(backgroundFrame: backgroundFrame, transition: contentTransition)
}
}
}
}
@@ -327,6 +327,7 @@ open class BlurredBackgroundView: UIView {
if let color = self._color, self.enableBlur && !sharedIsReduceTransparencyEnabled && ((color.alpha > .ulpOfOne && color.alpha < 0.95) || forceKeepBlur) {
if self.effectView == nil {
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
//effectView.isHidden = true
for subview in effectView.subviews {
if subview.description.contains("VisualEffectSubview") {
@@ -768,12 +768,13 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
strongSelf.animationNode = animationNode
strongSelf.addSubnode(animationNode)
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .cached)
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource, isVideo: isVideo), width: 80, height: 80, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
}
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
animationNode.isHidden = !item.playAnimatedStickers
strongSelf.imageNode.isHidden = item.playAnimatedStickers
if let animationNode = strongSelf.animationNode {
animationNode.updateLayout(size: imageFrame.size)
transition.updateFrame(node: animationNode, frame: imageFrame)
}
}
@@ -111,8 +111,8 @@
{
if (request.requestContext != nil)
{
[_dropReponseContexts addObject:[[MTDropResponseContext alloc] initWithDropMessageId:request.requestContext.messageId]];
anyNewDropRequests = true;
//[_dropReponseContexts addObject:[[MTDropResponseContext alloc] initWithDropMessageId:request.requestContext.messageId]];
//anyNewDropRequests = true;
}
if (request.requestContext.messageId != 0) {
@@ -729,7 +729,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: action == .archive ? presentationData.strings.StickerPackActionInfo_ArchivedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(archivedItem.info.title).string, undo: true, info: archivedItem.info, topItem: archivedItem.topItems.first, context: context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: archivedItem.info, items: items, positionInList: positionInList).start()
let _ = context.engine.stickers.addStickerPackInteractively(info: archivedItem.info, items: items.compactMap({ $0 as? StickerPackItem }), positionInList: positionInList).start()
}
return true
}))
@@ -3,7 +3,7 @@ import Postbox
import SwiftSignalKit
func _internal_addStickerPackInteractively(postbox: Postbox, info: StickerPackCollectionInfo, items: [ItemCollectionItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
func _internal_addStickerPackInteractively(postbox: Postbox, info: StickerPackCollectionInfo, items: [StickerPackItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
let namespace: SynchronizeInstalledStickerPacksOperationNamespace?
switch info.id.namespace {
@@ -33,7 +33,12 @@ func _internal_addStickerPackInteractively(postbox: Postbox, info: StickerPackCo
} else {
updatedInfos.insert(mappedInfo, at: 0)
}
transaction.replaceItemCollectionItems(collectionId: mappedInfo.id, items: items)
var indexedItems: [ItemCollectionItem] = []
for item in items {
indexedItems.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(indexedItems.count), id: item.index.id), file: item.file, indexKeys: item.indexKeys))
}
transaction.replaceItemCollectionItems(collectionId: mappedInfo.id, items: indexedItems)
}
transaction.replaceItemCollectionInfos(namespace: mappedInfo.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) })
}
@@ -46,7 +46,7 @@ public extension TelegramEngine {
return _internal_searchGifs(account: self.account, query: query, nextOffset: nextOffset)
}
public func addStickerPackInteractively(info: StickerPackCollectionInfo, items: [ItemCollectionItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
public func addStickerPackInteractively(info: StickerPackCollectionInfo, items: [StickerPackItem], positionInList: Int? = nil) -> Signal<Void, NoError> {
return _internal_addStickerPackInteractively(postbox: self.account.postbox, info: info, items: items, positionInList: positionInList)
}
@@ -276,7 +276,6 @@ public enum PresentationResourceKey: Int32 {
case chatKeyboardActionButtonProfileIcon
case chatKeyboardActionButtonAddToChatIcon
case chatKeyboardActionButtonWebAppIcon
case chatEntityKeyboardLock
case uploadToneIcon
}
@@ -313,4 +312,7 @@ public enum PresentationResourceParameterKey: Hashable {
case chatMessageCommentsArrowIcon(incoming: Bool)
case chatMessageCommentsUnreadDotIcon(incoming: Bool)
case chatMessageRepliesIcon(incoming: Bool)
case chatEntityKeyboardLock(color: UInt32)
case chatInputMediaPanelGridDismissImage(color: UInt32)
}
@@ -371,9 +371,9 @@ public struct PresentationResourcesChat {
})
}
public static func chatInputMediaPanelGridDismissImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputMediaPanelGridDismissImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/GridDismissIcon"), color: theme.chat.inputMediaPanel.stickersSectionTextColor)
public static func chatInputMediaPanelGridDismissImage(_ theme: PresentationTheme, color: UIColor) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatInputMediaPanelGridDismissImage(color: color.argb), { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/GridDismissIcon"), color: color)
})
}
@@ -1282,9 +1282,9 @@ public struct PresentationResourcesChat {
})
}
public static func chatEntityKeyboardLock(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatEntityKeyboardLock.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.chat.inputMediaPanel.stickersSectionTextColor)
public static func chatEntityKeyboardLock(_ theme: PresentationTheme, color: UIColor) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatEntityKeyboardLock(color: color.argb), { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: color)
})
}
}
@@ -34,15 +34,18 @@ private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, E
return result
}
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> (String, [NSRange])? {
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> (text: String, spoilerRanges: [NSRange], customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)])? {
if let attributedString = universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: forChatList) {
var ranges: [NSRange] = []
var customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)] = []
attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: [], using: { attributes, range, _ in
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)] {
ranges.append(range)
} else if let value = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute {
customEmojiRanges.append((range, value))
}
})
return (attributedString.string, ranges)
return (attributedString.string, ranges, customEmojiRanges)
} else {
return nil
}
@@ -5,9 +5,18 @@
#import <ImageDCT/YuvConversion.h>
@interface ImageDCTTable : NSObject
- (instancetype _Nonnull)initWithQuality:(NSInteger)quality isChroma:(bool)isChroma;
- (instancetype _Nullable)initWithData:(NSData * _Nonnull)data;
- (NSData * _Nonnull)serializedData;
@end
@interface ImageDCT : NSObject
- (instancetype _Nonnull)initWithQuality:(NSInteger)quality;
- (instancetype _Nonnull)initWithTable:(ImageDCTTable * _Nonnull)table;
- (void)forwardWithPixels:(uint8_t const * _Nonnull)pixels coefficients:(int16_t * _Nonnull)coefficients width:(NSInteger)width height:(NSInteger)height bytesPerRow:(NSInteger)bytesPerRow __attribute__((objc_direct));
- (void)inverseWithCoefficients:(int16_t const * _Nonnull)coefficients pixels:(uint8_t * _Nonnull)pixels width:(NSInteger)width height:(NSInteger)height coefficientsPerRow:(NSInteger)coefficientsPerRow bytesPerRow:(NSInteger)bytesPerRow __attribute__((objc_direct));
@@ -118,6 +118,16 @@ static DCTELEM std_luminance_quant_tbl[DCTSIZE2] = {
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
static DCTELEM std_chrominance_quant_tbl[DCTSIZE2] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
int jpeg_quality_scaling(int quality)
/* Convert a user-specified quality rating to a percentage scaling factor
@@ -143,7 +153,7 @@ int jpeg_quality_scaling(int quality)
return quality;
}
void jpeg_add_quant_table(DCTELEM *qtable, DCTELEM *basicTable, int scale_factor, bool forceBaseline)
void jpeg_add_quant_table(DCTELEM *qtable, DCTELEM const *basicTable, int scale_factor, bool forceBaseline)
/* Define a quantization table equal to the basic_table times
* a scale factor (given as a percentage).
* If force_baseline is TRUE, the computed quantization table entries
@@ -164,7 +174,7 @@ void jpeg_add_quant_table(DCTELEM *qtable, DCTELEM *basicTable, int scale_factor
}
}
void jpeg_set_quality(DCTELEM *qtable, int quality)
void jpeg_set_quality(DCTELEM *qtable, DCTELEM const *basicTable, int quality)
/* Set or change the 'quality' (quantization) setting, using default tables.
* This is the standard quality-adjusting entry point for typical user
* interfaces; only those who want detailed control over quantization tables
@@ -175,10 +185,10 @@ void jpeg_set_quality(DCTELEM *qtable, int quality)
quality = jpeg_quality_scaling(quality);
/* Set up standard quality tables */
jpeg_add_quant_table(qtable, std_luminance_quant_tbl, quality, false);
jpeg_add_quant_table(qtable, basicTable, quality, false);
}
void getDivisors(DCTELEM *dtbl, DCTELEM *qtable) {
void getDivisors(DCTELEM *dtbl, DCTELEM const *qtable) {
#define CONST_BITS 14
#define RIGHT_SHIFT(x, shft) ((x) >> (shft))
@@ -234,22 +244,15 @@ void quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
}
}
void generateForwardDctData(int quality, std::vector<uint8_t> &data) {
void generateForwardDctData(DCTELEM const *qtable, std::vector<uint8_t> &data) {
data.resize(DCTSIZE2 * 4 * sizeof(DCTELEM));
DCTELEM qtable[DCTSIZE2];
jpeg_set_quality(qtable, quality);
getDivisors((DCTELEM *)data.data(), qtable);
}
void generateInverseDctData(int quality, std::vector<uint8_t> &data) {
void generateInverseDctData(DCTELEM const *qtable, std::vector<uint8_t> &data) {
data.resize(DCTSIZE2 * sizeof(IFAST_MULT_TYPE));
IFAST_MULT_TYPE *ifmtbl = (IFAST_MULT_TYPE *)data.data();
DCTELEM qtable[DCTSIZE2];
jpeg_set_quality(qtable, quality);
#define CONST_BITS 14
static const int16_t aanscales[DCTSIZE2] = {
/* precomputed values scaled up by 14 bits */
@@ -338,13 +341,32 @@ void performInverseDct(int16_t const * coefficients, uint8_t *pixels, int width,
namespace dct {
DCTTable DCTTable::generate(int quality, bool isChroma) {
DCTTable result;
result.table.resize(DCTSIZE2);
if (isChroma) {
jpeg_set_quality(result.table.data(), std_chrominance_quant_tbl, quality);
} else {
jpeg_set_quality(result.table.data(), std_luminance_quant_tbl, quality);
}
return result;
}
DCTTable DCTTable::initializeEmpty() {
DCTTable result;
result.table.resize(DCTSIZE2);
return result;
}
class DCTInternal {
public:
DCTInternal(int quality) {
DCTInternal(DCTTable const &dctTable) {
auxiliaryData = createDctAuxiliaryData();
generateForwardDctData(quality, forwardDctData);
generateInverseDctData(quality, inverseDctData);
generateForwardDctData(dctTable.table.data(), forwardDctData);
generateInverseDctData(dctTable.table.data(), inverseDctData);
}
~DCTInternal() {
@@ -357,8 +379,8 @@ public:
std::vector<uint8_t> inverseDctData;
};
DCT::DCT(int quality) {
_internal = new DCTInternal(quality);
DCT::DCT(DCTTable const &dctTable) {
_internal = new DCTInternal(dctTable);
}
DCT::~DCT() {
@@ -3,15 +3,23 @@
#include "DCTCommon.h"
#include <vector>
#include <stdint.h>
namespace dct {
class DCTInternal;
struct DCTTable {
static DCTTable generate(int quality, bool isChroma);
static DCTTable initializeEmpty();
std::vector<int16_t> table;
};
class DCT {
public:
DCT(int quality);
DCT(DCTTable const &dctTable);
~DCT();
void forward(uint8_t const *pixels, int16_t *coefficients, int width, int height, int bytesPerRow);
@@ -4,6 +4,41 @@
#include "DCT.h"
@interface ImageDCTTable () {
@public
dct::DCTTable _table;
}
@end
@implementation ImageDCTTable
- (instancetype _Nonnull)initWithQuality:(NSInteger)quality isChroma:(bool)isChroma {
self = [super init];
if (self != nil) {
_table = dct::DCTTable::generate((int)quality, isChroma);
}
return self;
}
- (instancetype _Nullable)initWithData:(NSData * _Nonnull)data {
self = [super init];
if (self != nil) {
_table = dct::DCTTable::initializeEmpty();
if (data.length != _table.table.size() * 2) {
return nil;
}
memcpy(_table.table.data(), data.bytes, data.length);
}
return self;
}
- (NSData * _Nonnull)serializedData {
return [[NSData alloc] initWithBytes:_table.table.data() length:_table.table.size() * 2];
}
@end
@interface ImageDCT () {
std::unique_ptr<dct::DCT> _dct;
}
@@ -12,10 +47,10 @@
@implementation ImageDCT
- (instancetype _Nonnull)initWithQuality:(NSInteger)quality {
- (instancetype _Nonnull)initWithTable:(ImageDCTTable * _Nonnull)table {
self = [super init];
if (self != nil) {
_dct = std::unique_ptr<dct::DCT>(new dct::DCT((int)quality));
_dct = std::unique_ptr<dct::DCT>(new dct::DCT(table->_table));
}
return self;
}
@@ -294,10 +294,10 @@ private final class AnimationCacheItemWriterInternal {
}
let dctData: DctData
if let current = self.currentDctData, current.quality == self.dctQuality {
if let current = self.currentDctData {
dctData = current
} else {
dctData = DctData(quality: self.dctQuality)
dctData = DctData(generatingTablesAtQuality: self.dctQuality)
self.currentDctData = dctData
}
@@ -310,11 +310,18 @@ private final class AnimationCacheItemWriterInternal {
yuvaSurface.dct(dctData: dctData, target: dctCoefficients)
if isFirstFrame {
self.file.write(3 as UInt32)
self.file.write(4 as UInt32)
self.file.write(UInt32(dctCoefficients.yPlane.width))
self.file.write(UInt32(dctCoefficients.yPlane.height))
self.file.write(UInt32(dctData.quality))
let lumaDctTable = dctData.lumaTable.serializedData()
self.file.write(UInt32(lumaDctTable.count))
let _ = self.file.write(lumaDctTable)
let chromaDctTable = dctData.chromaTable.serializedData()
self.file.write(UInt32(chromaDctTable.count))
let _ = self.file.write(chromaDctTable)
self.contentLengthOffset = Int(self.file.position())
self.file.write(0 as UInt32)
@@ -501,10 +508,10 @@ private final class AnimationCacheItemWriterImpl: AnimationCacheItemWriter {
}
let dctData: DctData
if let current = self.currentDctData, current.quality == self.dctQuality {
if let current = self.currentDctData {
dctData = current
} else {
dctData = DctData(quality: self.dctQuality)
dctData = DctData(generatingTablesAtQuality: self.dctQuality)
self.currentDctData = dctData
}
@@ -526,11 +533,18 @@ private final class AnimationCacheItemWriterImpl: AnimationCacheItemWriter {
yuvaSurface.dct(dctData: dctData, target: dctCoefficients)
if isFirstFrame {
file.write(3 as UInt32)
file.write(4 as UInt32)
file.write(UInt32(dctCoefficients.yPlane.width))
file.write(UInt32(dctCoefficients.yPlane.height))
file.write(UInt32(dctData.quality))
let lumaDctTable = dctData.lumaTable.serializedData()
file.write(UInt32(lumaDctTable.count))
let _ = file.write(lumaDctTable)
let chromaDctTable = dctData.chromaTable.serializedData()
file.write(UInt32(chromaDctTable.count))
let _ = file.write(chromaDctTable)
self.contentLengthOffset = Int(file.position())
file.write(0 as UInt32)
@@ -652,10 +666,10 @@ private final class AnimationCacheItemAccessor {
private var currentFrame: CurrentFrame?
private var currentYUVASurface: ImageYUVA420?
private var currentDctData: DctData
private let currentDctData: DctData
private var sharedDctCoefficients: DctCoefficientsYUVA420?
init(data: Data, range: Range<Int>, frameMapping: [FrameInfo], width: Int, height: Int, dctQuality: Int) {
init(data: Data, range: Range<Int>, frameMapping: [FrameInfo], width: Int, height: Int, dctData: DctData) {
self.data = data
self.range = range
self.width = width
@@ -673,7 +687,7 @@ private final class AnimationCacheItemAccessor {
self.frameMapping = resultFrameMapping
self.durationMapping = durationMapping
self.currentDctData = DctData(quality: dctQuality)
self.currentDctData = dctData
}
private func loadNextFrame() {
@@ -835,6 +849,16 @@ private final class AnimationCacheItemAccessor {
}
}
private func readData(data: Data, offset: Int, count: Int) -> Data {
var result = Data(count: count)
result.withUnsafeMutableBytes { bytes -> Void in
data.withUnsafeBytes { dataBytes -> Void in
memcpy(bytes.baseAddress!, dataBytes.baseAddress!.advanced(by: offset), count)
}
}
return result
}
private func readUInt32(data: Data, offset: Int) -> UInt32 {
var value: UInt32 = 0
withUnsafeMutableBytes(of: &value, { bytes -> Void in
@@ -1071,7 +1095,7 @@ private func loadItem(path: String) throws -> AnimationCacheItem {
}
let formatVersion = readUInt32(data: compressedData, offset: offset)
offset += 4
if formatVersion != 3 {
if formatVersion != 4 {
throw LoadItemError.dataError
}
@@ -1090,9 +1114,27 @@ private func loadItem(path: String) throws -> AnimationCacheItem {
if offset + 4 > dataLength {
throw LoadItemError.dataError
}
let dctQuality = readUInt32(data: compressedData, offset: offset)
let dctLumaTableLength = readUInt32(data: compressedData, offset: offset)
offset += 4
if offset + Int(dctLumaTableLength) > dataLength {
throw LoadItemError.dataError
}
let dctLumaData = readData(data: compressedData, offset: offset, count: Int(dctLumaTableLength))
offset += Int(dctLumaTableLength)
if offset + 4 > dataLength {
throw LoadItemError.dataError
}
let dctChromaTableLength = readUInt32(data: compressedData, offset: offset)
offset += 4
if offset + Int(dctChromaTableLength) > dataLength {
throw LoadItemError.dataError
}
let dctChromaData = readData(data: compressedData, offset: offset, count: Int(dctChromaTableLength))
offset += Int(dctChromaTableLength)
if offset + 4 > dataLength {
throw LoadItemError.dataError
}
@@ -1119,7 +1161,11 @@ private func loadItem(path: String) throws -> AnimationCacheItem {
frameMapping.append(AnimationCacheItemAccessor.FrameInfo(duration: Double(frameDuration)))
}
let itemAccessor = AnimationCacheItemAccessor(data: compressedData, range: compressedFrameDataRange, frameMapping: frameMapping, width: Int(width), height: Int(height), dctQuality: Int(dctQuality))
guard let dctData = DctData(lumaTable: dctLumaData, chromaTable: dctChromaData) else {
throw LoadItemError.dataError
}
let itemAccessor = AnimationCacheItemAccessor(data: compressedData, range: compressedFrameDataRange, frameMapping: frameMapping, width: Int(width), height: Int(height), dctData: dctData)
return AnimationCacheItem(numFrames: frameMapping.count, advanceImpl: { advance, requestedFormat in
return itemAccessor.advance(advance: advance, requestedFormat: requestedFormat)
@@ -1397,7 +1443,9 @@ public final class AnimationCacheImpl: AnimationCache {
let itemFirstFramePath = "\(itemDirectoryPath)/\(sourceIdPath.fileName)-f"
if FileManager.default.fileExists(atPath: itemFirstFramePath) {
return try? loadItem(path: itemFirstFramePath)
if let item = try? loadItem(path: itemFirstFramePath) {
return item
}
}
if let adaptationItemPath = findHigherResolutionFileForAdaptation(itemDirectoryPath: itemDirectoryPath, baseName: "\(hashString)_", baseSuffix: "-f", width: Int(size.width), height: Int(size.height)) {
@@ -152,12 +152,33 @@ extension ImageYUVA420 {
}
final class DctData {
let quality: Int
let dct: ImageDCT
let lumaTable: ImageDCTTable
let lumaDct: ImageDCT
init(quality: Int) {
self.quality = quality
self.dct = ImageDCT(quality: quality)
let chromaTable: ImageDCTTable
let chromaDct: ImageDCT
init?(lumaTable: Data, chromaTable: Data) {
guard let lumaTableData = ImageDCTTable(data: lumaTable) else {
return nil
}
guard let chromaTableData = ImageDCTTable(data: chromaTable) else {
return nil
}
self.lumaTable = lumaTableData
self.lumaDct = ImageDCT(table: lumaTableData)
self.chromaTable = chromaTableData
self.chromaDct = ImageDCT(table: chromaTableData)
}
init(generatingTablesAtQuality quality: Int) {
self.lumaTable = ImageDCTTable(quality: quality, isChroma: false)
self.lumaDct = ImageDCT(table: self.lumaTable)
self.chromaTable = ImageDCTTable(quality: quality, isChroma: true)
self.chromaDct = ImageDCT(table: self.chromaTable)
}
}
@@ -168,19 +189,24 @@ extension ImageYUVA420 {
for i in 0 ..< 4 {
let sourcePlane: ImagePlane
let targetPlane: DctCoefficientPlane
let isChroma: Bool
switch i {
case 0:
sourcePlane = self.yPlane
targetPlane = target.yPlane
isChroma = false
case 1:
sourcePlane = self.uPlane
targetPlane = target.uPlane
isChroma = true
case 2:
sourcePlane = self.vPlane
targetPlane = target.vPlane
isChroma = true
case 3:
sourcePlane = self.aPlane
targetPlane = target.aPlane
isChroma = false
default:
preconditionFailure()
}
@@ -191,7 +217,8 @@ extension ImageYUVA420 {
targetPlane.data.withUnsafeMutableBytes { bytes in
let coefficients = bytes.baseAddress!.assumingMemoryBound(to: Int16.self)
dctData.dct.forward(withPixels: sourcePixels, coefficients: coefficients, width: sourcePlane.width, height: sourcePlane.height, bytesPerRow: sourcePlane.bytesPerRow)
let dct = isChroma ? dctData.chromaDct : dctData.lumaDct
dct.forward(withPixels: sourcePixels, coefficients: coefficients, width: sourcePlane.width, height: sourcePlane.height, bytesPerRow: sourcePlane.bytesPerRow)
}
}
}
@@ -211,19 +238,24 @@ extension DctCoefficientsYUVA420 {
for i in 0 ..< 4 {
let sourcePlane: DctCoefficientPlane
let targetPlane: ImagePlane
let isChroma: Bool
switch i {
case 0:
sourcePlane = self.yPlane
targetPlane = target.yPlane
isChroma = false
case 1:
sourcePlane = self.uPlane
targetPlane = target.uPlane
isChroma = true
case 2:
sourcePlane = self.vPlane
targetPlane = target.vPlane
isChroma = true
case 3:
sourcePlane = self.aPlane
targetPlane = target.aPlane
isChroma = false
default:
preconditionFailure()
}
@@ -234,7 +266,8 @@ extension DctCoefficientsYUVA420 {
targetPlane.data.withUnsafeMutableBytes { bytes in
let pixels = bytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
dctData.dct.inverse(withCoefficients: coefficients, pixels: pixels, width: sourcePlane.width, height: sourcePlane.height, coefficientsPerRow: targetPlane.width, bytesPerRow: targetPlane.bytesPerRow)
let dct = isChroma ? dctData.chromaDct : dctData.lumaDct
dct.inverse(withCoefficients: coefficients, pixels: pixels, width: sourcePlane.width, height: sourcePlane.height, coefficientsPerRow: targetPlane.width, bytesPerRow: targetPlane.bytesPerRow)
}
}
}
@@ -24,6 +24,16 @@ private func traceScrollView(view: UIView, point: CGPoint) -> (UIScrollView?, Bo
return (nil, true)
}
private func traceScrollViewUp(view: UIView) -> UIScrollView? {
if let scrollView = view as? UIScrollView {
return scrollView
} else if let superview = view.superview {
return traceScrollViewUp(view: superview)
} else {
return nil
}
}
private final class ExpansionPanRecognizer: UIGestureRecognizer, UIGestureRecognizerDelegate {
enum LockDirection {
case up
@@ -87,8 +97,8 @@ private final class ExpansionPanRecognizer: UIGestureRecognizer, UIGestureRecogn
if let _ = hitView as? UIButton {
} else if let hitView = hitView, hitView.asyncdisplaykit_node is ASButtonNode {
} else {
if let scrollView = traceScrollView(view: view, point: point).0 {
if scrollView is ListViewScroller || scrollView is GridNodeScrollerView {
if let scrollView = traceScrollView(view: view, point: point).0 ?? hitView.flatMap(traceScrollViewUp) {
if scrollView is ListViewScroller || scrollView is GridNodeScrollerView || scrollView.asyncdisplaykit_node is ASScrollNode {
found = false
} else {
found = true
File diff suppressed because it is too large Load Diff
@@ -78,6 +78,7 @@ public final class EntityKeyboardComponent: Component {
public let emojiContent: EmojiPagerContentComponent
public let stickerContent: EmojiPagerContentComponent?
public let gifContent: GifPagerContentComponent?
public let hasRecentGifs: Bool
public let availableGifSearchEmojies: [GifSearchEmoji]
public let defaultToEmojiTab: Bool
public let externalTopPanelContainer: PagerExternalTopPanelContainer?
@@ -96,6 +97,7 @@ public final class EntityKeyboardComponent: Component {
emojiContent: EmojiPagerContentComponent,
stickerContent: EmojiPagerContentComponent?,
gifContent: GifPagerContentComponent?,
hasRecentGifs: Bool,
availableGifSearchEmojies: [GifSearchEmoji],
defaultToEmojiTab: Bool,
externalTopPanelContainer: PagerExternalTopPanelContainer?,
@@ -113,6 +115,7 @@ public final class EntityKeyboardComponent: Component {
self.emojiContent = emojiContent
self.stickerContent = stickerContent
self.gifContent = gifContent
self.hasRecentGifs = hasRecentGifs
self.availableGifSearchEmojies = availableGifSearchEmojies
self.defaultToEmojiTab = defaultToEmojiTab
self.externalTopPanelContainer = externalTopPanelContainer
@@ -142,6 +145,9 @@ public final class EntityKeyboardComponent: Component {
if lhs.gifContent != rhs.gifContent {
return false
}
if lhs.hasRecentGifs != rhs.hasRecentGifs {
return false
}
if lhs.availableGifSearchEmojies != rhs.availableGifSearchEmojies {
return false
}
@@ -165,6 +171,8 @@ public final class EntityKeyboardComponent: Component {
}
public final class View: UIView {
private let tintContainerView: UIView
private let pagerView: ComponentHostView<EntityKeyboardChildEnvironment>
private var component: EntityKeyboardComponent?
@@ -185,6 +193,7 @@ public final class EntityKeyboardComponent: Component {
}
override init(frame: CGRect) {
self.tintContainerView = UIView()
self.pagerView = ComponentHostView<EntityKeyboardChildEnvironment>()
super.init(frame: frame)
@@ -219,18 +228,20 @@ public final class EntityKeyboardComponent: Component {
contents.append(AnyComponentWithIdentity(id: "gifs", component: AnyComponent(gifContent)))
var topGifItems: [EntityKeyboardTopPanelComponent.Item] = []
//TODO:localize
topGifItems.append(EntityKeyboardTopPanelComponent.Item(
id: "recent",
isReorderable: false,
content: AnyComponent(EntityKeyboardIconTopPanelComponent(
imageName: "Chat/Input/Media/RecentTabIcon",
theme: component.theme,
title: "Recent",
pressed: { [weak self] in
self?.component?.switchToGifSubject(.recent)
}
if component.hasRecentGifs {
topGifItems.append(EntityKeyboardTopPanelComponent.Item(
id: "recent",
isReorderable: false,
content: AnyComponent(EntityKeyboardIconTopPanelComponent(
imageName: "Chat/Input/Media/RecentTabIcon",
theme: component.theme,
title: "Recent",
pressed: { [weak self] in
self?.component?.switchToGifSubject(.recent)
}
))
))
))
}
topGifItems.append(EntityKeyboardTopPanelComponent.Item(
id: "trending",
isReorderable: false,
@@ -384,7 +395,7 @@ public final class EntityKeyboardComponent: Component {
maxSize: nil
)),
action: {
stickerContent.inputInteraction.openStickerSettings()
stickerContent.inputInteractionHolder.inputInteraction?.openStickerSettings()
}
).minSize(CGSize(width: 38.0, height: 38.0)))))
}
@@ -486,7 +497,7 @@ public final class EntityKeyboardComponent: Component {
component.switchToTextInput()
}
).minSize(CGSize(width: 38.0, height: 38.0)))))
let deleteBackwards = component.emojiContent.inputInteraction.deleteBackwards
let deleteBackwards = component.emojiContent.inputInteractionHolder.inputInteraction?.deleteBackwards
contentAccessoryRightButtons.append(AnyComponentWithIdentity(id: "emoji", component: AnyComponent(Button(
content: AnyComponent(BundleIconComponent(
name: "Chat/Input/Media/EntityInputClearIcon",
@@ -494,11 +505,11 @@ public final class EntityKeyboardComponent: Component {
maxSize: nil
)),
action: {
deleteBackwards()
deleteBackwards?()
AudioServicesPlaySystemSound(1155)
}
).withHoldAction({
deleteBackwards()
deleteBackwards?()
AudioServicesPlaySystemSound(1155)
}).minSize(CGSize(width: 38.0, height: 38.0)))))
@@ -521,9 +532,10 @@ public final class EntityKeyboardComponent: Component {
contentAccessoryLeftButtons: contentAccessoryLeftButtons,
contentAccessoryRightButtons: contentAccessoryRightButtons,
defaultId: component.defaultToEmojiTab ? "emoji" : "stickers",
contentBackground: AnyComponent(BlurredBackgroundComponent(
color: component.theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75)
)),
contentBackground: nil/*AnyComponent(BlurredBackgroundComponent(
color: component.theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75),
tintContainerView: self.tintContainerView
))*/,
topPanel: AnyComponent(EntityKeyboardTopContainerPanelComponent(
theme: component.theme,
overflowHeight: component.hiddenInputHeight,
@@ -534,7 +546,7 @@ public final class EntityKeyboardComponent: Component {
theme: component.theme,
bottomInset: component.bottomInset,
deleteBackwards: { [weak self] in
self?.component?.emojiContent.inputInteraction.deleteBackwards()
self?.component?.emojiContent.inputInteractionHolder.inputInteraction?.deleteBackwards()
AudioServicesPlaySystemSound(0x451)
}
)),
@@ -437,6 +437,7 @@ final class EntityKeyboardStaticStickersPanelComponent: Component {
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.alwaysBounceHorizontal = false
self.scrollView.scrollsToTop = false
self.scrollView.delegate = self
self.scrollViewContainer.addSubview(self.scrollView)
@@ -1114,6 +1115,7 @@ final class EntityKeyboardTopPanelComponent: Component {
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.alwaysBounceHorizontal = true
self.scrollView.scrollsToTop = false
self.scrollView.delegate = self
self.addSubview(self.scrollView)
@@ -213,7 +213,7 @@ public final class GifPagerContentComponent: Component {
return true
}
public final class View: ContextControllerSourceView, UIScrollViewDelegate {
public final class View: ContextControllerSourceView, PagerContentViewWithBackground, UIScrollViewDelegate {
private struct ItemGroupDescription: Equatable {
let hasTitle: Bool
let itemCount: Int
@@ -400,6 +400,8 @@ public final class GifPagerContentComponent: Component {
private final class ContentScrollView: UIScrollView, PagerExpandableScrollView {
}
private let backgroundView: BlurredBackgroundView
private let shimmerHostView: PortalSourceView
private let standaloneShimmerEffect: StandaloneShimmerEffect
@@ -418,6 +420,8 @@ public final class GifPagerContentComponent: Component {
private var currentLoadMoreToken: String?
override init(frame: CGRect) {
self.backgroundView = BlurredBackgroundView(color: nil)
self.shimmerHostView = PortalSourceView()
self.standaloneShimmerEffect = StandaloneShimmerEffect()
@@ -427,6 +431,8 @@ public final class GifPagerContentComponent: Component {
super.init(frame: frame)
self.addSubview(self.backgroundView)
self.shimmerHostView.alpha = 0.0
self.addSubview(self.shimmerHostView)
@@ -439,6 +445,7 @@ public final class GifPagerContentComponent: Component {
}
self.scrollView.showsVerticalScrollIndicator = true
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.scrollsToTop = false
self.scrollView.delegate = self
self.addSubview(self.scrollView)
@@ -744,6 +751,15 @@ public final class GifPagerContentComponent: Component {
}
}
public func pagerUpdateBackground(backgroundFrame: CGRect, transition: Transition) {
guard let theme = self.theme else {
return
}
self.backgroundView.updateColor(color: theme.chat.inputMediaPanel.stickersBackgroundColor.withMultipliedAlpha(0.75), enableBlur: true, forceKeepBlur: false, transition: transition.containedViewLayoutTransition)
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
self.backgroundView.update(size: backgroundFrame.size, transition: transition.containedViewLayoutTransition)
}
func update(component: GifPagerContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
var contentReset = false
if let previousComponent = self.component, previousComponent.subject != component.subject {
@@ -107,27 +107,6 @@ private final class ItemAnimationContext {
data.withUnsafeBytes { bytes -> Void in
memcpy(context.bytes, bytes.baseAddress!, height * bytesPerRow)
/*var sourceBuffer = vImage_Buffer()
sourceBuffer.width = UInt(width)
sourceBuffer.height = UInt(height)
sourceBuffer.data = UnsafeMutableRawPointer(mutating: bytes.baseAddress!.advanced(by: firstFrame.range.lowerBound))
sourceBuffer.rowBytes = bytesPerRow
var destinationBuffer = vImage_Buffer()
destinationBuffer.width = UInt(32)
destinationBuffer.height = UInt(32)
destinationBuffer.data = context.bytes
destinationBuffer.rowBytes = bytesPerRow
vImageBoxConvolve_ARGB8888(&sourceBuffer,
&destinationBuffer,
nil,
UInt(width - 32 - 16), UInt(height - 32 - 16),
UInt32(31),
UInt32(31),
nil,
vImage_Flags(kvImageEdgeExtend))*/
}
guard let image = context.generateImage() else {
@@ -184,42 +163,6 @@ private final class ItemAnimationContext {
destinationBuffer.data = context.bytes
destinationBuffer.rowBytes = context.bytesPerRow
/*var sourceBuffer = vImage_Buffer()
sourceBuffer.width = UInt(width)
sourceBuffer.height = UInt(height)
sourceBuffer.data = UnsafeMutableRawPointer(mutating: bytes.baseAddress!)
sourceBuffer.rowBytes = bytesPerRow
let tempBufferBytes = malloc(blurredHeight * context.bytesPerRow)
defer {
free(tempBufferBytes)
}
let temp2BufferBytes = malloc(blurredHeight * context.bytesPerRow)
defer {
free(temp2BufferBytes)
}
memset(temp2BufferBytes, Int32(bitPattern: color?.argb ?? 0xffffffff), blurredHeight * context.bytesPerRow)
var tempBuffer = vImage_Buffer()
tempBuffer.width = UInt(blurredWidth)
tempBuffer.height = UInt(blurredHeight)
tempBuffer.data = tempBufferBytes
tempBuffer.rowBytes = context.bytesPerRow
var temp2Buffer = vImage_Buffer()
temp2Buffer.width = UInt(blurredWidth)
temp2Buffer.height = UInt(blurredHeight)
temp2Buffer.data = temp2BufferBytes
temp2Buffer.rowBytes = context.bytesPerRow
vImageScale_ARGB8888(&sourceBuffer, &tempBuffer, nil, vImage_Flags(kvImageDoNotTile))
//vImageUnpremultiplyData_ARGB8888(&tempBuffer, &tempBuffer, vImage_Flags(kvImageDoNotTile))
vImagePremultipliedAlphaBlend_ARGB8888(&tempBuffer, &temp2Buffer, &destinationBuffer, vImage_Flags(kvImageDoNotTile))
//vImageCopyBuffer(&tempBuffer, &destinationBuffer, 4, vImage_Flags(kvImageDoNotTile))*/
vImageBoxConvolve_ARGB8888(&destinationBuffer,
&destinationBuffer,
nil,
@@ -302,14 +245,6 @@ private final class ItemAnimationContext {
}
strongSelf.item = result.item
strongSelf.updateIsPlaying()
if result.item == nil {
for target in strongSelf.targets.copyItems() {
if let target = target.value {
target.updateDisplayPlaceholder(displayPlaceholder: true)
}
}
}
}
})
}
@@ -127,14 +127,14 @@ public final class TextNodeWithEntities {
var found = false
string.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: fullRange, options: [], using: { value, range, stop in
if let value = value as? ChatTextInputTextCustomEmojiAttribute, let font = string.attribute(.font, at: range.location, effectiveRange: nil) as? UIFont {
let updatedSubstring = NSMutableAttributedString(string: ".")
let updatedSubstring = NSMutableAttributedString(string: "😀")
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
updatedSubstring.addAttributes(string.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
updatedSubstring.addAttribute(NSAttributedString.Key("Attribute__EmbeddedItem"), value: InlineStickerItem(emoji: value, file: value.file, fontSize: font.pointSize), range: replacementRange)
updatedSubstring.addAttribute(originalTextAttributeKey, value: string.attributedSubstring(from: range).string, range: replacementRange)
let itemSize = font.pointSize * 24.0 / 17.0
let itemSize = (font.pointSize * 24.0 / 17.0) * 0.5
let runDelegateData = RunDelegateData(
ascent: font.ascender,
@@ -230,7 +230,9 @@ public final class TextNodeWithEntities {
let itemSize = floor(stickerItem.fontSize * 24.0 / 17.0)
let itemFrame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left, dy: textLayout.insets.top + 0.0).center, size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0)
var itemFrame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left, dy: textLayout.insets.top + 1.0).center, size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0)
itemFrame.origin.x = floorToScreenPixels(itemFrame.origin.x)
itemFrame.origin.y = floorToScreenPixels(itemFrame.origin.y)
let itemLayer: InlineStickerItemLayer
if let current = self.inlineStickerItemLayers[id] {
@@ -1,22 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "StickersGroupCross@2x-1.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "StickersGroupCross@3x.png",
"scale" : "3x"
"filename" : "Frame 1.svg",
"idiom" : "universal"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}
@@ -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

@@ -1577,6 +1577,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -2112,6 +2114,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))).withUpdatedComposeDisableUrlPreview(nil) }
})
@@ -7343,6 +7347,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))).withUpdatedComposeDisableUrlPreview(nil) }
})
@@ -11221,6 +11227,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -11283,6 +11291,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -11342,6 +11352,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -11365,6 +11377,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -11821,6 +11835,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else {
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12136,6 +12152,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12183,6 +12201,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12242,6 +12262,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12260,6 +12282,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12582,6 +12606,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12898,6 +12924,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12969,6 +12997,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -12985,6 +13015,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -13013,6 +13045,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -13158,6 +13192,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -13267,6 +13303,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -13362,6 +13400,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedRecordedMediaPreview(nil).updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
@@ -126,6 +126,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private(set) var accessoryPanelNode: AccessoryPanelNode?
private var inputContextPanelNode: ChatInputContextPanelNode?
private let inputContextPanelContainer: ChatControllerTitlePanelNodeContainer
private let inputContextOverTextPanelContainer: ChatControllerTitlePanelNodeContainer
private var overlayContextPanelNode: ChatInputContextPanelNode?
private var inputNode: ChatInputNode?
@@ -271,6 +272,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.titleAccessoryPanelContainer.clipsToBounds = true
self.inputContextPanelContainer = ChatControllerTitlePanelNodeContainer()
self.inputContextOverTextPanelContainer = ChatControllerTitlePanelNodeContainer()
var source: ChatHistoryListSource
if case let .forwardedMessages(messageIds, options) = subject {
@@ -540,8 +542,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
self.addSubnode(self.inputPanelContainerNode)
self.addSubnode(self.inputContextPanelContainer)
self.addSubnode(self.inputPanelContainerNode)
self.addSubnode(self.inputContextOverTextPanelContainer)
self.inputPanelContainerNode.addSubnode(self.inputPanelClippingNode)
self.inputPanelClippingNode.addSubnode(self.inputPanelBackgroundNode)
@@ -1213,7 +1216,18 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self?.updateInputPanelBackgroundExtension(transition: transition)
}
inputNode.hideInputUpdated = { [weak self] transition in
self?.updateInputPanelBackgroundExpansion(transition: transition)
guard let strongSelf = self else {
return
}
let applyAutocorrection = strongSelf.inputNode?.hideInput ?? false
strongSelf.updateInputPanelBackgroundExpansion(transition: transition)
if applyAutocorrection, let textInputPanelNode = strongSelf.textInputPanelNode {
if let textInputNode = textInputPanelNode.textInputNode, textInputNode.isFirstResponder() {
Keyboard.applyAutocorrection(textView: textInputNode.textView)
}
}
}
dismissedInputNode = self.inputNode
@@ -1308,6 +1322,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
transition.updateFrame(node: self.titleAccessoryPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: 66.0)))
transition.updateFrame(node: self.inputContextPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height)))
transition.updateFrame(node: self.inputContextOverTextPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height)))
var titleAccessoryPanelFrame: CGRect?
if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
@@ -1355,8 +1370,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if inputContextPanelNode !== self.inputContextPanelNode {
dismissedInputContextPanelNode = self.inputContextPanelNode
self.inputContextPanelNode = inputContextPanelNode
self.inputContextPanelContainer.addSubnode(inputContextPanelNode)
switch inputContextPanelNode.placement {
case .overPanels:
self.inputContextPanelContainer.addSubnode(inputContextPanelNode)
case .overTextInput:
self.inputContextOverTextPanelContainer.addSubnode(inputContextPanelNode)
}
immediatelyLayoutInputContextPanelAndAnimateAppearance = true
}
} else if let inputContextPanelNode = self.inputContextPanelNode {
@@ -2358,14 +2377,15 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if case let .peer(id) = self.chatPresentationInterfaceState.chatLocation {
peerId = id
}
let _ = peerId
let inputNode = ChatEntityKeyboardInputNode(
context: self.context,
currentInputData: inputMediaNodeData,
updatedInputData: self.inputMediaNodeDataPromise.get(),
defaultToEmojiTab: !self.chatPresentationInterfaceState.interfaceState.effectiveInputState.inputText.string.isEmpty,
controllerInteraction: self.controllerInteraction
controllerInteraction: self.controllerInteraction,
interfaceInteraction: self.interfaceInteraction,
chatPeerId: peerId
)
return inputNode
@@ -2962,6 +2982,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.setupSendActionOnViewUpdate({ [weak self] in
if let strongSelf = self, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode {
strongSelf.collapseInput()
strongSelf.ignoreUpdateHeight = true
textInputPanelNode.text = ""
strongSelf.requestUpdateChatInterfaceState(.immediate, true, { $0.withUpdatedReplyMessageId(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeDisableUrlPreview(nil) })
File diff suppressed because it is too large Load Diff
@@ -74,7 +74,7 @@ final class ChatMediaInputStickerGridSectionNode: ASDisplayNode {
self.setupNode = setupNode
case .clear:
let setupNode = HighlightableButtonNode()
setupNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme), for: [])
setupNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme, color: theme.chat.inputMediaPanel.stickersSectionTextColor), for: [])
self.setupNode = setupNode
}
@@ -42,6 +42,24 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
private var absoluteRect: (CGRect, CGSize)?
override var visibility: ListViewItemNodeVisibility {
didSet {
if oldValue != self.visibility {
switch self.visibility {
case .none:
self.labelNode.visibilityRect = nil
//self.spoilerTextNode?.visibilityRect = nil
case let .visible(_, subRect):
var subRect = subRect
subRect.origin.x = 0.0
subRect.size.width = 10000.0
self.labelNode.visibilityRect = subRect
//self.spoilerTextNode?.visibilityRect = subRect
}
}
}
}
required init() {
self.labelNode = TextNodeWithEntities()
self.labelNode.textNode.isUserInteractionEnabled = false
@@ -340,6 +358,18 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
strongSelf.backgroundColorNode.frame = CGRect(origin: CGPoint(), size: image.size)
strongSelf.cachedMaskBackgroundImage = (offset, image, labelRects)
switch strongSelf.visibility {
case .none:
strongSelf.labelNode.visibilityRect = nil
//strongSelf.spoilerTextNode?.visibilityRect = nil
case let .visible(_, subRect):
var subRect = subRect
subRect.origin.x = 0.0
subRect.size.width = 10000.0
strongSelf.labelNode.visibilityRect = subRect
//strongSelf.spoilerTextNode?.visibilityRect = subRect
}
}
}
})
@@ -206,7 +206,7 @@ final class ChatMessageAccessibilityData {
if let chatPeer = message.peers[item.message.id.peerId] {
let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
let (_, _, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
let (_, _, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
var text = messageText
@@ -138,7 +138,7 @@ class StickerPanePeerSpecificSetupGridItemNode: GridItemNode {
var updateButtonBackgroundImage: UIImage?
if currentItem?.theme !== item.theme {
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddPackButtonImage(item.theme)
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme), for: [])
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme, color: item.theme.chat.inputMediaPanel.stickersSectionTextColor), for: [])
}
let leftInset: CGFloat = 12.0
@@ -525,7 +525,7 @@ class StickerPaneTrendingListGridItemNode: GridItemNode {
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
if currentItem?.theme !== item.theme {
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme), for: [])
self.dismissButtonNode.setImage(PresentationResourcesChat.chatInputMediaPanelGridDismissImage(item.theme, color: item.theme.chat.inputMediaPanel.stickersSectionTextColor), for: [])
}
let leftInset: CGFloat = 9.0