From f7ec8a0bf2d9d7d8aa677f6d2fe1880434417cb8 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 26 May 2022 03:05:10 +0400 Subject: [PATCH] Various improvements --- .../Sources/InAppPurchaseManager.swift | 1 + .../Sources/PremiumIntroScreen.swift | 74 ++++++++++++++++--- .../TelegramUI/Sources/OpenResolvedUrl.swift | 2 +- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift index f326830dc6..a00809bbd9 100644 --- a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift +++ b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift @@ -27,6 +27,7 @@ public final class InAppPurchaseManager: NSObject { public enum PurchaseError { case generic + case cancelled } private final class PaymentTransactionContext { diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index 68212c7c62..1be2281a79 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -19,7 +19,7 @@ import ConfettiEffect import TextFormat import InstantPageCache -public enum PremiumSource { +public enum PremiumSource: Equatable { case settings case stickers case reactions @@ -33,6 +33,7 @@ public enum PremiumSource { case folders case chatsPerFolder case accounts + case deeplink(String?) var identifier: String { switch self { @@ -62,6 +63,12 @@ public enum PremiumSource { return "double_limits__dialog_filters_chats" case .accounts: return "double_limits__accounts" + case let .deeplink(reference): + if let reference = reference { + return "deeplink_\(reference)" + } else { + return "deeplink" + } } } } @@ -718,14 +725,16 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { typealias EnvironmentType = (ViewControllerComponentContainer.Environment, ScrollChildEnvironment) let context: AccountContext + let source: PremiumSource let isPremium: Bool? let price: String? let present: (ViewController) -> Void let buy: () -> Void let updateIsFocused: (Bool) -> Void - init(context: AccountContext, isPremium: Bool?, price: String?, present: @escaping (ViewController) -> Void, buy: @escaping () -> Void, updateIsFocused: @escaping (Bool) -> Void) { + init(context: AccountContext, source: PremiumSource, isPremium: Bool?, price: String?, present: @escaping (ViewController) -> Void, buy: @escaping () -> Void, updateIsFocused: @escaping (Bool) -> Void) { self.context = context + self.source = source self.isPremium = isPremium self.price = price self.present = present @@ -737,6 +746,9 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { if lhs.context !== rhs.context { return false } + if lhs.source != rhs.source { + return false + } if lhs.isPremium != rhs.isPremium { return false } @@ -749,11 +761,13 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { final class State: ComponentState { private let context: AccountContext + + var price: String? private var disposable: Disposable? - var configuration = PremiumIntroConfiguration.defaultValue + private(set) var configuration = PremiumIntroConfiguration.defaultValue - init(context: AccountContext) { + init(context: AccountContext, source: PremiumSource) { self.context = context super.init() @@ -768,6 +782,25 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { if let strongSelf = self { strongSelf.configuration = PremiumIntroConfiguration.with(appConfiguration: appConfiguration) strongSelf.updated(transition: .immediate) + + var jsonString: String = "{" + jsonString += "\"source\": \"\(source.identifier)\"," + + jsonString += "\"data\": {\"premium_promo_order\":[" + var isFirst = true + for perk in strongSelf.configuration.perks { + if !isFirst { + jsonString += "," + } + isFirst = false + jsonString += "\"\(perk.identifier)\"" + } + jsonString += "]}}" + + + if let data = jsonString.data(using: .utf8), let json = JSON(data: data) { + addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_show", data: json) + } } }) } @@ -778,7 +811,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { } func makeState() -> State { - return State(context: self.context) + return State(context: self.context, source: self.source) } static var body: Body { @@ -797,6 +830,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { let scrollEnvironment = context.environment[ScrollChildEnvironment.self].value let environment = context.environment[ViewControllerComponentContainer.Environment.self].value let state = context.state + state.price = context.component.price let theme = environment.theme let strings = environment.strings @@ -882,7 +916,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { let present = context.component.present let buy = context.component.buy let updateIsFocused = context.component.updateIsFocused - let price = context.component.price + var i = 0 for perk in state.configuration.perks { let iconBackgroundColors = gradientColors[i] @@ -904,7 +938,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { ) ) ), - action: { + action: { [weak state] in var demoSubject: PremiumDemoScreen.Subject switch perk { case .doubleLimits: @@ -933,7 +967,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { let controller = PremiumDemoScreen( context: accountContext, subject: demoSubject, - source: .intro(price), + source: .intro(state?.price), action: { dismissImpl?() buy() @@ -947,6 +981,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { controller?.dismiss(animated: true, completion: nil) } updateIsFocused(true) + + addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier]) } )) i += 1 @@ -1141,12 +1177,14 @@ private final class PremiumIntroScreenComponent: CombinedComponent { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext + let source: PremiumSource let updateInProgress: (Bool) -> Void let present: (ViewController) -> Void let completion: () -> Void - init(context: AccountContext, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void) { + init(context: AccountContext, source: PremiumSource, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void) { self.context = context + self.source = source self.updateInProgress = updateInProgress self.present = present self.completion = completion @@ -1156,6 +1194,9 @@ private final class PremiumIntroScreenComponent: CombinedComponent { if lhs.context !== rhs.context { return false } + if lhs.source != rhs.source { + return false + } return true } @@ -1214,6 +1255,8 @@ private final class PremiumIntroScreenComponent: CombinedComponent { return } + addAppLogEvent(postbox: self.context.account.postbox, type: "premium.promo_screen_accept") + self.inProgress = true self.updateInProgress(true) self.updated(transition: .immediate) @@ -1230,11 +1273,18 @@ private final class PremiumIntroScreenComponent: CombinedComponent { } })) } - }, error: { [weak self] _ in + }, error: { [weak self] error in if let strongSelf = self { strongSelf.inProgress = false strongSelf.updateInProgress(false) strongSelf.updated(transition: .immediate) + + switch error { + case .generic: + addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail") + case .cancelled: + break + } } })) } @@ -1350,6 +1400,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent { component: ScrollComponent( content: AnyComponent(PremiumIntroScreenContentComponent( context: context.component.context, + source: context.component.source, isPremium: state.isPremium, price: state.premiumProduct?.price, present: context.component.present, @@ -1459,7 +1510,7 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer { return self._ready } - public init(context: AccountContext, modal: Bool = true, reference: String? = nil, source: PremiumSource? = nil) { + public init(context: AccountContext, modal: Bool = true, source: PremiumSource) { self.context = context var updateInProgressImpl: ((Bool) -> Void)? @@ -1467,6 +1518,7 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer { var completionImpl: (() -> Void)? super.init(context: context, component: PremiumIntroScreenComponent( context: context, + source: source, updateInProgress: { inProgress in updateInProgressImpl?(inProgress) }, diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index b3ed446341..79648135f8 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -522,7 +522,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur |> deliverOnMainQueue).start(next: { peer in let isPremium = peer?.isPremium ?? false if !isPremium { - let controller = PremiumIntroScreen(context: context, reference: reference) + let controller = PremiumIntroScreen(context: context, source: .deeplink(reference)) if let navigationController = navigationController { navigationController.pushViewController(controller, animated: true) }