mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Stars slider improvements
This commit is contained in:
parent
4ea0a99778
commit
524ce21f5e
@ -228,6 +228,14 @@ private final class BadgeComponent: Component {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.badgeView.frame.contains(point) {
|
||||
return self
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: BadgeComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
if self.component == nil {
|
||||
self.badgeIcon.image = UIImage(bundleImageName: "Premium/SendStarsStarSliderIcon")?.withRenderingMode(.alwaysTemplate)
|
||||
@ -806,7 +814,7 @@ private final class SliderBackgroundComponent: Component {
|
||||
topBackgroundTextView.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: animateTopTextAdditionalX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.3, damping: 100.0, additive: true)
|
||||
}
|
||||
|
||||
topForegroundTextView.isHidden = component.topCutoff == nil
|
||||
topForegroundTextView.isHidden = component.topCutoff == nil || topLineFrame.maxX + topTextSize.width + 20.0 > availableSize.width
|
||||
topBackgroundTextView.isHidden = topForegroundTextView.isHidden
|
||||
self.topBackgroundLine.isHidden = topX < 10.0
|
||||
self.topForegroundLine.isHidden = self.topBackgroundLine.isHidden
|
||||
@ -915,6 +923,83 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
private struct Amount: Equatable {
|
||||
private let sliderSteps: [Int]
|
||||
private let maxRealValue: Int
|
||||
let maxSliderValue: Int
|
||||
private let isLogarithmic: Bool
|
||||
|
||||
private(set) var realValue: Int
|
||||
private(set) var sliderValue: Int
|
||||
|
||||
private static func makeSliderSteps(maxRealValue: Int, isLogarithmic: Bool) -> [Int] {
|
||||
if isLogarithmic {
|
||||
var sliderSteps: [Int] = [ 1, 10, 50, 100, 500, 1_000, 2_000, 5_000, 7_500, 10_000 ]
|
||||
sliderSteps.removeAll(where: { $0 >= maxRealValue })
|
||||
sliderSteps.append(maxRealValue)
|
||||
return sliderSteps
|
||||
} else {
|
||||
return [1, maxRealValue]
|
||||
}
|
||||
}
|
||||
|
||||
private static func remapValueToSlider(realValue: Int, maxSliderValue: Int, steps: [Int]) -> Int {
|
||||
guard realValue >= steps.first!, realValue <= steps.last! else { return 0 }
|
||||
|
||||
for i in 0 ..< steps.count - 1 {
|
||||
if realValue >= steps[i] && realValue <= steps[i + 1] {
|
||||
let range = steps[i + 1] - steps[i]
|
||||
let relativeValue = realValue - steps[i]
|
||||
let stepFraction = Float(relativeValue) / Float(range)
|
||||
return Int(Float(i) * Float(maxSliderValue) / Float(steps.count - 1)) + Int(stepFraction * Float(maxSliderValue) / Float(steps.count - 1))
|
||||
}
|
||||
}
|
||||
return maxSliderValue // Return max slider position if value equals the last step
|
||||
}
|
||||
|
||||
private static func remapSliderToValue(sliderValue: Int, maxSliderValue: Int, steps: [Int]) -> Int {
|
||||
guard sliderValue >= 0, sliderValue <= maxSliderValue else { return steps.first! }
|
||||
|
||||
let stepIndex = Int(Float(sliderValue) / Float(maxSliderValue) * Float(steps.count - 1))
|
||||
let fraction = Float(sliderValue) / Float(maxSliderValue) * Float(steps.count - 1) - Float(stepIndex)
|
||||
|
||||
if stepIndex >= steps.count - 1 {
|
||||
return steps.last!
|
||||
} else {
|
||||
let range = steps[stepIndex + 1] - steps[stepIndex]
|
||||
return steps[stepIndex] + Int(fraction * Float(range))
|
||||
}
|
||||
}
|
||||
|
||||
init(realValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
|
||||
self.sliderSteps = Amount.makeSliderSteps(maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
|
||||
self.maxRealValue = maxRealValue
|
||||
self.maxSliderValue = maxSliderValue
|
||||
self.isLogarithmic = isLogarithmic
|
||||
|
||||
self.realValue = realValue
|
||||
self.sliderValue = Amount.remapValueToSlider(realValue: self.realValue, maxSliderValue: self.maxSliderValue, steps: self.sliderSteps)
|
||||
}
|
||||
|
||||
init(sliderValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
|
||||
self.sliderSteps = Amount.makeSliderSteps(maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
|
||||
self.maxRealValue = maxRealValue
|
||||
self.maxSliderValue = maxSliderValue
|
||||
self.isLogarithmic = isLogarithmic
|
||||
|
||||
self.sliderValue = sliderValue
|
||||
self.realValue = Amount.remapSliderToValue(sliderValue: self.sliderValue, maxSliderValue: self.maxSliderValue, steps: self.sliderSteps)
|
||||
}
|
||||
|
||||
func withRealValue(_ realValue: Int) -> Amount {
|
||||
return Amount(realValue: realValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
|
||||
}
|
||||
|
||||
func withSliderValue(_ sliderValue: Int) -> Amount {
|
||||
return Amount(sliderValue: sliderValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
|
||||
}
|
||||
}
|
||||
|
||||
final class View: UIView, UIScrollViewDelegate {
|
||||
private let dimView: UIView
|
||||
private let backgroundLayer: SimpleLayer
|
||||
@ -959,7 +1044,9 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
private var topOffsetDistance: CGFloat?
|
||||
|
||||
private var balance: Int64?
|
||||
private var amount: Int64 = 1
|
||||
|
||||
private var amount: Amount = Amount(realValue: 1, maxRealValue: 1000, maxSliderValue: 1000, isLogarithmic: true)
|
||||
|
||||
private var isAnonymous: Bool = false
|
||||
private var cachedStarImage: (UIImage, PresentationTheme)?
|
||||
private var cachedCloseImage: UIImage?
|
||||
@ -1058,6 +1145,12 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
return result
|
||||
}
|
||||
|
||||
if let badgeView = self.badge.view, badgeView.hitTest(self.convert(point, to: badgeView), with: event) != nil {
|
||||
if let sliderView = self.slider.view as? SliderComponent.View, let hitTestTarget = sliderView.hitTestTarget {
|
||||
return hitTestTarget
|
||||
}
|
||||
}
|
||||
|
||||
let result = super.hitTest(point, with: event)
|
||||
return result
|
||||
}
|
||||
@ -1135,7 +1228,11 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
|
||||
if self.component == nil {
|
||||
self.balance = component.balance
|
||||
self.amount = 50
|
||||
var isLogarithmic = true
|
||||
if let data = component.context.currentAppConfiguration.with({ $0 }).data, let value = data["ios_stars_reaction_logarithmic_scale"] as? Double {
|
||||
isLogarithmic = Int(value) != 0
|
||||
}
|
||||
self.amount = Amount(realValue: 50, maxRealValue: component.maxAmount, maxSliderValue: 999, isLogarithmic: isLogarithmic)
|
||||
if let myTopPeer = component.myTopPeer {
|
||||
self.isAnonymous = myTopPeer.isAnonymous
|
||||
}
|
||||
@ -1182,8 +1279,8 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
let sliderSize = self.slider.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(SliderComponent(
|
||||
valueCount: component.maxAmount,
|
||||
value: Int(self.amount),
|
||||
valueCount: self.amount.maxSliderValue + 1,
|
||||
value: self.amount.sliderValue,
|
||||
markPositions: false,
|
||||
trackBackgroundColor: .clear,
|
||||
trackForegroundColor: .clear,
|
||||
@ -1193,7 +1290,8 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
self.amount = 1 + Int64(value)
|
||||
self.amount = self.amount.withSliderValue(value)
|
||||
|
||||
self.state?.updated(transition: ComponentTransition(animation: .none).withUserData(IsAdjustingAmountHint()))
|
||||
|
||||
let sliderValue = Float(value) / Float(component.maxAmount)
|
||||
@ -1250,7 +1348,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
let sliderFrame = CGRect(origin: CGPoint(x: sliderInset, y: contentHeight + 127.0), size: sliderSize)
|
||||
let sliderBackgroundFrame = CGRect(origin: CGPoint(x: sliderFrame.minX - 8.0, y: sliderFrame.minY + 7.0), size: CGSize(width: sliderFrame.width + 16.0, height: sliderFrame.height - 14.0))
|
||||
|
||||
let progressFraction: CGFloat = CGFloat(self.amount) / CGFloat(component.maxAmount - 1)
|
||||
let progressFraction: CGFloat = CGFloat(self.amount.sliderValue) / CGFloat(self.amount.maxSliderValue)
|
||||
|
||||
let topOthersCount: Int? = component.topPeers.filter({ !$0.isMy }).max(by: { $0.count < $1.count })?.count
|
||||
var topCount: Int?
|
||||
@ -1310,7 +1408,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
transition: transition,
|
||||
component: AnyComponent(BadgeComponent(
|
||||
theme: environment.theme,
|
||||
title: "\(self.amount)",
|
||||
title: "\(self.amount.realValue)",
|
||||
inertiaDirection: effectiveInertiaDirection
|
||||
)),
|
||||
environment: {},
|
||||
@ -1542,7 +1640,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
if let index = mappedTopPeers.firstIndex(where: { $0.isMy }) {
|
||||
mappedTopPeers.remove(at: index)
|
||||
}
|
||||
var myCount = Int(self.amount)
|
||||
var myCount = Int(self.amount.realValue)
|
||||
if let myTopPeer = component.myTopPeer {
|
||||
myCount += myTopPeer.count
|
||||
}
|
||||
@ -1747,7 +1845,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
self.cachedStarImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: .white)!, environment.theme)
|
||||
}
|
||||
|
||||
let buttonString = environment.strings.SendStarReactions_SendButtonTitle("\(self.amount)").string
|
||||
let buttonString = environment.strings.SendStarReactions_SendButtonTitle("\(self.amount.realValue)").string
|
||||
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: .white, paragraphAlignment: .center)
|
||||
if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.cachedStarImage?.0 {
|
||||
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
|
||||
@ -1778,7 +1876,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
if balance < self.amount {
|
||||
if balance < self.amount.realValue {
|
||||
let _ = (component.context.engine.payments.starsTopUpOptions()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] options in
|
||||
@ -1789,7 +1887,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
let purchaseScreen = component.context.sharedContext.makeStarsPurchaseScreen(context: component.context, starsContext: starsContext, options: options, purpose: .transfer(peerId: component.peer.id, requiredStars: self.amount), completion: { result in
|
||||
let purchaseScreen = component.context.sharedContext.makeStarsPurchaseScreen(context: component.context, starsContext: starsContext, options: options, purpose: .transfer(peerId: component.peer.id, requiredStars: Int64(self.amount.realValue)), completion: { result in
|
||||
let _ = result
|
||||
//TODO:release
|
||||
})
|
||||
@ -1805,13 +1903,13 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
}
|
||||
let isBecomingTop: Bool
|
||||
if let topCount {
|
||||
isBecomingTop = self.amount > topCount
|
||||
isBecomingTop = self.amount.realValue > topCount
|
||||
} else {
|
||||
isBecomingTop = true
|
||||
}
|
||||
|
||||
component.completion(
|
||||
self.amount,
|
||||
Int64(self.amount.realValue),
|
||||
self.isAnonymous,
|
||||
isBecomingTop,
|
||||
ChatSendStarsScreen.TransitionOut(
|
||||
|
@ -70,6 +70,10 @@ public final class SliderComponent: Component {
|
||||
private var component: SliderComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
|
||||
public var hitTestTarget: UIView? {
|
||||
return self.sliderView
|
||||
}
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user