mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
d62c37adf1
commit
3fb73a8b95
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user