Emoji improvements

This commit is contained in:
Ali 2022-07-24 15:25:27 +02:00
parent cb83ca4ec8
commit 6fd38af0fe
12 changed files with 170 additions and 89 deletions

View File

@ -1200,7 +1200,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let draftText = stringWithAppliedEntities(draftState.text, entities: draftState.entities, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, message: nil) let draftText = stringWithAppliedEntities(draftState.text, entities: draftState.entities, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, message: nil)
attributedText = foldLineBreaks(draftText) attributedText = foldLineBreaks(draftText)
} else if let message = messages.last { } else if let message = messages.first {
var composedString: NSMutableAttributedString var composedString: NSMutableAttributedString
if let peerText = peerText { if let peerText = peerText {

View File

@ -64,7 +64,7 @@ private final class PendingUpdateMessageManagerImpl {
} }
} }
func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool) { func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool) {
if let context = self.contexts[messageId] { if let context = self.contexts[messageId] {
self.contexts.removeValue(forKey: messageId) self.contexts.removeValue(forKey: messageId)
context.disposable.dispose() context.disposable.dispose()
@ -75,7 +75,7 @@ private final class PendingUpdateMessageManagerImpl {
self.contexts[messageId] = context self.contexts[messageId] = context
let queue = self.queue let queue = self.queue
disposable.set((requestEditMessage(postbox: self.postbox, network: self.network, stateManager: self.stateManager, transformOutgoingMessageMedia: self.transformOutgoingMessageMedia, messageMediaPreuploadManager: self.messageMediaPreuploadManager, mediaReferenceRevalidationContext: self.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, scheduleTime: nil) disposable.set((requestEditMessage(postbox: self.postbox, network: self.network, stateManager: self.stateManager, transformOutgoingMessageMedia: self.transformOutgoingMessageMedia, messageMediaPreuploadManager: self.messageMediaPreuploadManager, mediaReferenceRevalidationContext: self.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: nil)
|> deliverOn(self.queue)).start(next: { [weak self, weak context] value in |> deliverOn(self.queue)).start(next: { [weak self, weak context] value in
queue.async { queue.async {
guard let strongSelf = self, let initialContext = context else { guard let strongSelf = self, let initialContext = context else {
@ -163,9 +163,9 @@ public final class PendingUpdateMessageManager {
}) })
} }
public func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute? = nil, disableUrlPreview: Bool = false) { public func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool = false) {
self.impl.with { impl in self.impl.with { impl in
impl.add(messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview) impl.add(messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview)
} }
} }

View File

@ -27,15 +27,15 @@ public enum RequestEditMessageError {
case invalidGrouping case invalidGrouping
} }
func _internal_requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute? = nil, disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> { func _internal_requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
return requestEditMessage(postbox: account.postbox, network: account.network, stateManager: account.stateManager, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime) return requestEditMessage(postbox: account.postbox, network: account.network, stateManager: account.stateManager, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime)
} }
func requestEditMessage(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, scheduleTime: Int32?) -> Signal<RequestEditMessageResult, RequestEditMessageError> { func requestEditMessage(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool, scheduleTime: Int32?) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
return requestEditMessageInternal(postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: false) return requestEditMessageInternal(postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: false)
|> `catch` { error -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> in |> `catch` { error -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> in
if case .invalidReference = error { if case .invalidReference = error {
return requestEditMessageInternal(postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: true) return requestEditMessageInternal(postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: true)
} else { } else {
return .fail(error) return .fail(error)
} }
@ -50,7 +50,7 @@ func requestEditMessage(postbox: Postbox, network: Network, stateManager: Accoun
} }
} }
private func requestEditMessageInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, scheduleTime: Int32?, forceReupload: Bool) -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> { private func requestEditMessageInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool, scheduleTime: Int32?, forceReupload: Bool) -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> {
let uploadedMedia: Signal<PendingMessageUploadedContentResult?, NoError> let uploadedMedia: Signal<PendingMessageUploadedContentResult?, NoError>
switch media { switch media {
case .keep: case .keep:
@ -96,6 +96,10 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat
return (nil, nil, SimpleDictionary()) return (nil, nil, SimpleDictionary())
} }
for (_, file) in inlineStickers {
transaction.storeMediaIfNotPresent(media: file)
}
if text.isEmpty { if text.isEmpty {
for media in message.media { for media in message.media {
switch media { switch media {

View File

@ -85,8 +85,8 @@ public extension TelegramEngine {
return _internal_clearAuthorHistory(account: self.account, peerId: peerId, memberId: memberId) return _internal_clearAuthorHistory(account: self.account, peerId: peerId, memberId: memberId)
} }
public func requestEditMessage(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute? = nil, disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> { public func requestEditMessage(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
return _internal_requestEditMessage(account: self.account, messageId: messageId, text: text, media: media, entities: entities, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime) return _internal_requestEditMessage(account: self.account, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime)
} }
public func requestEditLiveLocation(messageId: MessageId, stop: Bool, coordinate: (latitude: Double, longitude: Double, accuracyRadius: Int32?)?, heading: Int32?, proximityNotificationRadius: Int32?) -> Signal<Void, NoError> { public func requestEditLiveLocation(messageId: MessageId, stop: Bool, coordinate: (latitude: Double, longitude: Double, accuracyRadius: Int32?)?, heading: Int32?, proximityNotificationRadius: Int32?) -> Signal<Void, NoError> {

View File

@ -1284,7 +1284,7 @@ public struct PresentationResourcesChat {
public static func chatEntityKeyboardLock(_ theme: PresentationTheme, color: UIColor) -> UIImage? { public static func chatEntityKeyboardLock(_ theme: PresentationTheme, color: UIColor) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatEntityKeyboardLock(color: color.argb), { theme in return theme.image(PresentationResourceParameterKey.chatEntityKeyboardLock(color: color.argb), { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: color) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/PanelSectionLockIcon"), color: color)
}) })
} }
} }

View File

@ -579,7 +579,7 @@ private final class GroupHeaderLayer: UIView {
cache: AnimationCache, cache: AnimationCache,
renderer: MultiAnimationRenderer, renderer: MultiAnimationRenderer,
attemptSynchronousLoad: Bool attemptSynchronousLoad: Bool
) -> CGSize { ) -> (size: CGSize, centralContentWidth: CGFloat) {
var themeUpdated = false var themeUpdated = false
if self.theme !== theme { if self.theme !== theme {
self.theme = theme self.theme = theme
@ -606,48 +606,8 @@ private final class GroupHeaderLayer: UIView {
let titleHorizontalOffset: CGFloat let titleHorizontalOffset: CGFloat
if isPremiumLocked { if isPremiumLocked {
let lockIconLayer: SimpleLayer titleHorizontalOffset = 10.0 + 2.0
if let current = self.lockIconLayer {
lockIconLayer = current
} else {
lockIconLayer = SimpleLayer()
self.lockIconLayer = lockIconLayer
self.layer.addSublayer(lockIconLayer)
}
if let image = PresentationResourcesChat.chatEntityKeyboardLock(theme, color: color) {
let imageSize = image.size.aspectFitted(CGSize(width: 16.0, height: 16.0))
lockIconLayer.contents = image.cgImage
titleHorizontalOffset = imageSize.width + 2.0
lockIconLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: imageSize)
} else {
lockIconLayer.contents = nil
titleHorizontalOffset = 0.0
}
let tintLockIconLayer: SimpleLayer
if let current = self.tintLockIconLayer {
tintLockIconLayer = current
} else {
tintLockIconLayer = SimpleLayer()
self.tintLockIconLayer = tintLockIconLayer
self.tintContentLayer.addSublayer(tintLockIconLayer)
}
if let image = PresentationResourcesChat.chatEntityKeyboardLock(theme, color: .white) {
let imageSize = image.size.aspectFitted(CGSize(width: 16.0, height: 16.0))
tintLockIconLayer.contents = image.cgImage
tintLockIconLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: imageSize)
} else {
tintLockIconLayer.contents = nil
}
} else { } else {
if let lockIconLayer = self.lockIconLayer {
self.lockIconLayer = nil
lockIconLayer.removeFromSuperlayer()
}
if let tintLockIconLayer = self.tintLockIconLayer {
self.tintLockIconLayer = nil
tintLockIconLayer.removeFromSuperlayer()
}
titleHorizontalOffset = 0.0 titleHorizontalOffset = 0.0
} }
@ -712,15 +672,53 @@ private final class GroupHeaderLayer: UIView {
} }
let textFrame: CGRect let textFrame: CGRect
if (layoutType == .compact && hasClear) || subtitle != nil { textFrame = CGRect(origin: CGPoint(x: titleHorizontalOffset + floor((constrainedSize.width - titleHorizontalOffset - textSize.width) / 2.0), y: textOffsetY), size: textSize)
textFrame = CGRect(origin: CGPoint(x: titleHorizontalOffset, y: textOffsetY), size: textSize)
} else {
textFrame = CGRect(origin: CGPoint(x: floor((constrainedSize.width - textSize.width) / 2.0), y: textOffsetY), size: textSize)
}
self.textLayer.frame = textFrame self.textLayer.frame = textFrame
self.tintTextLayer.frame = textFrame self.tintTextLayer.frame = textFrame
self.tintTextLayer.isHidden = !needsTintText self.tintTextLayer.isHidden = !needsTintText
if isPremiumLocked {
let lockIconLayer: SimpleLayer
if let current = self.lockIconLayer {
lockIconLayer = current
} else {
lockIconLayer = SimpleLayer()
self.lockIconLayer = lockIconLayer
self.layer.addSublayer(lockIconLayer)
}
if let image = PresentationResourcesChat.chatEntityKeyboardLock(theme, color: color) {
let imageSize = image.size
lockIconLayer.contents = image.cgImage
lockIconLayer.frame = CGRect(origin: CGPoint(x: textFrame.minX - imageSize.width - 3.0, y: 2.0 + UIScreenPixel), size: imageSize)
} else {
lockIconLayer.contents = nil
}
let tintLockIconLayer: SimpleLayer
if let current = self.tintLockIconLayer {
tintLockIconLayer = current
} else {
tintLockIconLayer = SimpleLayer()
self.tintLockIconLayer = tintLockIconLayer
self.tintContentLayer.addSublayer(tintLockIconLayer)
}
if let image = PresentationResourcesChat.chatEntityKeyboardLock(theme, color: .white) {
tintLockIconLayer.contents = image.cgImage
tintLockIconLayer.frame = lockIconLayer.frame
} else {
tintLockIconLayer.contents = nil
}
} else {
if let lockIconLayer = self.lockIconLayer {
self.lockIconLayer = nil
lockIconLayer.removeFromSuperlayer()
}
if let tintLockIconLayer = self.tintLockIconLayer {
self.tintLockIconLayer = nil
tintLockIconLayer.removeFromSuperlayer()
}
}
let subtitleSize: CGSize let subtitleSize: CGSize
if let subtitle = subtitle { if let subtitle = subtitle {
var updateSubtitleContents: UIImage? var updateSubtitleContents: UIImage?
@ -836,11 +834,7 @@ private final class GroupHeaderLayer: UIView {
} }
var size: CGSize var size: CGSize
if layoutType == .compact && hasClear { size = CGSize(width: constrainedSize.width, height: constrainedSize.height)
size = CGSize(width: titleHorizontalOffset + textSize.width + clearWidth, height: constrainedSize.height)
} else {
size = CGSize(width: constrainedSize.width, height: constrainedSize.height)
}
if let embeddedItems = embeddedItems { if let embeddedItems = embeddedItems {
let groupEmbeddedView: GroupEmbeddedView let groupEmbeddedView: GroupEmbeddedView
@ -908,7 +902,7 @@ private final class GroupHeaderLayer: UIView {
} }
} }
return size return (size, titleHorizontalOffset + textSize.width + clearWidth)
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
@ -1552,14 +1546,14 @@ public final class EmojiPagerContentComponent: Component {
if width >= 420.0 { if width >= 420.0 {
self.itemInsets = UIEdgeInsets(top: containerInsets.top, left: containerInsets.left + 5.0, bottom: containerInsets.bottom, right: containerInsets.right + 5.0) self.itemInsets = UIEdgeInsets(top: containerInsets.top, left: containerInsets.left + 5.0, bottom: containerInsets.bottom, right: containerInsets.right + 5.0)
self.headerInsets = UIEdgeInsets(top: containerInsets.top, left: containerInsets.left + 5.0, bottom: containerInsets.bottom, right: containerInsets.right + 5.0)
minSpacing = 2.0 minSpacing = 2.0
} else { } else {
self.itemInsets = UIEdgeInsets(top: containerInsets.top, left: containerInsets.left + 7.0, bottom: containerInsets.bottom, right: containerInsets.right + 7.0) self.itemInsets = UIEdgeInsets(top: containerInsets.top, left: containerInsets.left + 7.0, bottom: containerInsets.bottom, right: containerInsets.right + 7.0)
self.headerInsets = UIEdgeInsets(top: containerInsets.top, left: containerInsets.left + 7.0, bottom: containerInsets.bottom, right: containerInsets.right + 7.0)
minSpacing = 9.0 minSpacing = 9.0
} }
self.headerInsets = UIEdgeInsets(top: containerInsets.top, left: containerInsets.left + 16.0, bottom: containerInsets.bottom, right: containerInsets.right + 16.0)
self.itemDefaultHeaderHeight = 24.0 self.itemDefaultHeaderHeight = 24.0
self.itemFeaturedHeaderHeight = self.itemDefaultHeaderHeight self.itemFeaturedHeaderHeight = self.itemDefaultHeaderHeight
case .detailed: case .detailed:
@ -3039,7 +3033,7 @@ public final class EmojiPagerContentComponent: Component {
assignTopVisibleSubgroupId = true assignTopVisibleSubgroupId = true
} }
var headerSize: CGSize? var headerCentralContentWidth: CGFloat?
var headerSizeUpdated = false var headerSizeUpdated = false
if let title = itemGroup.title { if let title = itemGroup.title {
validGroupHeaderIds.insert(itemGroup.groupId) validGroupHeaderIds.insert(itemGroup.groupId)
@ -3076,7 +3070,7 @@ public final class EmojiPagerContentComponent: Component {
let hasTopSeparator = false let hasTopSeparator = false
let groupHeaderSize = groupHeaderView.update( let (groupHeaderSize, centralContentWidth) = groupHeaderView.update(
context: component.context, context: component.context,
theme: theme, theme: theme,
layoutType: itemLayout.layoutType, layoutType: itemLayout.layoutType,
@ -3097,11 +3091,11 @@ public final class EmojiPagerContentComponent: Component {
if groupHeaderView.bounds.size != groupHeaderSize { if groupHeaderView.bounds.size != groupHeaderSize {
headerSizeUpdated = true headerSizeUpdated = true
} }
headerCentralContentWidth = centralContentWidth
let groupHeaderFrame = CGRect(origin: CGPoint(x: floor((itemLayout.contentSize.width - groupHeaderSize.width) / 2.0), y: itemGroupLayout.frame.minY + 1.0), size: groupHeaderSize) let groupHeaderFrame = CGRect(origin: CGPoint(x: floor((itemLayout.contentSize.width - groupHeaderSize.width) / 2.0), y: itemGroupLayout.frame.minY + 1.0), size: groupHeaderSize)
groupHeaderView.bounds = CGRect(origin: CGPoint(), size: groupHeaderFrame.size) groupHeaderView.bounds = CGRect(origin: CGPoint(), size: groupHeaderFrame.size)
groupHeaderTransition.setPosition(view: groupHeaderView, position: CGPoint(x: groupHeaderFrame.midX, y: groupHeaderFrame.midY)) groupHeaderTransition.setPosition(view: groupHeaderView, position: CGPoint(x: groupHeaderFrame.midX, y: groupHeaderFrame.midY))
headerSize = CGSize(width: groupHeaderSize.width, height: groupHeaderSize.height)
} }
let groupBorderRadius: CGFloat = 16.0 let groupBorderRadius: CGFloat = 16.0
@ -3134,8 +3128,8 @@ public final class EmojiPagerContentComponent: Component {
if groupBorderLayer.bounds.size != groupBorderFrame.size || headerSizeUpdated { if groupBorderLayer.bounds.size != groupBorderFrame.size || headerSizeUpdated {
let headerWidth: CGFloat let headerWidth: CGFloat
if let headerSize = headerSize { if let headerCentralContentWidth = headerCentralContentWidth {
headerWidth = headerSize.width + 14.0 headerWidth = headerCentralContentWidth + 14.0
} else { } else {
headerWidth = 0.0 headerWidth = 0.0
} }

View File

@ -185,9 +185,14 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
} else if let titleView = self.titleView { } else if let titleView = self.titleView {
self.titleView = nil self.titleView = nil
if let view = titleView.view { if let view = titleView.view {
transition.setAlpha(view: view, alpha: 0.0, completion: { [weak view] _ in if !transition.animation.isImmediate {
view?.removeFromSuperview() view.alpha = 0.0
}) view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.08, completion: { [weak view] _ in
view?.removeFromSuperview()
})
} else {
view.removeFromSuperview()
}
} }
} }
@ -392,9 +397,14 @@ final class EntityKeyboardIconTopPanelComponent: Component {
} else if let titleView = self.titleView { } else if let titleView = self.titleView {
self.titleView = nil self.titleView = nil
if let view = titleView.view { if let view = titleView.view {
transition.setAlpha(view: view, alpha: 0.0, completion: { [weak view] _ in if !transition.animation.isImmediate {
view?.removeFromSuperview() view.alpha = 0.0
}) view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.08, completion: { [weak view] _ in
view?.removeFromSuperview()
})
} else {
view.removeFromSuperview()
}
} }
} }
@ -724,9 +734,14 @@ final class EntityKeyboardStaticStickersPanelComponent: Component {
} else if let titleView = self.titleView { } else if let titleView = self.titleView {
self.titleView = nil self.titleView = nil
if let view = titleView.view { if let view = titleView.view {
transition.setAlpha(view: view, alpha: 0.0, completion: { [weak view] _ in if !transition.animation.isImmediate {
view?.removeFromSuperview() view.alpha = 0.0
}) view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.08, completion: { [weak view] _ in
view?.removeFromSuperview()
})
} else {
view.removeFromSuperview()
}
} }
} }

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Locked.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,4 @@
<svg width="7" height="10" viewBox="0 0 7 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 0.835039C2.02816 0.835039 0.835 2.0282 0.835 3.50004V4.67699C0.548874 4.82654 0.316237 5.06149 0.169545 5.34939C0 5.68214 0 6.11774 0 6.98893V7.51115C0 8.38234 0 8.81794 0.169545 9.15069C0.318682 9.44339 0.556652 9.68136 0.849348 9.83049C1.1821 10 1.6177 10 2.48889 10H4.51111C5.3823 10 5.8179 10 6.15065 9.83049C6.44335 9.68136 6.68132 9.44339 6.83045 9.15069C7 8.81794 7 8.38234 7 7.51115V6.98893C7 6.11774 7 5.68214 6.83045 5.34939C6.68376 5.06149 6.45113 4.82654 6.165 4.67699V3.50004C6.165 2.0282 4.97184 0.835039 3.5 0.835039ZM4.835 4.50043V3.50004C4.835 2.76274 4.2373 2.16504 3.5 2.16504C2.7627 2.16504 2.165 2.76274 2.165 3.50004V4.50043C2.26584 4.50004 2.37355 4.50004 2.48889 4.50004H4.51111C4.62645 4.50004 4.73416 4.50004 4.835 4.50043Z" fill="black" style="mix-blend-mode:overlay"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 0.835039C2.02816 0.835039 0.835 2.0282 0.835 3.50004V4.67699C0.548874 4.82654 0.316237 5.06149 0.169545 5.34939C0 5.68214 0 6.11774 0 6.98893V7.51115C0 8.38234 0 8.81794 0.169545 9.15069C0.318682 9.44339 0.556652 9.68136 0.849348 9.83049C1.1821 10 1.6177 10 2.48889 10H4.51111C5.3823 10 5.8179 10 6.15065 9.83049C6.44335 9.68136 6.68132 9.44339 6.83045 9.15069C7 8.81794 7 8.38234 7 7.51115V6.98893C7 6.11774 7 5.68214 6.83045 5.34939C6.68376 5.06149 6.45113 4.82654 6.165 4.67699V3.50004C6.165 2.0282 4.97184 0.835039 3.5 0.835039ZM4.835 4.50043V3.50004C4.835 2.76274 4.2373 2.16504 3.5 2.16504C2.7627 2.16504 2.165 2.76274 2.165 3.50004V4.50043C2.26584 4.50004 2.37355 4.50004 2.48889 4.50004H4.51111C4.62645 4.50004 4.73416 4.50004 4.835 4.50043Z" fill="black" fill-opacity="0.15"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -3090,7 +3090,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break break
} }
} }
strongSelf.editMessageDisposable.set((strongSelf.context.engine.messages.requestEditMessage(messageId: messageId, text: message.text, media: .keep, entities: entities, disableUrlPreview: false, scheduleTime: time) |> deliverOnMainQueue).start(next: { result in
let inlineStickers: [MediaId: TelegramMediaFile] = [:]
strongSelf.editMessageDisposable.set((strongSelf.context.engine.messages.requestEditMessage(messageId: messageId, text: message.text, media: .keep, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: false, scheduleTime: time) |> deliverOnMainQueue).start(next: { result in
}, error: { error in }, error: { error in
})) }))
} }
@ -7105,6 +7107,44 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
entitiesAttribute = TextEntitiesMessageAttribute(entities: entities) entitiesAttribute = TextEntitiesMessageAttribute(entities: entities)
} }
var inlineStickers: [MediaId: TelegramMediaFile] = [:]
var firstLockedPremiumEmoji: TelegramMediaFile?
text.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: NSRange(location: 0, length: text.length), using: { value, _, _ in
if let value = value as? ChatTextInputTextCustomEmojiAttribute {
if let file = value.file {
inlineStickers[file.fileId] = file
if file.isPremiumEmoji && !strongSelf.presentationInterfaceState.isPremium {
if firstLockedPremiumEmoji == nil {
firstLockedPremiumEmoji = file
}
}
}
}
})
if let firstLockedPremiumEmoji = firstLockedPremiumEmoji {
//let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
//TODO:localize
strongSelf.controllerInteraction?.displayUndo(.sticker(context: strongSelf.context, file: firstLockedPremiumEmoji, title: nil, text: "Subscribe to Telegram Premium to unlock premium emoji.", undoText: "More", customAction: {
guard let strongSelf = self else {
return
}
strongSelf.chatDisplayNode.dismissTextInput()
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumDemoScreen(context: strongSelf.context, subject: .animatedEmoji, action: {
let controller = PremiumIntroScreen(context: strongSelf.context, source: .animatedEmoji)
replaceImpl?(controller)
})
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
strongSelf.present(controller, in: .window(.root), with: nil)
}))
return
}
var updatingMedia = false var updatingMedia = false
let media: RequestEditMessageMedia let media: RequestEditMessageMedia
if let editMediaReference = strongSelf.presentationInterfaceState.editMessageState?.mediaReference { if let editMediaReference = strongSelf.presentationInterfaceState.editMessageState?.mediaReference {
@ -7121,7 +7161,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let currentMessage = currentMessage { if let currentMessage = currentMessage {
let currentEntities = currentMessage.textEntitiesAttribute?.entities ?? [] let currentEntities = currentMessage.textEntitiesAttribute?.entities ?? []
if currentMessage.text != text.string || currentEntities != entities || updatingMedia { if currentMessage.text != text.string || currentEntities != entities || updatingMedia {
strongSelf.context.account.pendingUpdateMessageManager.add(messageId: editMessage.messageId, text: text.string, media: media, entities: entitiesAttribute, disableUrlPreview: disableUrlPreview) strongSelf.context.account.pendingUpdateMessageManager.add(messageId: editMessage.messageId, text: text.string, media: media, entities: entitiesAttribute, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview)
} }
} }

View File

@ -1374,6 +1374,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
case .overPanels: case .overPanels:
self.inputContextPanelContainer.addSubnode(inputContextPanelNode) self.inputContextPanelContainer.addSubnode(inputContextPanelNode)
case .overTextInput: case .overTextInput:
inputContextPanelNode.view.disablesInteractiveKeyboardGestureRecognizer = true
self.inputContextOverTextPanelContainer.addSubnode(inputContextPanelNode) self.inputContextOverTextPanelContainer.addSubnode(inputContextPanelNode)
} }
immediatelyLayoutInputContextPanelAndAnimateAppearance = true immediatelyLayoutInputContextPanelAndAnimateAppearance = true

View File

@ -945,6 +945,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
fileprivate var emojiInputInteraction: EmojiPagerContentComponent.InputInteraction? fileprivate var emojiInputInteraction: EmojiPagerContentComponent.InputInteraction?
private var stickerInputInteraction: EmojiPagerContentComponent.InputInteraction? private var stickerInputInteraction: EmojiPagerContentComponent.InputInteraction?
private weak var currentUndoOverlayController: UndoOverlayController?
init(context: AccountContext, currentInputData: InputData, updatedInputData: Signal<InputData, NoError>, defaultToEmojiTab: Bool, controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, chatPeerId: PeerId?) { init(context: AccountContext, currentInputData: InputData, updatedInputData: Signal<InputData, NoError>, defaultToEmojiTab: Bool, controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, chatPeerId: PeerId?) {
self.context = context self.context = context
self.currentInputData = currentInputData self.currentInputData = currentInputData
@ -973,9 +975,9 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|> distinctUntilChanged |> distinctUntilChanged
self.emojiInputInteraction = EmojiPagerContentComponent.InputInteraction( self.emojiInputInteraction = EmojiPagerContentComponent.InputInteraction(
performItemAction: { [weak interfaceInteraction, weak controllerInteraction] _, item, _, _, _ in performItemAction: { [weak self, weak interfaceInteraction, weak controllerInteraction] _, item, _, _, _ in
let _ = (hasPremium |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in let _ = (hasPremium |> take(1) |> deliverOnMainQueue).start(next: { hasPremium in
guard let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else { guard let strongSelf = self, let controllerInteraction = controllerInteraction, let interfaceInteraction = interfaceInteraction else {
return return
} }
@ -994,10 +996,17 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
} }
if file.isPremiumEmoji && !hasPremium { if file.isPremiumEmoji && !hasPremium {
var animateInAsReplacement = false
if let currentUndoOverlayController = strongSelf.currentUndoOverlayController {
currentUndoOverlayController.dismissWithCommitActionAndReplacementAnimation()
strongSelf.currentUndoOverlayController = nil
animateInAsReplacement = true
}
//TODO:localize //TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
controllerInteraction.presentController(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Subscribe to Telegram Premium to unlock this emoji.", undoText: "More", customAction: { [weak controllerInteraction] in let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Subscribe to Telegram Premium to unlock this emoji.", undoText: "More", customAction: { [weak controllerInteraction] in
guard let controllerInteraction = controllerInteraction else { guard let controllerInteraction = controllerInteraction else {
return return
} }
@ -1014,7 +1023,9 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
/*let controller = PremiumIntroScreen(context: context, source: .stickers) /*let controller = PremiumIntroScreen(context: context, source: .stickers)
controllerInteraction.navigationController()?.pushViewController(controller)*/ controllerInteraction.navigationController()?.pushViewController(controller)*/
}), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) }), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false })
strongSelf.currentUndoOverlayController = controller
controllerInteraction.presentController(controller, nil)
return return
} }