Various improvements

This commit is contained in:
Ilya Laktyushin 2022-05-15 19:43:19 +04:00
parent 7008cd1559
commit fcd43ff537
17 changed files with 448 additions and 133 deletions

View File

@ -7597,8 +7597,7 @@ Sorry for the inconvenience.";
"Premium.Avatar" = "Animated Profile Pictures";
"Premium.AvatarInfo" = "Video avatars animated in chat lists and chats to allow for additional self-expression.";
"Premium.HelpUs" = "Help us maintain Premium Features while keeping Telegram free for everyone.";
"Premium.SubscribeFor" = "Subscribe for %@ per month";
"Premium.AboutTitle" = "ABOUT TELEGRAM PREMIUM";
"Premium.AboutText" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";

View File

@ -18,6 +18,7 @@ public final class SolidRoundedButtonComponent: Component {
public let gloss: Bool
public let iconName: String?
public let iconPosition: SolidRoundedButtonIconPosition
public let isLoading: Bool
public let action: () -> Void
public init(
@ -31,6 +32,7 @@ public final class SolidRoundedButtonComponent: Component {
gloss: Bool = false,
iconName: String? = nil,
iconPosition: SolidRoundedButtonIconPosition = .left,
isLoading: Bool = false,
action: @escaping () -> Void
) {
self.title = title
@ -43,6 +45,7 @@ public final class SolidRoundedButtonComponent: Component {
self.gloss = gloss
self.iconName = iconName
self.iconPosition = iconPosition
self.isLoading = isLoading
self.action = action
}
@ -77,7 +80,9 @@ public final class SolidRoundedButtonComponent: Component {
if lhs.iconPosition != rhs.iconPosition {
return false
}
if lhs.isLoading != rhs.isLoading {
return false
}
return true
}
@ -85,6 +90,8 @@ public final class SolidRoundedButtonComponent: Component {
private var component: SolidRoundedButtonComponent?
private var button: SolidRoundedButtonView?
private var currentIsLoading = false
public func update(component: SolidRoundedButtonComponent, availableSize: CGSize, transition: Transition) -> CGSize {
if self.button == nil {
let button = SolidRoundedButtonView(
@ -98,6 +105,7 @@ public final class SolidRoundedButtonComponent: Component {
gloss: component.gloss
)
button.iconPosition = component.iconPosition
button.progressType = .embedded
button.icon = component.iconName.flatMap { UIImage(bundleImageName: $0) }
self.button = button
self.addSubview(button)
@ -111,6 +119,15 @@ public final class SolidRoundedButtonComponent: Component {
button.updateTheme(component.theme)
let height = button.updateLayout(width: availableSize.width, transition: .immediate)
transition.setFrame(view: button, frame: CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: height)), completion: nil)
if self.currentIsLoading != component.isLoading {
self.currentIsLoading = component.isLoading
if component.isLoading {
button.transitionToProgress()
} else {
button.transitionFromProgress()
}
}
}
self.component = component

View File

@ -334,6 +334,7 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
var statusBarTransition = transition
var ignoreInputHeight = false
if let pending = self.state.pending {
if pending.isReady {
self.state.pending = nil
@ -344,6 +345,9 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
if pending.value.value.view.disableAutomaticKeyboardHandling.isEmpty {
updatedLayout = updatedLayout.withUpdatedInputHeight(nil)
}
if case .regular = layout.metrics.widthClass, pending.value.layout.inputHeight == nil {
ignoreInputHeight = true
}
self.topTransition(from: previous, to: pending.value, transitionType: pending.transitionType, layout: updatedLayout, transition: pending.transition)
self.state.top?.value.isInFocus = self.isInFocus
statusBarTransition = pending.transition
@ -369,6 +373,9 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
updatedLayout = updatedLayout.withUpdatedInputHeight(nil)
}
}
if ignoreInputHeight {
updatedLayout = updatedLayout.withUpdatedInputHeight(nil)
}
self.applyLayout(layout: updatedLayout, to: top, isMaster: true, transition: transition)
if let childTransition = self.state.transition, childTransition.coordinator.isInteractive {
switch childTransition.type {

View File

@ -5,15 +5,6 @@ import StoreKit
import Postbox
import TelegramCore
private final class PaymentTransactionContext {
var state: SKPaymentTransactionState?
let subscriber: (SKPaymentTransactionState) -> Void
init(subscriber: @escaping (SKPaymentTransactionState) -> Void) {
self.subscriber = subscriber
}
}
public final class InAppPurchaseManager: NSObject {
public final class Product {
let skProduct: SKProduct
@ -30,14 +21,31 @@ public final class InAppPurchaseManager: NSObject {
}
}
public enum PurchaseResult {
case success
public enum PurchaseState {
case purchased(transactionId: String)
}
public enum PurchaseError {
case generic
}
private final class PaymentTransactionContext {
var state: SKPaymentTransactionState?
let subscriber: (TransactionState) -> Void
init(subscriber: @escaping (TransactionState) -> Void) {
self.subscriber = subscriber
}
}
private enum TransactionState {
case purchased(transactionId: String?)
case restored(transactionId: String?)
case purchasing
case failed
case deferred
}
private let premiumProductId: String
private var products: [Product] = []
@ -57,7 +65,7 @@ public final class InAppPurchaseManager: NSObject {
}
deinit {
SKPaymentQueue.default().remove(self)
}
private func requestProducts() {
@ -79,27 +87,28 @@ public final class InAppPurchaseManager: NSObject {
return self.productsPromise.get()
}
public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseResult, PurchaseError> {
public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseState, PurchaseError> {
let payment = SKMutablePayment(product: product.skProduct)
payment.applicationUsername = "\(account.peerId.id._internalGetInt64Value())"
SKPaymentQueue.default().add(payment)
let productIdentifier = payment.productIdentifier
let signal = Signal<PurchaseResult, PurchaseError> { subscriber in
let signal = Signal<PurchaseState, PurchaseError> { subscriber in
let disposable = MetaDisposable()
self.stateQueue.async {
let paymentContext = PaymentTransactionContext(subscriber: { state in
switch state {
case .purchased, .restored:
subscriber.putNext(.success)
subscriber.putCompletion()
case let .purchased(transactionId), let .restored(transactionId):
if let transactionId = transactionId {
subscriber.putNext(.purchased(transactionId: transactionId))
subscriber.putCompletion()
} else {
subscriber.putError(.generic)
}
case .failed:
subscriber.putError(.generic)
case .deferred, .purchasing:
break
default:
break
}
})
self.paymentContexts[productIdentifier] = paymentContext
@ -135,7 +144,24 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
let productIdentifier = transaction.payment.productIdentifier
self.stateQueue.async {
if let context = self.paymentContexts[productIdentifier] {
context.subscriber(transaction.transactionState)
let transactionState: TransactionState?
switch transaction.transactionState {
case .purchased:
transactionState = .purchased(transactionId: transaction.transactionIdentifier)
case .restored:
transactionState = .restored(transactionId: transaction.transactionIdentifier)
case .failed:
transactionState = .failed
case .purchasing:
transactionState = .purchasing
case .deferred:
transactionState = .deferred
default:
transactionState = nil
}
if let transactionState = transactionState {
context.subscriber(transactionState)
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1002 B

View File

@ -53,6 +53,9 @@ private class StarComponent: Component {
private let sceneView: SCNView
private var previousInteractionTimestamp: Double = 0.0
private var timer: SwiftSignalKit.Timer?
override init(frame: CGRect) {
self.sceneView = SCNView(frame: frame)
self.sceneView.backgroundColor = .clear
@ -79,11 +82,17 @@ private class StarComponent: Component {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.timer?.invalidate()
}
@objc private func handleTap(_ gesture: UITapGestureRecognizer) {
guard let scene = self.sceneView.scene, let node = scene.rootNode.childNode(withName: "star", recursively: false) else {
return
}
self.previousInteractionTimestamp = CACurrentMediaTime()
var left = true
if let view = gesture.view {
let point = gesture.location(in: view)
@ -133,6 +142,8 @@ private class StarComponent: Component {
return
}
self.previousInteractionTimestamp = CACurrentMediaTime()
if #available(iOS 11.0, *) {
node.removeAnimation(forKey: "rotate", blendOutDuration: 0.1)
node.removeAnimation(forKey: "tapRotate", blendOutDuration: 0.1)
@ -189,6 +200,17 @@ private class StarComponent: Component {
self.setupShineAnimation()
self.playAppearanceAnimation(explode: true)
self.previousInteractionTimestamp = CACurrentMediaTime()
self.timer = SwiftSignalKit.Timer(timeout: 1.0, repeat: true, completion: { [weak self] in
if let strongSelf = self {
let currentTimestamp = CACurrentMediaTime()
if currentTimestamp > strongSelf.previousInteractionTimestamp + 5.0 {
strongSelf.playAppearanceAnimation()
}
}
}, queue: Queue.mainQueue())
self.timer?.start()
}
private func setupGradientAnimation() {
@ -240,6 +262,8 @@ private class StarComponent: Component {
return
}
self.previousInteractionTimestamp = CACurrentMediaTime()
if explode, let node = scene.rootNode.childNode(withName: "swirl", recursively: false), let particles = scene.rootNode.childNode(withName: "particles", recursively: false) {
let particleSystem = particles.particleSystems?.first
particleSystem?.particleColorVariation = SCNVector4(0.15, 0.2, 0.35, 0.3)
@ -251,7 +275,7 @@ private class StarComponent: Component {
Queue.mainQueue().after(1.0) {
node.physicsField?.isActive = false
particles.particleSystems?.first?.birthRate = 1.2
particleSystem?.particleVelocity = 1.65
particleSystem?.particleVelocity = 1.0
particleSystem?.particleLifeSpan = 4.0
}
}
@ -269,6 +293,10 @@ private class StarComponent: Component {
let to = SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: toValue)
let distance = rad2deg(to.w - from.w)
guard !distance.isZero else {
return
}
let springAnimation = CASpringAnimation(keyPath: "rotation")
springAnimation.fromValue = NSValue(scnVector4: from)
springAnimation.toValue = NSValue(scnVector4: to)
@ -302,9 +330,11 @@ private class StarComponent: Component {
private final class SectionGroupComponent: Component {
public final class Item: Equatable {
public let content: AnyComponentWithIdentity<Empty>
public let action: () -> Void
public init(_ content: AnyComponentWithIdentity<Empty>) {
public init(_ content: AnyComponentWithIdentity<Empty>, action: @escaping () -> Void) {
self.content = content
self.action = action
}
public static func ==(lhs: Item, rhs: Item) -> Bool {
@ -318,15 +348,18 @@ private final class SectionGroupComponent: Component {
public let items: [Item]
public let backgroundColor: UIColor
public let selectionColor: UIColor
public let separatorColor: UIColor
public init(
items: [Item],
backgroundColor: UIColor,
selectionColor: UIColor,
separatorColor: UIColor
) {
self.items = items
self.backgroundColor = backgroundColor
self.selectionColor = selectionColor
self.separatorColor = separatorColor
}
@ -337,6 +370,9 @@ private final class SectionGroupComponent: Component {
if lhs.backgroundColor != rhs.backgroundColor {
return false
}
if lhs.selectionColor != rhs.selectionColor {
return false
}
if lhs.separatorColor != rhs.separatorColor {
return false
}
@ -344,28 +380,34 @@ private final class SectionGroupComponent: Component {
}
public final class View: UIView {
private let backgroundView: UIView
private var buttonViews: [AnyHashable: HighlightTrackingButton] = [:]
private var itemViews: [AnyHashable: ComponentHostView<Empty>] = [:]
private var separatorViews: [UIView] = []
private var component: SectionGroupComponent?
override init(frame: CGRect) {
self.backgroundView = UIView()
super.init(frame: frame)
self.addSubview(self.backgroundView)
self.backgroundView.layer.cornerRadius = 10.0
self.backgroundView.layer.masksToBounds = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func buttonPressed(_ sender: HighlightTrackingButton) {
guard let component = self.component else {
return
}
if let (id, _) = self.buttonViews.first(where: { $0.value === sender }), let item = component.items.first(where: { $0.content.id == id }) {
item.action()
}
}
func update(component: SectionGroupComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let sideInset: CGFloat = 16.0
self.backgroundView.backgroundColor = component.backgroundColor
self.backgroundColor = component.backgroundColor
var size = CGSize(width: availableSize.width, height: 0.0)
@ -375,8 +417,19 @@ private final class SectionGroupComponent: Component {
for item in component.items {
validIds.append(item.content.id)
let buttonView: HighlightTrackingButton
let itemView: ComponentHostView<Empty>
var itemTransition = transition
if let current = self.buttonViews[item.content.id] {
buttonView = current
} else {
buttonView = HighlightTrackingButton()
buttonView.addTarget(self, action: #selector(self.buttonPressed(_:)), for: .touchUpInside)
self.buttonViews[item.content.id] = buttonView
self.addSubview(buttonView)
}
if let current = self.itemViews[item.content.id] {
itemView = current
} else {
@ -393,7 +446,19 @@ private final class SectionGroupComponent: Component {
)
let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height), size: itemSize)
buttonView.frame = CGRect(origin: itemFrame.origin, size: CGSize(width: availableSize.width, height: itemSize.height + UIScreenPixel))
itemView.frame = CGRect(origin: CGPoint(x: itemFrame.minX + sideInset, y: itemFrame.minY + floor((itemFrame.height - itemSize.height) / 2.0)), size: itemSize)
itemView.isUserInteractionEnabled = false
buttonView.highligthedChanged = { [weak buttonView] highlighted in
if highlighted {
buttonView?.backgroundColor = component.selectionColor
} else {
UIView.animate(withDuration: 0.3, animations: {
buttonView?.backgroundColor = nil
})
}
}
size.height += itemSize.height
@ -431,7 +496,7 @@ private final class SectionGroupComponent: Component {
self.separatorViews.removeSubrange((component.items.count - 1) ..< self.separatorViews.count)
}
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: size), completion: nil)
self.component = component
return size
}
@ -508,10 +573,15 @@ private final class ScrollComponent<ChildEnvironment: Equatable>: Component {
}
self.delegate = self
self.showsVerticalScrollIndicator = false
self.canCancelContentTouches = true
self.addSubview(self.contentView)
}
public override func touchesShouldCancel(in view: UIView) -> Bool {
return true
}
private var ignoreDidScroll = false
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let component = self.component, !self.ignoreDidScroll else {
@ -740,6 +810,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
let fade = Child(RoundedRectangle.self)
let text = Child(MultilineTextComponent.self)
let section = Child(SectionGroupComponent.self)
let infoBackground = Child(RoundedRectangle.self)
let infoTitle = Child(MultilineTextComponent.self)
let infoText = Child(MultilineTextComponent.self)
return { context in
@ -780,7 +852,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
.position(CGPoint(x: fade.size.width / 2.0, y: fade.size.height / 2.0))
)
size.height += 183.0 + 10.0
size.height += 183.0 + 10.0 + environment.navigationHeight - 56.0
let textColor = theme.list.itemPrimaryTextColor
let titleColor = theme.list.itemPrimaryTextColor
@ -833,7 +905,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
SectionGroupComponent.Item(
AnyComponentWithIdentity(
@ -852,7 +927,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
SectionGroupComponent.Item(
AnyComponentWithIdentity(
@ -871,7 +949,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
SectionGroupComponent.Item(
AnyComponentWithIdentity(
@ -890,7 +971,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
SectionGroupComponent.Item(
AnyComponentWithIdentity(
@ -909,7 +993,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
SectionGroupComponent.Item(
AnyComponentWithIdentity(
@ -928,7 +1015,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
SectionGroupComponent.Item(
AnyComponentWithIdentity(
@ -947,7 +1037,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
SectionGroupComponent.Item(
AnyComponentWithIdentity(
@ -966,10 +1059,14 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
arrowColor: arrowColor
)
)
)
),
action: {
}
),
],
backgroundColor: environment.theme.list.itemBlocksBackgroundColor,
selectionColor: environment.theme.list.itemHighlightedBackgroundColor,
separatorColor: environment.theme.list.itemBlocksSeparatorColor
),
environment: {},
@ -978,31 +1075,65 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
)
context.add(section
.position(CGPoint(x: availableWidth / 2.0, y: size.height + section.size.height / 2.0))
.clipsToBounds(true)
.cornerRadius(10.0)
)
size.height += section.size.height
size.height += 17.0
size.height += 23.0
let infoText = infoText.update(
let textSideInset: CGFloat = 16.0
let textPadding: CGFloat = 13.0
let infoTitle = infoTitle.update(
component: MultilineTextComponent(
text: .plain(
NSAttributedString(
string: strings.Premium_HelpUs,
font: Font.regular(15.0),
textColor: environment.theme.list.freeTextColor
)
NSAttributedString(string: strings.Premium_AboutTitle.uppercased(), font: Font.regular(14.0), textColor: environment.theme.list.freeTextColor)
),
horizontalAlignment: .center,
horizontalAlignment: .natural,
maximumNumberOfLines: 0,
lineSpacing: 0.2
),
environment: {},
availableSize: CGSize(width: availableWidth - sideInsets, height: 120.0),
availableSize: CGSize(width: availableWidth - sideInsets, height: .greatestFiniteMagnitude),
transition: context.transition
)
context.add(infoText
.position(CGPoint(x: size.width / 2.0, y: size.height + infoText.size.height / 2.0))
context.add(infoTitle
.position(CGPoint(x: sideInset + environment.safeInsets.left + textSideInset + infoTitle.size.width / 2.0, y: size.height + infoTitle.size.height / 2.0))
)
size.height += text.size.height
size.height += infoTitle.size.height
size.height += 3.0
let infoText = infoText.update(
component: MultilineTextComponent(
text: .markdown(
text: strings.Premium_AboutText,
attributes: markdownAttributes
),
horizontalAlignment: .natural,
maximumNumberOfLines: 0,
lineSpacing: 0.2
),
environment: {},
availableSize: CGSize(width: availableWidth - sideInsets - textSideInset * 2.0, height: .greatestFiniteMagnitude),
transition: context.transition
)
let infoBackground = infoBackground.update(
component: RoundedRectangle(
color: environment.theme.list.itemBlocksBackgroundColor,
cornerRadius: 10.0
),
environment: {},
availableSize: CGSize(width: availableWidth - sideInsets, height: infoText.size.height + textPadding * 2.0),
transition: context.transition
)
context.add(infoBackground
.position(CGPoint(x: size.width / 2.0, y: size.height + infoBackground.size.height / 2.0))
)
context.add(infoText
.position(CGPoint(x: sideInset + environment.safeInsets.left + textSideInset + infoText.size.width / 2.0, y: size.height + textPadding + infoText.size.height / 2.0))
)
size.height += infoBackground.size.height
size.height += 3.0
size.height += scrollEnvironment.insets.bottom
@ -1089,7 +1220,8 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
var inProgress = false
var premiumProduct: InAppPurchaseManager.Product?
private var disposable: Disposable?
private var actionDisposable = MetaDisposable()
private var paymentDisposable = MetaDisposable()
private var activationDisposable = MetaDisposable()
init(context: AccountContext, updateInProgress: @escaping (Bool) -> Void, completion: @escaping () -> Void) {
self.context = context
@ -1111,7 +1243,8 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
deinit {
self.disposable?.dispose()
self.actionDisposable.dispose()
self.paymentDisposable.dispose()
self.activationDisposable.dispose()
}
func buy() {
@ -1124,10 +1257,17 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
self.updateInProgress(true)
self.updated(transition: .immediate)
self.actionDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct, account: self.context.account)
|> deliverOnMainQueue).start(next: { [weak self] _ in
if let strongSelf = self {
strongSelf.completion()
self.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct, account: self.context.account)
|> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self, case let .purchased(transactionId) = status {
strongSelf.activationDisposable.set((strongSelf.context.engine.payments.assignAppStoreTransaction(transactionId: transactionId)
|> deliverOnMainQueue).start(error: { _ in
}, completed: { [weak self] in
if let strongSelf = self {
strongSelf.completion()
}
}))
}
}, error: { [weak self] _ in
if let strongSelf = self {
@ -1202,7 +1342,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
component: SolidRoundedButtonComponent(
title: environment.strings.Premium_SubscribeFor(state.premiumProduct?.price ?? "").string,
theme: SolidRoundedButtonComponent.Theme(
backgroundColor: .black,
backgroundColor: UIColor(rgb: 0x8878ff),
backgroundColors: [
UIColor(rgb: 0x0077ff),
UIColor(rgb: 0x6b93ff),
@ -1214,6 +1354,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
height: 50.0,
cornerRadius: 10.0,
gloss: true,
isLoading: state.inProgress,
action: {
state.buy()
}
@ -1263,6 +1404,8 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
transition: context.transition
)
let topInset: CGFloat = environment.navigationHeight - 56.0
context.add(background
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
)
@ -1274,7 +1417,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
let topPanelAlpha: CGFloat
let titleOffset: CGFloat
let titleScale: CGFloat
let titleOffsetDelta = 160.0 - environment.navigationHeight / 2.0
let titleOffsetDelta = (topInset + 160.0) - (environment.statusBarHeight + (environment.navigationHeight - environment.statusBarHeight) / 2.0)
if let topContentOffset = state.topContentOffset {
topPanelAlpha = min(20.0, max(0.0, topContentOffset - 95.0)) / 20.0
@ -1289,7 +1432,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
}
context.add(star
.position(CGPoint(x: context.availableSize.width / 2.0, y: star.size.height / 2.0 - 30.0 - titleOffset * titleScale))
.position(CGPoint(x: context.availableSize.width / 2.0, y: topInset + star.size.height / 2.0 - 30.0 - titleOffset * titleScale))
.scale(titleScale)
)
@ -1303,7 +1446,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
)
context.add(title
.position(CGPoint(x: context.availableSize.width / 2.0, y: max(160.0 - titleOffset, environment.navigationHeight / 2.0)))
.position(CGPoint(x: context.availableSize.width / 2.0, y: max(topInset + 160.0 - titleOffset, environment.statusBarHeight + (environment.navigationHeight - environment.statusBarHeight) / 2.0)))
.scale(titleScale)
)
@ -1340,7 +1483,7 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer {
return self._ready
}
public init(context: AccountContext) {
public init(context: AccountContext, modal: Bool = true) {
self.context = context
var updateInProgressImpl: ((Bool) -> Void)?
@ -1357,10 +1500,13 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let cancelItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
self.navigationItem.setLeftBarButton(cancelItem, animated: false)
self.navigationPresentation = .modal
if modal {
let cancelItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
self.navigationItem.setLeftBarButton(cancelItem, animated: false)
self.navigationPresentation = .modal
} else {
self.navigationPresentation = .modalInLargeLayout
}
updateInProgressImpl = { [weak self] inProgress in
if let strongSelf = self {

View File

@ -71,6 +71,8 @@ private class PremiumLimitAnimationComponent: Component {
private let badgeIcon: UIImageView
private let badgeCountLabel: RollingLabel
private let hapticFeedback = HapticFeedback()
override init(frame: CGRect) {
self.container = SimpleLayer()
self.container.masksToBounds = true
@ -102,6 +104,8 @@ private class PremiumLimitAnimationComponent: Component {
self.badgeMaskView = UIView()
self.badgeMaskView.addSubview(self.badgeMaskBackgroundView)
self.badgeMaskView.addSubview(self.badgeMaskArrowView)
self.badgeMaskView.layer.rasterizationScale = UIScreenScale
self.badgeMaskView.layer.shouldRasterize = true
self.badgeView.mask = self.badgeMaskView
self.badgeForeground = SimpleLayer()
@ -156,6 +160,10 @@ private class PremiumLimitAnimationComponent: Component {
rotateAnimation.fillMode = .forwards
rotateAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
Queue.mainQueue().after(0.5, {
self.hapticFeedback.impact(.light)
})
let returnAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
returnAnimation.fromValue = 0.2 as NSNumber
returnAnimation.toValue = 0.0 as NSNumber

View File

@ -11,7 +11,7 @@ private func generateIndefiniteActivityIndicatorImage(color: UIColor, diameter:
context.setStrokeColor(color.cgColor)
context.setLineWidth(lineWidth)
context.setLineCap(.round)
let cutoutAngle: CGFloat = CGFloat.pi * 30.0 / 180.0
let cutoutAngle: CGFloat = CGFloat.pi * 60.0 / 180.0
context.addArc(center: CGPoint(x: size.width / 2.0, y: size.height / 2.0), radius: size.width / 2.0 - lineWidth / 2.0, startAngle: 0.0, endAngle: CGFloat.pi * 2.0 - cutoutAngle, clockwise: false)
context.strokePath()
})
@ -52,6 +52,11 @@ public enum SolidRoundedButtonIconPosition {
case right
}
public enum SolidRoundedButtonProgressType {
case fullSize
case embedded
}
public final class SolidRoundedButtonNode: ASDisplayNode {
private var theme: SolidRoundedButtonTheme
private var font: SolidRoundedButtonFont
@ -518,6 +523,8 @@ public final class SolidRoundedButtonView: UIView {
}
}
public var progressType: SolidRoundedButtonProgressType = .fullSize
public init(title: String? = nil, icon: UIImage? = nil, theme: SolidRoundedButtonTheme, font: SolidRoundedButtonFont = .bold, fontSize: CGFloat = 17.0, height: CGFloat = 48.0, cornerRadius: CGFloat = 24.0, gloss: Bool = false) {
self.theme = theme
self.font = font
@ -530,9 +537,8 @@ public final class SolidRoundedButtonView: UIView {
self.buttonBackgroundNode.clipsToBounds = true
self.buttonBackgroundNode.layer.cornerRadius = cornerRadius
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
if theme.backgroundColors.count > 1 {
self.buttonBackgroundNode.backgroundColor = nil
var locations: [CGFloat] = []
let delta = 1.0 / CGFloat(theme.backgroundColors.count - 1)
for i in 0 ..< theme.backgroundColors.count {
@ -544,8 +550,6 @@ public final class SolidRoundedButtonView: UIView {
buttonBackgroundAnimationView.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
self.buttonBackgroundNode.addSubview(buttonBackgroundAnimationView)
self.buttonBackgroundAnimationView = buttonBackgroundAnimationView
} else {
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
}
self.buttonNode = HighlightTrackingButton()
@ -675,40 +679,90 @@ public final class SolidRoundedButtonView: UIView {
self.isUserInteractionEnabled = false
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
rotationAnimation.duration = 1.0
rotationAnimation.fromValue = NSNumber(value: Float(0.0))
rotationAnimation.toValue = NSNumber(value: Float.pi * 2.0)
rotationAnimation.repeatCount = Float.infinity
rotationAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
rotationAnimation.beginTime = 1.0
let buttonOffset = self.buttonBackgroundNode.frame.minX
let buttonWidth = self.buttonBackgroundNode.frame.width
let progressFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(buttonOffset + (buttonWidth - self.buttonHeight) / 2.0), y: 0.0), size: CGSize(width: self.buttonHeight, height: self.buttonHeight))
let progressNode = UIImageView()
progressNode.frame = progressFrame
progressNode.image = generateIndefiniteActivityIndicatorImage(color: self.buttonBackgroundNode.backgroundColor ?? .clear, diameter: self.buttonHeight, lineWidth: 2.0 + UIScreenPixel)
self.insertSubview(progressNode, at: 0)
switch self.progressType {
case .fullSize:
let progressFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(buttonOffset + (buttonWidth - self.buttonHeight) / 2.0), y: 0.0), size: CGSize(width: self.buttonHeight, height: self.buttonHeight))
progressNode.frame = progressFrame
progressNode.image = generateIndefiniteActivityIndicatorImage(color: self.buttonBackgroundNode.backgroundColor ?? .clear, diameter: self.buttonHeight, lineWidth: 2.0 + UIScreenPixel)
self.buttonBackgroundNode.layer.cornerRadius = self.buttonHeight / 2.0
self.buttonBackgroundNode.layer.animate(from: self.buttonCornerRadius as NSNumber, to: self.buttonHeight / 2.0 as NSNumber, keyPath: "cornerRadius", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2)
self.buttonBackgroundNode.layer.animateFrame(from: self.buttonBackgroundNode.frame, to: progressFrame, duration: 0.2)
self.buttonBackgroundNode.alpha = 0.0
self.buttonBackgroundNode.layer.animateAlpha(from: 0.55, to: 0.0, duration: 0.2, removeOnCompletion: false)
self.insertSubview(progressNode, at: 0)
case .embedded:
let diameter: CGFloat = self.buttonHeight - 22.0
let progressFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(buttonOffset + (buttonWidth - diameter) / 2.0), y: floorToScreenPixels((self.buttonHeight - diameter) / 2.0)), size: CGSize(width: diameter, height: diameter))
progressNode.frame = progressFrame
progressNode.image = generateIndefiniteActivityIndicatorImage(color: self.theme.foregroundColor, diameter: diameter, lineWidth: 3.0)
self.addSubview(progressNode)
}
progressNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
progressNode.layer.add(rotationAnimation, forKey: "progressRotation")
self.progressNode = progressNode
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
basicAnimation.duration = 0.5
basicAnimation.fromValue = NSNumber(value: Float(0.0))
basicAnimation.toValue = NSNumber(value: Float.pi * 2.0)
basicAnimation.repeatCount = Float.infinity
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
basicAnimation.beginTime = 1.0
progressNode.layer.add(basicAnimation, forKey: "progressRotation")
self.buttonBackgroundNode.layer.cornerRadius = self.buttonHeight / 2.0
self.buttonBackgroundNode.layer.animate(from: self.buttonCornerRadius as NSNumber, to: self.buttonHeight / 2.0 as NSNumber, keyPath: "cornerRadius", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2)
self.buttonBackgroundNode.layer.animateFrame(from: self.buttonBackgroundNode.frame, to: progressFrame, duration: 0.2)
self.buttonBackgroundNode.alpha = 0.0
self.buttonBackgroundNode.layer.animateAlpha(from: 0.55, to: 0.0, duration: 0.2, removeOnCompletion: false)
progressNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, removeOnCompletion: false)
self.titleNode.alpha = 0.0
self.titleNode.layer.animateAlpha(from: 0.55, to: 0.0, duration: 0.2)
self.subtitleNode.alpha = 0.0
self.subtitleNode.layer.animateAlpha(from: 0.55, to: 0.0, duration: 0.2)
self.shimmerView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
self.borderShimmerView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
public func transitionFromProgress() {
guard let progressNode = self.progressNode else {
return
}
self.progressNode = nil
switch self.progressType {
case .fullSize:
self.buttonBackgroundNode.layer.cornerRadius = self.buttonCornerRadius
self.buttonBackgroundNode.layer.animate(from: self.buttonHeight / 2.0 as NSNumber, to: self.buttonCornerRadius as NSNumber, keyPath: "cornerRadius", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2)
self.buttonBackgroundNode.layer.animateFrame(from: progressNode.frame, to: self.bounds, duration: 0.2)
self.buttonBackgroundNode.alpha = 1.0
self.buttonBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, removeOnCompletion: false)
case .embedded:
break
}
progressNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak progressNode, weak self] _ in
progressNode?.removeFromSuperview()
self?.isUserInteractionEnabled = true
})
self.titleNode.alpha = 1.0
self.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.subtitleNode.alpha = 1.0
self.subtitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.shimmerView?.layer.removeAllAnimations()
self.shimmerView?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.borderShimmerView?.layer.removeAllAnimations()
self.borderShimmerView?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
func updateShimmerParameters() {
@ -744,9 +798,8 @@ public final class SolidRoundedButtonView: UIView {
}
self.theme = theme
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
if theme.backgroundColors.count > 1 {
self.buttonBackgroundNode.backgroundColor = nil
var locations: [CGFloat] = []
let delta = 1.0 / CGFloat(theme.backgroundColors.count - 1)
for i in 0 ..< theme.backgroundColors.count {
@ -754,7 +807,6 @@ public final class SolidRoundedButtonView: UIView {
}
self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: self.buttonHeight), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
} else {
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
self.buttonBackgroundNode.image = nil
}

View File

@ -188,7 +188,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
var centerOffset: CGFloat = 0.0
if self.item.file.isPremiumSticker {
let originalImageFrame = imageFrame
imageFrame.origin.x = size.width - imageFrame.width
imageFrame.origin.x = size.width - imageFrame.width - 18.0
centerOffset = imageFrame.minX - originalImageFrame.minX
}
self.imageNode.frame = imageFrame
@ -197,7 +197,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
animationNode.updateLayout(size: imageSize)
if let additionalAnimationNode = self.additionalAnimationNode {
additionalAnimationNode.frame = imageFrame.offsetBy(dx: -imageFrame.width * 0.25, dy: 0.0).insetBy(dx: -imageFrame.width * 0.25, dy: -imageFrame.height * 0.25)
additionalAnimationNode.frame = imageFrame.offsetBy(dx: -imageFrame.width * 0.245 + 21, dy: -1.0).insetBy(dx: -imageFrame.width * 0.245, dy: -imageFrame.height * 0.245)
additionalAnimationNode.updateLayout(size: additionalAnimationNode.frame.size)
}
}

View File

@ -4,7 +4,6 @@ import MtProtoKit
import SwiftSignalKit
import TelegramApi
public enum AssignAppStoreTransactionError {
case generic
}
@ -17,6 +16,17 @@ func _internal_assignAppStoreTransaction(account: Account, transactionId: String
|> mapToSignal { updates -> Signal<Never, AssignAppStoreTransactionError> in
account.stateManager.addUpdates(updates)
return .never()
return account.postbox.peerView(id: account.peerId)
|> castError(AssignAppStoreTransactionError.self)
|> take(until: { view in
if let peer = view.peers[view.peerId], peer.isPremium {
return SignalTakeAction(passthrough: false, complete: true)
} else {
return SignalTakeAction(passthrough: false, complete: false)
}
})
|> mapToSignal { _ -> Signal<Never, AssignAppStoreTransactionError> in
return .never()
}
}
}

View File

@ -238,11 +238,11 @@ public struct PresentationResourcesChatList {
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
let colorsArray: [CGColor] = [
UIColor(rgb: 0x6B93FF).cgColor,
UIColor(rgb: 0x6B93FF).cgColor,
UIColor(rgb: 0x976FFF).cgColor,
UIColor(rgb: 0xE46ACE).cgColor,
UIColor(rgb: 0xE46ACE).cgColor
UIColor(rgb: 0x1d95fa).cgColor,
UIColor(rgb: 0x1d95fa).cgColor,
UIColor(rgb: 0x7c8cfe).cgColor,
UIColor(rgb: 0xcb87f7).cgColor,
UIColor(rgb: 0xcb87f7).cgColor
]
var locations: [CGFloat] = [0.0, 0.35, 0.5, 0.65, 1.0]
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!

View File

@ -9374,6 +9374,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
override public func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UIView.performWithoutAnimation {
self.view.endEditing(true)
}
self.chatDisplayNode.historyNode.canReadHistory.set(.single(false))
self.saveInterfaceState()

View File

@ -721,7 +721,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) {
let displaySize = CGSize(width: 180.0, height: 180.0)
var displaySize = CGSize(width: 180.0, height: 180.0)
let telegramFile = self.telegramFile
let emojiFile = self.emojiFile
let telegramDice = self.telegramDice
@ -742,7 +742,16 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let accessibilityData = ChatMessageAccessibilityData(item: item, isSelected: nil)
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
let incoming = item.content.effectivelyIncoming(item.context.account.peerId, associatedData: item.associatedData)
var imageSize: CGSize = CGSize(width: 200.0, height: 200.0)
var imageVerticalInset: CGFloat = 0.0
var imageHorizontalOffset: CGFloat = 0.0
if !(telegramFile?.videoThumbnails.isEmpty ?? true) {
displaySize = CGSize(width: 240.0, height: 240.0)
imageVerticalInset = -30.0
imageHorizontalOffset = 12.0
}
var isEmoji = false
if let _ = telegramDice {
imageSize = displaySize
@ -879,7 +888,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let imageInset: CGFloat = 10.0
var innerImageSize = imageSize
imageSize = CGSize(width: imageSize.width + imageInset * 2.0, height: imageSize.height + imageInset * 2.0)
let imageFrame = CGRect(origin: CGPoint(x: 0.0 + (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + avatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - imageSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: 0.0), size: CGSize(width: imageSize.width, height: imageSize.height))
let imageFrame = CGRect(origin: CGPoint(x: 0.0 + (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + avatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - imageSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset - imageHorizontalOffset)), y: imageVerticalInset), size: CGSize(width: imageSize.width, height: imageSize.height))
if isEmoji {
innerImageSize = imageSize
}
@ -1017,7 +1026,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
}
let contentHeight = max(imageSize.height, layoutConstants.image.minDimensions.height)
let contentHeight = max(imageSize.height + imageVerticalInset * 2.0, layoutConstants.image.minDimensions.height)
var forwardSource: Peer?
var forwardAuthorSignature: String?
@ -1632,7 +1641,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
additionalAnimationNode.setup(source: source, width: Int(animationSize.width * 2), height: Int(animationSize.height * 2), playbackMode: .once, mode: .direct(cachePathPrefix: pathPrefix))
var animationFrame: CGRect
if isStickerEffect {
animationFrame = animationNode.frame.offsetBy(dx: incomingMessage ? animationNode.frame.width * 0.5 : -animationNode.frame.width * 0.5, dy: 35.0).insetBy(dx: -animationNode.frame.width * 0.5, dy: -animationNode.frame.height * 0.5)
let scale: CGFloat = 0.245
animationFrame = animationNode.frame.offsetBy(dx: incomingMessage ? animationNode.frame.width * scale : -animationNode.frame.width * scale + 21.0, dy: -1.0).insetBy(dx: -animationNode.frame.width * scale, dy: -animationNode.frame.height * scale)
if incomingMessage {
animationNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
}

View File

@ -6132,6 +6132,26 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
fileprivate func openSettings(section: PeerInfoSettingsSection) {
let push: (ViewController) -> Void = { [weak self] c in
guard let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController else {
return
}
var updatedControllers = navigationController.viewControllers
for controller in navigationController.viewControllers.reversed() {
if controller !== strongSelf && !(controller is TabBarController) {
updatedControllers.removeLast()
} else {
break
}
}
updatedControllers.append(c)
var animated = true
if let validLayout = strongSelf.validLayout?.0, case .regular = validLayout.metrics.widthClass {
animated = false
}
navigationController.setViewControllers(updatedControllers, animated: animated)
}
switch section {
case .avatar:
self.openAvatarForEditing()
@ -6144,21 +6164,21 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: self.context.account.peerId)))
}
case .recentCalls:
self.controller?.push(CallListController(context: context, mode: .navigation))
push(CallListController(context: context, mode: .navigation))
case .devices:
let _ = (self.activeSessionsContextAndCount.get()
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] activeSessionsContextAndCount in
if let strongSelf = self, let activeSessionsContextAndCount = activeSessionsContextAndCount {
let (activeSessionsContext, _, webSessionsContext) = activeSessionsContextAndCount
strongSelf.controller?.push(recentSessionsController(context: strongSelf.context, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, websitesOnly: false))
push(recentSessionsController(context: strongSelf.context, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, websitesOnly: false))
}
})
case .chatFolders:
self.controller?.push(chatListFilterPresetListController(context: self.context, mode: .default))
push(chatListFilterPresetListController(context: self.context, mode: .default))
case .notificationsAndSounds:
if let settings = self.data?.globalSettings {
self.controller?.push(notificationsAndSoundsController(context: self.context, exceptionsList: settings.notificationExceptions))
push(notificationsAndSoundsController(context: self.context, exceptionsList: settings.notificationExceptions))
}
case .privacyAndSecurity:
if let settings = self.data?.globalSettings {
@ -6166,7 +6186,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] blockedPeersContext, hasTwoStepAuth in
if let strongSelf = self {
strongSelf.controller?.push(privacyAndSecurityController(context: strongSelf.context, initialSettings: settings.privacySettings, updatedSettings: { [weak self] settings in
push(privacyAndSecurityController(context: strongSelf.context, initialSettings: settings.privacySettings, updatedSettings: { [weak self] settings in
self?.privacySettings.set(.single(settings))
}, updatedBlockedPeers: { [weak self] blockedPeersContext in
self?.blockedPeers.set(.single(blockedPeersContext))
@ -6177,23 +6197,23 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
})
}
case .dataAndStorage:
self.controller?.push(dataAndStorageController(context: self.context))
push(dataAndStorageController(context: self.context))
case .appearance:
self.controller?.push(themeSettingsController(context: self.context))
push(themeSettingsController(context: self.context))
case .language:
self.controller?.push(LocalizationListController(context: self.context))
push(LocalizationListController(context: self.context))
case .premium:
self.controller?.push(PremiumIntroScreen(context: self.context))
self.controller?.push(PremiumIntroScreen(context: self.context, modal: false))
case .stickers:
if let settings = self.data?.globalSettings {
self.controller?.push(installedStickerPacksController(context: self.context, mode: .general, archivedPacks: settings.archivedStickerPacks, updatedPacks: { [weak self] packs in
push(installedStickerPacksController(context: self.context, mode: .general, archivedPacks: settings.archivedStickerPacks, updatedPacks: { [weak self] packs in
self?.archivedPacks.set(.single(packs))
}))
}
case .passport:
self.controller?.push(SecureIdAuthController(context: self.context, mode: .list))
case .watch:
self.controller?.push(watchSettingsController(context: self.context))
push(watchSettingsController(context: self.context))
case .support:
let supportPeer = Promise<PeerId?>()
supportPeer.set(context.engine.peers.supportPeerId())
@ -6204,7 +6224,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { [weak self] in
self?.supportPeerDisposable.set((supportPeer.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peerId in
if let strongSelf = self, let peerId = peerId {
strongSelf.controller?.push(strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: nil, botStart: nil, mode: .standard(previewing: false)))
push(strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: nil, botStart: nil, mode: .standard(previewing: false)))
}
}))
})]), in: .window(.root))
@ -6219,10 +6239,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
navigationController.replaceTopController(ChangePhoneNumberController(context: strongSelf.context), animated: true)
}
})
self.controller?.push(introController)
push(introController)
}
case .username:
self.controller?.push(usernameSetupController(context: self.context))
push(usernameSetupController(context: self.context))
case .addAccount:
self.context.sharedContext.beginNewAuth(testingEnvironment: self.context.account.testingEnvironment)
case .logout:
@ -6233,7 +6253,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
case .rememberPassword:
let context = self.context
let controller = TwoFactorDataInputScreen(sharedContext: self.context.sharedContext, engine: .authorized(self.context.engine), mode: .rememberPassword(doneText: self.presentationData.strings.TwoFactorSetup_Done_Action), stateUpdated: { _ in
let controller = TwoFactorDataInputScreen(sharedContext: self.context.sharedContext, engine: .authorized(self.context.engine), mode: .rememberPassword(doneText: self.presentationData.strings.TwoFactorSetup_Done_Action), stateUpdated: { _ in
}, presentation: .modalInLargeLayout)
controller.twoStepAuthSettingsController = { configuration in
return twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: .single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationAccessConfiguration(configuration: configuration, password: nil)))))
@ -6241,7 +6261,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
controller.passwordRemembered = {
let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePassword).start()
}
self.controller?.push(controller)
push(controller)
}
}

View File

@ -437,6 +437,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
return
}
let eventData = (body["eventData"] as? String)?.data(using: .utf8)
let json = try? JSONSerialization.jsonObject(with: eventData ?? Data(), options: []) as? [String: Any]
switch eventName {
case "web_app_ready":
self.animateTransitionIn()
@ -447,7 +450,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
case "web_app_setup_main_button":
if let webView = self.webView, !webView.didTouchOnce && controller.url == nil {
self.delayedScriptMessage = message
} else if let eventData = (body["eventData"] as? String)?.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: eventData, options: []) as? [String: Any] {
} else if let json = json {
if var isVisible = json["is_visible"] as? Bool {
let text = json["text"] as? String
if (text ?? "").trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
@ -475,6 +478,14 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.controller?.requestAttachmentMenuExpansion()
case "web_app_close":
self.controller?.dismiss()
case "web_app_open_tg_link":
if let json = json, let path = json["path_full"] as? String {
print(path)
}
case "web_app_open_invoice":
if let json = json, let slug = json["slug"] as? String {
print(slug)
}
default:
break
}
@ -527,6 +538,11 @@ public final class WebAppController: ViewController, AttachmentContainable {
themeParamsString.append("}}")
self.webView?.sendEvent(name: "theme_changed", data: themeParamsString)
}
private func sendInvoiceClosedEvent(slug: String, status: String) {
let paramsString = "{slug: \"\(slug)\", status: \"\(status)\"}"
self.webView?.sendEvent(name: "invoice_closed", data: paramsString)
}
}
fileprivate var controllerNode: Node {