chore: migrate to new version + fixed several critical bugs

- Migrated project to latest Telegram iOS base (v12.3.2+)
- Fixed circular dependency between GhostModeManager and MiscSettingsManager
- Fixed multiple Bazel build configuration errors (select() default conditions)
- Fixed duplicate type definitions in PeerInfoScreen
- Fixed swiftmodule directory resolution in build scripts
- Added Ghostgram Settings tab in main Settings menu with all 5 features
- Cleared sensitive credentials from config.json (template-only now)
- Excluded bazel-cache from version control
This commit is contained in:
ichmagmaus 812
2026-02-23 23:04:32 +01:00
parent 703e291bcb
commit db53826061
1017 changed files with 62337 additions and 40559 deletions
+2
View File
@@ -44,6 +44,8 @@ swift_library(
"//submodules/TelegramUI/Components/MinimizedContainer",
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
"//submodules/TelegramUI/Components/EdgeEffect",
"//submodules/TelegramUI/Components/LiquidLens",
"//submodules/TelegramUI/Components/TabSelectionRecognizer",
],
visibility = [
"//visibility:public",
@@ -24,6 +24,8 @@ import LegacyMessageInputPanelInputView
import ReactionSelectionNode
import TopMessageReactions
import GlassBackgroundComponent
import LiquidLens
import TabSelectionRecognizer
private let legacyButtonSize = CGSize(width: 88.0, height: 49.0)
private let glassButtonSize = CGSize(width: 72.0, height: 62.0)
@@ -887,7 +889,7 @@ private final class MainButtonNode: HighlightTrackingButtonNode {
}
}
final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDelegate {
enum Style {
case glass
case legacy
@@ -912,12 +914,22 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
private let containerNode: ASDisplayNode
private var backgroundView: GlassBackgroundView?
private var liquidLensView: LiquidLensView?
private let backgroundNode: NavigationBackgroundNode
private let scrollNode: ASScrollNode
private let separatorNode: ASDisplayNode
private let selectionNode: ASImageNode
private var buttonViews: [AnyHashable: ComponentHostView<Empty>] = [:]
private var itemsContainer = UIView()
private var itemViews: [AnyHashable: ComponentHostView<Empty>] = [:]
private var selectedItemsContainer = UIView()
private var selectedItemViews: [AnyHashable: ComponentHostView<Empty>] = [:]
private var itemSizes: [AnyHashable: CGSize] = [:]
private var tabSelectionRecognizer: TabSelectionRecognizer?
private var selectionGestureState: (startX: CGFloat, currentX: CGFloat, itemId: AnyHashable, isLifted: Bool)?
private var lensIsLifted = false
private var textInputPanelNode: AttachmentTextInputPanelNode?
private var progressNode: LoadingProgressNode?
@@ -971,7 +983,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
self.makeEntityInputView = makeEntityInputView
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: chatLocation ?? .peer(id: context.account.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil)
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: chatLocation ?? .peer(id: context.account.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil)
self.containerNode = ASDisplayNode()
self.containerNode.clipsToBounds = false
@@ -987,7 +999,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
self.mainButtonNode = MainButtonNode()
self.secondaryButtonNode = MainButtonNode()
super.init()
self.addSubnode(self.containerNode)
@@ -995,7 +1007,6 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
switch style {
case .glass:
self.scrollNode.cornerRadius = glassButtonSize.height * 0.5
self.scrollNode.addSubnode(self.selectionNode)
case .legacy:
self.containerNode.addSubnode(self.backgroundNode)
self.containerNode.addSubnode(self.separatorNode)
@@ -1135,7 +1146,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
}
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text?.string ?? "", link: link, apply: { [weak self] link in
let controller = chatTextLinkEditController(context: strongSelf.context, updatedPresentationData: (presentationData, .never()), text: text?.string ?? "", link: link, apply: { [weak self] link in
if let strongSelf = self, let inputMode = inputMode, let selectionRange = selectionRange {
if let link = link {
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
@@ -1419,6 +1430,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
self.view.accessibilityTraits = .tabBar
}
func requestLayout(transition: ContainedViewLayoutTransition) {
if let layout = self.validLayout {
let _ = self.update(layout: layout, buttons: self.buttons, isSelecting: self.isSelecting, selectionCount: self.selectionCount, elevateProgress: self.elevateProgress, transition: transition)
}
}
@objc private func mainButtonPressed() {
self.onMainButtonPressed()
}
@@ -1473,6 +1490,105 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
}
}
private func item(at point: CGPoint) -> AnyHashable? {
let contentOffset = self.scrollNode.view.contentOffset.x
let point = point.offsetBy(dx: contentOffset, dy: 0.0)
var closestItem: (AnyHashable, CGFloat)?
for (id, itemView) in self.itemViews {
if itemView.frame.contains(point) {
return id
} else {
let distance = abs(point.x - itemView.center.x)
if let closestItemValue = closestItem {
if closestItemValue.1 > distance {
closestItem = (id, distance)
}
} else {
closestItem = (id, distance)
}
}
}
return closestItem?.0
}
@objc private func onTabSelectionGesture(_ recognizer: TabSelectionRecognizer) {
guard let liquidLensView = self.liquidLensView else {
return
}
let location = recognizer.location(in: liquidLensView.contentView)
switch recognizer.state {
case .began:
if let itemId = self.item(at: location), let itemView = self.itemViews[itemId] {
let startX = itemView.frame.minX
self.selectionGestureState = (startX, startX, itemId, !self.scrollNode.view.isScrollEnabled)
self.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
}
case .changed:
if var selectionGestureState = self.selectionGestureState {
selectionGestureState.currentX = selectionGestureState.startX + recognizer.translation(in: self.view).x
if let itemId = self.item(at: location) {
selectionGestureState.itemId = itemId
}
self.selectionGestureState = selectionGestureState
self.requestLayout(transition: .immediate)
}
case .ended, .cancelled:
if let selectionGestureState = self.selectionGestureState {
if !selectionGestureState.isLifted {
self.lensIsLifted = true
self.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
self.liquidLensView?.clipsToBounds = false
Queue.mainQueue().after(0.1, {
self.lensIsLifted = false
self.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
Queue.mainQueue().after(0.4, {
self.liquidLensView?.clipsToBounds = true
})
})
}
self.selectionGestureState = nil
if case .ended = recognizer.state {
guard let index = self.buttons.firstIndex(where: { AnyHashable($0.key) == selectionGestureState.itemId }) else {
return
}
let button = self.buttons[index]
self.skipLensUpdate = true
if self.selectionChanged(button) {
self.selectedIndex = index
if self.buttons.count > 5, let button = self.itemViews[button.key] {
let transition = ComponentTransition.spring(duration: 0.4)
let scrollView = self.scrollNode.view
let targetRect = button.frame.insetBy(dx: -35.0, dy: 0.0)
var newBounds = scrollView.bounds
if targetRect.minX < scrollView.bounds.minX {
newBounds.origin.x = targetRect.minX
}
else if targetRect.maxX > scrollView.bounds.maxX {
newBounds.origin.x = targetRect.maxX - scrollView.bounds.width
}
let minX = 0.0
let maxX = scrollView.contentSize.width - scrollView.bounds.width
newBounds.origin.x = max(minX, min(newBounds.origin.x, maxX))
transition.setBounds(view: scrollView, bounds: newBounds)
self.updateItemContainers(contentOffset: newBounds.minX, transition: transition)
}
}
self.skipLensUpdate = false
}
self.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
}
default:
break
}
}
func updateViews(transition: ComponentTransition) {
guard let layout = self.validLayout else {
return
@@ -1486,18 +1602,16 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
case .legacy:
panelSideInset = 3.0
}
let visibleRect = self.scrollNode.bounds.insetBy(dx: -180.0, dy: 0.0)
var distanceBetweenNodes = floorToScreenPixels((width - panelSideInset * 2.0 - self.buttonSize.width) / CGFloat(max(1, self.buttons.count - 1)))
let internalWidth = distanceBetweenNodes * CGFloat(self.buttons.count - 1)
var buttonWidth = self.buttonSize.width
var leftNodeOriginX: CGFloat
var maxButtonsToFit = 6
var maxButtonsToFit = 5
switch self.panelStyle {
case .glass:
leftNodeOriginX = layout.safeInsets.left + 3.0 + buttonWidth / 2.0
if layout.size.width < 400.0 {
leftNodeOriginX = layout.safeInsets.left + buttonWidth / 2.0
if layout.size.width < 420.0 {
maxButtonsToFit = 5
}
case .legacy:
@@ -1513,7 +1627,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
buttonWidth = smallButtonWidth
distanceBetweenNodes = 60.0
}
leftNodeOriginX = layout.safeInsets.left + 3.0 + buttonWidth / 2.0
leftNodeOriginX = layout.safeInsets.left + buttonWidth / 2.0
}
var validIds = Set<AnyHashable>()
@@ -1521,25 +1635,28 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
var selectionFrame = CGRect()
var mostRightX = 0.0
for i in 0 ..< self.buttons.count {
let originX = floor(leftNodeOriginX + CGFloat(i) * distanceBetweenNodes - buttonWidth / 2.0)
let buttonFrame = CGRect(origin: CGPoint(x: originX, y: 0.0), size: CGSize(width: buttonWidth, height: self.buttonSize.height))
let originX = floorToScreenPixels(leftNodeOriginX + CGFloat(i) * distanceBetweenNodes - buttonWidth / 2.0)
let buttonFrame = CGRect(origin: CGPoint(x: originX, y: -3.0), size: CGSize(width: buttonWidth, height: self.buttonSize.height))
mostRightX = buttonFrame.maxX
if !visibleRect.intersects(buttonFrame) {
continue
}
let type = self.buttons[i]
let _ = validIds.insert(type.key)
var buttonTransition = transition
let buttonView: ComponentHostView<Empty>
if let current = self.buttonViews[type.key] {
let selectedButtonView: ComponentHostView<Empty>
if let current = self.itemViews[type.key], let currentSelected = self.selectedItemViews[type.key] {
buttonView = current
selectedButtonView = currentSelected
} else {
buttonTransition = .immediate
buttonView = ComponentHostView<Empty>()
self.buttonViews[type.key] = buttonView
self.scrollNode.view.addSubview(buttonView)
self.itemViews[type.key] = buttonView
self.itemsContainer.addSubview(buttonView)
selectedButtonView = ComponentHostView<Empty>()
self.selectedItemViews[type.key] = selectedButtonView
self.selectedItemsContainer.addSubview(selectedButtonView)
}
if case let .app(bot) = type {
@@ -1578,7 +1695,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
style: self.panelStyle == .glass ? .glass : .legacy,
type: type,
isFirstOrLast: i == 0 || i == self.buttons.count - 1,
isSelected: i == self.selectedIndex,
isSelected: false,
strings: self.presentationData.strings,
theme: self.presentationData.theme,
action: { [weak self] in
@@ -1587,7 +1704,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
strongSelf.selectedIndex = i
strongSelf.updateViews(transition: .init(animation: .curve(duration: 0.2, curve: .spring)))
if strongSelf.buttons.count > 5, let button = strongSelf.buttonViews[type.key] {
if strongSelf.buttons.count > 5, let button = strongSelf.itemViews[type.key] {
strongSelf.scrollNode.view.scrollRectToVisible(button.frame.insetBy(dx: -35.0, dy: 0.0), animated: true)
}
}
@@ -1601,11 +1718,32 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
environment: {},
containerSize: CGSize(width: buttonWidth, height: self.buttonSize.height)
)
self.itemSizes[type.key] = actualButtonSize
let _ = selectedButtonView.update(
transition: buttonTransition,
component: AnyComponent(AttachButtonComponent(
context: self.context,
style: self.panelStyle == .glass ? .glass : .legacy,
type: type,
isFirstOrLast: i == 0 || i == self.buttons.count - 1,
isSelected: true,
strings: self.presentationData.strings,
theme: self.presentationData.theme,
action: {
},
longPressAction: {
})
),
environment: {},
containerSize: CGSize(width: buttonWidth, height: self.buttonSize.height)
)
if i == self.selectedIndex {
selectionFrame = CGRect(origin: CGPoint(x: buttonFrame.midX - actualButtonSize.width * 0.5, y: buttonFrame.minY), size: actualButtonSize)
}
buttonTransition.setFrame(view: buttonView, frame: buttonFrame)
buttonTransition.setFrame(view: selectedButtonView, frame: buttonFrame)
var accessibilityTitle = ""
switch type {
case .gallery:
@@ -1634,14 +1772,14 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
buttonView.accessibilityTraits = [.button]
}
var removeIds: [AnyHashable] = []
for (id, itemView) in self.buttonViews {
for (id, itemView) in self.itemViews {
if !validIds.contains(id) {
removeIds.append(id)
itemView.removeFromSuperview()
}
}
for id in removeIds {
self.buttonViews.removeValue(forKey: id)
self.itemViews.removeValue(forKey: id)
}
selectionFrame = selectionFrame.insetBy(dx: 1.0, dy: 4.0)
@@ -1651,9 +1789,10 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
mostRightX += layout.safeInsets.right + 3.0
let contentSize = CGSize(width: mostRightX, height: self.buttonSize.height)
if contentSize != self.scrollNode.view.contentSize {
if contentSize != self.scrollNode.view.contentSize && self.scrollNode.view.bounds.width > 0.0 {
self.scrollNode.view.contentSize = contentSize
self.scrollNode.view.isScrollEnabled = abs(contentSize.width - self.scrollNode.view.bounds.width) > 1.0
self.scrollNode.view.isScrollEnabled = contentSize.width - self.scrollNode.view.bounds.width > 1.0
self.liquidLensView?.clipsToBounds = self.scrollNode.view.isScrollEnabled
}
}
@@ -1916,31 +2055,65 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
textPanelWidth = layout.size.width - panelSideInset * 2.0
}
self.updateViews(transition: .immediate)
let glassPanelHeight: CGFloat = 62.0
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: self.buttonSize.height + insets.bottom))
if case .glass = self.panelStyle {
let backgroundView: GlassBackgroundView
if let current = self.backgroundView {
backgroundView = current
let liquidLensView: LiquidLensView
if let currentBackground = self.backgroundView, let currentLens = self.liquidLensView {
backgroundView = currentBackground
liquidLensView = currentLens
} else {
backgroundView = GlassBackgroundView()
self.containerNode.view.addSubview(backgroundView)
self.containerNode.view.addSubview(self.scrollNode.view)
self.backgroundView = backgroundView
liquidLensView = LiquidLensView(kind: .noContainer)
liquidLensView.clipsToBounds = true
liquidLensView.layer.cornerRadius = 28.0
self.containerNode.view.addSubview(backgroundView)
self.containerNode.view.addSubview(liquidLensView)
self.containerNode.view.addSubview(self.scrollNode.view)
self.liquidLensView = liquidLensView
liquidLensView.contentView.addSubview(self.itemsContainer)
liquidLensView.selectedContentView.addSubview(self.selectedItemsContainer)
self.itemsContainer.clipsToBounds = true
self.itemsContainer.layer.cornerRadius = 28.0
self.selectedItemsContainer.clipsToBounds = true
self.selectedItemsContainer.layer.cornerRadius = 28.0
let tabSelectionRecognizer = TabSelectionRecognizer(target: self, action: #selector(self.onTabSelectionGesture(_:)))
tabSelectionRecognizer.delegate = self.wrappedGestureRecognizerDelegate
self.tabSelectionRecognizer = tabSelectionRecognizer
self.scrollNode.view.addGestureRecognizer(tabSelectionRecognizer)
}
let panelSize = CGSize(width: isSelecting ? textPanelWidth : layout.size.width - layout.safeInsets.left - layout.safeInsets.right - panelSideInset * 2.0, height: isSelecting ? textPanelHeight - 11.0 : glassPanelHeight)
let backgroundViewColor: UIColor
if self.presentationData.theme.overallDarkAppearance {
backgroundViewColor = self.presentationData.theme.list.modalBlocksBackgroundColor.withAlphaComponent(0.55)
} else {
backgroundViewColor = self.presentationData.theme.list.plainBackgroundColor.withAlphaComponent(0.75)
}
let cornerRadius: CGFloat = isSelecting ? min(20.0, panelSize.height * 0.5) : panelSize.height * 0.5
let backgroundOriginX: CGFloat = isSelecting ? panelSideInset : floorToScreenPixels((layout.size.width - panelSize.width) / 2.0)
backgroundView.update(size: panelSize, cornerRadius: isSelecting ? 20.0 : glassPanelHeight * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .custom, color: backgroundViewColor), transition: ComponentTransition(transition))
backgroundView.update(size: panelSize, cornerRadius: cornerRadius, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: self.presentationData.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: ComponentTransition(transition))
let lensSideInset: CGFloat = defaultPanelSideInset + layout.safeInsets.left
let lensPanelSize = CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - lensSideInset * 2.0, height: glassPanelHeight)
self.lensParams = (lensPanelSize, cornerRadius)
self.updateLiquidLens(transition: ComponentTransition(transition))
transition.updatePosition(layer: liquidLensView.layer, position: CGPoint(x: backgroundOriginX + panelSize.width * 0.5, y: panelSize.height * 0.5))
transition.updateBounds(layer: liquidLensView.layer, bounds: CGRect(origin: .zero, size: CGSize(width: lensPanelSize.width - 3.0 * 2.0, height: lensPanelSize.height - 3.0 * 2.0)))
transition.updatePosition(layer: backgroundView.layer, position: CGPoint(x: backgroundOriginX + panelSize.width * 0.5, y: panelSize.height * 0.5))
transition.updateBounds(layer: backgroundView.layer, bounds: CGRect(origin: .zero, size: panelSize))
let itemsContainerFrame = CGRect(origin: .zero, size: CGSize(width: lensPanelSize.width - 3.0 * 2.0, height: lensPanelSize.height - 3.0 * 2.0))
transition.updateBounds(layer: self.itemsContainer.layer, bounds: CGRect(origin: .zero, size: itemsContainerFrame.size))
transition.updateBounds(layer: self.selectedItemsContainer.layer, bounds: CGRect(origin: .zero, size: itemsContainerFrame.size))
transition.updatePosition(layer: self.itemsContainer.layer, position: itemsContainerFrame.center)
transition.updatePosition(layer: self.selectedItemsContainer.layer, position: itemsContainerFrame.center)
}
var containerTransition: ContainedViewLayoutTransition
@@ -2002,8 +2175,10 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
let alphaTransition = ContainedViewLayoutTransition.animated(duration: isSelecting ? 0.1 : 0.25, curve: .easeInOut)
alphaTransition.updateAlpha(node: self.scrollNode, alpha: isSelecting || isAnyButtonVisible ? 0.0 : 1.0)
containerTransition.updateTransformScale(node: self.scrollNode, scale: isSelecting || isAnyButtonVisible ? 0.85 : 1.0)
if let backgroundView = self.backgroundView {
containerTransition.updateTransformScale(layer: backgroundView.layer, scale: isAnyButtonVisible ? 0.85 : 1.0)
if let liquidLensView = self.liquidLensView {
alphaTransition.updateAlpha(layer: liquidLensView.layer, alpha: isSelecting || isAnyButtonVisible ? 0.0 : 1.0)
containerTransition.updateTransformScale(layer: liquidLensView.layer, scale: isSelecting || isAnyButtonVisible ? 0.85 : 1.0)
}
if isSelectingUpdated {
@@ -2022,7 +2197,10 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
alphaTransition.updateAlpha(node: textInputPanelNode, alpha: 1.0)
let componentTransition = ComponentTransition.easeInOut(duration: 0.25)
componentTransition.animateBlur(layer: self.scrollNode.layer, fromRadius: 0.0, toRadius: 10.0)
if let liquidLensView = self.liquidLensView {
componentTransition.animateBlur(layer: liquidLensView.layer, fromRadius: 0.0, toRadius: 10.0)
transition.animatePositionAdditive(layer: liquidLensView.layer, offset: .zero, to: CGPoint(x: -27.0, y: 0.0))
}
let blurTransition = ComponentTransition.easeInOut(duration: 0.18)
transition.animateTransformScale(node: textInputPanelNode.opaqueActionButtons, from: 0.01)
@@ -2030,9 +2208,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
textInputPanelNode.opaqueActionButtons.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
transition.animatePosition(node: textInputPanelNode.opaqueActionButtons, from: CGPoint(x: textInputPanelNode.opaqueActionButtons.position.x, y: textInputPanelNode.opaqueActionButtons.position.y + heightDelta))
blurTransition.animateBlur(layer: textInputPanelNode.inputModeView.layer, fromRadius: 4.0, toRadius: 0.0)
componentTransition.animateAlpha(view: textInputPanelNode.inputModeView, from: 0.0, to: 1.0)
transition.animatePositionAdditive(layer: textInputPanelNode.textPlaceholderNode.layer, offset: CGPoint(x: 6.0, y: heightDelta))
transition.animatePositionAdditive(layer: textInputPanelNode.inputModeView.layer, offset: CGPoint(x: 64.0, y: heightDelta))
textInputPanelNode.animateIn(transition: transition)
} else {
textInputPanelNode.alpha = 1.0
@@ -2054,7 +2235,10 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
alphaTransition.updateAlpha(node: textInputPanelNode, alpha: 0.0)
let componentTransition = ComponentTransition.easeInOut(duration: 0.25)
componentTransition.animateBlur(layer: self.scrollNode.layer, fromRadius: 10.0, toRadius: 0.0)
if let liquidLensView = self.liquidLensView {
componentTransition.animateBlur(layer: liquidLensView.layer, fromRadius: 10.0, toRadius: 0.0)
transition.animatePositionAdditive(layer: liquidLensView.layer, offset: CGPoint(x: -27.0, y: 0.0))
}
let blurTransition = ComponentTransition.easeInOut(duration: 0.18)
transition.animateTransformScale(layer: textInputPanelNode.opaqueActionButtons.layer, from: CGPoint(x: 1.0, y: 1.0), to: CGPoint(x: 0.01, y: 0.01))
@@ -2062,6 +2246,9 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
textInputPanelNode.opaqueActionButtons.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
transition.animatePosition(node: textInputPanelNode.opaqueActionButtons, to: CGPoint(x: textInputPanelNode.opaqueActionButtons.position.x, y: textInputPanelNode.opaqueActionButtons.position.y + heightDelta))
blurTransition.animateBlur(layer: textInputPanelNode.inputModeView.layer, fromRadius: 0.0, toRadius: 4.0)
componentTransition.animateAlpha(view: textInputPanelNode.inputModeView, from: 1.0, to: 0.0)
transition.animatePositionAdditive(layer: textInputPanelNode.textPlaceholderNode.layer, offset: .zero, to: CGPoint(x: 6.0, y: heightDelta))
transition.animatePositionAdditive(layer: textInputPanelNode.inputModeView.layer, offset: .zero, to: CGPoint(x: 64.0, y: heightDelta))
} else {
@@ -2086,8 +2273,6 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
transition.updateFrameAsPositionAndBounds(node: self.scrollNode, frame: CGRect(origin: CGPoint(x: self.isSelecting ? panelSideInset - defaultPanelSideInset : panelSideInset, y: self.isSelecting ? -11.0 : 0.0), size: CGSize(width: layout.size.width - panelSideInset * 2.0, height: self.buttonSize.height)))
}
self.updateViews(transition: .immediate)
if let progress = self.loadingProgress {
let loadingProgressNode: LoadingProgressNode
if let current = self.progressNode {
@@ -2183,8 +2368,70 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
return containerFrame.height
}
func updateItemContainers(contentOffset: CGFloat, transition: ComponentTransition) {
let transform = CATransform3DMakeTranslation(-contentOffset, 0.0, 0.0)
transition.setSublayerTransform(view: self.itemsContainer, transform: transform)
transition.setSublayerTransform(view: self.selectedItemsContainer, transform: transform)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if self.selectionGestureState != nil {
self.selectionGestureState = nil
self.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.updateItemContainers(contentOffset: scrollView.contentOffset.x, transition: .immediate)
self.updateViews(transition: .immediate)
self.updateLiquidLens(transition: .immediate)
}
private var skipLensUpdate = false
private var lensParams: (panelSize: CGSize, cornerRadius: CGFloat)?
func updateLiquidLens(transition: ComponentTransition) {
guard !self.skipLensUpdate, let liquidLensView = self.liquidLensView, let (panelSize, _) = self.lensParams else {
return
}
var selectionFrame = CGRect()
if self.selectedIndex >= 0 && self.selectedIndex < self.buttons.count, let itemView = self.itemViews[self.buttons[self.selectedIndex].key], let itemSize = self.itemSizes[self.buttons[self.selectedIndex].key] {
let contentOffset = self.scrollNode.view.contentOffset.x
selectionFrame = CGRect(origin: CGPoint(x: itemView.center.x - itemSize.width / 2.0 - contentOffset, y: itemView.frame.minY), size: itemSize)
}
var lensSelection: (x: CGFloat, width: CGFloat)
if let selectionGestureState = self.selectionGestureState, selectionGestureState.isLifted {
lensSelection = (selectionGestureState.currentX, selectionFrame.width)
} else {
lensSelection = (selectionFrame.minX, selectionFrame.width)
}
if !self.scrollNode.view.isScrollEnabled {
lensSelection.x = max(0.0, min(lensSelection.x, panelSize.width - lensSelection.width))
}
var isLifted = self.selectionGestureState?.isLifted == true || self.lensIsLifted
if let widthClass = self.validLayout?.metrics.widthClass, case .regular = widthClass {
isLifted = false
}
let inset: CGFloat = 3.0
liquidLensView.update(size: CGSize(width: panelSize.width - inset * 2.0, height: panelSize.height - inset * 2.0), cornerRadius: 28.0, selectionOrigin: CGPoint(x: lensSelection.x, y: 0.0), selectionSize: CGSize(width: lensSelection.width, height: panelSize.height - inset * 2.0), inset: 0.0, isDark: self.presentationData.theme.overallDarkAppearance, isLifted: isLifted, isCollapsed: self.isSelecting || self.buttons.count < 2, transition: transition)
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == self.tabSelectionRecognizer {
return true
}
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}