Various fixes

This commit is contained in:
Ilya Laktyushin
2026-01-28 19:05:47 +04:00
parent 52a22d8cef
commit a1aa4d9094
10 changed files with 94 additions and 26 deletions

View File

@@ -466,6 +466,9 @@ public final class ButtonComponent: Component {
super.init(frame: frame)
self.button.isExclusiveTouch = true
self.layer.rasterizationScale = UIScreenScale
self.addSubview(self.containerView)
self.addSubview(self.button)
@@ -477,12 +480,24 @@ public final class ButtonComponent: Component {
case .glass:
let transition = ComponentTransition(animation: .curve(duration: highlighted ? 0.25 : 0.35, curve: .spring))
if highlighted {
self.layer.shouldRasterize = true
let highlightedColor = component.background.color.withMultiplied(hue: 1.0, saturation: 0.77, brightness: 1.01)
transition.setBackgroundColor(view: self.containerView, color: highlightedColor)
transition.setScale(view: self.containerView, scale: 1.05)
transition.setScale(view: self.containerView, scale: 1.05, completion: { finished in
if finished {
self.layer.shouldRasterize = false
}
})
} else {
self.layer.shouldRasterize = true
transition.setBackgroundColor(view: self.containerView, color: component.background.color)
transition.setScale(view: self.containerView, scale: 1.0)
transition.setScale(view: self.containerView, scale: 1.0, completion: { finished in
if finished {
self.layer.shouldRasterize = false
}
})
}
case .legacy:
if highlighted {

View File

@@ -49,6 +49,7 @@ swift_library(
"//submodules/TelegramUI/Components/SpaceWarpView",
"//submodules/ConfettiEffect",
"//submodules/TelegramNotices",
"//submodules/TelegramUI/Components/Gifts/GiftLoadingShimmerView",
],
visibility = [
"//visibility:public",

View File

@@ -546,7 +546,7 @@ final class GiftSlotComponent: Component {
self.state = state
let backgroundFrame = CGRect(origin: .zero, size: availableSize).insetBy(dx: 1.0, dy: 1.0)
self.backgroundView.update(size: backgroundFrame.size, cornerRadius: 28.0, isDark: true, tintColor: .init(kind: .custom(style: .default, color: component.buttonColor)), transition: .immediate)
self.backgroundView.update(size: backgroundFrame.size, cornerRadius: 28.0, isDark: true, tintColor: .init(kind: .custom(style: .default, color: component.buttonColor)), isInteractive: true, transition: .immediate)
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
if component.gift == nil && component.isCrafting && previousComponent?.isCrafting == false {
transition.setBlur(layer: self.backgroundView.layer, radius: 10.0)

View File

@@ -106,7 +106,7 @@ final class DialIndicatorComponent: Component {
self.backgroundLayer.lineCap = .round
self.foregroundLayer.lineCap = .round
self.addSubview(self.containerView)
self.containerView.layer.addSublayer(self.backgroundLayer)

View File

@@ -166,9 +166,7 @@ private final class CraftGiftPageContent: Component {
private let infoTitle = ComponentView<Empty>()
private let infoDescription = ComponentView<Empty>()
private var infoList = ComponentView<Empty>()
private var actionButton = ComponentView<Empty>()
private var craftState: CraftGiftsContext.State?
private var craftStateDisposable: Disposable?
@@ -338,6 +336,7 @@ private final class CraftGiftPageContent: Component {
}
self.starGiftsMap = starGiftsMap
component.externalState.starGiftsMap = starGiftsMap
self.state?.updated()
}))
}
@@ -1616,8 +1615,16 @@ private final class SheetContainerComponent: CombinedComponent {
tintColor: .white
)
)),
action: { _ in
dismiss(true)
action: { [weak state] _ in
guard let state else {
return
}
if state.displayInfo {
state.displayInfo = false
state.updated(transition: .spring(duration: 0.3))
} else {
dismiss(true)
}
}
)
),

View File

@@ -21,6 +21,7 @@ import ResizableSheetComponent
import TooltipUI
import GlassBarButtonComponent
import ConfettiEffect
import GiftLoadingShimmerView
final class SelectGiftPageContent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@@ -74,6 +75,7 @@ final class SelectGiftPageContent: Component {
private let myGiftsTitle = ComponentView<Empty>()
private var gifts: [AnyHashable: ComponentView<Empty>] = [:]
private let myGiftsPlaceholder = ComponentView<Empty>()
private let loadingView = GiftLoadingShimmerView()
private let storeGiftsTitle = ComponentView<Empty>()
private let storeGifts = ComponentView<Empty>()
@@ -94,6 +96,8 @@ final class SelectGiftPageContent: Component {
self.layer.cornerRadius = 40.0
self.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
self.addSubview(self.loadingView)
}
required init?(coder: NSCoder) {
@@ -204,10 +208,25 @@ final class SelectGiftPageContent: Component {
}
let itemWidth = (availableSize.width - itemSideInset * 2.0 - itemSpacing * CGFloat(itemsInRow - 1)) / CGFloat(itemsInRow)
let itemSize = CGSize(width: itemWidth, height: itemWidth)
var itemFrame = CGRect(origin: CGPoint(x: itemSideInset, y: contentHeight), size: itemSize)
var isLoading = false
if self.availableGifts.isEmpty, case .loading = (self.craftState?.dataState ?? .loading) {
isLoading = true
}
let loadingTransition: ComponentTransition = .easeInOut(duration: 0.25)
let loadingSize = CGSize(width: availableSize.width, height: 180.0)
if isLoading {
contentHeight += 120.0
self.loadingView.update(size: loadingSize, theme: environment.theme, itemSize: itemSize, showFilters: false, isPlain: true, transition: .immediate)
loadingTransition.setAlpha(view: self.loadingView, alpha: 1.0)
} else {
loadingTransition.setAlpha(view: self.loadingView, alpha: 0.0)
}
transition.setFrame(view: self.loadingView, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight - 170.0), size: loadingSize))
var itemFrame = CGRect(origin: CGPoint(x: itemSideInset, y: contentHeight), size: itemSize)
var itemsHeight: CGFloat = 0.0
var validIds: [AnyHashable] = []
for gift in self.availableGifts {
let isVisible = "".isEmpty
@@ -272,17 +291,15 @@ final class SelectGiftPageContent: Component {
)
if let itemView = visibleItem.view {
if itemView.superview == nil {
self.addSubview(itemView)
if let _ = self.loadingView.superview {
self.insertSubview(itemView, belowSubview: self.loadingView)
} else {
self.addSubview(itemView)
}
if !transition.animation.isImmediate {
let delay = ((itemFrame.minY - contentHeight) / itemSize.height) * 0.07
itemView.layer.animateScale(from: 0.01, to: 1.0, duration: 0.25, delay: delay)
itemView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: delay)
itemView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
}
}
itemView.isUserInteractionEnabled = !component.selectedGiftIds.contains(gift.gift.id)
itemView.alpha = component.selectedGiftIds.contains(gift.gift.id) ? 0.4 : 1.0
itemView.layer.allowsGroupOpacity = itemView.alpha < 1.0
itemTransition.setFrame(view: itemView, frame: itemFrame)
}
}
@@ -315,7 +332,7 @@ final class SelectGiftPageContent: Component {
for id in removeIds {
self.gifts.removeValue(forKey: id)
}
if let state = self.craftState, case .ready = state.dataState, self.availableGifts.isEmpty {
contentHeight += 10.0
let myGiftsPlaceholderSize = self.myGiftsPlaceholder.update(

View File

@@ -139,7 +139,7 @@ public final class GiftLoadingShimmerView: UIView {
required init?(coder: NSCoder) { fatalError() }
public func update(size: CGSize, theme: PresentationTheme, showFilters: Bool = false, isPlain: Bool = false, transition: ContainedViewLayoutTransition) {
public func update(size: CGSize, theme: PresentationTheme, itemSize: CGSize? = nil, showFilters: Bool = false, isPlain: Bool = false, transition: ContainedViewLayoutTransition) {
let backgroundColor = isPlain ? theme.list.itemBlocksBackgroundColor : theme.list.blocksBackgroundColor
let color = theme.list.itemSecondaryTextColor.mixedWith(theme.list.blocksBackgroundColor, alpha: 0.85)
@@ -169,7 +169,7 @@ public final class GiftLoadingShimmerView: UIView {
let optionSpacing: CGFloat = 10.0
let optionWidth = (size.width - sideInset * 2.0 - optionSpacing * 2.0) / 3.0
let itemSize = CGSize(width: optionWidth, height: 154.0)
let itemSize = itemSize ?? CGSize(width: optionWidth, height: 154.0)
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)

View File

@@ -202,6 +202,8 @@ private final class GiftUpgradeVariantsScreenComponent: Component {
self.containerView.addSubview(self.navigationBarContainer)
self.dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:))))
self.alpha = 0.0
}
required init?(coder: NSCoder) {
@@ -271,6 +273,7 @@ private final class GiftUpgradeVariantsScreenComponent: Component {
}
func animateIn() {
self.alpha = 1.0
self.dimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
let animateOffset: CGFloat = self.bounds.height - self.backgroundLayer.frame.minY
self.scrollContentClippingView.layer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
@@ -1061,6 +1064,13 @@ private final class GiftUpgradeVariantsScreenComponent: Component {
self.previewTimerTick()
}
self.state?.updated(transition: .easeInOut(duration: 0.25))
if let buttonView = self.playbackButton.view {
buttonView.isUserInteractionEnabled = false
Queue.mainQueue().after(0.3, {
buttonView.isUserInteractionEnabled = true
})
}
}
)),
environment: {},
@@ -1194,7 +1204,9 @@ public class GiftUpgradeVariantsScreen: ViewControllerComponentContainer {
self.didPlayAppearAnimation = true
if let componentView = self.node.hostView.componentView as? GiftUpgradeVariantsScreenComponent.View {
componentView.animateIn()
Queue.mainQueue().justDispatch {
componentView.animateIn()
}
}
}
}

