mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-06-20 18:24:43 +00:00
Merge branches 'master' and 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
+78
-21
@@ -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
|
||||
}))
|
||||
|
||||
+7
-2
@@ -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) })
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
+6
-6
@@ -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
|
||||
}
|
||||
|
||||
+10
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-2
@@ -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
|
||||
|
||||
+1714
-167
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)
|
||||
}
|
||||
)),
|
||||
|
||||
+2
@@ -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)
|
||||
|
||||
|
||||
+17
-1
@@ -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 {
|
||||
|
||||
-65
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+5
-3
@@ -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] {
|
||||
|
||||
Vendored
+5
-15
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+4
@@ -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 |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 508 B |
BIN
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
|
||||
|
||||
Reference in New Issue
Block a user