Various improvements

This commit is contained in:
Ilya Laktyushin 2022-06-06 00:39:32 +04:00
parent fa620eecde
commit 035ab8d2cb
10 changed files with 120 additions and 54 deletions

View File

@ -680,7 +680,6 @@ public protocol SharedAccountContext: AnyObject {
var locationManager: DeviceLocationManager? { get }
var callManager: PresentationCallManager? { get }
var contactDataManager: DeviceContactDataManager? { get }
var inAppPurchaseManager: InAppPurchaseManager? { get }
var activeAccountContexts: Signal<(primary: AccountContext?, accounts: [(AccountRecordId, AccountContext, Int32)], currentAuth: UnauthorizedAccount?), NoError> { get }
var activeAccountsWithInfo: Signal<(primary: AccountRecordId?, accounts: [AccountWithInfo]), NoError> { get }
@ -861,6 +860,7 @@ public protocol AccountContext: AnyObject {
var peerChannelMemberCategoriesContextsManager: PeerChannelMemberCategoriesContextsManager { get }
var wallpaperUploadManager: WallpaperUploadManager? { get }
var watchManager: WatchManager? { get }
var inAppPurchaseManager: InAppPurchaseManager? { get }
var currentLimitsConfiguration: Atomic<LimitsConfiguration> { get }
var currentContentSettings: Atomic<ContentSettings> { get }

View File

@ -114,7 +114,7 @@ public final class MultilineTextComponent: Component {
}
public final class View: ImmediateTextView {
public func update(component: MultilineTextComponent, availableSize: CGSize) -> CGSize {
public func update(component: MultilineTextComponent, availableSize: CGSize, transition: Transition) -> CGSize {
let attributedString: NSAttributedString
switch component.text {
case let .plain(string):
@ -122,6 +122,8 @@ public final class MultilineTextComponent: Component {
case let .markdown(text, attributes):
attributedString = parseMarkdownIntoAttributedString(text, attributes: attributes)
}
let previousText = self.attributedText?.string
self.attributedText = attributedString
self.maximumNumberOfLines = component.maximumNumberOfLines
@ -137,6 +139,18 @@ public final class MultilineTextComponent: Component {
self.highlightAttributeAction = component.highlightAction
self.tapAttributeAction = component.tapAction
self.longTapAttributeAction = component.longTapAction
if case let .curve(duration, _) = transition.animation, let previousText = previousText, previousText != attributedString.string {
if let snapshotView = self.snapshotView(afterScreenUpdates: false) {
snapshotView.center = self.center
self.superview?.addSubview(snapshotView)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
}
}
let size = self.updateLayout(availableSize)
@ -149,6 +163,6 @@ public final class MultilineTextComponent: Component {
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize)
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View File

@ -47,6 +47,7 @@ public final class InAppPurchaseManager: NSObject {
case deferred
}
private let engine: TelegramEngine
private let premiumProductId: String
private var products: [Product] = []
@ -56,7 +57,10 @@ public final class InAppPurchaseManager: NSObject {
private let stateQueue = Queue()
private var paymentContexts: [String: PaymentTransactionContext] = [:]
public init(premiumProductId: String) {
private let disposableSet = DisposableDict<String>()
public init(engine: TelegramEngine, premiumProductId: String) {
self.engine = engine
self.premiumProductId = premiumProductId
super.init()
@ -88,7 +92,7 @@ public final class InAppPurchaseManager: NSObject {
}
public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseState, PurchaseError> {
let payment = SKMutablePayment(product: product.skProduct)
let payment = SKPayment(product: product.skProduct)
SKPaymentQueue.default().add(payment)
let productIdentifier = payment.productIdentifier
@ -140,26 +144,47 @@ extension InAppPurchaseManager: SKProductsRequestDelegate {
extension InAppPurchaseManager: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
if let transaction = transactions.first {
for transaction in transactions {
let productIdentifier = transaction.payment.productIdentifier
self.stateQueue.async {
if let context = self.paymentContexts[productIdentifier] {
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 {
let transactionState: TransactionState?
switch transaction.transactionState {
case .purchased:
transactionState = .purchased(transactionId: transaction.transactionIdentifier)
if let transactionIdentifier = transaction.transactionIdentifier {
self.disposableSet.set(
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier).start(error: { error in
}, completed: {
queue.finishTransaction(transaction)
}),
forKey: transaction.transactionIdentifier ?? ""
)
}
case .restored:
transactionState = .restored(transactionId: transaction.transactionIdentifier)
if let transactionIdentifier = transaction.transactionIdentifier {
self.disposableSet.set(
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier).start(error: { error in
}, completed: {
queue.finishTransaction(transaction)
}),
forKey: transaction.transactionIdentifier ?? ""
)
}
case .failed:
transactionState = .failed
queue.finishTransaction(transaction)
case .purchasing:
transactionState = .purchasing
case .deferred:
transactionState = .deferred
default:
transactionState = nil
}
if let transactionState = transactionState {
if let context = self.paymentContexts[productIdentifier] {
context.subscriber(transactionState)
}
}

View File

@ -793,6 +793,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
private let context: AccountContext
var price: String?
var isPremium: Bool?
private var disposable: Disposable?
private(set) var configuration = PremiumIntroConfiguration.defaultValue
@ -867,6 +868,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
let state = context.state
state.price = context.component.price
state.isPremium = context.component.isPremium
let theme = environment.theme
let strings = environment.strings
@ -963,8 +965,6 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
let buy = context.component.buy
let updateIsFocused = context.component.updateIsFocused
let isPremium = context.component.isPremium ?? false
var i = 0
for perk in state.configuration.perks {
let iconBackgroundColors = gradientColors[i]
@ -989,11 +989,21 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
var demoSubject: PremiumDemoScreen.Subject
switch perk {
case .doubleLimits:
let controller = PremimLimitsListScreen(context: accountContext, buttonText: isPremium ? strings.Common_OK : strings.Premium_SubscribeFor(state?.price ?? "").string, isPremium: isPremium)
var dismissImpl: (() -> Void)?
let controller = PremimLimitsListScreen(context: accountContext, buttonText: state?.isPremium == true ? strings.Common_OK : strings.Premium_SubscribeFor(state?.price ?? "").string, isPremium: state?.isPremium == true)
controller.action = { [weak state] in
dismissImpl?()
if state?.isPremium == false {
buy()
}
}
controller.disposed = {
updateIsFocused(false)
}
present(controller)
dismissImpl = { [weak controller] in
controller?.dismiss(animated: true, completion: nil)
}
updateIsFocused(true)
return
case .moreUpload:
@ -1018,15 +1028,13 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
demoSubject = .appIcons
}
var dismissImpl: (() -> Void)?
let controller = PremiumDemoScreen(
context: accountContext,
subject: demoSubject,
source: .intro(state?.price),
order: state?.configuration.perks,
action: {
dismissImpl?()
if !isPremium {
if state?.isPremium == false {
buy()
}
}
@ -1035,9 +1043,6 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
updateIsFocused(false)
}
present(controller)
dismissImpl = { [weak controller] in
controller?.dismiss(animated: true, completion: nil)
}
updateIsFocused(true)
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
@ -1315,7 +1320,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
super.init()
if let inAppPurchaseManager = context.sharedContext.inAppPurchaseManager {
if let inAppPurchaseManager = context.inAppPurchaseManager {
let otherPeerName: Signal<String?, NoError>
if case let .profile(peerId) = source {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -1353,27 +1358,38 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
}
func buy() {
guard let inAppPurchaseManager = self.context.sharedContext.inAppPurchaseManager,
guard let inAppPurchaseManager = self.context.inAppPurchaseManager,
let premiumProduct = self.premiumProduct, !self.inProgress else {
return
}
addAppLogEvent(postbox: self.context.account.postbox, type: "premium.promo_screen_accept")
self.inProgress = true
self.updateInProgress(true)
self.updated(transition: .immediate)
let _ = (self.context.engine.payments.canPurchasePremium()
|> deliverOnMainQueue).start(next: { [weak self] available in
if let strongSelf = self {
if available {
strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct, account: strongSelf.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)
if let strongSelf = self, case .purchased = status {
strongSelf.activationDisposable.set((strongSelf.context.account.postbox.peerView(id: strongSelf.context.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()
}
|> deliverOnMainQueue).start(error: { _ in
}, completed: { [weak self] in
if let strongSelf = self {
strongSelf.isPremium = true
@ -1387,7 +1403,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
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")
@ -1421,7 +1437,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
let star = Child(PremiumStarComponent.self)
let topPanel = Child(BlurredRectangle.self)
let topSeparator = Child(Rectangle.self)
let title = Child(Text.self)
let title = Child(MultilineTextComponent.self)
let secondaryTitle = Child(MultilineTextComponent.self)
let bottomPanel = Child(BlurredRectangle.self)
let bottomSeparator = Child(Rectangle.self)
@ -1468,10 +1484,11 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
}
let title = title.update(
component: Text(
text: titleString,
font: Font.bold(28.0),
color: environment.theme.rootController.navigationBar.primaryTextColor
component: MultilineTextComponent(
text: .plain(NSAttributedString(string: titleString, font: Font.bold(28.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)),
horizontalAlignment: .center,
truncationType: .end,
maximumNumberOfLines: 1
),
availableSize: context.availableSize,
transition: context.transition

View File

@ -452,6 +452,10 @@ public class PremimLimitsListScreen: ViewController {
self.containerView.addSubview(self.scrollView)
self.containerView.addSubnode(self.footerNode)
self.scrollView.addSubview(self.hostView)
self.footerNode.action = { [weak self] in
self?.controller?.action()
}
}
override func didLoad() {
@ -891,6 +895,7 @@ public class PremimLimitsListScreen: ViewController {
private let buttonText: String
private let buttonGloss: Bool
var action: () -> Void = {}
var disposed: () -> Void = {}
public convenience init(context: AccountContext, buttonText: String, isPremium: Bool) {

View File

@ -18,6 +18,7 @@ import AsyncDisplayKit
import PresentationDataUtils
import MeshAnimationCache
import FetchManagerImpl
import InAppPurchaseManager
private final class DeviceSpecificContactImportContext {
let disposable = MetaDisposable()
@ -122,6 +123,7 @@ public final class AccountContextImpl: AccountContext {
public let peersNearbyManager: PeersNearbyManager?
public let wallpaperUploadManager: WallpaperUploadManager?
private let themeUpdateManager: ThemeUpdateManager?
public let inAppPurchaseManager: InAppPurchaseManager?
public let peerChannelMemberCategoriesContextsManager = PeerChannelMemberCategoriesContextsManager()
@ -184,10 +186,16 @@ public final class AccountContextImpl: AccountContext {
self.prefetchManager = PrefetchManagerImpl(sharedContext: sharedContext, account: account, engine: self.engine, fetchManager: self.fetchManager)
self.wallpaperUploadManager = WallpaperUploadManagerImpl(sharedContext: sharedContext, account: account, presentationData: sharedContext.presentationData)
self.themeUpdateManager = ThemeUpdateManagerImpl(sharedContext: sharedContext, account: account)
if let premiumProductId = sharedContext.premiumProductId {
self.inAppPurchaseManager = InAppPurchaseManager(engine: self.engine, premiumProductId: premiumProductId)
} else {
self.inAppPurchaseManager = nil
}
} else {
self.prefetchManager = nil
self.wallpaperUploadManager = nil
self.themeUpdateManager = nil
self.inAppPurchaseManager = nil
}
if let locationManager = self.sharedContextImpl.locationManager, sharedContext.applicationBindings.isMainApp && !temp {

View File

@ -33,7 +33,6 @@ import TelegramAudio
import DebugSettingsUI
import BackgroundTasks
import UIKitRuntimeUtils
import InAppPurchaseManager
#if canImport(AppCenter)
import AppCenter
@ -711,8 +710,6 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
UINavigationController.attemptRotationToDeviceOrientation()
})
let inAppPurchaseManager = InAppPurchaseManager(premiumProductId: buildConfig.premiumIAPProductId)
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false, useCaches: true, removeDatabaseOnError: true)
self.accountManager = accountManager
@ -755,7 +752,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
})
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, inAppPurchaseManager: inAppPurchaseManager, 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, premiumProductId: buildConfig.premiumIAPProductId, rootPath: rootPath, legacyBasePath: legacyBasePath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init), setNotificationCall: { call in
setPresentationCall?(call)
}, navigateToChat: { accountId, peerId, messageId in
self.openChatWhenReady(accountId: accountId, peerId: peerId, messageId: messageId)

View File

@ -138,7 +138,7 @@ public final class NotificationViewControllerImpl {
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), inAppPurchaseManager: 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), premiumProductId: nil, rootPath: rootPath, legacyBasePath: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
presentationDataPromise.set(sharedAccountContext!.presentationData)
}

View File

@ -234,7 +234,7 @@ public class ShareRootControllerImpl {
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), inAppPurchaseManager: 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), premiumProductId: nil, rootPath: rootPath, legacyBasePath: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
presentationDataPromise.set(sharedContext.presentationData)
internalContext = InternalContext(sharedContext: sharedContext)
globalInternalContext = internalContext

View File

@ -90,7 +90,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
public let contactDataManager: DeviceContactDataManager?
public let locationManager: DeviceLocationManager?
public var callManager: PresentationCallManager?
public var inAppPurchaseManager: InAppPurchaseManager?
let premiumProductId: String?
private var callDisposable: Disposable?
private var callStateDisposable: Disposable?
@ -164,7 +164,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
private var spotlightDataContext: SpotlightDataContext?
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, 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 }) {
public init(mainWindow: Window1?, sharedContainerPath: String, basePath: String, encryptionParameters: ValueBoxEncryptionParameters, accountManager: AccountManager<TelegramAccountManagerTypes>, appLockContext: AppLockContext, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, premiumProductId: String?, 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())
precondition(!testHasInstance)
@ -178,7 +178,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
self.navigateToChatImpl = navigateToChat
self.displayUpgradeProgress = displayUpgradeProgress
self.appLockContext = appLockContext
self.inAppPurchaseManager = inAppPurchaseManager
self.premiumProductId = premiumProductId
self.accountManager.mediaBox.fetchCachedResourceRepresentation = { (resource, representation) -> Signal<CachedMediaResourceRepresentationResult, NoError> in
return fetchCachedSharedResourceRepresentation(accountManager: accountManager, resource: resource, representation: representation)