View File

@@ -37,6 +37,8 @@ public func buyStarGiftImpl(
parseMarkdown: true
)
controller.present(alertController, in: .window(.root))
beforeCompletion()
return
}
@@ -207,6 +209,8 @@ public func buyStarGiftImpl(
context.sharedContext.applicationBindings.openUrl(fragmentUrl)
}
))
beforeCompletion()
} else {
proceed()
}

View File

@@ -108,6 +108,7 @@ public final class PlainButtonComponent: Component {
super.init(frame: frame)
self.isExclusiveTouch = true
self.layer.rasterizationScale = UIScreenScale
self.contentContainer.isUserInteractionEnabled = false
self.addSubview(self.contentContainer)
@@ -130,8 +131,13 @@ public final class PlainButtonComponent: Component {
self.contentContainer.alpha = 0.7
}
if animateScale {
self.layer.shouldRasterize = true
let transition = ComponentTransition(animation: .curve(duration: 0.2, curve: .easeInOut))
transition.setScale(layer: self.contentContainer.layer, scale: topScale)
transition.setScale(layer: self.contentContainer.layer, scale: topScale, completion: { finished in
if finished {
self.layer.shouldRasterize = false
}
})
}
} else {
if animateAlpha {
@@ -140,15 +146,21 @@ public final class PlainButtonComponent: Component {
}
if animateScale {
self.layer.shouldRasterize = true
let transition = ComponentTransition(animation: .none)
transition.setScale(layer: self.contentContainer.layer, scale: 1.0)
self.contentContainer.layer.animateScale(from: topScale, to: maxScale, duration: 0.13, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, completion: { [weak self] _ in
guard let self else {
return
}
self.contentContainer.layer.animateScale(from: maxScale, to: 1.0, duration: 0.1, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue)
self.contentContainer.layer.animateScale(from: maxScale, to: 1.0, duration: 0.1, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue, completion: { finished in
if finished {
self.layer.shouldRasterize = false
}
})
})
}
}