This commit is contained in:
Isaac
2025-10-31 17:51:37 +04:00
parent 0e5337636d
commit 5145b9e605
23 changed files with 1515 additions and 1013 deletions

View File

@@ -332,8 +332,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
private let hapticFeedback = HapticFeedback()
private var currentInputHasText: Bool = false
public var inputTextState: ChatTextInputState {
if let textInputNode = self.textInputNode {
let selectionRange: Range<Int> = textInputNode.selectedRange.location ..< (textInputNode.selectedRange.location + textInputNode.selectedRange.length)
@@ -1517,16 +1515,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
if let textInputNode = self.textInputNode, let attributedText = textInputNode.attributedText, attributedText.length != 0 {
inputHasText = true
}
let inputHadText = self.currentInputHasText
self.currentInputHasText = inputHasText
var useBounceAnimation = inputHasText && !inputHadText
if accessoryPanel != nil || self.accessoryPanel != nil {
useBounceAnimation = false
}
if !self.enableBounceAnimations {
useBounceAnimation = false
}
var hasMenuButton = false
var menuButtonExpanded = false
@@ -2728,10 +2716,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.updateCounterTextNode(backgroundSize: textInputContainerBackgroundFrame.size, transition: transition)
var textInputContainerBackgroundTransition = ComponentTransition(transition)
if useBounceAnimation, case let .animated(_, curve) = transition, case .spring = curve {
textInputContainerBackgroundTransition = textInputContainerBackgroundTransition.withUserData(GlassBackgroundView.TransitionFlagBounce())
}
let textInputContainerBackgroundTransition = ComponentTransition(transition)
self.textInputContainerBackgroundView.update(size: textInputContainerBackgroundFrame.size, cornerRadius: floor(minimalInputHeight * 0.5), isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), isInteractive: true, transition: textInputContainerBackgroundTransition)
transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: textInputContainerBackgroundFrame)
@@ -3018,7 +3003,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
if starReactionButtonView.superview == nil {
self.glassBackgroundContainer.contentView.addSubview(starReactionButtonView)
self.view.addSubview(starReactionButtonView)
if transition.isAnimated {
starReactionButtonView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
transition.animateTransformScale(view: starReactionButtonView, from: 0.001)
@@ -3038,13 +3023,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
sendActionButtonsFrame.origin.x += (sendActionButtonsSize.width - 3.0 * 2.0) * 0.5 - 3.0
}
if useBounceAnimation, case let .animated(duration, curve) = transition, case .spring = curve {
ContainedViewLayoutTransition.animated(duration: duration, curve: curve).updateScaleSpring(layer: self.sendActionButtons.layer, scale: sendActionsScale)
ContainedViewLayoutTransition.animated(duration: duration, curve: curve).updatePositionSpring(layer: self.sendActionButtons.layer, position: sendActionButtonsFrame.center)
} else {
transition.updateTransformScale(node: self.sendActionButtons, scale: CGPoint(x: sendActionsScale, y: sendActionsScale))
transition.updatePosition(node: self.sendActionButtons, position: sendActionButtonsFrame.center)
}
transition.updateTransformScale(node: self.sendActionButtons, scale: CGPoint(x: sendActionsScale, y: sendActionsScale))
transition.updatePosition(node: self.sendActionButtons, position: sendActionButtonsFrame.center)
transition.updateBounds(node: self.sendActionButtons, bounds: CGRect(origin: CGPoint(), size: sendActionButtonsFrame.size))
if let (rect, containerSize) = self.absoluteRect {
self.sendActionButtons.updateAbsoluteRect(CGRect(x: rect.origin.x + sendActionButtonsFrame.origin.x, y: rect.origin.y + sendActionButtonsFrame.origin.y, width: sendActionButtonsFrame.width, height: sendActionButtonsFrame.height), within: containerSize, transition: transition)

View File

@@ -73,7 +73,7 @@ final class StarReactionButtonBadgeComponent: Component {
containerSize: CGSize(width: 100.0, height: 100.0)
)
let size = CGSize(width: textSize.width + sideInset * 2.0, height: height)
let size = CGSize(width: max(height, textSize.width + sideInset * 2.0), height: height)
let backgroundFrame = CGRect(origin: CGPoint(), size: size)
let backgroundTintColor: GlassBackgroundView.TintColor
@@ -86,7 +86,7 @@ final class StarReactionButtonBadgeComponent: Component {
self.backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: component.theme.overallDarkAppearance, tintColor: backgroundTintColor, isInteractive: true, transition: transition)
if let textView = self.text.view {
let textFrame = textSize.centered(in: CGRect(origin: CGPoint(), size: size))
let textFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundFrame.width - textSize.width) * 0.5), y: floorToScreenPixels((backgroundFrame.height - textSize.height) * 0.5)), size: textSize)
if textView.superview == nil {
textView.isUserInteractionEnabled = false
@@ -147,10 +147,11 @@ final class StarReactionButtonComponent: Component {
}
final class View: UIView {
private let containerView: UIView
private let backgroundView: GlassBackgroundView
private let backgroundEffectLayer: StarsParticleEffectLayer
private let backgroundMaskView: UIView
private let backgroundBadgeMask: UIImageView
private var backgroundBadgeMask: UIImageView?
private let iconView: UIImageView
private var badge: ComponentView<Empty>?
@@ -160,15 +161,14 @@ final class StarReactionButtonComponent: Component {
private weak var state: EmptyComponentState?
override init(frame: CGRect) {
self.containerView = UIView()
self.backgroundView = GlassBackgroundView()
self.backgroundMaskView = UIView()
self.backgroundBadgeMask = UIImageView()
self.backgroundMaskView.addSubview(self.backgroundBadgeMask)
self.backgroundEffectLayer = StarsParticleEffectLayer()
self.backgroundView.contentView.layer.addSublayer(self.backgroundEffectLayer)
//self.backgroundView.mask = self.backgroundMaskView
self.backgroundView.mask = self.backgroundMaskView
self.backgroundMaskView.backgroundColor = .white
if let filter = CALayer.luminanceToAlpha() {
@@ -179,13 +179,31 @@ final class StarReactionButtonComponent: Component {
super.init(frame: frame)
self.addSubview(self.backgroundView)
self.addSubview(self.containerView)
self.containerView.addSubview(self.backgroundView)
self.backgroundView.contentView.addSubview(self.iconView)
let longTapRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.longTapAction(_:)))
longTapRecognizer.tapActionAtPoint = { _ in
return .waitForSingleTap
}
longTapRecognizer.highlight = { [weak self] point in
guard let self else {
return
}
let currentTransform: CATransform3D
if self.containerView.layer.animation(forKey: "transform") != nil || self.containerView.layer.animation(forKey: "transform.scale") != nil {
currentTransform = self.containerView.layer.presentation()?.transform ?? layer.transform
} else {
currentTransform = self.containerView.layer.transform
}
let currentScale = sqrt((currentTransform.m11 * currentTransform.m11) + (currentTransform.m12 * currentTransform.m12) + (currentTransform.m13 * currentTransform.m13))
let updatedScale: CGFloat = point != nil ? 1.35 : 1.0
self.containerView.layer.transform = CATransform3DMakeScale(updatedScale, updatedScale, 1.0)
self.containerView.layer.animateSpring(from: currentScale as NSNumber, to: updatedScale as NSNumber, keyPath: "transform.scale", duration: point != nil ? 0.4 : 0.8, damping: 70.0)
}
self.longTapRecognizer = longTapRecognizer
self.backgroundView.contentView.addGestureRecognizer(longTapRecognizer)
}
@@ -213,6 +231,7 @@ final class StarReactionButtonComponent: Component {
}
func update(component: StarReactionButtonComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
let previousComponent = self.component
self.component = component
self.state = state
@@ -232,6 +251,15 @@ final class StarReactionButtonComponent: Component {
badge = ComponentView()
self.badge = badge
}
let backgroundBadgeMask: UIImageView
if let current = self.backgroundBadgeMask {
backgroundBadgeMask = current
} else {
backgroundBadgeMask = UIImageView()
self.backgroundBadgeMask = backgroundBadgeMask
}
let badgeSize = badge.update(
transition: badgeTransition,
component: AnyComponent(StarReactionButtonBadgeComponent(
@@ -250,19 +278,54 @@ final class StarReactionButtonComponent: Component {
if badgeView.superview == nil {
badgeView.isUserInteractionEnabled = false
self.backgroundView.contentView.addSubview(badgeView)
self.containerView.addSubview(badgeView)
badgeView.frame = badgeFrame
transition.animateScale(view: badgeView, from: 0.001, to: 1.0)
transition.animateAlpha(view: badgeView, from: 0.0, to: 1.0)
}
transition.setFrame(view: badgeView, frame: badgeFrame)
let badgeBorderWidth: CGFloat = 1.0
if backgroundBadgeMask.image?.size.height != (badgeFrame.height + badgeBorderWidth * 2.0) {
backgroundBadgeMask.image = generateStretchableFilledCircleImage(diameter: badgeFrame.height + badgeBorderWidth * 2.0, color: .black)
}
let backgroundBadgeFrame = badgeFrame.insetBy(dx: -badgeBorderWidth, dy: -badgeBorderWidth)
if backgroundBadgeMask.superview == nil {
self.backgroundMaskView.addSubview(backgroundBadgeMask)
backgroundBadgeMask.frame = backgroundBadgeFrame
transition.animateScale(view: backgroundBadgeMask, from: 0.001, to: 1.0)
transition.animateAlpha(view: backgroundBadgeMask, from: 0.0, to: 1.0)
}
transition.setFrame(view: backgroundBadgeMask, frame: backgroundBadgeFrame)
}
} else if let badge = self.badge {
self.badge = nil
if let badgeView = badge.view {
transition.setScale(view: badgeView, scale: 0.001)
transition.setAlpha(view: badgeView, alpha: 0.0, completion: { [weak badgeView] _ in
badgeView?.removeFromSuperview()
} else {
if let badge = self.badge {
if let previousComponent {
let _ = badge.update(
transition: transition,
component: AnyComponent(StarReactionButtonBadgeComponent(
theme: component.theme,
count: previousComponent.count,
isFilled: previousComponent.isFilled
)),
environment: {},
containerSize: CGSize(width: 100.0, height: 100.0)
)
}
self.badge = nil
if let badgeView = badge.view {
transition.setScale(view: badgeView, scale: 0.001)
transition.setAlpha(view: badgeView, alpha: 0.0, completion: { [weak badgeView] _ in
badgeView?.removeFromSuperview()
})
}
}
if let backgroundBadgeMask = self.backgroundBadgeMask {
self.backgroundBadgeMask = nil
transition.setScale(view: backgroundBadgeMask, scale: 0.001)
transition.setAlpha(view: backgroundBadgeMask, alpha: 0.0, completion: { [weak backgroundBadgeMask] _ in
backgroundBadgeMask?.removeFromSuperview()
})
}
}
@@ -276,21 +339,13 @@ final class StarReactionButtonComponent: Component {
backgroundTintColor = .init(kind: .panel, color: component.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
}
self.backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: component.theme.overallDarkAppearance, tintColor: backgroundTintColor, isInteractive: true, transition: transition)
self.backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: component.theme.overallDarkAppearance, tintColor: backgroundTintColor, isInteractive: false, transition: transition)
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
transition.setFrame(view: self.backgroundMaskView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
transition.setFrame(layer: self.backgroundEffectLayer, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
self.backgroundEffectLayer.update(color: UIColor(white: 1.0, alpha: 0.25), rate: 10.0, size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, transition: transition)
let badgeDiameter: CGFloat = 15.0
if self.backgroundBadgeMask.image == nil {
self.backgroundBadgeMask.image = generateStretchableFilledCircleImage(diameter: badgeDiameter + 1.0 * 2.0, color: .black)
}
let badgeWidth: CGFloat = 20.0
let badgeFrame = CGRect(origin: CGPoint(x: backgroundFrame.width - badgeWidth, y: 0.0), size: CGSize(width: badgeWidth, height: badgeDiameter))
transition.setFrame(view: self.backgroundBadgeMask, frame: badgeFrame.insetBy(dx: -1.0, dy: -1.0))
self.iconView.tintColor = component.theme.chat.inputPanel.panelControlColor
if let image = self.iconView.image {
@@ -298,6 +353,9 @@ final class StarReactionButtonComponent: Component {
transition.setFrame(view: self.iconView, frame: iconFrame)
}
transition.setPosition(view: self.containerView, position: CGPoint(x: size.width * 0.5, y: size.height * 0.5))
transition.setBounds(view: self.containerView, bounds: CGRect(origin: CGPoint(), size: size))
return size
}
}