mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' into beta
This commit is contained in:
commit
5c1f6348c2
@ -7893,6 +7893,9 @@ Sorry for the inconvenience.";
|
|||||||
"EmojiPackActionInfo.MultipleRemovedText_1" = "%@ emoji pack is no longer in your emoji.";
|
"EmojiPackActionInfo.MultipleRemovedText_1" = "%@ emoji pack is no longer in your emoji.";
|
||||||
"EmojiPackActionInfo.MultipleRemovedText_any" = "%@ emoji packs are no longer in your emoji.";
|
"EmojiPackActionInfo.MultipleRemovedText_any" = "%@ emoji packs are no longer in your emoji.";
|
||||||
|
|
||||||
|
"StickerPackActionInfo.MultipleRemovedText_1" = "%@ sticker pack is no longer in your stickers.";
|
||||||
|
"StickerPackActionInfo.MultipleRemovedText_any" = "%@ sticker packs are no longer in your stickers.";
|
||||||
|
|
||||||
"MaskPackActionInfo.RemovedTitle" = "Masks Removed";
|
"MaskPackActionInfo.RemovedTitle" = "Masks Removed";
|
||||||
"MaskPackActionInfo.ArchivedTitle" = "Masks Archived";
|
"MaskPackActionInfo.ArchivedTitle" = "Masks Archived";
|
||||||
"MaskPackActionInfo.RemovedText" = "%@ is no longer in your masks.";
|
"MaskPackActionInfo.RemovedText" = "%@ is no longer in your masks.";
|
||||||
@ -7936,3 +7939,6 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"EmojiInput.PremiumEmojiToast.Text" = "Subscribe to Telegram Premium to unlock premium emoji.";
|
"EmojiInput.PremiumEmojiToast.Text" = "Subscribe to Telegram Premium to unlock premium emoji.";
|
||||||
"EmojiInput.PremiumEmojiToast.Action" = "More";
|
"EmojiInput.PremiumEmojiToast.Action" = "More";
|
||||||
|
|
||||||
|
"StickerPacks.DeleteEmojiPacksConfirmation_1" = "Delete 1 Emoji Pack";
|
||||||
|
"StickerPacks.DeleteEmojiPacksConfirmation_any" = "Delete %@ Emoji Packs";
|
||||||
|
@ -951,6 +951,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !message._asMessage().isCopyProtected() {
|
||||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||||
c.dismiss(completion: { [weak self] in
|
c.dismiss(completion: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -958,6 +959,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
}
|
||||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||||
c.dismiss(completion: { [weak self] in
|
c.dismiss(completion: { [weak self] in
|
||||||
self?.openMessage(EnginePeer(message.peers[message.id.peerId]!), message.id, false)
|
self?.openMessage(EnginePeer(message.peers[message.id.peerId]!), message.id, false)
|
||||||
|
@ -1005,7 +1005,16 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
|||||||
toolbarItem = StickersToolbarItem(selectedCount: selectedCount, actions: [.init(title: presentationData.strings.StickerPacks_ActionDelete, isEnabled: selectedCount > 0, action: {
|
toolbarItem = StickersToolbarItem(selectedCount: selectedCount, actions: [.init(title: presentationData.strings.StickerPacks_ActionDelete, isEnabled: selectedCount > 0, action: {
|
||||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||||
var items: [ActionSheetItem] = []
|
var items: [ActionSheetItem] = []
|
||||||
items.append(ActionSheetButtonItem(title: presentationData.strings.StickerPacks_DeleteStickerPacksConfirmation(selectedCount), color: .destructive, action: { [weak actionSheet] in
|
|
||||||
|
let title: String
|
||||||
|
switch mode {
|
||||||
|
case .emoji:
|
||||||
|
title = presentationData.strings.StickerPacks_DeleteEmojiPacksConfirmation(selectedCount)
|
||||||
|
default:
|
||||||
|
title = presentationData.strings.StickerPacks_DeleteStickerPacksConfirmation(selectedCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
items.append(ActionSheetButtonItem(title: title, color: .destructive, action: { [weak actionSheet] in
|
||||||
actionSheet?.dismissAnimated()
|
actionSheet?.dismissAnimated()
|
||||||
|
|
||||||
if case .modal = mode {
|
if case .modal = mode {
|
||||||
|
@ -620,17 +620,28 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if installedCount == self.currentStickerPacks.count {
|
if installedCount == self.currentStickerPacks.count {
|
||||||
|
var removedPacks: Signal<[(info: ItemCollectionInfo, index: Int, items: [ItemCollectionItem])], NoError> = .single([])
|
||||||
for (info, _, _) in self.currentStickerPacks {
|
for (info, _, _) in self.currentStickerPacks {
|
||||||
let _ = (self.context.engine.stickers.removeStickerPackInteractively(id: info.id, option: .delete)
|
removedPacks = removedPacks
|
||||||
|> deliverOnMainQueue).start(next: { _ in
|
|> mapToSignal { current -> Signal<[(info: ItemCollectionInfo, index: Int, items: [ItemCollectionItem])], NoError> in
|
||||||
// guard let (positionInList, _) = indexAndItems else {
|
return self.context.engine.stickers.removeStickerPackInteractively(id: info.id, option: .delete)
|
||||||
// return
|
|> map { result -> [(info: ItemCollectionInfo, index: Int, items: [ItemCollectionItem])] in
|
||||||
// }
|
if let result = result {
|
||||||
// if dismissed {
|
return current + [(info, result.0, result.1)]
|
||||||
// actionPerformed?(info, items, .remove(positionInList: positionInList))
|
} else {
|
||||||
// }
|
return current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = (removedPacks
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] results in
|
||||||
|
if !results.isEmpty {
|
||||||
|
self?.controller?.actionPerformed?(results.map { result -> (StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction) in
|
||||||
|
return (result.0 as! StickerPackCollectionInfo, result.2.map { $0 as! StickerPackItem }, .remove(positionInList: result.1))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
var installedPacks: [(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)] = []
|
var installedPacks: [(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)] = []
|
||||||
for (info, items, isInstalled) in self.currentStickerPacks {
|
for (info, items, isInstalled) in self.currentStickerPacks {
|
||||||
|
@ -2123,6 +2123,13 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum VisualItemKey: Hashable {
|
||||||
|
case item(id: ItemLayer.Key)
|
||||||
|
case header(groupId: AnyHashable)
|
||||||
|
case groupExpandButton(groupId: AnyHashable)
|
||||||
|
case groupActionButton(groupId: AnyHashable)
|
||||||
|
}
|
||||||
|
|
||||||
private let shimmerHostView: PortalSourceView?
|
private let shimmerHostView: PortalSourceView?
|
||||||
private let standaloneShimmerEffect: StandaloneShimmerEffect?
|
private let standaloneShimmerEffect: StandaloneShimmerEffect?
|
||||||
|
|
||||||
@ -3012,7 +3019,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
self.updateScrollingOffset(isReset: false, transition: transition)
|
self.updateScrollingOffset(isReset: false, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateVisibleItems(transition: Transition, attemptSynchronousLoads: Bool, previousItemPositions: [ItemLayer.Key: CGPoint]?, updatedItemPositions: [ItemLayer.Key: CGPoint]?) {
|
private func updateVisibleItems(transition: Transition, attemptSynchronousLoads: Bool, previousItemPositions: [VisualItemKey: CGPoint]?, previousAbsoluteItemPositions: [VisualItemKey: CGPoint]? = nil, updatedItemPositions: [VisualItemKey: CGPoint]?, hintDisappearingGroupFrame: (groupId: AnyHashable, frame: CGRect)? = nil) {
|
||||||
guard let component = self.component, let pagerEnvironment = self.pagerEnvironment, let keyboardChildEnvironment = self.keyboardChildEnvironment, let itemLayout = self.itemLayout else {
|
guard let component = self.component, let pagerEnvironment = self.pagerEnvironment, let keyboardChildEnvironment = self.keyboardChildEnvironment, let itemLayout = self.itemLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -3190,10 +3197,12 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
|
|
||||||
let groupPremiumButton: ComponentView<Empty>
|
let groupPremiumButton: ComponentView<Empty>
|
||||||
var groupPremiumButtonTransition = transition
|
var groupPremiumButtonTransition = transition
|
||||||
|
var animateButtonIn = false
|
||||||
if let current = self.visibleGroupPremiumButtons[itemGroup.groupId] {
|
if let current = self.visibleGroupPremiumButtons[itemGroup.groupId] {
|
||||||
groupPremiumButton = current
|
groupPremiumButton = current
|
||||||
} else {
|
} else {
|
||||||
groupPremiumButtonTransition = .immediate
|
groupPremiumButtonTransition = .immediate
|
||||||
|
animateButtonIn = !transition.animation.isImmediate
|
||||||
groupPremiumButton = ComponentView<Empty>()
|
groupPremiumButton = ComponentView<Empty>()
|
||||||
self.visibleGroupPremiumButtons[itemGroup.groupId] = groupPremiumButton
|
self.visibleGroupPremiumButtons[itemGroup.groupId] = groupPremiumButton
|
||||||
}
|
}
|
||||||
@ -3257,13 +3266,19 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
)
|
)
|
||||||
let groupPremiumButtonFrame = CGRect(origin: CGPoint(x: itemLayout.itemInsets.left, y: itemGroupLayout.frame.maxY - groupPremiumButtonSize.height + 1.0), size: groupPremiumButtonSize)
|
let groupPremiumButtonFrame = CGRect(origin: CGPoint(x: itemLayout.itemInsets.left, y: itemGroupLayout.frame.maxY - groupPremiumButtonSize.height + 1.0), size: groupPremiumButtonSize)
|
||||||
if let view = groupPremiumButton.view {
|
if let view = groupPremiumButton.view {
|
||||||
var animateIn = false
|
|
||||||
if view.superview == nil {
|
if view.superview == nil {
|
||||||
animateIn = true
|
|
||||||
self.scrollView.addSubview(view)
|
self.scrollView.addSubview(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if animateButtonIn, !transition.animation.isImmediate {
|
||||||
|
if let previousItemPosition = previousItemPositions?[.groupActionButton(groupId: itemGroup.groupId)], transitionHintInstalledGroupId != itemGroup.groupId, transitionHintExpandedGroupId != itemGroup.groupId {
|
||||||
|
groupPremiumButtonTransition = transition
|
||||||
|
view.center = previousItemPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
groupPremiumButtonTransition.setFrame(view: view, frame: groupPremiumButtonFrame)
|
groupPremiumButtonTransition.setFrame(view: view, frame: groupPremiumButtonFrame)
|
||||||
if animateIn, !transition.animation.isImmediate {
|
if animateButtonIn, !transition.animation.isImmediate {
|
||||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
transition.animateScale(view: view, from: 0.01, to: 1.0)
|
transition.animateScale(view: view, from: 0.01, to: 1.0)
|
||||||
}
|
}
|
||||||
@ -3275,12 +3290,14 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
validGroupExpandActionButtons.insert(itemGroup.groupId)
|
validGroupExpandActionButtons.insert(itemGroup.groupId)
|
||||||
let groupId = itemGroup.groupId
|
let groupId = itemGroup.groupId
|
||||||
|
|
||||||
|
var animateButtonIn = false
|
||||||
var groupExpandActionButtonTransition = transition
|
var groupExpandActionButtonTransition = transition
|
||||||
let groupExpandActionButton: GroupExpandActionButton
|
let groupExpandActionButton: GroupExpandActionButton
|
||||||
if let current = self.visibleGroupExpandActionButtons[itemGroup.groupId] {
|
if let current = self.visibleGroupExpandActionButtons[itemGroup.groupId] {
|
||||||
groupExpandActionButton = current
|
groupExpandActionButton = current
|
||||||
} else {
|
} else {
|
||||||
groupExpandActionButtonTransition = .immediate
|
groupExpandActionButtonTransition = .immediate
|
||||||
|
animateButtonIn = !transition.animation.isImmediate
|
||||||
groupExpandActionButton = GroupExpandActionButton(pressed: { [weak self] in
|
groupExpandActionButton = GroupExpandActionButton(pressed: { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -3292,6 +3309,13 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
self.mirrorContentScrollView.layer.addSublayer(groupExpandActionButton.tintContainerLayer)
|
self.mirrorContentScrollView.layer.addSublayer(groupExpandActionButton.tintContainerLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if animateButtonIn, !transition.animation.isImmediate {
|
||||||
|
if let previousItemPosition = previousItemPositions?[.groupExpandButton(groupId: itemGroup.groupId)], transitionHintInstalledGroupId != itemGroup.groupId, transitionHintExpandedGroupId != itemGroup.groupId {
|
||||||
|
groupExpandActionButtonTransition = transition
|
||||||
|
groupExpandActionButton.center = previousItemPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let baseItemFrame = itemLayout.frame(groupIndex: groupItems.groupIndex, itemIndex: collapsedItemIndex)
|
let baseItemFrame = itemLayout.frame(groupIndex: groupItems.groupIndex, itemIndex: collapsedItemIndex)
|
||||||
let buttonSize = groupExpandActionButton.update(theme: keyboardChildEnvironment.theme, title: collapsedItemText)
|
let buttonSize = groupExpandActionButton.update(theme: keyboardChildEnvironment.theme, title: collapsedItemText)
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: baseItemFrame.minX + floor((baseItemFrame.width - buttonSize.width) / 2.0), y: baseItemFrame.minY + floor((baseItemFrame.height - buttonSize.height) / 2.0)), size: buttonSize)
|
let buttonFrame = CGRect(origin: CGPoint(x: baseItemFrame.minX + floor((baseItemFrame.width - buttonSize.width) / 2.0), y: baseItemFrame.minY + floor((baseItemFrame.height - buttonSize.height) / 2.0)), size: buttonSize)
|
||||||
@ -3404,11 +3428,11 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
itemTransition.setBounds(layer: itemLayer, bounds: CGRect(origin: CGPoint(), size: itemFrame.size))
|
itemTransition.setBounds(layer: itemLayer, bounds: CGRect(origin: CGPoint(), size: itemFrame.size))
|
||||||
|
|
||||||
if animateItemIn, !transition.animation.isImmediate {
|
if animateItemIn, !transition.animation.isImmediate {
|
||||||
if let previousItemPosition = previousItemPositions?[itemId], transitionHintInstalledGroupId != itemId.groupId, transitionHintExpandedGroupId != itemId.groupId {
|
if let previousItemPosition = previousItemPositions?[.item(id: itemId)], transitionHintInstalledGroupId != itemId.groupId, transitionHintExpandedGroupId != itemId.groupId {
|
||||||
itemTransition = transition
|
itemTransition = transition
|
||||||
itemLayer.position = previousItemPosition
|
itemLayer.position = previousItemPosition
|
||||||
} else {
|
} else {
|
||||||
if let contentAnimation = contentAnimation, case .groupExpanded(id: itemGroup.groupId) = contentAnimation.type {
|
if transitionHintInstalledGroupId == itemId.groupId || transitionHintExpandedGroupId == itemId.groupId {
|
||||||
itemLayer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
itemLayer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||||
itemLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
itemLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||||
} else {
|
} else {
|
||||||
@ -3454,7 +3478,18 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
removedIds.append(id)
|
removedIds.append(id)
|
||||||
|
|
||||||
if !transition.animation.isImmediate {
|
if !transition.animation.isImmediate {
|
||||||
if let position = updatedItemPositions?[id], transitionHintInstalledGroupId != id.groupId {
|
if let hintDisappearingGroupFrame = hintDisappearingGroupFrame, hintDisappearingGroupFrame.groupId == id.groupId {
|
||||||
|
if let previousAbsolutePosition = previousAbsoluteItemPositions?[.item(id: id)] {
|
||||||
|
itemLayer.position = self.convert(previousAbsolutePosition, to: self.scrollView)
|
||||||
|
transition.setPosition(layer: itemLayer, position: CGPoint(x: hintDisappearingGroupFrame.frame.midX, y: hintDisappearingGroupFrame.frame.minY + 20.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
itemLayer.opacity = 0.0
|
||||||
|
itemLayer.animateScale(from: 1.0, to: 0.01, duration: 0.16)
|
||||||
|
itemLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.16, completion: { [weak itemLayer] _ in
|
||||||
|
itemLayer?.removeFromSuperlayer()
|
||||||
|
})
|
||||||
|
} else if let position = updatedItemPositions?[.item(id: id)], transitionHintInstalledGroupId != id.groupId {
|
||||||
transition.setPosition(layer: itemLayer, position: position, completion: { [weak itemLayer] _ in
|
transition.setPosition(layer: itemLayer, position: position, completion: { [weak itemLayer] _ in
|
||||||
itemLayer?.removeFromSuperlayer()
|
itemLayer?.removeFromSuperlayer()
|
||||||
})
|
})
|
||||||
@ -3485,13 +3520,28 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
removedGroupHeaderIds.append(id)
|
removedGroupHeaderIds.append(id)
|
||||||
|
|
||||||
if !transition.animation.isImmediate {
|
if !transition.animation.isImmediate {
|
||||||
groupHeaderLayer.alpha = 0.0
|
var isAnimatingDisappearance = false
|
||||||
groupHeaderLayer.layer.animateScale(from: 1.0, to: 0.5, duration: 0.2)
|
if let hintDisappearingGroupFrame = hintDisappearingGroupFrame, hintDisappearingGroupFrame.groupId == id, let previousAbsolutePosition = previousAbsoluteItemPositions?[VisualItemKey.header(groupId: id)] {
|
||||||
|
groupHeaderLayer.center = self.convert(previousAbsolutePosition, to: self.scrollView)
|
||||||
|
transition.setPosition(layer: groupHeaderLayer.layer, position: CGPoint(x: hintDisappearingGroupFrame.frame.midX, y: hintDisappearingGroupFrame.frame.minY + 20.0))
|
||||||
|
isAnimatingDisappearance = true
|
||||||
|
}
|
||||||
|
|
||||||
let tintContentLayer = groupHeaderLayer.tintContentLayer
|
let tintContentLayer = groupHeaderLayer.tintContentLayer
|
||||||
groupHeaderLayer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak groupHeaderLayer, weak tintContentLayer] _ in
|
|
||||||
|
if !isAnimatingDisappearance, let position = updatedItemPositions?[.header(groupId: id)] {
|
||||||
|
transition.setPosition(layer: groupHeaderLayer.layer, position: position, completion: { [weak groupHeaderLayer, weak tintContentLayer] _ in
|
||||||
groupHeaderLayer?.removeFromSuperview()
|
groupHeaderLayer?.removeFromSuperview()
|
||||||
tintContentLayer?.removeFromSuperlayer()
|
tintContentLayer?.removeFromSuperlayer()
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
groupHeaderLayer.alpha = 0.0
|
||||||
|
groupHeaderLayer.layer.animateScale(from: 1.0, to: 0.5, duration: 0.16)
|
||||||
|
groupHeaderLayer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.16, completion: { [weak groupHeaderLayer, weak tintContentLayer] _ in
|
||||||
|
groupHeaderLayer?.removeFromSuperview()
|
||||||
|
tintContentLayer?.removeFromSuperlayer()
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
groupHeaderLayer.removeFromSuperview()
|
groupHeaderLayer.removeFromSuperview()
|
||||||
groupHeaderLayer.tintContentLayer.removeFromSuperlayer()
|
groupHeaderLayer.tintContentLayer.removeFromSuperlayer()
|
||||||
@ -3516,9 +3566,35 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
|
|
||||||
var removedGroupPremiumButtonIds: [AnyHashable] = []
|
var removedGroupPremiumButtonIds: [AnyHashable] = []
|
||||||
for (id, groupPremiumButton) in self.visibleGroupPremiumButtons {
|
for (id, groupPremiumButton) in self.visibleGroupPremiumButtons {
|
||||||
if !validGroupPremiumButtonIds.contains(id) {
|
if !validGroupPremiumButtonIds.contains(id), let buttonView = groupPremiumButton.view {
|
||||||
|
if !transition.animation.isImmediate {
|
||||||
|
var isAnimatingDisappearance = false
|
||||||
|
if let position = updatedItemPositions?[.groupActionButton(groupId: id)], position.y > buttonView.center.y {
|
||||||
|
} else if let hintDisappearingGroupFrame = hintDisappearingGroupFrame, hintDisappearingGroupFrame.groupId == id, let previousAbsolutePosition = previousAbsoluteItemPositions?[VisualItemKey.groupActionButton(groupId: id)] {
|
||||||
|
buttonView.center = self.convert(previousAbsolutePosition, to: self.scrollView)
|
||||||
|
transition.setPosition(layer: buttonView.layer, position: CGPoint(x: hintDisappearingGroupFrame.frame.midX, y: hintDisappearingGroupFrame.frame.minY + 20.0))
|
||||||
|
isAnimatingDisappearance = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAnimatingDisappearance, let position = updatedItemPositions?[.groupActionButton(groupId: id)] {
|
||||||
|
buttonView.alpha = 0.0
|
||||||
|
buttonView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.16, completion: { [weak buttonView] _ in
|
||||||
|
buttonView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
transition.setPosition(layer: buttonView.layer, position: position)
|
||||||
|
} else {
|
||||||
|
buttonView.alpha = 0.0
|
||||||
|
if transitionHintExpandedGroupId == id || hintDisappearingGroupFrame?.groupId == id {
|
||||||
|
buttonView.layer.animateScale(from: 1.0, to: 0.5, duration: 0.16)
|
||||||
|
}
|
||||||
|
buttonView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.16, completion: { [weak buttonView] _ in
|
||||||
|
buttonView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
removedGroupPremiumButtonIds.append(id)
|
removedGroupPremiumButtonIds.append(id)
|
||||||
groupPremiumButton.view?.removeFromSuperview()
|
buttonView.removeFromSuperview()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for id in removedGroupPremiumButtonIds {
|
for id in removedGroupPremiumButtonIds {
|
||||||
@ -3530,14 +3606,32 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
if !validGroupExpandActionButtons.contains(id) {
|
if !validGroupExpandActionButtons.contains(id) {
|
||||||
removedGroupExpandActionButtonIds.append(id)
|
removedGroupExpandActionButtonIds.append(id)
|
||||||
|
|
||||||
if !transition.animation.isImmediate && transitionHintExpandedGroupId == id {
|
if !transition.animation.isImmediate {
|
||||||
button.alpha = 0.0
|
var isAnimatingDisappearance = false
|
||||||
button.layer.animateScale(from: 1.0, to: 0.5, duration: 0.2)
|
if self.visibleGroupHeaders[id] == nil, let hintDisappearingGroupFrame = hintDisappearingGroupFrame, hintDisappearingGroupFrame.groupId == id, let previousAbsolutePosition = previousAbsoluteItemPositions?[.groupExpandButton(groupId: id)] {
|
||||||
|
button.center = self.convert(previousAbsolutePosition, to: self.scrollView)
|
||||||
|
button.tintContainerLayer.position = button.center
|
||||||
|
transition.setPosition(layer: button.layer, position: CGPoint(x: hintDisappearingGroupFrame.frame.midX, y: hintDisappearingGroupFrame.frame.minY + 20.0))
|
||||||
|
isAnimatingDisappearance = true
|
||||||
|
}
|
||||||
|
|
||||||
let tintContainerLayer = button.tintContainerLayer
|
let tintContainerLayer = button.tintContainerLayer
|
||||||
button.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak button, weak tintContainerLayer] _ in
|
|
||||||
|
if !isAnimatingDisappearance, let position = updatedItemPositions?[.groupExpandButton(groupId: id)] {
|
||||||
|
transition.setPosition(layer: button.layer, position: position, completion: { [weak button, weak tintContainerLayer] _ in
|
||||||
button?.removeFromSuperview()
|
button?.removeFromSuperview()
|
||||||
tintContainerLayer?.removeFromSuperlayer()
|
tintContainerLayer?.removeFromSuperlayer()
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
button.alpha = 0.0
|
||||||
|
if transitionHintExpandedGroupId == id || hintDisappearingGroupFrame?.groupId == id {
|
||||||
|
button.layer.animateScale(from: 1.0, to: 0.5, duration: 0.16)
|
||||||
|
}
|
||||||
|
button.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.16, completion: { [weak button, weak tintContainerLayer] _ in
|
||||||
|
button?.removeFromSuperview()
|
||||||
|
tintContainerLayer?.removeFromSuperlayer()
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
button.removeFromSuperview()
|
button.removeFromSuperview()
|
||||||
button.tintContainerLayer.removeFromSuperlayer()
|
button.tintContainerLayer.removeFromSuperlayer()
|
||||||
@ -3627,15 +3721,34 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
standaloneShimmerEffect.update(background: shimmerBackgroundColor, foreground: shimmerForegroundColor)
|
standaloneShimmerEffect.update(background: shimmerBackgroundColor, foreground: shimmerForegroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
var previousItemPositions: [ItemLayer.Key: CGPoint]?
|
var previousItemPositions: [VisualItemKey: CGPoint]?
|
||||||
|
|
||||||
var calculateUpdatedItemPositions = false
|
var calculateUpdatedItemPositions = false
|
||||||
var updatedItemPositions: [ItemLayer.Key: CGPoint]?
|
var updatedItemPositions: [VisualItemKey: CGPoint]?
|
||||||
|
|
||||||
var anchorItem: (key: ItemLayer.Key, frame: CGRect)?
|
let contentAnimation = transition.userData(ContentAnimation.self)
|
||||||
|
|
||||||
|
var transitionHintInstalledGroupId: AnyHashable?
|
||||||
|
var transitionHintExpandedGroupId: AnyHashable?
|
||||||
|
if let contentAnimation = contentAnimation {
|
||||||
|
switch contentAnimation.type {
|
||||||
|
case let .groupInstalled(groupId):
|
||||||
|
transitionHintInstalledGroupId = groupId
|
||||||
|
case let .groupExpanded(groupId):
|
||||||
|
transitionHintExpandedGroupId = groupId
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = transitionHintExpandedGroupId
|
||||||
|
|
||||||
|
var hintDisappearingGroupFrame: (groupId: AnyHashable, frame: CGRect)?
|
||||||
|
var previousAbsoluteItemPositions: [VisualItemKey: CGPoint] = [:]
|
||||||
|
|
||||||
|
var anchorItems: [ItemLayer.Key: CGRect] = [:]
|
||||||
if let previousComponent = previousComponent, let previousItemLayout = self.itemLayout, previousComponent.itemGroups != component.itemGroups {
|
if let previousComponent = previousComponent, let previousItemLayout = self.itemLayout, previousComponent.itemGroups != component.itemGroups {
|
||||||
if !transition.animation.isImmediate {
|
if !transition.animation.isImmediate {
|
||||||
var previousItemPositionsValue: [ItemLayer.Key: CGPoint] = [:]
|
var previousItemPositionsValue: [VisualItemKey: CGPoint] = [:]
|
||||||
for groupIndex in 0 ..< previousComponent.itemGroups.count {
|
for groupIndex in 0 ..< previousComponent.itemGroups.count {
|
||||||
let itemGroup = previousComponent.itemGroups[groupIndex]
|
let itemGroup = previousComponent.itemGroups[groupIndex]
|
||||||
for itemIndex in 0 ..< itemGroup.items.count {
|
for itemIndex in 0 ..< itemGroup.items.count {
|
||||||
@ -3649,7 +3762,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let itemFrame = previousItemLayout.frame(groupIndex: groupIndex, itemIndex: itemIndex)
|
let itemFrame = previousItemLayout.frame(groupIndex: groupIndex, itemIndex: itemIndex)
|
||||||
previousItemPositionsValue[itemKey] = CGPoint(x: itemFrame.midX, y: itemFrame.midY)
|
previousItemPositionsValue[.item(id: itemKey)] = CGPoint(x: itemFrame.midX, y: itemFrame.midY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
previousItemPositions = previousItemPositionsValue
|
previousItemPositions = previousItemPositionsValue
|
||||||
@ -3657,23 +3770,78 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let effectiveVisibleBounds = CGRect(origin: self.scrollView.bounds.origin, size: self.effectiveVisibleSize)
|
let effectiveVisibleBounds = CGRect(origin: self.scrollView.bounds.origin, size: self.effectiveVisibleSize)
|
||||||
let topVisibleDetectionBounds = effectiveVisibleBounds.offsetBy(dx: 0.0, dy: pagerEnvironment.containerInsets.top)
|
let topVisibleDetectionBounds = effectiveVisibleBounds
|
||||||
for (key, itemLayer) in self.visibleItemLayers {
|
for (key, itemLayer) in self.visibleItemLayers {
|
||||||
if !topVisibleDetectionBounds.intersects(itemLayer.frame) {
|
if !topVisibleDetectionBounds.intersects(itemLayer.frame) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if let anchorItemValue = anchorItem {
|
|
||||||
if itemLayer.frame.minY < anchorItemValue.frame.minY {
|
let absoluteFrame = self.scrollView.convert(itemLayer.frame, to: self)
|
||||||
anchorItem = (key, itemLayer.frame)
|
|
||||||
} else if itemLayer.frame.minY == anchorItemValue.frame.minY && itemLayer.frame.minX < anchorItemValue.frame.minX {
|
if let transitionHintInstalledGroupId = transitionHintInstalledGroupId, transitionHintInstalledGroupId == key.groupId {
|
||||||
anchorItem = (key, itemLayer.frame)
|
if let hintDisappearingGroupFrameValue = hintDisappearingGroupFrame {
|
||||||
}
|
hintDisappearingGroupFrame = (hintDisappearingGroupFrameValue.groupId, absoluteFrame.union(hintDisappearingGroupFrameValue.frame))
|
||||||
} else {
|
} else {
|
||||||
anchorItem = (key, itemLayer.frame)
|
hintDisappearingGroupFrame = (key.groupId, absoluteFrame)
|
||||||
|
}
|
||||||
|
previousAbsoluteItemPositions[.item(id: key)] = CGPoint(x: absoluteFrame.midX, y: absoluteFrame.midY)
|
||||||
|
} else {
|
||||||
|
anchorItems[key] = absoluteFrame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let anchorItemValue = anchorItem {
|
|
||||||
anchorItem = (anchorItemValue.key, self.scrollView.convert(anchorItemValue.frame, to: self))
|
for (id, groupHeader) in self.visibleGroupHeaders {
|
||||||
|
if !topVisibleDetectionBounds.intersects(groupHeader.frame) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let absoluteFrame = self.scrollView.convert(groupHeader.frame, to: self)
|
||||||
|
|
||||||
|
if let transitionHintInstalledGroupId = transitionHintInstalledGroupId, transitionHintInstalledGroupId == id {
|
||||||
|
if let hintDisappearingGroupFrameValue = hintDisappearingGroupFrame {
|
||||||
|
hintDisappearingGroupFrame = (hintDisappearingGroupFrameValue.groupId, absoluteFrame.union(hintDisappearingGroupFrameValue.frame))
|
||||||
|
} else {
|
||||||
|
hintDisappearingGroupFrame = (id, absoluteFrame)
|
||||||
|
}
|
||||||
|
previousAbsoluteItemPositions[.header(groupId: id)] = CGPoint(x: absoluteFrame.midX, y: absoluteFrame.midY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, button) in self.visibleGroupExpandActionButtons {
|
||||||
|
if !topVisibleDetectionBounds.intersects(button.frame) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let absoluteFrame = self.scrollView.convert(button.frame, to: self)
|
||||||
|
|
||||||
|
if let transitionHintInstalledGroupId = transitionHintInstalledGroupId, transitionHintInstalledGroupId == id {
|
||||||
|
if let hintDisappearingGroupFrameValue = hintDisappearingGroupFrame {
|
||||||
|
hintDisappearingGroupFrame = (hintDisappearingGroupFrameValue.groupId, absoluteFrame.union(hintDisappearingGroupFrameValue.frame))
|
||||||
|
} else {
|
||||||
|
hintDisappearingGroupFrame = (id, absoluteFrame)
|
||||||
|
}
|
||||||
|
previousAbsoluteItemPositions[.groupExpandButton(groupId: id)] = CGPoint(x: absoluteFrame.midX, y: absoluteFrame.midY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, button) in self.visibleGroupPremiumButtons {
|
||||||
|
guard let buttonView = button.view else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !topVisibleDetectionBounds.intersects(buttonView.frame) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let absoluteFrame = self.scrollView.convert(buttonView.frame, to: self)
|
||||||
|
|
||||||
|
if let transitionHintInstalledGroupId = transitionHintInstalledGroupId, transitionHintInstalledGroupId == id {
|
||||||
|
if let hintDisappearingGroupFrameValue = hintDisappearingGroupFrame {
|
||||||
|
hintDisappearingGroupFrame = (hintDisappearingGroupFrameValue.groupId, absoluteFrame.union(hintDisappearingGroupFrameValue.frame))
|
||||||
|
} else {
|
||||||
|
hintDisappearingGroupFrame = (id, absoluteFrame)
|
||||||
|
}
|
||||||
|
previousAbsoluteItemPositions[.groupActionButton(groupId: id)] = CGPoint(x: absoluteFrame.midX, y: absoluteFrame.midY)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3742,9 +3910,19 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
}
|
}
|
||||||
self.previousScrollingOffset = ScrollingOffsetState(value: scrollView.contentOffset.y, isDraggingOrDecelerating: scrollView.isDragging || scrollView.isDecelerating)
|
self.previousScrollingOffset = ScrollingOffsetState(value: scrollView.contentOffset.y, isDraggingOrDecelerating: scrollView.isDragging || scrollView.isDecelerating)
|
||||||
|
|
||||||
if let anchorItem = anchorItem {
|
var animatedScrollOffset: CGFloat = 0.0
|
||||||
|
if !anchorItems.isEmpty {
|
||||||
|
let sortedAnchorItems: [(ItemLayer.Key, CGRect)] = anchorItems.sorted(by: { lhs, rhs in
|
||||||
|
if lhs.value.minY != rhs.value.minY {
|
||||||
|
return lhs.value.minY < rhs.value.minY
|
||||||
|
} else {
|
||||||
|
return lhs.value.minX < rhs.value.minX
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
outer: for i in 0 ..< component.itemGroups.count {
|
outer: for i in 0 ..< component.itemGroups.count {
|
||||||
if component.itemGroups[i].groupId != anchorItem.key.groupId {
|
for anchorItem in sortedAnchorItems {
|
||||||
|
if component.itemGroups[i].groupId != anchorItem.0.groupId {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for j in 0 ..< component.itemGroups[i].items.count {
|
for j in 0 ..< component.itemGroups[i].items.count {
|
||||||
@ -3757,10 +3935,10 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if itemKey == anchorItem.key {
|
if itemKey == anchorItem.0 {
|
||||||
let itemFrame = itemLayout.frame(groupIndex: i, itemIndex: j)
|
let itemFrame = itemLayout.frame(groupIndex: i, itemIndex: j)
|
||||||
|
|
||||||
var contentOffsetY = itemFrame.minY - anchorItem.frame.minY
|
var contentOffsetY = itemFrame.minY - anchorItem.1.minY
|
||||||
if contentOffsetY > self.scrollView.contentSize.height - self.scrollView.bounds.height {
|
if contentOffsetY > self.scrollView.contentSize.height - self.scrollView.bounds.height {
|
||||||
contentOffsetY = self.scrollView.contentSize.height - self.scrollView.bounds.height
|
contentOffsetY = self.scrollView.contentSize.height - self.scrollView.bounds.height
|
||||||
}
|
}
|
||||||
@ -3770,20 +3948,24 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
|
|
||||||
let previousBounds = self.scrollView.bounds
|
let previousBounds = self.scrollView.bounds
|
||||||
self.scrollView.setContentOffset(CGPoint(x: 0.0, y: contentOffsetY), animated: false)
|
self.scrollView.setContentOffset(CGPoint(x: 0.0, y: contentOffsetY), animated: false)
|
||||||
transition.animateBoundsOrigin(view: self.scrollView, from: CGPoint(x: 0.0, y: previousBounds.minY - contentOffsetY), to: CGPoint(), additive: true)
|
let scrollOffset = previousBounds.minY - contentOffsetY
|
||||||
|
transition.animateBoundsOrigin(view: self.scrollView, from: CGPoint(x: 0.0, y: scrollOffset), to: CGPoint(), additive: true)
|
||||||
|
animatedScrollOffset = scrollOffset
|
||||||
|
|
||||||
break outer
|
break outer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.ignoreScrolling = false
|
self.ignoreScrolling = false
|
||||||
|
|
||||||
if calculateUpdatedItemPositions {
|
if calculateUpdatedItemPositions {
|
||||||
var updatedItemPositionsValue: [ItemLayer.Key: CGPoint] = [:]
|
var updatedItemPositionsValue: [VisualItemKey: CGPoint] = [:]
|
||||||
for groupIndex in 0 ..< component.itemGroups.count {
|
for groupIndex in 0 ..< component.itemGroups.count {
|
||||||
let itemGroup = component.itemGroups[groupIndex]
|
let itemGroup = component.itemGroups[groupIndex]
|
||||||
|
let itemGroupLayout = itemLayout.itemGroupLayouts[groupIndex]
|
||||||
for itemIndex in 0 ..< itemGroup.items.count {
|
for itemIndex in 0 ..< itemGroup.items.count {
|
||||||
let item = itemGroup.items[itemIndex]
|
let item = itemGroup.items[itemIndex]
|
||||||
let itemKey: ItemLayer.Key
|
let itemKey: ItemLayer.Key
|
||||||
@ -3795,13 +3977,24 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let itemFrame = itemLayout.frame(groupIndex: groupIndex, itemIndex: itemIndex)
|
let itemFrame = itemLayout.frame(groupIndex: groupIndex, itemIndex: itemIndex)
|
||||||
updatedItemPositionsValue[itemKey] = CGPoint(x: itemFrame.midX, y: itemFrame.midY)
|
updatedItemPositionsValue[.item(id: itemKey)] = CGPoint(x: itemFrame.midX, y: itemFrame.midY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let groupPremiumButtonFrame = CGRect(origin: CGPoint(x: itemLayout.itemInsets.left, y: itemGroupLayout.frame.maxY - itemLayout.premiumButtonHeight + 1.0), size: CGSize(width: itemLayout.width - itemLayout.itemInsets.left - itemLayout.itemInsets.right, height: itemLayout.premiumButtonHeight))
|
||||||
|
updatedItemPositionsValue[.groupActionButton(groupId: itemGroup.groupId)] = CGPoint(x: groupPremiumButtonFrame.midX, y: groupPremiumButtonFrame.midY)
|
||||||
}
|
}
|
||||||
updatedItemPositions = updatedItemPositionsValue
|
updatedItemPositions = updatedItemPositionsValue
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateVisibleItems(transition: itemTransition, attemptSynchronousLoads: !(scrollView.isDragging || scrollView.isDecelerating), previousItemPositions: previousItemPositions, updatedItemPositions: updatedItemPositions)
|
if let hintDisappearingGroupFrameValue = hintDisappearingGroupFrame {
|
||||||
|
hintDisappearingGroupFrame = (hintDisappearingGroupFrameValue.groupId, self.scrollView.convert(hintDisappearingGroupFrameValue.frame, from: self))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, position) in previousAbsoluteItemPositions {
|
||||||
|
previousAbsoluteItemPositions[id] = position.offsetBy(dx: 0.0, dy: animatedScrollOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.updateVisibleItems(transition: itemTransition, attemptSynchronousLoads: !(scrollView.isDragging || scrollView.isDecelerating), previousItemPositions: previousItemPositions, previousAbsoluteItemPositions: previousAbsoluteItemPositions, updatedItemPositions: updatedItemPositions, hintDisappearingGroupFrame: hintDisappearingGroupFrame)
|
||||||
|
|
||||||
return availableSize
|
return availableSize
|
||||||
}
|
}
|
||||||
|
@ -1833,7 +1833,7 @@ final class EntityKeyboardTopPanelComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let isRound: Bool
|
let isRound: Bool
|
||||||
if let string = activeContentItemId.base as? String, (string == "recent" || string == "static" || string == "trending") {
|
if let string = activeContentItemId.base as? String, (string == "featuredTop" || string == "recent" || string == "static" || string == "trending") {
|
||||||
isRound = true
|
isRound = true
|
||||||
} else {
|
} else {
|
||||||
isRound = false
|
isRound = false
|
||||||
|
@ -553,11 +553,12 @@ public final class MultiAnimationRendererImpl: MultiAnimationRenderer {
|
|||||||
self.f()
|
self.f()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let displayTimer = Foundation.Timer(timeInterval: CGFloat(self.frameSkip) / 60.0, target: TimerTarget { [weak self] in
|
let frameInterval = Double(self.frameSkip) / 60.0
|
||||||
|
let displayTimer = Foundation.Timer(timeInterval: frameInterval, target: TimerTarget { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.animationTick()
|
strongSelf.animationTick(frameInterval: frameInterval)
|
||||||
}, selector: #selector(TimerTarget.timerEvent), userInfo: nil, repeats: true)
|
}, selector: #selector(TimerTarget.timerEvent), userInfo: nil, repeats: true)
|
||||||
self.displayTimer = displayTimer
|
self.displayTimer = displayTimer
|
||||||
RunLoop.main.add(displayTimer, forMode: .common)
|
RunLoop.main.add(displayTimer, forMode: .common)
|
||||||
@ -646,8 +647,8 @@ public final class MultiAnimationRendererImpl: MultiAnimationRenderer {
|
|||||||
self.isPlaying = isPlaying
|
self.isPlaying = isPlaying
|
||||||
}
|
}
|
||||||
|
|
||||||
private func animationTick() {
|
private func animationTick(frameInterval: Double) {
|
||||||
let secondsPerFrame = Double(self.frameSkip) / 60.0
|
let secondsPerFrame = frameInterval
|
||||||
|
|
||||||
var tasks: [LoadFrameGroupTask] = []
|
var tasks: [LoadFrameGroupTask] = []
|
||||||
if let groupContext = self.groupContext {
|
if let groupContext = self.groupContext {
|
||||||
|
@ -1139,6 +1139,31 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
|
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
|
||||||
return true
|
return true
|
||||||
}))
|
}))
|
||||||
|
} else if actions.allSatisfy({
|
||||||
|
if case .remove = $0.2 {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
let isEmoji = actions[0].0.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
|
||||||
|
|
||||||
|
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_MultipleRemovedText(Int32(actions.count)) : presentationData.strings.StickerPackActionInfo_MultipleRemovedText(Int32(actions.count)), undo: true, info: actions[0].0, topItem: actions[0].1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { action in
|
||||||
|
if case .undo = action {
|
||||||
|
var itemsAndIndices: [(StickerPackCollectionInfo, [StickerPackItem], Int)] = actions.compactMap { action -> (StickerPackCollectionInfo, [StickerPackItem], Int)? in
|
||||||
|
if case let .remove(index) = action.2 {
|
||||||
|
return (action.0, action.1, index)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemsAndIndices.sort(by: { $0.2 < $1.2 })
|
||||||
|
for (info, items, index) in itemsAndIndices.reversed() {
|
||||||
|
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: index).start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
} else if let (info, items, action) = actions.first {
|
} else if let (info, items, action) = actions.first {
|
||||||
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
|
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
|
||||||
@ -10963,7 +10988,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let inputPanelNode = AttachmentTextInputPanelNode(context: self.context, presentationInterfaceState: presentationInterfaceState, isCaption: true, presentController: { _ in }, makeEntityInputView: { [weak self] in
|
let inputPanelNode = AttachmentTextInputPanelNode(context: self.context, presentationInterfaceState: presentationInterfaceState, isCaption: true, presentController: { [weak self] c in
|
||||||
|
self?.presentInGlobalOverlay(c)
|
||||||
|
}, makeEntityInputView: { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -793,8 +793,21 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
self.contentContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
self.contentContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
|
||||||
let visibleRootModalDismissProgress: CGFloat = 1.0 - self.inputPanelContainerNode.expansionFraction
|
let isOverlay: Bool
|
||||||
if self.inputPanelContainerNode.expansionFraction != 0.0 {
|
switch self.chatPresentationInterfaceState.mode {
|
||||||
|
case .overlay:
|
||||||
|
isOverlay = true
|
||||||
|
default:
|
||||||
|
isOverlay = false
|
||||||
|
}
|
||||||
|
|
||||||
|
let visibleRootModalDismissProgress: CGFloat
|
||||||
|
if isOverlay {
|
||||||
|
visibleRootModalDismissProgress = 1.0
|
||||||
|
} else {
|
||||||
|
visibleRootModalDismissProgress = 1.0 - self.inputPanelContainerNode.expansionFraction
|
||||||
|
}
|
||||||
|
if !isOverlay && self.inputPanelContainerNode.expansionFraction != 0.0 {
|
||||||
let navigationModalFrame: NavigationModalFrame
|
let navigationModalFrame: NavigationModalFrame
|
||||||
var animateFromFraction: CGFloat?
|
var animateFromFraction: CGFloat?
|
||||||
if let current = self.navigationModalFrame {
|
if let current = self.navigationModalFrame {
|
||||||
@ -886,6 +899,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
containerNode.cornerRadius = 15.0
|
containerNode.cornerRadius = 15.0
|
||||||
containerNode.addSubnode(self.backgroundNode)
|
containerNode.addSubnode(self.backgroundNode)
|
||||||
containerNode.addSubnode(self.historyNodeContainer)
|
containerNode.addSubnode(self.historyNodeContainer)
|
||||||
|
self.contentContainerNode.isHidden = true
|
||||||
if let restrictedNode = self.restrictedNode {
|
if let restrictedNode = self.restrictedNode {
|
||||||
containerNode.addSubnode(restrictedNode)
|
containerNode.addSubnode(restrictedNode)
|
||||||
}
|
}
|
||||||
|
@ -2030,7 +2030,25 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
|||||||
},
|
},
|
||||||
addGroupAction: { _, _ in
|
addGroupAction: { _, _ in
|
||||||
},
|
},
|
||||||
clearGroup: { _ in
|
clearGroup: { [weak self] groupId in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if groupId == AnyHashable("recent") {
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
let actionSheet = ActionSheetController(theme: ActionSheetControllerTheme(presentationTheme: presentationData.theme, fontSize: presentationData.listsFontSize))
|
||||||
|
var items: [ActionSheetItem] = []
|
||||||
|
items.append(ActionSheetButtonItem(title: presentationData.strings.Emoji_ClearRecent, color: .destructive, action: { [weak actionSheet] in
|
||||||
|
actionSheet?.dismissAnimated()
|
||||||
|
let _ = context.engine.stickers.clearRecentlyUsedEmoji().start()
|
||||||
|
}))
|
||||||
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||||
|
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||||
|
actionSheet?.dismissAnimated()
|
||||||
|
})
|
||||||
|
])])
|
||||||
|
strongSelf.presentController?(actionSheet)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pushController: { _ in
|
pushController: { _ in
|
||||||
},
|
},
|
||||||
@ -2062,7 +2080,14 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
|||||||
gifs: nil,
|
gifs: nil,
|
||||||
availableGifSearchEmojies: []
|
availableGifSearchEmojies: []
|
||||||
),
|
),
|
||||||
updatedInputData: .never(),
|
updatedInputData: ChatEntityKeyboardInputNode.emojiInputData(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, isStandalone: true, isSecret: isSecret) |> map { emojiComponent -> ChatEntityKeyboardInputNode.InputData in
|
||||||
|
return ChatEntityKeyboardInputNode.InputData(
|
||||||
|
emoji: emojiComponent,
|
||||||
|
stickers: nil,
|
||||||
|
gifs: nil,
|
||||||
|
availableGifSearchEmojies: []
|
||||||
|
)
|
||||||
|
},
|
||||||
defaultToEmojiTab: true,
|
defaultToEmojiTab: true,
|
||||||
controllerInteraction: nil,
|
controllerInteraction: nil,
|
||||||
interfaceInteraction: nil,
|
interfaceInteraction: nil,
|
||||||
|
@ -71,6 +71,22 @@ private final class EffectImageLayer: SimpleLayer, GradientBackgroundPatternOver
|
|||||||
case never
|
case never
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fillWithColorUntilLoaded: UIColor? {
|
||||||
|
didSet {
|
||||||
|
if self.fillWithColorUntilLoaded != oldValue {
|
||||||
|
if let fillWithColorUntilLoaded = self.fillWithColorUntilLoaded {
|
||||||
|
if self.currentContents == nil {
|
||||||
|
self.backgroundColor = fillWithColorUntilLoaded.cgColor
|
||||||
|
} else {
|
||||||
|
self.backgroundColor = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.backgroundColor = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var patternContentImage: UIImage? {
|
var patternContentImage: UIImage? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.patternContentImage !== oldValue {
|
if self.patternContentImage !== oldValue {
|
||||||
@ -252,6 +268,8 @@ private final class EffectImageLayer: SimpleLayer, GradientBackgroundPatternOver
|
|||||||
self.allowSettingContents = true
|
self.allowSettingContents = true
|
||||||
self.contents = contents?.cgImage
|
self.contents = contents?.cgImage
|
||||||
self.allowSettingContents = false
|
self.allowSettingContents = false
|
||||||
|
|
||||||
|
self.backgroundColor = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,16 +854,14 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
|||||||
|
|
||||||
self.patternImageLayer.isHidden = false
|
self.patternImageLayer.isHidden = false
|
||||||
let invertPattern = intensity < 0
|
let invertPattern = intensity < 0
|
||||||
|
|
||||||
|
self.patternImageLayer.fillWithColorUntilLoaded = invertPattern ? .black : nil
|
||||||
|
|
||||||
if invertPattern {
|
if invertPattern {
|
||||||
self.backgroundColor = .black
|
self.backgroundColor = .black
|
||||||
let contentAlpha = abs(intensity)
|
let contentAlpha = abs(intensity)
|
||||||
self.gradientBackgroundNode?.contentView.alpha = contentAlpha
|
self.gradientBackgroundNode?.contentView.alpha = contentAlpha
|
||||||
self.contentNode.alpha = contentAlpha
|
self.contentNode.alpha = contentAlpha
|
||||||
if self.patternImageLayer.contents != nil {
|
|
||||||
self.patternImageLayer.backgroundColor = nil
|
|
||||||
} else {
|
|
||||||
self.patternImageLayer.backgroundColor = nil
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.backgroundColor = nil
|
self.backgroundColor = nil
|
||||||
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
||||||
@ -856,6 +872,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
|||||||
self.patternImageDisposable.set(nil)
|
self.patternImageDisposable.set(nil)
|
||||||
self.validPatternImage = nil
|
self.validPatternImage = nil
|
||||||
self.patternImageLayer.isHidden = true
|
self.patternImageLayer.isHidden = true
|
||||||
|
self.patternImageLayer.fillWithColorUntilLoaded = nil
|
||||||
self.patternImageLayer.backgroundColor = nil
|
self.patternImageLayer.backgroundColor = nil
|
||||||
self.backgroundColor = nil
|
self.backgroundColor = nil
|
||||||
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
||||||
@ -953,11 +970,6 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
|||||||
if invertPattern {
|
if invertPattern {
|
||||||
patternColor = .clear
|
patternColor = .clear
|
||||||
patternBackgroundColor = .clear
|
patternBackgroundColor = .clear
|
||||||
if self.patternImageLayer.contents == nil {
|
|
||||||
self.patternImageLayer.backgroundColor = UIColor.black.cgColor
|
|
||||||
} else {
|
|
||||||
self.patternImageLayer.backgroundColor = nil
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if patternIsLight {
|
if patternIsLight {
|
||||||
patternColor = .black
|
patternColor = .black
|
||||||
|
Loading…
x
Reference in New Issue
Block a user