Various fixes

This commit is contained in:
Ilya Laktyushin 2025-02-28 22:43:33 +04:00
parent d62c37adf1
commit 3fb73a8b95
6 changed files with 176 additions and 91 deletions

View File

@ -885,13 +885,7 @@ struct PremiumIntroConfiguration {
if perks.count < 4 { if perks.count < 4 {
perks = PremiumIntroConfiguration.defaultValue.perks perks = PremiumIntroConfiguration.defaultValue.perks
} }
#if DEBUG
if !perks.contains(.paidMessages) {
perks.append(.paidMessages)
}
#endif
var businessPerks: [PremiumPerk] = [] var businessPerks: [PremiumPerk] = []
if let values = data["business_promo_order"] as? [String] { if let values = data["business_promo_order"] as? [String] {
for value in values { for value in values {

View File

@ -356,7 +356,7 @@ public func incomingMessagePrivacyScreen(context: AccountContext, value: GlobalP
}, },
openPremiumInfo: { openPremiumInfo: {
var replaceImpl: ((ViewController) -> Void)? var replaceImpl: ((ViewController) -> Void)?
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .paidMessages, forceDark: false, action: { let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .messagePrivacy, forceDark: false, action: {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .paidMessages, forceDark: false, dismissed: nil) let controller = context.sharedContext.makePremiumIntroController(context: context, source: .paidMessages, forceDark: false, dismissed: nil)
replaceImpl?(controller) replaceImpl?(controller)
}, dismissed: nil) }, dismissed: nil)

View File

@ -219,11 +219,14 @@ public final class ChatUserInfoItemNode: ListViewItemNode, ASGestureRecognizerDe
} }
public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let location = gestureRecognizer.location(in: self.offsetContainer.view) if gestureRecognizer.view === self.offsetContainer.view {
if let backgroundContent = self.backgroundContent, backgroundContent.frame.contains(location) { let location = gestureRecognizer.location(in: self.offsetContainer.view)
return true if let backgroundContent = self.backgroundContent, backgroundContent.frame.contains(location) {
return true
}
return false
} }
return false return true
} }
@objc private func tapGesture(_ gestureRecognizer: UITapGestureRecognizer) { @objc private func tapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
@ -366,7 +369,7 @@ public final class ChatUserInfoItemNode: ListViewItemNode, ASGestureRecognizerDe
var estimatedValueOffset: CGFloat = 0.0 var estimatedValueOffset: CGFloat = 0.0
if groupsInCommonCount > 0 { if groupsInCommonCount > 0 {
groupsValueText = NSMutableAttributedString(string: item.presentationData.strings.Chat_NonContactUser_GroupsCount(groupsInCommonCount), font: Font.semibold(13.0), textColor: primaryTextColor) groupsValueText = NSMutableAttributedString(string: item.presentationData.strings.Chat_NonContactUser_GroupsCount(groupsInCommonCount), font: Font.semibold(13.0), textColor: primaryTextColor)
estimatedValueOffset = avatarImageSize + CGFloat(min(2, max(0, item.groupsInCommonCount - 1))) * avatarSpacing + 4.0 estimatedValueOffset = avatarImageSize + CGFloat(min(2, max(0, item.groupsInCommonCount - 1))) * avatarSpacing + 4.0 + 10.0
} else { } else {
groupsValueText = NSMutableAttributedString(string: "", font: Font.semibold(13.0), textColor: primaryTextColor) groupsValueText = NSMutableAttributedString(string: "", font: Font.semibold(13.0), textColor: primaryTextColor)
} }
@ -380,7 +383,7 @@ public final class ChatUserInfoItemNode: ListViewItemNode, ASGestureRecognizerDe
backgroundSize.height += groupsValueLayoutAndApply?.0.size.height ?? 0.0 backgroundSize.height += groupsValueLayoutAndApply?.0.size.height ?? 0.0
maxTitleWidth = max(maxTitleWidth, groupsTitleLayoutAndApply?.0.size.width ?? 0) maxTitleWidth = max(maxTitleWidth, groupsTitleLayoutAndApply?.0.size.width ?? 0)
maxValueWidth = max(maxValueWidth, groupsValueLayoutAndApply?.0.size.width ?? 0 + estimatedValueOffset) maxValueWidth = max(maxValueWidth, (groupsValueLayoutAndApply?.0.size.width ?? 0) + estimatedValueOffset)
} else { } else {
groupsTitleLayoutAndApply = nil groupsTitleLayoutAndApply = nil
groupsValueLayoutAndApply = nil groupsValueLayoutAndApply = nil
@ -474,15 +477,15 @@ public final class ChatUserInfoItemNode: ListViewItemNode, ASGestureRecognizerDe
var attributeMidpoints: [CGFloat] = [] var attributeMidpoints: [CGFloat] = []
func appendAttributeMidpoint(titleLayout: TextNodeLayout?, valueLayout: TextNodeLayout?) { func appendAttributeMidpoint(titleLayout: TextNodeLayout?, valueLayout: TextNodeLayout?, valueOffset: CGFloat = 0.0) {
if let valueLayout { if let valueLayout {
let midpoint = backgroundSize.width - horizontalContentInset - valueLayout.size.width - attributeSpacing / 2.0 let midpoint = backgroundSize.width - horizontalContentInset - valueLayout.size.width - valueOffset - attributeSpacing / 2.0
attributeMidpoints.append(midpoint) attributeMidpoints.append(midpoint)
} }
} }
appendAttributeMidpoint(titleLayout: phoneCountryTitleLayoutAndApply?.0, valueLayout: phoneCountryValueLayoutAndApply?.0) appendAttributeMidpoint(titleLayout: phoneCountryTitleLayoutAndApply?.0, valueLayout: phoneCountryValueLayoutAndApply?.0)
appendAttributeMidpoint(titleLayout: registrationDateTitleLayoutAndApply?.0, valueLayout: registrationDateValueLayoutAndApply?.0) appendAttributeMidpoint(titleLayout: registrationDateTitleLayoutAndApply?.0, valueLayout: registrationDateValueLayoutAndApply?.0)
appendAttributeMidpoint(titleLayout: groupsTitleLayoutAndApply?.0, valueLayout: groupsValueLayoutAndApply?.0) appendAttributeMidpoint(titleLayout: groupsTitleLayoutAndApply?.0, valueLayout: groupsValueLayoutAndApply?.0, valueOffset: estimatedValueOffset)
let middleX = floorToScreenPixels(attributeMidpoints.min() ?? backgroundSize.width / 2.0) let middleX = floorToScreenPixels(attributeMidpoints.min() ?? backgroundSize.width / 2.0)

View File

@ -63,6 +63,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
public let context: AccountContext public let context: AccountContext
public let peerId: EnginePeer.Id public let peerId: EnginePeer.Id
public let giftsContext: ProfileGiftsContext public let giftsContext: ProfileGiftsContext
public let hasBackground: Bool
public let avatarCenter: CGPoint public let avatarCenter: CGPoint
public let avatarScale: CGFloat public let avatarScale: CGFloat
public let defaultHeight: CGFloat public let defaultHeight: CGFloat
@ -74,6 +75,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
context: AccountContext, context: AccountContext,
peerId: EnginePeer.Id, peerId: EnginePeer.Id,
giftsContext: ProfileGiftsContext, giftsContext: ProfileGiftsContext,
hasBackground: Bool,
avatarCenter: CGPoint, avatarCenter: CGPoint,
avatarScale: CGFloat, avatarScale: CGFloat,
defaultHeight: CGFloat, defaultHeight: CGFloat,
@ -84,6 +86,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
self.giftsContext = giftsContext self.giftsContext = giftsContext
self.hasBackground = hasBackground
self.avatarCenter = avatarCenter self.avatarCenter = avatarCenter
self.avatarScale = avatarScale self.avatarScale = avatarScale
self.defaultHeight = defaultHeight self.defaultHeight = defaultHeight
@ -99,6 +102,9 @@ public final class PeerInfoGiftsCoverComponent: Component {
if lhs.peerId != rhs.peerId { if lhs.peerId != rhs.peerId {
return false return false
} }
if lhs.hasBackground != rhs.hasBackground {
return false
}
if lhs.avatarCenter != rhs.avatarCenter { if lhs.avatarCenter != rhs.avatarCenter {
return false return false
} }
@ -202,11 +208,11 @@ public final class PeerInfoGiftsCoverComponent: Component {
avatarFrame: CGSize(width: 100, height: 100).centered(around: component.avatarCenter), avatarFrame: CGSize(width: 100, height: 100).centered(around: component.avatarCenter),
minDistance: 75.0, minDistance: 75.0,
maxDistance: availableSize.width / 2.0, maxDistance: availableSize.width / 2.0,
padding: 16.0, padding: 12.0,
seed: self.seed, seed: self.seed,
excludeRects: excludeRects excludeRects: excludeRects
) )
self.iconPositions = positionGenerator.generatePositions(count: 6, viewSize: iconSize) self.iconPositions = positionGenerator.generatePositions(count: 9, viewSize: iconSize)
} }
if self.giftsDisposable == nil { if self.giftsDisposable == nil {
@ -256,7 +262,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
var validIds = Set<AnyHashable>() var validIds = Set<AnyHashable>()
var index = 0 var index = 0
for gift in self.gifts.prefix(6) { for gift in self.gifts.prefix(9) {
let id: AnyHashable let id: AnyHashable
if case let .unique(uniqueGift) = gift.gift { if case let .unique(uniqueGift) = gift.gift {
id = uniqueGift.slug id = uniqueGift.slug
@ -270,7 +276,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
if let current = self.iconLayers[id] { if let current = self.iconLayers[id] {
iconLayer = current iconLayer = current
} else { } else {
iconLayer = GiftIconLayer(context: component.context, gift: gift, size: iconSize) iconLayer = GiftIconLayer(context: component.context, gift: gift, size: iconSize, glowing: component.hasBackground)
iconLayer.startHovering() iconLayer.startHovering()
self.iconLayers[id] = iconLayer self.iconLayers[id] = iconLayer
self.layer.addSublayer(iconLayer) self.layer.addSublayer(iconLayer)
@ -279,8 +285,8 @@ public final class PeerInfoGiftsCoverComponent: Component {
iconLayer.animateScale(from: 0.01, to: 1.0, duration: 0.2) iconLayer.animateScale(from: 0.01, to: 1.0, duration: 0.2)
} }
let zeroPosition = component.avatarCenter let centerPosition = component.avatarCenter
let finalPosition = iconPosition.center let finalPosition = iconPosition.center.offsetBy(dx: component.avatarCenter.x, dy: component.avatarCenter.y)
let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: 0.0, reverse: false) let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: 0.0, reverse: false)
func interpolateRect(from: CGPoint, to: CGPoint, t: CGFloat) -> CGPoint { func interpolateRect(from: CGPoint, to: CGPoint, t: CGFloat) -> CGPoint {
@ -295,7 +301,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
) )
} }
let effectivePosition = interpolateRect(from: finalPosition, to: zeroPosition, t: itemScaleFraction) let effectivePosition = interpolateRect(from: finalPosition, to: centerPosition, t: itemScaleFraction)
transition.setBounds(layer: iconLayer, bounds: CGRect(origin: .zero, size: iconSize)) transition.setBounds(layer: iconLayer, bounds: CGRect(origin: .zero, size: iconSize))
transition.setPosition(layer: iconLayer, position: effectivePosition) transition.setPosition(layer: iconLayer, position: effectivePosition)
@ -350,10 +356,10 @@ private class PositionGenerator {
init( init(
containerSize: CGSize, containerSize: CGSize,
avatarFrame: CGRect, avatarFrame: CGRect,
minDistance: CGFloat = 20, minDistance: CGFloat,
maxDistance: CGFloat = 100, maxDistance: CGFloat,
padding: CGFloat = 10, padding: CGFloat,
seed: UInt = UInt.random(in: 0 ..< 10), seed: UInt,
excludeRects: [CGRect] = [] excludeRects: [CGRect] = []
) { ) {
self.containerSize = containerSize self.containerSize = containerSize
@ -376,13 +382,13 @@ private class PositionGenerator {
let maxDist = distanceRanges[i].1 let maxDist = distanceRanges[i].1
let isEven = i % 2 == 0 let isEven = i % 2 == 0
// Try to generate a valid position with multiple attempts
var attempts = 0 var attempts = 0
let maxAttempts = 20 let maxAttempts = 20
var foundPosition = false
var currentMaxDist = maxDist var currentMaxDist = maxDist
while !foundPosition && attempts < maxAttempts { var result: CGPoint?
while result == nil && attempts < maxAttempts {
attempts += 1 attempts += 1
if let position = generateSinglePosition( if let position = generateSinglePosition(
@ -391,54 +397,55 @@ private class PositionGenerator {
maxDist: currentMaxDist, maxDist: currentMaxDist,
rightSide: !isEven rightSide: !isEven
) { ) {
// Skip distance check if this is the first position
let isFarEnough = positions.isEmpty || positions.allSatisfy { existingPosition in let isFarEnough = positions.isEmpty || positions.allSatisfy { existingPosition in
let distance = hypot(position.x - existingPosition.center.x, position.y - existingPosition.center.y) let distance = hypot(position.x - existingPosition.center.x, position.y - existingPosition.center.y)
return distance > (viewSize.width + padding) let minRequiredDistance = max(viewSize.width, viewSize.height) / 2 + max(viewSize.width, viewSize.height) / 2 + padding
return distance > minRequiredDistance
} }
let distance = hypot(position.x - self.avatarFrame.center.x, position.y - self.avatarFrame.center.y)
var scale = max(1.0, min(0.55, 1.0 - (distance - 50.0) / 100.0))
scale = scale * scale
if isFarEnough { if isFarEnough {
positions.append(Position(center: position, scale: scale)) result = position
foundPosition = true
break break
} }
} }
if attempts % 5 == 0 && !foundPosition { if attempts % 5 == 0 && result == nil {
currentMaxDist *= 1.2 currentMaxDist *= 1.2
} }
} }
if !foundPosition { if result == nil {
if let lastChancePosition = generateSinglePosition( if let lastChancePosition = self.generateSinglePosition(
viewSize: viewSize, viewSize: viewSize,
minDist: minDist, minDist: minDist,
maxDist: maxDist * 2.0, // Try with a much larger distance maxDist: maxDist * 2.0,
rightSide: !isEven rightSide: !isEven
) { ) {
let distance = hypot(lastChancePosition.x - self.avatarFrame.center.x, result = lastChancePosition
lastChancePosition.y - self.avatarFrame.center.y)
var scale = max(1.0, min(0.55, 1.0 - (distance - 50.0) / 100.0))
scale = scale * scale
positions.append(Position(center: lastChancePosition, scale: scale))
} else { } else {
// If all else fails, create a position with default values to ensure we don't return fewer positions than requested
let defaultX = self.avatarFrame.center.x + (isEven ? -1 : 1) * (minDist + CGFloat(i * 20)) let defaultX = self.avatarFrame.center.x + (isEven ? -1 : 1) * (minDist + CGFloat(i * 20))
let defaultY = self.avatarFrame.center.y + CGFloat(i * 15) let defaultY = self.avatarFrame.center.y + CGFloat(i * 15)
let defaultPosition = CGPoint(x: defaultX, y: defaultY) let defaultPosition = CGPoint(x: defaultX, y: defaultY)
// Use a smaller scale for these fallback positions result = defaultPosition
positions.append(Position(center: defaultPosition, scale: 0.5))
} }
} }
if let result {
let distance = hypot(result.x - self.avatarFrame.center.x, result.y - self.avatarFrame.center.y)
let baseScale = min(1.0, max(0.77, 1.0 - (distance - 75.0) / 75.0))
let randomFactor = 0.05 + (1.0 - baseScale) * 0.1
let randomValue = -randomFactor + CGFloat(self.rng.next()) * 2.0 * randomFactor
let finalScale = min(1.1, max(baseScale * 0.7, baseScale + randomValue))
positions.append(Position(center: result, scale: finalScale))
}
} }
return positions return positions.map {
Position(center: $0.center.offsetBy(dx: -self.avatarFrame.center.x, dy: -self.avatarFrame.center.y), scale: $0.scale)
}
} }
private func calculateDistanceRanges(count: Int) -> [(CGFloat, CGFloat)] { private func calculateDistanceRanges(count: Int) -> [(CGFloat, CGFloat)] {
@ -452,7 +459,7 @@ private class PositionGenerator {
} }
for _ in 0..<4 { for _ in 0..<4 {
let min = self.minDistance + (totalRange * 0.16) let min = self.minDistance + (totalRange * 0.19)
let max = self.minDistance + (totalRange * 0.6) let max = self.minDistance + (totalRange * 0.6)
ranges.append((min, max)) ranges.append((min, max))
} }
@ -533,25 +540,83 @@ private var shadowImage: UIImage? = {
}) })
}() }()
private final class StarsEffectLayer: SimpleLayer {
private let emitterLayer = CAEmitterLayer()
override init() {
super.init()
self.addSublayer(self.emitterLayer)
}
override init(layer: Any) {
super.init(layer: layer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(color: UIColor, size: CGSize) {
let emitter = CAEmitterCell()
emitter.name = "emitter"
emitter.contents = UIImage(bundleImageName: "Premium/Stars/Particle")?.cgImage
emitter.birthRate = 8.0
emitter.lifetime = 2.0
emitter.velocity = 0.1
emitter.scale = (size.width / 40.0) * 0.12
emitter.scaleRange = 0.02
emitter.alphaRange = 0.1
emitter.emissionRange = .pi * 2.0
let staticColors: [Any] = [
color.withAlphaComponent(0.0).cgColor,
color.withAlphaComponent(0.58).cgColor,
color.withAlphaComponent(0.58).cgColor,
color.withAlphaComponent(0.0).cgColor
]
let staticColorBehavior = CAEmitterCell.createEmitterBehavior(type: "colorOverLife")
staticColorBehavior.setValue(staticColors, forKey: "colors")
emitter.setValue([staticColorBehavior], forKey: "emitterBehaviors")
self.emitterLayer.emitterCells = [emitter]
}
func update(color: UIColor, size: CGSize) {
if self.emitterLayer.emitterCells == nil {
self.setup(color: color, size: size)
}
self.emitterLayer.seed = UInt32.random(in: .min ..< .max)
self.emitterLayer.emitterShape = .circle
self.emitterLayer.emitterSize = size
self.emitterLayer.emitterMode = .surface
self.emitterLayer.frame = CGRect(origin: .zero, size: size)
self.emitterLayer.emitterPosition = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
}
}
private class GiftIconLayer: SimpleLayer { private class GiftIconLayer: SimpleLayer {
private let context: AccountContext private let context: AccountContext
private let gift: ProfileGiftsContext.State.StarGift private let gift: ProfileGiftsContext.State.StarGift
private let size: CGSize private let size: CGSize
private let glowing: Bool
let shadowLayer = SimpleLayer() let shadowLayer = SimpleLayer()
let starsLayer = StarsEffectLayer()
let animationLayer: InlineStickerItemLayer let animationLayer: InlineStickerItemLayer
override init(layer: Any) { override init(layer: Any) {
guard let layer = layer as? GiftIconLayer else { guard let layer = layer as? GiftIconLayer else {
fatalError() fatalError()
} }
let context = layer.context let context = layer.context
let gift = layer.gift let gift = layer.gift
let size = layer.size let size = layer.size
let glowing = layer.glowing
var file: TelegramMediaFile? var file: TelegramMediaFile?
var color: UIColor? var color: UIColor = .white
switch gift.gift { switch gift.gift {
case let .generic(gift): case let .generic(gift):
file = gift.file file = gift.file
@ -585,29 +650,40 @@ private class GiftIconLayer: SimpleLayer {
) )
self.shadowLayer.contents = shadowImage?.cgImage self.shadowLayer.contents = shadowImage?.cgImage
self.shadowLayer.layerTintColor = color?.cgColor self.shadowLayer.layerTintColor = color.cgColor
self.context = context self.context = context
self.gift = gift self.gift = gift
self.size = size self.size = size
self.glowing = glowing
super.init() super.init()
self.addSublayer(self.shadowLayer) let side = floor(size.width * 1.25)
let starsFrame = CGSize(width: side, height: side).centered(in: CGRect(origin: .zero, size: size))
self.starsLayer.frame = starsFrame
self.starsLayer.update(color: glowing ? .white : color, size: starsFrame.size)
if glowing {
self.addSublayer(self.shadowLayer)
}
self.addSublayer(self.starsLayer)
self.addSublayer(self.animationLayer) self.addSublayer(self.animationLayer)
} }
init( init(
context: AccountContext, context: AccountContext,
gift: ProfileGiftsContext.State.StarGift, gift: ProfileGiftsContext.State.StarGift,
size: CGSize size: CGSize,
glowing: Bool
) { ) {
self.context = context self.context = context
self.gift = gift self.gift = gift
self.size = size self.size = size
self.glowing = glowing
var file: TelegramMediaFile? var file: TelegramMediaFile?
var color: UIColor? var color: UIColor = .white
switch gift.gift { switch gift.gift {
case let .generic(gift): case let .generic(gift):
file = gift.file file = gift.file
@ -641,11 +717,19 @@ private class GiftIconLayer: SimpleLayer {
) )
self.shadowLayer.contents = shadowImage?.cgImage self.shadowLayer.contents = shadowImage?.cgImage
self.shadowLayer.layerTintColor = color?.cgColor self.shadowLayer.layerTintColor = color.cgColor
super.init() super.init()
self.addSublayer(self.shadowLayer) let side = floor(size.width * 1.25)
let starsFrame = CGSize(width: side, height: side).centered(in: CGRect(origin: .zero, size: size))
self.starsLayer.frame = starsFrame
self.starsLayer.update(color: glowing ? .white : color, size: starsFrame.size)
if glowing {
self.addSublayer(self.shadowLayer)
}
self.addSublayer(self.starsLayer)
self.addSublayer(self.animationLayer) self.addSublayer(self.animationLayer)
} }
@ -658,30 +742,26 @@ private class GiftIconLayer: SimpleLayer {
self.animationLayer.frame = CGRect(origin: .zero, size: self.bounds.size) self.animationLayer.frame = CGRect(origin: .zero, size: self.bounds.size)
} }
func startHovering( func startHovering(distance: CGFloat = 3.0, duration: TimeInterval = 4.0, timingFunction: CAMediaTimingFunction = CAMediaTimingFunction(name: .easeInEaseOut)) {
distance: CGFloat = 3.0, let hoverAnimation = CABasicAnimation(keyPath: "transform.translation.y")
duration: TimeInterval = 4.0, hoverAnimation.duration = duration
timingFunction: CAMediaTimingFunction = CAMediaTimingFunction(name: .easeInEaseOut) hoverAnimation.fromValue = -distance
) { hoverAnimation.toValue = distance
let hoverAnimation = CABasicAnimation(keyPath: "transform.translation.y") hoverAnimation.autoreverses = true
hoverAnimation.duration = duration hoverAnimation.repeatCount = .infinity
hoverAnimation.fromValue = -distance hoverAnimation.timingFunction = timingFunction
hoverAnimation.toValue = distance hoverAnimation.beginTime = Double.random(in: 0.0 ..< 12.0)
hoverAnimation.autoreverses = true hoverAnimation.isAdditive = true
hoverAnimation.repeatCount = .infinity self.add(hoverAnimation, forKey: "hover")
hoverAnimation.timingFunction = timingFunction
hoverAnimation.beginTime = Double.random(in: 0.0 ..< 12.0) let glowAnimation = CABasicAnimation(keyPath: "transform.scale")
hoverAnimation.isAdditive = true glowAnimation.duration = duration
self.add(hoverAnimation, forKey: "hover") glowAnimation.fromValue = 1.0
glowAnimation.toValue = 1.2
let glowAnimation = CABasicAnimation(keyPath: "transform.scale") glowAnimation.autoreverses = true
glowAnimation.duration = duration glowAnimation.repeatCount = .infinity
glowAnimation.fromValue = 1.0 glowAnimation.timingFunction = timingFunction
glowAnimation.toValue = 1.2 glowAnimation.beginTime = Double.random(in: 0.0 ..< 12.0)
glowAnimation.autoreverses = true self.shadowLayer.add(glowAnimation, forKey: "glow")
glowAnimation.repeatCount = .infinity }
glowAnimation.timingFunction = timingFunction
glowAnimation.beginTime = Double.random(in: 0.0 ..< 12.0)
self.shadowLayer.add(glowAnimation, forKey: "glow")
}
} }

View File

@ -836,6 +836,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
starsState = .single(nil) starsState = .single(nil)
} }
let profileGiftsContext = ProfileGiftsContext(account: context.account, peerId: peerId)
return combineLatest( return combineLatest(
context.account.viewTracker.peerView(peerId, updateData: true), context.account.viewTracker.peerView(peerId, updateData: true),
accountsAndPeers, accountsAndPeers,
@ -945,7 +947,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
starsRevenueStatsContext: nil, starsRevenueStatsContext: nil,
revenueStatsState: nil, revenueStatsState: nil,
revenueStatsContext: nil, revenueStatsContext: nil,
profileGiftsContext: nil, profileGiftsContext: profileGiftsContext,
premiumGiftOptions: [], premiumGiftOptions: [],
webAppPermissions: nil webAppPermissions: nil
) )

View File

@ -2277,6 +2277,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let backgroundCoverSubject: PeerInfoCoverComponent.Subject? let backgroundCoverSubject: PeerInfoCoverComponent.Subject?
var backgroundCoverAnimateIn = false var backgroundCoverAnimateIn = false
var backgroundDefaultHeight: CGFloat = 254.0 var backgroundDefaultHeight: CGFloat = 254.0
var hasBackground = false
if let status = peer?.emojiStatus, case .starGift = status.content { if let status = peer?.emojiStatus, case .starGift = status.content {
backgroundCoverSubject = .status(status) backgroundCoverSubject = .status(status)
if !self.didSetupBackgroundCover { if !self.didSetupBackgroundCover {
@ -2288,8 +2289,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if !buttonKeys.isEmpty { if !buttonKeys.isEmpty {
backgroundDefaultHeight = 327.0 backgroundDefaultHeight = 327.0
} }
hasBackground = true
} else if let peer { } else if let peer {
backgroundCoverSubject = .peer(EnginePeer(peer)) backgroundCoverSubject = .peer(EnginePeer(peer))
if peer.profileColor != nil {
hasBackground = true
}
} else { } else {
backgroundCoverSubject = nil backgroundCoverSubject = nil
} }
@ -2344,6 +2349,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
context: self.context, context: self.context,
peerId: peer.id, peerId: peer.id,
giftsContext: profileGiftsContext, giftsContext: profileGiftsContext,
hasBackground: hasBackground,
avatarCenter: apparentAvatarFrame.center, avatarCenter: apparentAvatarFrame.center,
avatarScale: avatarScale, avatarScale: avatarScale,
defaultHeight: backgroundDefaultHeight, defaultHeight: backgroundDefaultHeight,