Various improvements

This commit is contained in:
Ilya Laktyushin 2022-06-06 16:28:23 +04:00
parent 5d1e4b4be0
commit 9ad1b7bf86
6 changed files with 263 additions and 175 deletions

View File

@ -160,7 +160,8 @@ class IncreaseLimitHeaderItemNode: ListViewItemNode {
activeTitleColor: .white, activeTitleColor: .white,
badgeIconName: badgeIconName, badgeIconName: badgeIconName,
badgeText: "\(item.count)", badgeText: "\(item.count)",
badgePosition: CGFloat(item.count) / CGFloat(item.premiumCount) badgePosition: CGFloat(item.count) / CGFloat(item.premiumCount),
isPremiumDisabled: false
)), )),
environment: {}, environment: {},
containerSize: CGSize(width: layout.size.width - params.leftInset - params.rightInset, height: 200.0) containerSize: CGSize(width: layout.size.width - params.leftInset - params.rightInset, height: 200.0)

View File

@ -1320,7 +1320,13 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
super.init() super.init()
let availableProducts: Signal<[InAppPurchaseManager.Product], NoError>
if let inAppPurchaseManager = context.inAppPurchaseManager { if let inAppPurchaseManager = context.inAppPurchaseManager {
availableProducts = inAppPurchaseManager.availableProducts
} else {
availableProducts = .single([])
}
let otherPeerName: Signal<String?, NoError> let otherPeerName: Signal<String?, NoError>
if case let .profile(peerId) = source { if case let .profile(peerId) = source {
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -1334,7 +1340,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
self.disposable = combineLatest( self.disposable = combineLatest(
queue: Queue.mainQueue(), queue: Queue.mainQueue(),
inAppPurchaseManager.availableProducts, availableProducts,
context.account.postbox.peerView(id: context.account.peerId) context.account.postbox.peerView(id: context.account.peerId)
|> map { view -> Bool in |> map { view -> Bool in
return view.peers[view.peerId]?.isPremium ?? false return view.peers[view.peerId]?.isPremium ?? false
@ -1349,7 +1355,6 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
} }
}) })
} }
}
deinit { deinit {
self.disposable?.dispose() self.disposable?.dispose()

View File

@ -44,6 +44,7 @@ private class PremiumLimitAnimationComponent: Component {
private let textColor: UIColor private let textColor: UIColor
private let badgeText: String? private let badgeText: String?
private let badgePosition: CGFloat private let badgePosition: CGFloat
private let isPremiumDisabled: Bool
init( init(
iconName: String?, iconName: String?,
@ -51,7 +52,8 @@ private class PremiumLimitAnimationComponent: Component {
activeColors: [UIColor], activeColors: [UIColor],
textColor: UIColor, textColor: UIColor,
badgeText: String?, badgeText: String?,
badgePosition: CGFloat badgePosition: CGFloat,
isPremiumDisabled: Bool
) { ) {
self.iconName = iconName self.iconName = iconName
self.inactiveColor = inactiveColor self.inactiveColor = inactiveColor
@ -59,6 +61,7 @@ private class PremiumLimitAnimationComponent: Component {
self.textColor = textColor self.textColor = textColor
self.badgeText = badgeText self.badgeText = badgeText
self.badgePosition = badgePosition self.badgePosition = badgePosition
self.isPremiumDisabled = isPremiumDisabled
} }
static func ==(lhs: PremiumLimitAnimationComponent, rhs: PremiumLimitAnimationComponent) -> Bool { static func ==(lhs: PremiumLimitAnimationComponent, rhs: PremiumLimitAnimationComponent) -> Bool {
@ -80,6 +83,9 @@ private class PremiumLimitAnimationComponent: Component {
if lhs.badgePosition != rhs.badgePosition { if lhs.badgePosition != rhs.badgePosition {
return false return false
} }
if lhs.isPremiumDisabled != rhs.isPremiumDisabled {
return false
}
return true return true
} }
@ -183,42 +189,39 @@ private class PremiumLimitAnimationComponent: Component {
func playAppearanceAnimation(component: PremiumLimitAnimationComponent, availableSize: CGSize) { func playAppearanceAnimation(component: PremiumLimitAnimationComponent, availableSize: CGSize) {
self.badgeView.layer.animateScale(from: 0.1, to: 1.0, duration: 0.4, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue) self.badgeView.layer.animateScale(from: 0.1, to: 1.0, duration: 0.4, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
let now = self.badgeView.layer.convertTime(CACurrentMediaTime(), from: nil)
let positionAnimation = CABasicAnimation(keyPath: "position.x") let positionAnimation = CABasicAnimation(keyPath: "position.x")
positionAnimation.fromValue = NSValue(cgPoint: CGPoint(x: 0.0, y: 0.0)) positionAnimation.fromValue = NSValue(cgPoint: CGPoint(x: 0.0, y: 0.0))
positionAnimation.toValue = NSValue(cgPoint: self.badgeView.center) positionAnimation.toValue = NSValue(cgPoint: self.badgeView.center)
positionAnimation.duration = 0.5 positionAnimation.duration = 0.5
positionAnimation.fillMode = .forwards positionAnimation.fillMode = .forwards
positionAnimation.beginTime = now self.badgeView.layer.add(positionAnimation, forKey: "appearance1")
Queue.mainQueue().after(0.5, {
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z") let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotateAnimation.fromValue = 0.0 as NSNumber rotateAnimation.fromValue = 0.0 as NSNumber
rotateAnimation.toValue = 0.2 as NSNumber rotateAnimation.toValue = 0.2 as NSNumber
rotateAnimation.isAdditive = true
rotateAnimation.duration = 0.2 rotateAnimation.duration = 0.2
rotateAnimation.beginTime = now + 0.5
rotateAnimation.fillMode = .forwards rotateAnimation.fillMode = .forwards
rotateAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut) rotateAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
rotateAnimation.isRemovedOnCompletion = false
self.badgeView.layer.add(rotateAnimation, forKey: "appearance2")
Queue.mainQueue().after(0.5, {
if !self.badgeView.isHidden { if !self.badgeView.isHidden {
self.hapticFeedback.impact(.light) self.hapticFeedback.impact(.light)
} }
})
Queue.mainQueue().after(0.2) {
let returnAnimation = CABasicAnimation(keyPath: "transform.rotation.z") let returnAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
returnAnimation.fromValue = 0.2 as NSNumber returnAnimation.fromValue = 0.2 as NSNumber
returnAnimation.toValue = 0.0 as NSNumber returnAnimation.toValue = 0.0 as NSNumber
returnAnimation.isAdditive = true
returnAnimation.duration = 0.18 returnAnimation.duration = 0.18
returnAnimation.beginTime = now + 0.5 + 0.2
returnAnimation.fillMode = .forwards returnAnimation.fillMode = .forwards
returnAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn) returnAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)
self.badgeView.layer.add(positionAnimation, forKey: "appearance1")
self.badgeView.layer.add(rotateAnimation, forKey: "appearance2")
self.badgeView.layer.add(returnAnimation, forKey: "appearance3") self.badgeView.layer.add(returnAnimation, forKey: "appearance3")
self.badgeView.layer.removeAnimation(forKey: "appearance2")
}
})
self.badgeView.alpha = 1.0 self.badgeView.alpha = 1.0
self.badgeView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) self.badgeView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
@ -241,6 +244,7 @@ private class PremiumLimitAnimationComponent: Component {
let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - lineHeight), size: CGSize(width: availableSize.width, height: lineHeight)) let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - lineHeight), size: CGSize(width: availableSize.width, height: lineHeight))
self.container.frame = containerFrame self.container.frame = containerFrame
if !component.isPremiumDisabled {
self.inactiveBackground.frame = CGRect(origin: .zero, size: CGSize(width: containerFrame.width / 2.0, height: lineHeight)) self.inactiveBackground.frame = CGRect(origin: .zero, size: CGSize(width: containerFrame.width / 2.0, height: lineHeight))
self.activeContainer.frame = CGRect(origin: CGPoint(x: containerFrame.width / 2.0, y: 0.0), size: CGSize(width: containerFrame.width / 2.0, height: lineHeight)) self.activeContainer.frame = CGRect(origin: CGPoint(x: containerFrame.width / 2.0, y: 0.0), size: CGSize(width: containerFrame.width / 2.0, height: lineHeight))
@ -248,6 +252,7 @@ private class PremiumLimitAnimationComponent: Component {
if self.activeBackground.animation(forKey: "movement") == nil { if self.activeBackground.animation(forKey: "movement") == nil {
self.activeBackground.position = CGPoint(x: containerFrame.width * 3.0 / 4.0 - self.activeBackground.frame.width * 0.35, y: lineHeight / 2.0) self.activeBackground.position = CGPoint(x: containerFrame.width * 3.0 / 4.0 - self.activeBackground.frame.width * 0.35, y: lineHeight / 2.0)
} }
}
let countWidth: CGFloat let countWidth: CGFloat
if let badgeText = component.badgeText { if let badgeText = component.badgeText {
@ -276,26 +281,43 @@ private class PremiumLimitAnimationComponent: Component {
self.badgeMaskTailView.frame = CGRect(origin: CGPoint(x: badgeSize.width - 44.0, y: badgeSize.height - 36.0), size: CGSize(width: 44.0, height: 36.0)) self.badgeMaskTailView.frame = CGRect(origin: CGPoint(x: badgeSize.width - 44.0, y: badgeSize.height - 36.0), size: CGSize(width: 44.0, height: 36.0))
self.badgeView.bounds = CGRect(origin: .zero, size: badgeSize) self.badgeView.bounds = CGRect(origin: .zero, size: badgeSize)
if component.badgePosition > 1.0 - .ulpOfOne {
var badgePosition = component.badgePosition
if component.isPremiumDisabled {
badgePosition = 0.5
}
if badgePosition > 1.0 - .ulpOfOne {
self.badgeView.layer.anchorPoint = CGPoint(x: 1.0, y: 1.0) self.badgeView.layer.anchorPoint = CGPoint(x: 1.0, y: 1.0)
self.badgeMaskTailView.isHidden = false self.badgeMaskTailView.isHidden = false
self.badgeMaskArrowView.isHidden = true self.badgeMaskArrowView.isHidden = true
self.badgeView.center = CGPoint(x: 3.0 + (availableSize.width - 6.0) * component.badgePosition + 3.0, y: 82.0) if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
self.badgeView.center = CGPoint(x: 3.0 + (availableSize.width - 6.0) * badgePosition + 3.0, y: 82.0)
}
} else { } else {
self.badgeView.layer.anchorPoint = CGPoint(x: 0.5, y: 1.0) self.badgeView.layer.anchorPoint = CGPoint(x: 0.5, y: 1.0)
self.badgeMaskTailView.isHidden = true self.badgeMaskTailView.isHidden = true
self.badgeMaskArrowView.isHidden = false self.badgeMaskArrowView.isHidden = component.isPremiumDisabled
self.badgeView.center = CGPoint(x: 3.0 + (availableSize.width - 6.0) * component.badgePosition, y: 82.0) if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
self.badgeView.center = CGPoint(x: 3.0 + (availableSize.width - 6.0) * badgePosition, y: 82.0)
}
if self.badgeView.frame.maxX > availableSize.width { if self.badgeView.frame.maxX > availableSize.width {
let delta = self.badgeView.frame.maxX - availableSize.width - 6.0 let delta = self.badgeView.frame.maxX - availableSize.width - 6.0
if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
self.badgeView.center = self.badgeView.center.offsetBy(dx: -delta, dy: 0.0) self.badgeView.center = self.badgeView.center.offsetBy(dx: -delta, dy: 0.0)
} }
} }
}
self.badgeForeground.bounds = CGRect(origin: CGPoint(), size: CGSize(width: badgeSize.width * 3.0, height: badgeSize.height)) self.badgeForeground.bounds = CGRect(origin: CGPoint(), size: CGSize(width: badgeSize.width * 3.0, height: badgeSize.height))
if self.badgeForeground.animation(forKey: "movement") == nil { if self.badgeForeground.animation(forKey: "movement") == nil {
self.badgeForeground.position = CGPoint(x: badgeSize.width * 3.0 / 2.0 - self.badgeForeground.frame.width * 0.35, y: badgeSize.height / 2.0) self.badgeForeground.position = CGPoint(x: badgeSize.width * 3.0 / 2.0 - self.badgeForeground.frame.width * 0.35, y: badgeSize.height / 2.0)
@ -304,8 +326,17 @@ private class PremiumLimitAnimationComponent: Component {
self.badgeIcon.frame = CGRect(x: 15.0, y: 9.0, width: 30.0, height: 30.0) self.badgeIcon.frame = CGRect(x: 15.0, y: 9.0, width: 30.0, height: 30.0)
self.badgeCountLabel.frame = CGRect(x: badgeSize.width - countWidth - 11.0, y: 10.0, width: countWidth, height: 48.0) self.badgeCountLabel.frame = CGRect(x: badgeSize.width - countWidth - 11.0, y: 10.0, width: countWidth, height: 48.0)
if component.isPremiumDisabled {
if !self.didPlayAppearanceAnimation { if !self.didPlayAppearanceAnimation {
self.didPlayAppearanceAnimation = true self.didPlayAppearanceAnimation = true
self.badgeView.alpha = 1.0
if let badgeText = component.badgeText {
self.badgeCountLabel.configure(with: badgeText, duration: 0.3)
}
}
} else if !self.didPlayAppearanceAnimation {
self.didPlayAppearanceAnimation = true
self.playAppearanceAnimation(component: component, availableSize: availableSize) self.playAppearanceAnimation(component: component, availableSize: availableSize)
} }
@ -396,6 +427,7 @@ public final class PremiumLimitDisplayComponent: CombinedComponent {
let badgeIconName: String? let badgeIconName: String?
let badgeText: String? let badgeText: String?
let badgePosition: CGFloat let badgePosition: CGFloat
let isPremiumDisabled: Bool
public init( public init(
inactiveColor: UIColor, inactiveColor: UIColor,
@ -408,7 +440,8 @@ public final class PremiumLimitDisplayComponent: CombinedComponent {
activeTitleColor: UIColor, activeTitleColor: UIColor,
badgeIconName: String?, badgeIconName: String?,
badgeText: String?, badgeText: String?,
badgePosition: CGFloat badgePosition: CGFloat,
isPremiumDisabled: Bool
) { ) {
self.inactiveColor = inactiveColor self.inactiveColor = inactiveColor
self.activeColors = activeColors self.activeColors = activeColors
@ -421,6 +454,7 @@ public final class PremiumLimitDisplayComponent: CombinedComponent {
self.badgeIconName = badgeIconName self.badgeIconName = badgeIconName
self.badgeText = badgeText self.badgeText = badgeText
self.badgePosition = badgePosition self.badgePosition = badgePosition
self.isPremiumDisabled = isPremiumDisabled
} }
public static func ==(lhs: PremiumLimitDisplayComponent, rhs: PremiumLimitDisplayComponent) -> Bool { public static func ==(lhs: PremiumLimitDisplayComponent, rhs: PremiumLimitDisplayComponent) -> Bool {
@ -457,6 +491,9 @@ public final class PremiumLimitDisplayComponent: CombinedComponent {
if lhs.badgePosition != rhs.badgePosition { if lhs.badgePosition != rhs.badgePosition {
return false return false
} }
if lhs.isPremiumDisabled != rhs.isPremiumDisabled {
return false
}
return true return true
} }
@ -473,6 +510,25 @@ public final class PremiumLimitDisplayComponent: CombinedComponent {
let height: CGFloat = 120.0 let height: CGFloat = 120.0
let lineHeight: CGFloat = 30.0 let lineHeight: CGFloat = 30.0
let animation = animation.update(
component: PremiumLimitAnimationComponent(
iconName: component.badgeIconName,
inactiveColor: component.inactiveColor,
activeColors: component.activeColors,
textColor: component.activeTitleColor,
badgeText: component.badgeText,
badgePosition: component.badgePosition,
isPremiumDisabled: component.isPremiumDisabled
),
availableSize: CGSize(width: context.availableSize.width, height: height),
transition: context.transition
)
context.add(animation
.position(CGPoint(x: context.availableSize.width / 2.0, y: height / 2.0))
)
if !component.isPremiumDisabled {
let inactiveTitle = inactiveTitle.update( let inactiveTitle = inactiveTitle.update(
component: MultilineTextComponent( component: MultilineTextComponent(
text: .plain( text: .plain(
@ -529,23 +585,6 @@ public final class PremiumLimitDisplayComponent: CombinedComponent {
transition: context.transition transition: context.transition
) )
let animation = animation.update(
component: PremiumLimitAnimationComponent(
iconName: component.badgeIconName,
inactiveColor: component.inactiveColor,
activeColors: component.activeColors,
textColor: component.activeTitleColor,
badgeText: component.badgeText,
badgePosition: component.badgePosition
),
availableSize: CGSize(width: context.availableSize.width, height: height),
transition: context.transition
)
context.add(animation
.position(CGPoint(x: context.availableSize.width / 2.0, y: height / 2.0))
)
context.add(inactiveTitle context.add(inactiveTitle
.position(CGPoint(x: inactiveTitle.size.width / 2.0 + 12.0, y: height - lineHeight / 2.0)) .position(CGPoint(x: inactiveTitle.size.width / 2.0 + 12.0, y: height - lineHeight / 2.0))
) )
@ -561,6 +600,7 @@ public final class PremiumLimitDisplayComponent: CombinedComponent {
context.add(activeValue context.add(activeValue
.position(CGPoint(x: context.availableSize.width - activeValue.size.width / 2.0 - 12.0, y: height - lineHeight / 2.0)) .position(CGPoint(x: context.availableSize.width - activeValue.size.width / 2.0 - 12.0, y: height - lineHeight / 2.0))
) )
}
return CGSize(width: context.availableSize.width, height: height) return CGSize(width: context.availableSize.width, height: height)
} }
@ -656,6 +696,9 @@ private final class LimitSheetContent: CombinedComponent {
let state = context.state let state = context.state
let subject = component.subject let subject = component.subject
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
let isPremiumDisabled = premiumConfiguration.isPremiumDisabled
let sideInset: CGFloat = 16.0 + environment.safeInsets.left let sideInset: CGFloat = 16.0 + environment.safeInsets.left
let textSideInset: CGFloat = 24.0 + environment.safeInsets.left let textSideInset: CGFloat = 24.0 + environment.safeInsets.left
@ -684,7 +727,7 @@ private final class LimitSheetContent: CombinedComponent {
var titleText = strings.Premium_LimitReached var titleText = strings.Premium_LimitReached
var buttonAnimationName = "premium_x2" var buttonAnimationName = "premium_x2"
let iconName: String let iconName: String
let badgeText: String var badgeText: String
var string: String var string: String
let defaultValue: String let defaultValue: String
let premiumValue: String let premiumValue: String
@ -703,6 +746,11 @@ private final class LimitSheetContent: CombinedComponent {
if !state.isPremium && badgePosition > 0.5 { if !state.isPremium && badgePosition > 0.5 {
string = strings.Premium_MaxFoldersCountText("\(limit)", "\(premiumLimit)").string string = strings.Premium_MaxFoldersCountText("\(limit)", "\(premiumLimit)").string
} }
if isPremiumDisabled {
badgeText = "\(limit)"
string = strings.Premium_MaxFoldersCountNoPremiumText("\(limit)").string
}
case .chatsPerFolder: case .chatsPerFolder:
let limit = state.limits.maxFolderChatsCount let limit = state.limits.maxFolderChatsCount
let premiumLimit = state.premiumLimits.maxFolderChatsCount let premiumLimit = state.premiumLimits.maxFolderChatsCount
@ -712,6 +760,11 @@ private final class LimitSheetContent: CombinedComponent {
defaultValue = component.count > limit ? "\(limit)" : "" defaultValue = component.count > limit ? "\(limit)" : ""
premiumValue = component.count >= premiumLimit ? "" : "\(premiumLimit)" premiumValue = component.count >= premiumLimit ? "" : "\(premiumLimit)"
badgePosition = CGFloat(component.count) / CGFloat(premiumLimit) badgePosition = CGFloat(component.count) / CGFloat(premiumLimit)
if isPremiumDisabled {
badgeText = "\(limit)"
string = strings.Premium_MaxChatsInFolderNoPremiumText("\(limit)").string
}
case .pins: case .pins:
let limit = state.limits.maxPinnedChatCount let limit = state.limits.maxPinnedChatCount
let premiumLimit = state.premiumLimits.maxPinnedChatCount let premiumLimit = state.premiumLimits.maxPinnedChatCount
@ -721,6 +774,11 @@ private final class LimitSheetContent: CombinedComponent {
defaultValue = component.count > limit ? "\(limit)" : "" defaultValue = component.count > limit ? "\(limit)" : ""
premiumValue = component.count >= premiumLimit ? "" : "\(premiumLimit)" premiumValue = component.count >= premiumLimit ? "" : "\(premiumLimit)"
badgePosition = CGFloat(component.count) / CGFloat(premiumLimit) badgePosition = CGFloat(component.count) / CGFloat(premiumLimit)
if isPremiumDisabled {
badgeText = "\(limit)"
string = strings.Premium_MaxPinsNoPremiumText("\(limit)").string
}
case .files: case .files:
let limit = Int64(state.limits.maxUploadFileParts) * 512 * 1024 + 1024 * 1024 * 100 let limit = Int64(state.limits.maxUploadFileParts) * 512 * 1024 + 1024 * 1024 * 100
let premiumLimit = Int64(state.premiumLimits.maxUploadFileParts) * 512 * 1024 + 1024 * 1024 * 100 let premiumLimit = Int64(state.premiumLimits.maxUploadFileParts) * 512 * 1024 + 1024 * 1024 * 100
@ -731,6 +789,11 @@ private final class LimitSheetContent: CombinedComponent {
premiumValue = component.count != 4 ? dataSizeString(premiumLimit, formatting: DataSizeStringFormatting(strings: environment.strings, decimalSeparator: environment.dateTimeFormat.decimalSeparator)) : "" premiumValue = component.count != 4 ? dataSizeString(premiumLimit, formatting: DataSizeStringFormatting(strings: environment.strings, decimalSeparator: environment.dateTimeFormat.decimalSeparator)) : ""
badgePosition = component.count == 4 ? 1.0 : 0.5 badgePosition = component.count == 4 ? 1.0 : 0.5
titleText = strings.Premium_FileTooLarge titleText = strings.Premium_FileTooLarge
if isPremiumDisabled {
badgeText = dataSizeString(limit, formatting: DataSizeStringFormatting(strings: environment.strings, decimalSeparator: environment.dateTimeFormat.decimalSeparator))
string = strings.Premium_MaxFileSizeNoPremiumText(dataSizeString(premiumLimit, formatting: DataSizeStringFormatting(strings: environment.strings, decimalSeparator: environment.dateTimeFormat.decimalSeparator))).string
}
case .accounts: case .accounts:
let limit = 3 let limit = 3
let premiumLimit = component.count + 1 let premiumLimit = component.count + 1
@ -745,6 +808,11 @@ private final class LimitSheetContent: CombinedComponent {
badgePosition = CGFloat(component.count) / CGFloat(premiumLimit) badgePosition = CGFloat(component.count) / CGFloat(premiumLimit)
} }
buttonAnimationName = "premium_addone" buttonAnimationName = "premium_addone"
if isPremiumDisabled {
badgeText = "\(limit)"
string = strings.Premium_MaxAccountsNoPremiumText("\(limit)").string
}
} }
var reachedMaximumLimit = badgePosition >= 1.0 var reachedMaximumLimit = badgePosition >= 1.0
if case .folders = subject, !state.isPremium { if case .folders = subject, !state.isPremium {
@ -784,16 +852,26 @@ private final class LimitSheetContent: CombinedComponent {
transition: .immediate transition: .immediate
) )
if state.initialized { let gradientColors: [UIColor]
let limit = limit.update( if isPremiumDisabled {
component: PremiumLimitDisplayComponent( gradientColors = [
inactiveColor: theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5), UIColor(rgb: 0x007afe),
activeColors: [ UIColor(rgb: 0x5494ff)
]
} else {
gradientColors = [
UIColor(rgb: 0x0077ff), UIColor(rgb: 0x0077ff),
UIColor(rgb: 0x6b93ff), UIColor(rgb: 0x6b93ff),
UIColor(rgb: 0x8878ff), UIColor(rgb: 0x8878ff),
UIColor(rgb: 0xe46ace) UIColor(rgb: 0xe46ace)
], ]
}
if state.initialized {
let limit = limit.update(
component: PremiumLimitDisplayComponent(
inactiveColor: theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5),
activeColors: gradientColors,
inactiveTitle: strings.Premium_Free, inactiveTitle: strings.Premium_Free,
inactiveValue: defaultValue, inactiveValue: defaultValue,
inactiveTitleColor: theme.list.itemPrimaryTextColor, inactiveTitleColor: theme.list.itemPrimaryTextColor,
@ -802,7 +880,8 @@ private final class LimitSheetContent: CombinedComponent {
activeTitleColor: .white, activeTitleColor: .white,
badgeIconName: iconName, badgeIconName: iconName,
badgeText: badgeText, badgeText: badgeText,
badgePosition: badgePosition badgePosition: badgePosition,
isPremiumDisabled: isPremiumDisabled
), ),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height),
transition: .immediate transition: .immediate
@ -812,47 +891,50 @@ private final class LimitSheetContent: CombinedComponent {
) )
} }
let isIncreaseButton = !reachedMaximumLimit && !isPremiumDisabled
let button = button.update( let button = button.update(
component: SolidRoundedButtonComponent( component: SolidRoundedButtonComponent(
title: !reachedMaximumLimit ? strings.Premium_IncreaseLimit : strings.Common_OK, title: isIncreaseButton ? strings.Premium_IncreaseLimit : strings.Common_OK,
theme: SolidRoundedButtonComponent.Theme( theme: SolidRoundedButtonComponent.Theme(
backgroundColor: .black, backgroundColor: .black,
backgroundColors: [ backgroundColors: gradientColors,
UIColor(rgb: 0x0077ff),
UIColor(rgb: 0x6b93ff),
UIColor(rgb: 0x8878ff),
UIColor(rgb: 0xe46ace)
],
foregroundColor: .white foregroundColor: .white
), ),
font: .bold, font: .bold,
fontSize: 17.0, fontSize: 17.0,
height: 50.0, height: 50.0,
cornerRadius: 10.0, cornerRadius: 10.0,
gloss: !reachedMaximumLimit, gloss: isIncreaseButton,
animationName: !reachedMaximumLimit ? buttonAnimationName : nil, animationName: isIncreaseButton ? buttonAnimationName : nil,
iconPosition: .right, iconPosition: .right,
action: { [weak component] in action: { [weak component] in
guard let component = component else { guard let component = component else {
return return
} }
component.dismiss() component.dismiss()
if isIncreaseButton {
component.action() component.action()
} }
}
), ),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
transition: context.transition transition: context.transition
) )
var textOffset: CGFloat = 228.0
if isPremiumDisabled {
textOffset -= 68.0
}
context.add(title context.add(title
.position(CGPoint(x: context.availableSize.width / 2.0, y: 28.0)) .position(CGPoint(x: context.availableSize.width / 2.0, y: 28.0))
) )
context.add(text context.add(text
.position(CGPoint(x: context.availableSize.width / 2.0, y: 228.0)) .position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset))
) )
let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: 228.0 + ceil(text.size.height / 2.0) + 38.0), size: button.size) let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: textOffset + ceil(text.size.height / 2.0) + 38.0), size: button.size)
context.add(button context.add(button
.position(CGPoint(x: buttonFrame.midX, y: buttonFrame.midY)) .position(CGPoint(x: buttonFrame.midX, y: buttonFrame.midY))
) )

View File

@ -167,7 +167,8 @@ private final class LimitComponent: CombinedComponent {
activeTitleColor: component.activeTextColor, activeTitleColor: component.activeTextColor,
badgeIconName: "", badgeIconName: "",
badgeText: nil, badgeText: nil,
badgePosition: 0.0 badgePosition: 0.0,
isPremiumDisabled: false
), ),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height),
transition: .immediate transition: .immediate

View File

@ -30,7 +30,6 @@ open class RollingLabel: UILabel {
open var showSymbol = false open var showSymbol = false
private var scrollLayers: [CAScrollLayer] = [] private var scrollLayers: [CAScrollLayer] = []
private var scrollLabels: [UILabel] = [] private var scrollLabels: [UILabel] = []
private let duration = 1.12
private let durationOffset = 0.2 private let durationOffset = 0.2
private let textsNotAnimated = [","] private let textsNotAnimated = [","]
@ -38,26 +37,26 @@ open class RollingLabel: UILabel {
self.suffix = suffix self.suffix = suffix
} }
func configure(with string: String) { func configure(with string: String, duration: Double = 0.9) {
fullText = string self.fullText = string
clean() self.clean()
setupSubviews() self.setupSubviews()
self.text = " " self.text = " "
self.animate() self.animate(duration: duration)
} }
private func animate(ascending: Bool = true) { private func animate(ascending: Bool = true, duration: Double) {
createAnimations(ascending: ascending) self.createAnimations(ascending: ascending, duration: duration)
} }
private func clean() { private func clean() {
self.text = nil self.text = nil
self.subviews.forEach { $0.removeFromSuperview() } self.subviews.forEach { $0.removeFromSuperview() }
self.layer.sublayers?.forEach { $0.removeFromSuperlayer() } self.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
scrollLayers.removeAll() self.scrollLayers.removeAll()
scrollLabels.removeAll() self.scrollLabels.removeAll()
} }
private func setupSubviews() { private func setupSubviews() {
@ -168,7 +167,7 @@ open class RollingLabel: UILabel {
} }
} }
private func createAnimations(ascending: Bool) { private func createAnimations(ascending: Bool, duration: Double) {
var offset: CFTimeInterval = 0.0 var offset: CFTimeInterval = 0.0
for scrollLayer in scrollLayers { for scrollLayer in scrollLayers {

View File

@ -257,7 +257,7 @@ private class StickerNode: ASDisplayNode {
} }
} }
let placeholderFrame = CGRect(origin: .zero, size: imageSize) let placeholderFrame = CGRect(origin: CGPoint(x: -10.0, y: 0.0), size: imageSize)
let thumbnailDimensions = PixelDimensions(width: 512, height: 512) let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: self.file.immediateThumbnailData, size: placeholderFrame.size, imageSize: thumbnailDimensions.cgSize) self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: self.file.immediateThumbnailData, size: placeholderFrame.size, imageSize: thumbnailDimensions.cgSize)
self.placeholderNode.frame = placeholderFrame self.placeholderNode.frame = placeholderFrame
@ -297,7 +297,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
super.init() super.init()
self.clipsToBounds = true // self.clipsToBounds = true
self.addSubnode(self.scrollNode) self.addSubnode(self.scrollNode)
self.scrollNode.addSubnode(self.tapNode) self.scrollNode.addSubnode(self.tapNode)