mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Various improvements
This commit is contained in:
parent
81f179be9d
commit
29aff4a8a6
@ -8,6 +8,7 @@ telegram_is_internal_build = "false"
|
|||||||
telegram_is_appstore_build = "true"
|
telegram_is_appstore_build = "true"
|
||||||
telegram_appstore_id = "686449807"
|
telegram_appstore_id = "686449807"
|
||||||
telegram_app_specific_url_scheme = "tg"
|
telegram_app_specific_url_scheme = "tg"
|
||||||
|
telegram_premium_iap_product_id = ""
|
||||||
telegram_aps_environment = "production"
|
telegram_aps_environment = "production"
|
||||||
telegram_enable_siri = True
|
telegram_enable_siri = True
|
||||||
telegram_enable_icloud = True
|
telegram_enable_icloud = True
|
||||||
|
@ -35,6 +35,7 @@ prepare_build_variables () {
|
|||||||
IS_APPSTORE_BUILD \
|
IS_APPSTORE_BUILD \
|
||||||
APPSTORE_ID \
|
APPSTORE_ID \
|
||||||
APP_SPECIFIC_URL_SCHEME \
|
APP_SPECIFIC_URL_SCHEME \
|
||||||
|
PREMIUM_IAP_PRODUCT_ID \
|
||||||
TELEGRAM_DISABLE_EXTENSIONS \
|
TELEGRAM_DISABLE_EXTENSIONS \
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -66,6 +67,7 @@ prepare_build_variables () {
|
|||||||
echo "telegram_is_appstore_build = \"$IS_APPSTORE_BUILD\"" >> "$VARIABLES_PATH"
|
echo "telegram_is_appstore_build = \"$IS_APPSTORE_BUILD\"" >> "$VARIABLES_PATH"
|
||||||
echo "telegram_appstore_id = \"$APPSTORE_ID\"" >> "$VARIABLES_PATH"
|
echo "telegram_appstore_id = \"$APPSTORE_ID\"" >> "$VARIABLES_PATH"
|
||||||
echo "telegram_app_specific_url_scheme = \"$APP_SPECIFIC_URL_SCHEME\"" >> "$VARIABLES_PATH"
|
echo "telegram_app_specific_url_scheme = \"$APP_SPECIFIC_URL_SCHEME\"" >> "$VARIABLES_PATH"
|
||||||
|
echo "telegram_premium_iap_product_id = \"$PREMIUM_IAP_PRODUCT_ID\"" >> "$VARIABLES_PATH"
|
||||||
echo "telegram_aps_environment = \"$APS_ENVIRONMENT\"" >> "$VARIABLES_PATH"
|
echo "telegram_aps_environment = \"$APS_ENVIRONMENT\"" >> "$VARIABLES_PATH"
|
||||||
|
|
||||||
if [ "$TELEGRAM_DISABLE_EXTENSIONS" == "1" ]; then
|
if [ "$TELEGRAM_DISABLE_EXTENSIONS" == "1" ]; then
|
||||||
|
@ -15,6 +15,7 @@ export IS_INTERNAL_BUILD="false"
|
|||||||
export IS_APPSTORE_BUILD="true"
|
export IS_APPSTORE_BUILD="true"
|
||||||
export APPSTORE_ID="686449807"
|
export APPSTORE_ID="686449807"
|
||||||
export APP_SPECIFIC_URL_SCHEME="tgapp"
|
export APP_SPECIFIC_URL_SCHEME="tgapp"
|
||||||
|
export PREMIUM_IAP_PRODUCT_ID="org.telegram.telegramPremium.monthly"
|
||||||
|
|
||||||
if [ -z "$BUILD_NUMBER" ]; then
|
if [ -z "$BUILD_NUMBER" ]; then
|
||||||
echo "BUILD_NUMBER is not defined"
|
echo "BUILD_NUMBER is not defined"
|
||||||
|
@ -22,6 +22,7 @@ swift_library(
|
|||||||
"//submodules/MusicAlbumArtResources:MusicAlbumArtResources",
|
"//submodules/MusicAlbumArtResources:MusicAlbumArtResources",
|
||||||
"//submodules/MeshAnimationCache:MeshAnimationCache",
|
"//submodules/MeshAnimationCache:MeshAnimationCache",
|
||||||
"//submodules/Utils/RangeSet:RangeSet",
|
"//submodules/Utils/RangeSet:RangeSet",
|
||||||
|
"//submodules/InAppPurchaseManager:InAppPurchaseManager",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -11,6 +11,7 @@ import Display
|
|||||||
import DeviceLocationManager
|
import DeviceLocationManager
|
||||||
import TemporaryCachedPeerDataManager
|
import TemporaryCachedPeerDataManager
|
||||||
import MeshAnimationCache
|
import MeshAnimationCache
|
||||||
|
import InAppPurchaseManager
|
||||||
|
|
||||||
public final class TelegramApplicationOpenUrlCompletion {
|
public final class TelegramApplicationOpenUrlCompletion {
|
||||||
public let completion: (Bool) -> Void
|
public let completion: (Bool) -> Void
|
||||||
@ -654,6 +655,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
var locationManager: DeviceLocationManager? { get }
|
var locationManager: DeviceLocationManager? { get }
|
||||||
var callManager: PresentationCallManager? { get }
|
var callManager: PresentationCallManager? { get }
|
||||||
var contactDataManager: DeviceContactDataManager? { get }
|
var contactDataManager: DeviceContactDataManager? { get }
|
||||||
|
var inAppPurchaseManager: InAppPurchaseManager? { get }
|
||||||
|
|
||||||
var activeAccountContexts: Signal<(primary: AccountContext?, accounts: [(AccountRecordId, AccountContext, Int32)], currentAuth: UnauthorizedAccount?), NoError> { get }
|
var activeAccountContexts: Signal<(primary: AccountContext?, accounts: [(AccountRecordId, AccountContext, Int32)], currentAuth: UnauthorizedAccount?), NoError> { get }
|
||||||
var activeAccountsWithInfo: Signal<(primary: AccountRecordId?, accounts: [AccountWithInfo]), NoError> { get }
|
var activeAccountsWithInfo: Signal<(primary: AccountRecordId?, accounts: [AccountWithInfo]), NoError> { get }
|
||||||
|
@ -7,6 +7,7 @@ load(
|
|||||||
"telegram_is_appstore_build",
|
"telegram_is_appstore_build",
|
||||||
"telegram_appstore_id",
|
"telegram_appstore_id",
|
||||||
"telegram_app_specific_url_scheme",
|
"telegram_app_specific_url_scheme",
|
||||||
|
"telegram_premium_iap_product_id",
|
||||||
)
|
)
|
||||||
|
|
||||||
objc_library(
|
objc_library(
|
||||||
@ -25,6 +26,7 @@ objc_library(
|
|||||||
"-DAPP_CONFIG_IS_APPSTORE_BUILD={}".format(telegram_is_appstore_build),
|
"-DAPP_CONFIG_IS_APPSTORE_BUILD={}".format(telegram_is_appstore_build),
|
||||||
"-DAPP_CONFIG_APPSTORE_ID={}".format(telegram_appstore_id),
|
"-DAPP_CONFIG_APPSTORE_ID={}".format(telegram_appstore_id),
|
||||||
"-DAPP_SPECIFIC_URL_SCHEME=\\\"{}\\\"".format(telegram_app_specific_url_scheme),
|
"-DAPP_SPECIFIC_URL_SCHEME=\\\"{}\\\"".format(telegram_app_specific_url_scheme),
|
||||||
|
"-DAPP_CONFIG_PREMIUM_IAP_PRODUCT_ID=\\\"{}\\\"".format(telegram_premium_iap_product_id),
|
||||||
],
|
],
|
||||||
hdrs = glob([
|
hdrs = glob([
|
||||||
"PublicHeaders/**/*.h",
|
"PublicHeaders/**/*.h",
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
@property (nonatomic, readonly) bool isAppStoreBuild;
|
@property (nonatomic, readonly) bool isAppStoreBuild;
|
||||||
@property (nonatomic, readonly) int64_t appStoreId;
|
@property (nonatomic, readonly) int64_t appStoreId;
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nonnull appSpecificUrlScheme;
|
@property (nonatomic, strong, readonly) NSString * _Nonnull appSpecificUrlScheme;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nonnull premiumIAPProductId;
|
||||||
|
|
||||||
+ (DeviceSpecificEncryptionParameters * _Nonnull)deviceSpecificEncryptionParameters:(NSString * _Nonnull)rootPath baseAppBundleId:(NSString * _Nonnull)baseAppBundleId;
|
+ (DeviceSpecificEncryptionParameters * _Nonnull)deviceSpecificEncryptionParameters:(NSString * _Nonnull)rootPath baseAppBundleId:(NSString * _Nonnull)baseAppBundleId;
|
||||||
- (NSData * _Nullable)bundleDataWithAppToken:(NSData * _Nullable)appToken signatureDict:(NSDictionary * _Nullable)signatureDict;
|
- (NSData * _Nullable)bundleDataWithAppToken:(NSData * _Nullable)appToken signatureDict:(NSDictionary * _Nullable)signatureDict;
|
||||||
|
@ -185,6 +185,10 @@ API_AVAILABLE(ios(10))
|
|||||||
return @(APP_SPECIFIC_URL_SCHEME);
|
return @(APP_SPECIFIC_URL_SCHEME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)premiumIAPProductId {
|
||||||
|
return @(APP_CONFIG_PREMIUM_IAP_PRODUCT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
+ (NSString * _Nullable)bundleSeedId {
|
+ (NSString * _Nullable)bundleSeedId {
|
||||||
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
|
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
(__bridge NSString *)kSecClassGenericPassword, (__bridge NSString *)kSecClass,
|
(__bridge NSString *)kSecClassGenericPassword, (__bridge NSString *)kSecClass,
|
||||||
|
20
submodules/InAppPurchaseManager/BUILD
Normal file
20
submodules/InAppPurchaseManager/BUILD
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "InAppPurchaseManager",
|
||||||
|
module_name = "InAppPurchaseManager",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
|
"//submodules/Postbox:Postbox",
|
||||||
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
22
submodules/InAppPurchaseManager/Info.plist
Normal file
22
submodules/InAppPurchaseManager/Info.plist
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -0,0 +1,143 @@
|
|||||||
|
import Foundation
|
||||||
|
import CoreLocation
|
||||||
|
import SwiftSignalKit
|
||||||
|
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
|
||||||
|
|
||||||
|
init(skProduct: SKProduct) {
|
||||||
|
self.skProduct = skProduct
|
||||||
|
}
|
||||||
|
|
||||||
|
public var price: String {
|
||||||
|
let numberFormatter = NumberFormatter()
|
||||||
|
numberFormatter.numberStyle = .currency
|
||||||
|
numberFormatter.locale = self.skProduct.priceLocale
|
||||||
|
return numberFormatter.string(from: self.skProduct.price) ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PurchaseResult {
|
||||||
|
case success
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PurchaseError {
|
||||||
|
case generic
|
||||||
|
}
|
||||||
|
|
||||||
|
private let premiumProductId: String
|
||||||
|
|
||||||
|
private var products: [Product] = []
|
||||||
|
private var productsPromise = Promise<[Product]>()
|
||||||
|
private var productRequest: SKProductsRequest?
|
||||||
|
|
||||||
|
private let stateQueue = Queue()
|
||||||
|
private var paymentContexts: [String: PaymentTransactionContext] = [:]
|
||||||
|
|
||||||
|
public init(premiumProductId: String) {
|
||||||
|
self.premiumProductId = premiumProductId
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
SKPaymentQueue.default().add(self)
|
||||||
|
self.requestProducts()
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func requestProducts() {
|
||||||
|
guard !self.premiumProductId.isEmpty else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let productRequest = SKProductsRequest(productIdentifiers: Set([self.premiumProductId]))
|
||||||
|
productRequest.delegate = self
|
||||||
|
productRequest.start()
|
||||||
|
|
||||||
|
self.productRequest = productRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public var availableProducts: Signal<[Product], NoError> {
|
||||||
|
if self.products.isEmpty && self.productRequest == nil {
|
||||||
|
self.requestProducts()
|
||||||
|
}
|
||||||
|
return self.productsPromise.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseResult, 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 disposable = MetaDisposable()
|
||||||
|
|
||||||
|
self.stateQueue.async {
|
||||||
|
let paymentContext = PaymentTransactionContext(subscriber: { state in
|
||||||
|
switch state {
|
||||||
|
case .purchased, .restored:
|
||||||
|
subscriber.putNext(.success)
|
||||||
|
subscriber.putCompletion()
|
||||||
|
case .failed:
|
||||||
|
subscriber.putError(.generic)
|
||||||
|
case .deferred, .purchasing:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.paymentContexts[productIdentifier] = paymentContext
|
||||||
|
|
||||||
|
disposable.set(ActionDisposable { [weak paymentContext] in
|
||||||
|
self.stateQueue.async {
|
||||||
|
if let current = self.paymentContexts[productIdentifier], current === paymentContext {
|
||||||
|
self.paymentContexts.removeValue(forKey: productIdentifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return disposable
|
||||||
|
}
|
||||||
|
return signal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension InAppPurchaseManager: SKProductsRequestDelegate {
|
||||||
|
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||||
|
self.productRequest = nil
|
||||||
|
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
self.productsPromise.set(.single(response.products.map { Product(skProduct: $0) }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension InAppPurchaseManager: SKPaymentTransactionObserver {
|
||||||
|
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
||||||
|
if let transaction = transactions.first {
|
||||||
|
let productIdentifier = transaction.payment.productIdentifier
|
||||||
|
self.stateQueue.async {
|
||||||
|
if let context = self.paymentContexts[productIdentifier] {
|
||||||
|
context.subscriber(transaction.transactionState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,8 @@ swift_library(
|
|||||||
"//submodules/Components/BundleIconComponent:BundleIconComponent",
|
"//submodules/Components/BundleIconComponent:BundleIconComponent",
|
||||||
"//submodules/Components/SolidRoundedButtonComponent:SolidRoundedButtonComponent",
|
"//submodules/Components/SolidRoundedButtonComponent:SolidRoundedButtonComponent",
|
||||||
"//submodules/Components/Forms/PrefixSectionGroupComponent:PrefixSectionGroupComponent",
|
"//submodules/Components/Forms/PrefixSectionGroupComponent:PrefixSectionGroupComponent",
|
||||||
|
"//submodules/InAppPurchaseManager:InAppPurchaseManager",
|
||||||
|
"//submodules/ConfettiEffect:ConfettiEffect",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -13,6 +13,8 @@ import BundleIconComponent
|
|||||||
import SolidRoundedButtonComponent
|
import SolidRoundedButtonComponent
|
||||||
import Markdown
|
import Markdown
|
||||||
import SceneKit
|
import SceneKit
|
||||||
|
import InAppPurchaseManager
|
||||||
|
import ConfettiEffect
|
||||||
|
|
||||||
private func deg2rad(_ number: Float) -> Float {
|
private func deg2rad(_ number: Float) -> Float {
|
||||||
return number * .pi / 180
|
return number * .pi / 180
|
||||||
@ -750,7 +752,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
let strings = environment.strings
|
let strings = environment.strings
|
||||||
|
|
||||||
let availableWidth = context.availableSize.width
|
let availableWidth = context.availableSize.width
|
||||||
let sideInsets = sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right
|
let sideInsets = sideInset * 2.0 + environment.safeInsets.left + environment.safeInsets.right
|
||||||
var size = CGSize(width: context.availableSize.width, height: 0.0)
|
var size = CGSize(width: context.availableSize.width, height: 0.0)
|
||||||
|
|
||||||
let overscroll = overscroll.update(
|
let overscroll = overscroll.update(
|
||||||
@ -1060,11 +1062,15 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
|
let updateInProgress: (Bool) -> Void
|
||||||
|
let completion: () -> Void
|
||||||
|
|
||||||
init(context: AccountContext) {
|
init(context: AccountContext, updateInProgress: @escaping (Bool) -> Void, completion: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
self.updateInProgress = updateInProgress
|
||||||
|
self.completion = completion
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: PremiumIntroScreenComponent, rhs: PremiumIntroScreenComponent) -> Bool {
|
static func ==(lhs: PremiumIntroScreenComponent, rhs: PremiumIntroScreenComponent) -> Bool {
|
||||||
if lhs.context !== rhs.context {
|
if lhs.context !== rhs.context {
|
||||||
return false
|
return false
|
||||||
@ -1073,12 +1079,68 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class State: ComponentState {
|
final class State: ComponentState {
|
||||||
|
private let context: AccountContext
|
||||||
|
private let updateInProgress: (Bool) -> Void
|
||||||
|
private let completion: () -> Void
|
||||||
|
|
||||||
var topContentOffset: CGFloat?
|
var topContentOffset: CGFloat?
|
||||||
var bottomContentOffset: CGFloat?
|
var bottomContentOffset: CGFloat?
|
||||||
|
|
||||||
|
var inProgress = false
|
||||||
|
var premiumProduct: InAppPurchaseManager.Product?
|
||||||
|
private var disposable: Disposable?
|
||||||
|
private var actionDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
init(context: AccountContext, updateInProgress: @escaping (Bool) -> Void, completion: @escaping () -> Void) {
|
||||||
|
self.context = context
|
||||||
|
self.updateInProgress = updateInProgress
|
||||||
|
self.completion = completion
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
if let inAppPurchaseManager = context.sharedContext.inAppPurchaseManager {
|
||||||
|
self.disposable = (inAppPurchaseManager.availableProducts
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] products in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.premiumProduct = products.first
|
||||||
|
strongSelf.updated(transition: .immediate)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.disposable?.dispose()
|
||||||
|
self.actionDisposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func buy() {
|
||||||
|
guard let inAppPurchaseManager = self.context.sharedContext.inAppPurchaseManager,
|
||||||
|
let premiumProduct = self.premiumProduct, !self.inProgress else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inProgress = true
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}, error: { [weak self] _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.inProgress = false
|
||||||
|
strongSelf.updateInProgress(false)
|
||||||
|
strongSelf.updated(transition: .immediate)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeState() -> State {
|
func makeState() -> State {
|
||||||
return State()
|
return State(context: self.context, updateInProgress: self.updateInProgress, completion: self.completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
static var body: Body {
|
static var body: Body {
|
||||||
@ -1138,7 +1200,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
let sideInset: CGFloat = 16.0
|
let sideInset: CGFloat = 16.0
|
||||||
let button = button.update(
|
let button = button.update(
|
||||||
component: SolidRoundedButtonComponent(
|
component: SolidRoundedButtonComponent(
|
||||||
title: environment.strings.Premium_SubscribeFor("$5").string,
|
title: environment.strings.Premium_SubscribeFor(state.premiumProduct?.price ?? "—").string,
|
||||||
theme: SolidRoundedButtonComponent.Theme(
|
theme: SolidRoundedButtonComponent.Theme(
|
||||||
backgroundColor: .black,
|
backgroundColor: .black,
|
||||||
backgroundColors: [
|
backgroundColors: [
|
||||||
@ -1152,7 +1214,9 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
height: 50.0,
|
height: 50.0,
|
||||||
cornerRadius: 10.0,
|
cornerRadius: 10.0,
|
||||||
gloss: true,
|
gloss: true,
|
||||||
action: {}
|
action: {
|
||||||
|
state.buy()
|
||||||
|
}
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0),
|
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0),
|
||||||
transition: context.transition)
|
transition: context.transition)
|
||||||
@ -1278,8 +1342,18 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer {
|
|||||||
|
|
||||||
public init(context: AccountContext) {
|
public init(context: AccountContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
super.init(context: context, component: PremiumIntroScreenComponent(context: context), navigationBarAppearance: .transparent)
|
var updateInProgressImpl: ((Bool) -> Void)?
|
||||||
|
var completionImpl: (() -> Void)?
|
||||||
|
super.init(context: context, component: PremiumIntroScreenComponent(
|
||||||
|
context: context,
|
||||||
|
updateInProgress: { inProgress in
|
||||||
|
updateInProgressImpl?(inProgress)
|
||||||
|
},
|
||||||
|
completion: {
|
||||||
|
completionImpl?()
|
||||||
|
}
|
||||||
|
), navigationBarAppearance: .transparent)
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
@ -1287,6 +1361,23 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer {
|
|||||||
self.navigationItem.setLeftBarButton(cancelItem, animated: false)
|
self.navigationItem.setLeftBarButton(cancelItem, animated: false)
|
||||||
|
|
||||||
self.navigationPresentation = .modal
|
self.navigationPresentation = .modal
|
||||||
|
|
||||||
|
updateInProgressImpl = { [weak self] inProgress in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.navigationItem.leftBarButtonItem?.isEnabled = !inProgress
|
||||||
|
strongSelf.view.disablesInteractiveTransitionGestureRecognizer = inProgress
|
||||||
|
strongSelf.view.disablesInteractiveModalDismiss = inProgress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
completionImpl = { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.view.addSubview(ConfettiView(frame: strongSelf.view.bounds))
|
||||||
|
Queue.mainQueue().after(2.0, {
|
||||||
|
self?.dismiss()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(coder aDecoder: NSCoder) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
|
@ -186,15 +186,14 @@ 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
|
||||||
|
|
||||||
self.inactiveBackground.frame = CGRect(origin: .zero, size: CGSize(width: containerFrame.width / 2.0 - 1.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 + 1.0, y: 0.0), size: CGSize(width: containerFrame.width / 2.0 - 1.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.activeBackground.bounds = CGRect(origin: .zero, size: CGSize(width: containerFrame.width * 3.0 / 2.0, height: lineHeight))
|
self.activeBackground.bounds = CGRect(origin: .zero, size: CGSize(width: containerFrame.width * 3.0 / 2.0, height: lineHeight))
|
||||||
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, 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 {
|
||||||
switch badgeText.count {
|
switch badgeText.count {
|
||||||
@ -219,10 +218,10 @@ private class PremiumLimitAnimationComponent: Component {
|
|||||||
|
|
||||||
self.badgeView.bounds = CGRect(origin: .zero, size: badgeSize)
|
self.badgeView.bounds = CGRect(origin: .zero, size: badgeSize)
|
||||||
self.badgeView.center = CGPoint(x: availableSize.width / 2.0, y: 82.0)
|
self.badgeView.center = CGPoint(x: availableSize.width / 2.0, y: 82.0)
|
||||||
if self.badgeForeground.animation(forKey: "movement") == nil {
|
|
||||||
self.badgeForeground.position = CGPoint(x: badgeSize.width * 3.0 / 2.0, y: badgeSize.height / 2.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 {
|
||||||
|
self.badgeForeground.position = CGPoint(x: badgeSize.width * 3.0 / 2.0 - self.badgeForeground.frame.width * 0.35, y: badgeSize.height / 2.0)
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -309,12 +309,13 @@ private func generatePremiumReactionIcon() -> UIImage? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let colorsArray: [CGColor] = [
|
let colorsArray: [CGColor] = [
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor,
|
UIColor(rgb: 0x976FFF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor
|
UIColor(rgb: 0xE46ACE).cgColor,
|
||||||
|
UIColor(rgb: 0xE46ACE).cgColor
|
||||||
]
|
]
|
||||||
var locations: [CGFloat] = [0.0, 0.15, 0.85, 1.0]
|
var locations: [CGFloat] = [0.0, 0.15, 0.5, 0.85, 1.0]
|
||||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||||
|
@ -792,10 +792,10 @@ public final class SolidRoundedButtonView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView {
|
if let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView {
|
||||||
if buttonBackgroundAnimationView.layer.animation(forKey: "movement") == nil {
|
|
||||||
buttonBackgroundAnimationView.center = CGPoint(x: buttonSize.width * 2.4 / 2.0, y: buttonSize.height / 2.0)
|
|
||||||
}
|
|
||||||
buttonBackgroundAnimationView.bounds = CGRect(origin: CGPoint(), size: CGSize(width: buttonSize.width * 2.4, height: buttonSize.height))
|
buttonBackgroundAnimationView.bounds = CGRect(origin: CGPoint(), size: CGSize(width: buttonSize.width * 2.4, height: buttonSize.height))
|
||||||
|
if buttonBackgroundAnimationView.layer.animation(forKey: "movement") == nil {
|
||||||
|
buttonBackgroundAnimationView.center = CGPoint(x: buttonSize.width * 2.4 / 2.0 - buttonBackgroundAnimationView.frame.width * 0.35, y: buttonSize.height / 2.0)
|
||||||
|
}
|
||||||
self.setupGradientAnimations()
|
self.setupGradientAnimations()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) }
|
dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) }
|
||||||
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
|
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
|
||||||
dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) }
|
dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) }
|
||||||
dict[1080663248] = { return Api.MessageAction.parse_messageActionPaymentSent($0) }
|
dict[-1776926890] = { return Api.MessageAction.parse_messageActionPaymentSent($0) }
|
||||||
dict[-1892568281] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) }
|
dict[-1892568281] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) }
|
||||||
dict[-2132731265] = { return Api.MessageAction.parse_messageActionPhoneCall($0) }
|
dict[-2132731265] = { return Api.MessageAction.parse_messageActionPhoneCall($0) }
|
||||||
dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) }
|
dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) }
|
||||||
@ -985,6 +985,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) }
|
dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) }
|
||||||
dict[816245886] = { return Api.messages.Stickers.parse_stickers($0) }
|
dict[816245886] = { return Api.messages.Stickers.parse_stickers($0) }
|
||||||
dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) }
|
dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) }
|
||||||
|
dict[-1442723025] = { return Api.messages.TranscribedAudio.parse_transcribedAudio($0) }
|
||||||
dict[1741309751] = { return Api.messages.TranslatedText.parse_translateNoResult($0) }
|
dict[1741309751] = { return Api.messages.TranslatedText.parse_translateNoResult($0) }
|
||||||
dict[-1575684144] = { return Api.messages.TranslatedText.parse_translateResultText($0) }
|
dict[-1575684144] = { return Api.messages.TranslatedText.parse_translateResultText($0) }
|
||||||
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
|
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
|
||||||
@ -1739,6 +1740,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.messages.Stickers:
|
case let _1 as Api.messages.Stickers:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.messages.TranscribedAudio:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.messages.TranslatedText:
|
case let _1 as Api.messages.TranslatedText:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.messages.VotesList:
|
case let _1 as Api.messages.VotesList:
|
||||||
|
@ -1009,7 +1009,7 @@ public extension Api {
|
|||||||
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
|
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
|
||||||
case messageActionHistoryClear
|
case messageActionHistoryClear
|
||||||
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64])
|
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64])
|
||||||
case messageActionPaymentSent(currency: String, totalAmount: Int64)
|
case messageActionPaymentSent(flags: Int32, currency: String, totalAmount: Int64, invoiceSlug: String?)
|
||||||
case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge)
|
case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge)
|
||||||
case messageActionPhoneCall(flags: Int32, callId: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?)
|
case messageActionPhoneCall(flags: Int32, callId: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?)
|
||||||
case messageActionPinMessage
|
case messageActionPinMessage
|
||||||
@ -1170,12 +1170,14 @@ public extension Api {
|
|||||||
serializeInt64(item, buffer: buffer, boxed: false)
|
serializeInt64(item, buffer: buffer, boxed: false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case .messageActionPaymentSent(let currency, let totalAmount):
|
case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1080663248)
|
buffer.appendInt32(-1776926890)
|
||||||
}
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeString(currency, buffer: buffer, boxed: false)
|
serializeString(currency, buffer: buffer, boxed: false)
|
||||||
serializeInt64(totalAmount, buffer: buffer, boxed: false)
|
serializeInt64(totalAmount, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {serializeString(invoiceSlug!, buffer: buffer, boxed: false)}
|
||||||
break
|
break
|
||||||
case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge):
|
case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -1303,8 +1305,8 @@ public extension Api {
|
|||||||
return ("messageActionHistoryClear", [])
|
return ("messageActionHistoryClear", [])
|
||||||
case .messageActionInviteToGroupCall(let call, let users):
|
case .messageActionInviteToGroupCall(let call, let users):
|
||||||
return ("messageActionInviteToGroupCall", [("call", String(describing: call)), ("users", String(describing: users))])
|
return ("messageActionInviteToGroupCall", [("call", String(describing: call)), ("users", String(describing: users))])
|
||||||
case .messageActionPaymentSent(let currency, let totalAmount):
|
case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug):
|
||||||
return ("messageActionPaymentSent", [("currency", String(describing: currency)), ("totalAmount", String(describing: totalAmount))])
|
return ("messageActionPaymentSent", [("flags", String(describing: flags)), ("currency", String(describing: currency)), ("totalAmount", String(describing: totalAmount)), ("invoiceSlug", String(describing: invoiceSlug))])
|
||||||
case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge):
|
case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge):
|
||||||
return ("messageActionPaymentSentMe", [("flags", String(describing: flags)), ("currency", String(describing: currency)), ("totalAmount", String(describing: totalAmount)), ("payload", String(describing: payload)), ("info", String(describing: info)), ("shippingOptionId", String(describing: shippingOptionId)), ("charge", String(describing: charge))])
|
return ("messageActionPaymentSentMe", [("flags", String(describing: flags)), ("currency", String(describing: currency)), ("totalAmount", String(describing: totalAmount)), ("payload", String(describing: payload)), ("info", String(describing: info)), ("shippingOptionId", String(describing: shippingOptionId)), ("charge", String(describing: charge))])
|
||||||
case .messageActionPhoneCall(let flags, let callId, let reason, let duration):
|
case .messageActionPhoneCall(let flags, let callId, let reason, let duration):
|
||||||
@ -1565,14 +1567,20 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static func parse_messageActionPaymentSent(_ reader: BufferReader) -> MessageAction? {
|
public static func parse_messageActionPaymentSent(_ reader: BufferReader) -> MessageAction? {
|
||||||
var _1: String?
|
var _1: Int32?
|
||||||
_1 = parseString(reader)
|
_1 = reader.readInt32()
|
||||||
var _2: Int64?
|
var _2: String?
|
||||||
_2 = reader.readInt64()
|
_2 = parseString(reader)
|
||||||
|
var _3: Int64?
|
||||||
|
_3 = reader.readInt64()
|
||||||
|
var _4: String?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
if _c1 && _c2 {
|
let _c3 = _3 != nil
|
||||||
return Api.MessageAction.messageActionPaymentSent(currency: _1!, totalAmount: _2!)
|
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 {
|
||||||
|
return Api.MessageAction.messageActionPaymentSent(flags: _1!, currency: _2!, totalAmount: _3!, invoiceSlug: _4)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -488,6 +488,42 @@ public extension Api.messages {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.messages {
|
||||||
|
enum TranscribedAudio: TypeConstructorDescription {
|
||||||
|
case transcribedAudio(text: String)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .transcribedAudio(let text):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1442723025)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .transcribedAudio(let text):
|
||||||
|
return ("transcribedAudio", [("text", String(describing: text))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_transcribedAudio(_ reader: BufferReader) -> TranscribedAudio? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.messages.TranscribedAudio.transcribedAudio(text: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.messages {
|
public extension Api.messages {
|
||||||
enum TranslatedText: TypeConstructorDescription {
|
enum TranslatedText: TypeConstructorDescription {
|
||||||
case translateNoResult
|
case translateNoResult
|
||||||
@ -1464,95 +1500,3 @@ public extension Api.photos {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.photos {
|
|
||||||
enum Photos: TypeConstructorDescription {
|
|
||||||
case photos(photos: [Api.Photo], users: [Api.User])
|
|
||||||
case photosSlice(count: Int32, photos: [Api.Photo], users: [Api.User])
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .photos(let photos, let users):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1916114267)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(photos.count))
|
|
||||||
for item in photos {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(users.count))
|
|
||||||
for item in users {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case .photosSlice(let count, let photos, let users):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(352657236)
|
|
||||||
}
|
|
||||||
serializeInt32(count, buffer: buffer, boxed: false)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(photos.count))
|
|
||||||
for item in photos {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(users.count))
|
|
||||||
for item in users {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .photos(let photos, let users):
|
|
||||||
return ("photos", [("photos", String(describing: photos)), ("users", String(describing: users))])
|
|
||||||
case .photosSlice(let count, let photos, let users):
|
|
||||||
return ("photosSlice", [("count", String(describing: count)), ("photos", String(describing: photos)), ("users", String(describing: users))])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_photos(_ reader: BufferReader) -> Photos? {
|
|
||||||
var _1: [Api.Photo]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self)
|
|
||||||
}
|
|
||||||
var _2: [Api.User]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.photos.Photos.photos(photos: _1!, users: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_photosSlice(_ reader: BufferReader) -> Photos? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: [Api.Photo]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self)
|
|
||||||
}
|
|
||||||
var _3: [Api.User]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.photos.Photos.photosSlice(count: _1!, photos: _2!, users: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,95 @@
|
|||||||
|
public extension Api.photos {
|
||||||
|
enum Photos: TypeConstructorDescription {
|
||||||
|
case photos(photos: [Api.Photo], users: [Api.User])
|
||||||
|
case photosSlice(count: Int32, photos: [Api.Photo], users: [Api.User])
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .photos(let photos, let users):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1916114267)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(photos.count))
|
||||||
|
for item in photos {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case .photosSlice(let count, let photos, let users):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(352657236)
|
||||||
|
}
|
||||||
|
serializeInt32(count, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(photos.count))
|
||||||
|
for item in photos {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .photos(let photos, let users):
|
||||||
|
return ("photos", [("photos", String(describing: photos)), ("users", String(describing: users))])
|
||||||
|
case .photosSlice(let count, let photos, let users):
|
||||||
|
return ("photosSlice", [("count", String(describing: count)), ("photos", String(describing: photos)), ("users", String(describing: users))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_photos(_ reader: BufferReader) -> Photos? {
|
||||||
|
var _1: [Api.Photo]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self)
|
||||||
|
}
|
||||||
|
var _2: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.photos.Photos.photos(photos: _1!, users: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_photosSlice(_ reader: BufferReader) -> Photos? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: [Api.Photo]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self)
|
||||||
|
}
|
||||||
|
var _3: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.photos.Photos.photosSlice(count: _1!, photos: _2!, users: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.stats {
|
public extension Api.stats {
|
||||||
enum BroadcastStats: TypeConstructorDescription {
|
enum BroadcastStats: TypeConstructorDescription {
|
||||||
case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, recentMessageInteractions: [Api.MessageInteractionCounters])
|
case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, recentMessageInteractions: [Api.MessageInteractionCounters])
|
||||||
|
@ -6024,6 +6024,22 @@ public extension Api.functions.messages {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.messages {
|
||||||
|
static func transcribeAudio(peer: Api.InputPeer, msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.TranscribedAudio>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(647928393)
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "messages.transcribeAudio", parameters: [("peer", String(describing: peer)), ("msgId", String(describing: msgId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.TranscribedAudio? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.messages.TranscribedAudio?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.messages.TranscribedAudio
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.messages {
|
public extension Api.functions.messages {
|
||||||
static func translateText(flags: Int32, peer: Api.InputPeer?, msgId: Int32?, text: String?, fromLang: String?, toLang: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.TranslatedText>) {
|
static func translateText(flags: Int32, peer: Api.InputPeer?, msgId: Int32?, text: String?, fromLang: String?, toLang: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.TranslatedText>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
@ -6177,6 +6193,21 @@ public extension Api.functions.messages {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.payments {
|
||||||
|
static func assignAppStoreTransaction(transactionId: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1654235439)
|
||||||
|
serializeString(transactionId, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "payments.assignAppStoreTransaction", parameters: [("transactionId", String(describing: transactionId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.payments {
|
public extension Api.functions.payments {
|
||||||
static func clearSavedInfo(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
static func clearSavedInfo(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
@ -7222,11 +7253,11 @@ public extension Api.functions.upload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.functions.upload {
|
public extension Api.functions.upload {
|
||||||
static func getFileHashes(location: Api.InputFileLocation, offset: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.FileHash]>) {
|
static func getFileHashes(location: Api.InputFileLocation, offset: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.FileHash]>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-956147407)
|
buffer.appendInt32(-1856595926)
|
||||||
location.serialize(buffer, true)
|
location.serialize(buffer, true)
|
||||||
serializeInt32(offset, buffer: buffer, boxed: false)
|
serializeInt64(offset, buffer: buffer, boxed: false)
|
||||||
return (FunctionDescription(name: "upload.getFileHashes", parameters: [("location", String(describing: location)), ("offset", String(describing: offset))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.FileHash]? in
|
return (FunctionDescription(name: "upload.getFileHashes", parameters: [("location", String(describing: location)), ("offset", String(describing: offset))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.FileHash]? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
var result: [Api.FileHash]?
|
var result: [Api.FileHash]?
|
||||||
|
@ -40,7 +40,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
|||||||
return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration, isVideo: isVideo))
|
return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration, isVideo: isVideo))
|
||||||
case .messageActionEmpty:
|
case .messageActionEmpty:
|
||||||
return nil
|
return nil
|
||||||
case let .messageActionPaymentSent(currency, totalAmount):
|
case let .messageActionPaymentSent(_, currency, totalAmount, _):
|
||||||
return TelegramMediaAction(action: .paymentSent(currency: currency, totalAmount: totalAmount))
|
return TelegramMediaAction(action: .paymentSent(currency: currency, totalAmount: totalAmount))
|
||||||
case .messageActionPaymentSentMe:
|
case .messageActionPaymentSentMe:
|
||||||
return nil
|
return nil
|
||||||
|
@ -456,6 +456,17 @@ extension Api.Updates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension Api.Updates {
|
extension Api.Updates {
|
||||||
|
var users: [Api.User] {
|
||||||
|
switch self {
|
||||||
|
case let .updates(_, users, _, _, _):
|
||||||
|
return users
|
||||||
|
case let .updatesCombined(_, users, _, _, _, _):
|
||||||
|
return users
|
||||||
|
default:
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var messages: [Api.Message] {
|
var messages: [Api.Message] {
|
||||||
switch self {
|
switch self {
|
||||||
case let .updates(updates, _, _, _, _):
|
case let .updates(updates, _, _, _, _):
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
import Foundation
|
||||||
|
import Postbox
|
||||||
|
import MtProtoKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramApi
|
||||||
|
|
||||||
|
|
||||||
|
public enum AssignAppStoreTransactionError {
|
||||||
|
case generic
|
||||||
|
}
|
||||||
|
|
||||||
|
func _internal_assignAppStoreTransaction(account: Account, transactionId: String) -> Signal<Never, AssignAppStoreTransactionError> {
|
||||||
|
return account.network.request(Api.functions.payments.assignAppStoreTransaction(transactionId: transactionId))
|
||||||
|
|> mapError { _ -> AssignAppStoreTransactionError in
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> mapToSignal { updates -> Signal<Never, AssignAppStoreTransactionError> in
|
||||||
|
account.stateManager.addUpdates(updates)
|
||||||
|
|
||||||
|
return .never()
|
||||||
|
}
|
||||||
|
}
|
@ -36,5 +36,9 @@ public extension TelegramEngine {
|
|||||||
public func clearBotPaymentInfo(info: BotPaymentInfo) -> Signal<Void, NoError> {
|
public func clearBotPaymentInfo(info: BotPaymentInfo) -> Signal<Void, NoError> {
|
||||||
return _internal_clearBotPaymentInfo(network: self.account.network, info: info)
|
return _internal_clearBotPaymentInfo(network: self.account.network, info: info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func assignAppStoreTransaction(transactionId: String) -> Signal<Never, AssignAppStoreTransactionError> {
|
||||||
|
return _internal_assignAppStoreTransaction(account: self.account, transactionId: transactionId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,12 +304,13 @@ public struct PresentationResourcesChat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let colorsArray: [CGColor] = [
|
let colorsArray: [CGColor] = [
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor,
|
UIColor(rgb: 0x976FFF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor
|
UIColor(rgb: 0xE46ACE).cgColor,
|
||||||
|
UIColor(rgb: 0xE46ACE).cgColor
|
||||||
]
|
]
|
||||||
var locations: [CGFloat] = [0.0, 0.35, 0.65, 1.0]
|
var locations: [CGFloat] = [0.0, 0.35, 0.5, 0.65, 1.0]
|
||||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||||
@ -329,12 +330,13 @@ public struct PresentationResourcesChat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let colorsArray: [CGColor] = [
|
let colorsArray: [CGColor] = [
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor,
|
UIColor(rgb: 0x976FFF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor
|
UIColor(rgb: 0xE46ACE).cgColor,
|
||||||
|
UIColor(rgb: 0xE46ACE).cgColor
|
||||||
]
|
]
|
||||||
var locations: [CGFloat] = [0.0, 0.15, 0.85, 1.0]
|
var locations: [CGFloat] = [0.0, 0.15, 0.5, 0.85, 1.0]
|
||||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||||
|
@ -238,12 +238,13 @@ public struct PresentationResourcesChatList {
|
|||||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||||
|
|
||||||
let colorsArray: [CGColor] = [
|
let colorsArray: [CGColor] = [
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor,
|
UIColor(rgb: 0x976FFF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor
|
UIColor(rgb: 0xE46ACE).cgColor,
|
||||||
|
UIColor(rgb: 0xE46ACE).cgColor
|
||||||
]
|
]
|
||||||
var locations: [CGFloat] = [0.0, 0.35, 0.65, 1.0]
|
var locations: [CGFloat] = [0.0, 0.35, 0.5, 0.65, 1.0]
|
||||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||||
|
@ -50,6 +50,33 @@ public struct PresentationResourcesSettings {
|
|||||||
|
|
||||||
drawBorder(context: context, rect: bounds)
|
drawBorder(context: context, rect: bounds)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
public static let premium = generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
|
||||||
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
|
context.clear(bounds)
|
||||||
|
|
||||||
|
let path = UIBezierPath(roundedRect: bounds, cornerRadius: 7.0)
|
||||||
|
context.addPath(path.cgPath)
|
||||||
|
context.clip()
|
||||||
|
|
||||||
|
let colorsArray: [CGColor] = [
|
||||||
|
UIColor(rgb: 0x6b93ff).cgColor,
|
||||||
|
UIColor(rgb: 0x6b93ff).cgColor,
|
||||||
|
UIColor(rgb: 0x8d77ff).cgColor,
|
||||||
|
UIColor(rgb: 0xb56eec).cgColor,
|
||||||
|
UIColor(rgb: 0xb56eec).cgColor
|
||||||
|
]
|
||||||
|
var locations: [CGFloat] = [0.0, 0.15, 0.5, 0.85, 1.0]
|
||||||
|
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||||
|
|
||||||
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||||
|
|
||||||
|
if let image = generateTintedImage(image: UIImage(bundleImageName: "Premium/ButtonIcon"), color: UIColor(rgb: 0xffffff)), let cgImage = image.cgImage {
|
||||||
|
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - image.size.width) / 2.0), y: floorToScreenPixels((bounds.height - image.size.height) / 2.0)), size: image.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
drawBorder(context: context, rect: bounds)
|
||||||
|
})
|
||||||
|
|
||||||
public static let passport = renderIcon(name: "Settings/Menu/Passport")
|
public static let passport = renderIcon(name: "Settings/Menu/Passport")
|
||||||
public static let watch = renderIcon(name: "Settings/Menu/Watch")
|
public static let watch = renderIcon(name: "Settings/Menu/Watch")
|
||||||
|
@ -270,6 +270,7 @@ swift_library(
|
|||||||
"//submodules/PremiumUI:PremiumUI",
|
"//submodules/PremiumUI:PremiumUI",
|
||||||
"//submodules/Components/HierarchyTrackingLayer:HierarchyTrackingLayer",
|
"//submodules/Components/HierarchyTrackingLayer:HierarchyTrackingLayer",
|
||||||
"//submodules/Utils/RangeSet:RangeSet",
|
"//submodules/Utils/RangeSet:RangeSet",
|
||||||
|
"//submodules/InAppPurchaseManager:InAppPurchaseManager",
|
||||||
] + select({
|
] + select({
|
||||||
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
||||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||||
|
@ -34,6 +34,7 @@ import TelegramAudio
|
|||||||
import DebugSettingsUI
|
import DebugSettingsUI
|
||||||
import BackgroundTasks
|
import BackgroundTasks
|
||||||
import UIKitRuntimeUtils
|
import UIKitRuntimeUtils
|
||||||
|
import InAppPurchaseManager
|
||||||
|
|
||||||
#if canImport(AppCenter)
|
#if canImport(AppCenter)
|
||||||
import AppCenter
|
import AppCenter
|
||||||
@ -705,6 +706,8 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||||||
UIDevice.current.setValue(value, forKey: "orientation")
|
UIDevice.current.setValue(value, forKey: "orientation")
|
||||||
UINavigationController.attemptRotationToDeviceOrientation()
|
UINavigationController.attemptRotationToDeviceOrientation()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let inAppPurchaseManager = InAppPurchaseManager(premiumProductId: buildConfig.premiumIAPProductId)
|
||||||
|
|
||||||
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false, useCaches: true, removeDatabaseOnError: true)
|
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false, useCaches: true, removeDatabaseOnError: true)
|
||||||
self.accountManager = accountManager
|
self.accountManager = accountManager
|
||||||
@ -748,7 +751,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||||||
})
|
})
|
||||||
|
|
||||||
var setPresentationCall: ((PresentationCall?) -> Void)?
|
var setPresentationCall: ((PresentationCall?) -> Void)?
|
||||||
let sharedContext = SharedAccountContextImpl(mainWindow: self.mainWindow, sharedContainerPath: legacyBasePath, basePath: rootPath, encryptionParameters: encryptionParameters, accountManager: accountManager, appLockContext: appLockContext, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings, networkArguments: networkArguments, rootPath: rootPath, legacyBasePath: legacyBasePath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init), setNotificationCall: { call in
|
let sharedContext = SharedAccountContextImpl(mainWindow: self.mainWindow, sharedContainerPath: legacyBasePath, basePath: rootPath, encryptionParameters: encryptionParameters, accountManager: accountManager, appLockContext: appLockContext, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings, networkArguments: networkArguments, inAppPurchaseManager: inAppPurchaseManager, rootPath: rootPath, legacyBasePath: legacyBasePath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init), setNotificationCall: { call in
|
||||||
setPresentationCall?(call)
|
setPresentationCall?(call)
|
||||||
}, navigateToChat: { accountId, peerId, messageId in
|
}, navigateToChat: { accountId, peerId, messageId in
|
||||||
self.openChatWhenReady(accountId: accountId, peerId: peerId, messageId: messageId)
|
self.openChatWhenReady(accountId: accountId, peerId: peerId, messageId: messageId)
|
||||||
|
@ -136,7 +136,7 @@ public final class NotificationViewControllerImpl {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
sharedAccountContext = SharedAccountContextImpl(mainWindow: nil, sharedContainerPath: self.initializationData.appGroupPath, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, appLockContext: appLockContext, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, apiHash: self.initializationData.apiHash, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(self.initializationData.bundleData), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), resolvedDeviceName: nil), rootPath: rootPath, legacyBasePath: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
|
sharedAccountContext = SharedAccountContextImpl(mainWindow: nil, sharedContainerPath: self.initializationData.appGroupPath, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, appLockContext: appLockContext, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, apiHash: self.initializationData.apiHash, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(self.initializationData.bundleData), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), resolvedDeviceName: nil), inAppPurchaseManager: nil, rootPath: rootPath, legacyBasePath: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
|
||||||
|
|
||||||
presentationDataPromise.set(sharedAccountContext!.presentationData)
|
presentationDataPromise.set(sharedAccountContext!.presentationData)
|
||||||
}
|
}
|
||||||
|
@ -2306,12 +2306,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
|
||||||
|
|
||||||
let colorsArray: [CGColor] = [
|
let colorsArray: [CGColor] = [
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xa34ecf).cgColor,
|
UIColor(rgb: 0x6B93FF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor,
|
UIColor(rgb: 0x976FFF).cgColor,
|
||||||
UIColor(rgb: 0xff7923).cgColor
|
UIColor(rgb: 0xE46ACE).cgColor,
|
||||||
|
UIColor(rgb: 0xE46ACE).cgColor
|
||||||
]
|
]
|
||||||
var locations: [CGFloat] = [0.0, 0.35, 0.65, 1.0]
|
var locations: [CGFloat] = [0.0, 0.35, 0.5, 0.65, 1.0]
|
||||||
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
|
||||||
|
@ -67,6 +67,7 @@ import TranslateUI
|
|||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
import CreateExternalMediaStreamScreen
|
import CreateExternalMediaStreamScreen
|
||||||
import PaymentMethodUI
|
import PaymentMethodUI
|
||||||
|
import PremiumUI
|
||||||
|
|
||||||
protocol PeerInfoScreenItem: AnyObject {
|
protocol PeerInfoScreenItem: AnyObject {
|
||||||
var id: AnyHashable { get }
|
var id: AnyHashable { get }
|
||||||
@ -420,6 +421,7 @@ private enum PeerInfoSettingsSection {
|
|||||||
case appearance
|
case appearance
|
||||||
case language
|
case language
|
||||||
case stickers
|
case stickers
|
||||||
|
case premium
|
||||||
case passport
|
case passport
|
||||||
case watch
|
case watch
|
||||||
case support
|
case support
|
||||||
@ -722,6 +724,10 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
|||||||
interaction.openSettings(.language)
|
interaction.openSettings(.language)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 100, label: .text(""), text: "Telegram Premium", icon: PresentationResourcesSettings.premium, action: {
|
||||||
|
interaction.openSettings(.premium)
|
||||||
|
}))
|
||||||
|
|
||||||
/*items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 100, label: .text(""), text: "Payment Method", icon: PresentationResourcesSettings.language, action: {
|
/*items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 100, label: .text(""), text: "Payment Method", icon: PresentationResourcesSettings.language, action: {
|
||||||
interaction.openPaymentMethod()
|
interaction.openPaymentMethod()
|
||||||
}))*/
|
}))*/
|
||||||
@ -6176,6 +6182,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
self.controller?.push(themeSettingsController(context: self.context))
|
self.controller?.push(themeSettingsController(context: self.context))
|
||||||
case .language:
|
case .language:
|
||||||
self.controller?.push(LocalizationListController(context: self.context))
|
self.controller?.push(LocalizationListController(context: self.context))
|
||||||
|
case .premium:
|
||||||
|
self.controller?.push(PremiumIntroScreen(context: self.context))
|
||||||
case .stickers:
|
case .stickers:
|
||||||
if let settings = self.data?.globalSettings {
|
if let settings = self.data?.globalSettings {
|
||||||
self.controller?.push(installedStickerPacksController(context: self.context, mode: .general, archivedPacks: settings.archivedStickerPacks, updatedPacks: { [weak self] packs in
|
self.controller?.push(installedStickerPacksController(context: self.context, mode: .general, archivedPacks: settings.archivedStickerPacks, updatedPacks: { [weak self] packs in
|
||||||
|
@ -232,7 +232,7 @@ public class ShareRootControllerImpl {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
let sharedContext = SharedAccountContextImpl(mainWindow: nil, sharedContainerPath: self.initializationData.appGroupPath, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, appLockContext: appLockContext, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, apiHash: self.initializationData.apiHash, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(self.initializationData.bundleData), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), resolvedDeviceName: nil), rootPath: rootPath, legacyBasePath: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
|
let sharedContext = SharedAccountContextImpl(mainWindow: nil, sharedContainerPath: self.initializationData.appGroupPath, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, appLockContext: appLockContext, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, apiHash: self.initializationData.apiHash, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(self.initializationData.bundleData), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), resolvedDeviceName: nil), inAppPurchaseManager: nil, rootPath: rootPath, legacyBasePath: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
|
||||||
presentationDataPromise.set(sharedContext.presentationData)
|
presentationDataPromise.set(sharedContext.presentationData)
|
||||||
internalContext = InternalContext(sharedContext: sharedContext)
|
internalContext = InternalContext(sharedContext: sharedContext)
|
||||||
globalInternalContext = internalContext
|
globalInternalContext = internalContext
|
||||||
|
@ -24,6 +24,7 @@ import PresentationDataUtils
|
|||||||
import LocationUI
|
import LocationUI
|
||||||
import AppLock
|
import AppLock
|
||||||
import WallpaperBackgroundNode
|
import WallpaperBackgroundNode
|
||||||
|
import InAppPurchaseManager
|
||||||
|
|
||||||
private final class AccountUserInterfaceInUseContext {
|
private final class AccountUserInterfaceInUseContext {
|
||||||
let subscribers = Bag<(Bool) -> Void>()
|
let subscribers = Bag<(Bool) -> Void>()
|
||||||
@ -88,6 +89,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
public let contactDataManager: DeviceContactDataManager?
|
public let contactDataManager: DeviceContactDataManager?
|
||||||
public let locationManager: DeviceLocationManager?
|
public let locationManager: DeviceLocationManager?
|
||||||
public var callManager: PresentationCallManager?
|
public var callManager: PresentationCallManager?
|
||||||
|
public var inAppPurchaseManager: InAppPurchaseManager?
|
||||||
|
|
||||||
private var callDisposable: Disposable?
|
private var callDisposable: Disposable?
|
||||||
private var callStateDisposable: Disposable?
|
private var callStateDisposable: Disposable?
|
||||||
@ -161,7 +163,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
private var spotlightDataContext: SpotlightDataContext?
|
private var spotlightDataContext: SpotlightDataContext?
|
||||||
private var widgetDataContext: WidgetDataContext?
|
private var widgetDataContext: WidgetDataContext?
|
||||||
|
|
||||||
public init(mainWindow: Window1?, sharedContainerPath: String, basePath: String, encryptionParameters: ValueBoxEncryptionParameters, accountManager: AccountManager<TelegramAccountManagerTypes>, appLockContext: AppLockContext, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, rootPath: String, legacyBasePath: String?, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void, displayUpgradeProgress: @escaping (Float?) -> Void = { _ in }) {
|
public init(mainWindow: Window1?, sharedContainerPath: String, basePath: String, encryptionParameters: ValueBoxEncryptionParameters, accountManager: AccountManager<TelegramAccountManagerTypes>, appLockContext: AppLockContext, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, inAppPurchaseManager: InAppPurchaseManager?, rootPath: String, legacyBasePath: String?, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void, displayUpgradeProgress: @escaping (Float?) -> Void = { _ in }) {
|
||||||
assert(Queue.mainQueue().isCurrent())
|
assert(Queue.mainQueue().isCurrent())
|
||||||
|
|
||||||
precondition(!testHasInstance)
|
precondition(!testHasInstance)
|
||||||
@ -175,6 +177,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
self.navigateToChatImpl = navigateToChat
|
self.navigateToChatImpl = navigateToChat
|
||||||
self.displayUpgradeProgress = displayUpgradeProgress
|
self.displayUpgradeProgress = displayUpgradeProgress
|
||||||
self.appLockContext = appLockContext
|
self.appLockContext = appLockContext
|
||||||
|
self.inAppPurchaseManager = inAppPurchaseManager
|
||||||
|
|
||||||
self.accountManager.mediaBox.fetchCachedResourceRepresentation = { (resource, representation) -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
self.accountManager.mediaBox.fetchCachedResourceRepresentation = { (resource, representation) -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||||
return fetchCachedSharedResourceRepresentation(accountManager: accountManager, resource: resource, representation: representation)
|
return fetchCachedSharedResourceRepresentation(accountManager: accountManager, resource: resource, representation: representation)
|
||||||
|
@ -130,12 +130,6 @@ public final class TelegramRootController: NavigationController {
|
|||||||
self.accountSettingsController = accountSettingsController
|
self.accountSettingsController = accountSettingsController
|
||||||
self.rootTabController = tabBarController
|
self.rootTabController = tabBarController
|
||||||
self.pushViewController(tabBarController, animated: false)
|
self.pushViewController(tabBarController, animated: false)
|
||||||
|
|
||||||
// Queue.mainQueue().after(1.0) {
|
|
||||||
//// let screen = PremiumLimitScreen(context: self.context, subject: .pins, action: {})
|
|
||||||
// let screen = PremiumIntroScreen(context: self.context, action: {})
|
|
||||||
// self.chatListController?.push(screen)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateRootControllers(showCallsTab: Bool) {
|
public func updateRootControllers(showCallsTab: Bool) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user