Various improvements

This commit is contained in:
Ilya Laktyushin 2022-06-05 14:58:40 +04:00
parent 57e35638d0
commit 699c703c94
9 changed files with 179 additions and 70 deletions

View File

@ -3330,7 +3330,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
strongSelf.push(controller)
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
navigationController.pushViewController(controller)
}
} else {
strongSelf.selectTab(id: .filter(id))
}

View File

@ -60,7 +60,7 @@ final class AppIconsDemoComponent: Component {
self.component = component
self.containerView.frame = CGRect(origin: .zero, size: availableSize)
self.containerView.frame = CGRect(origin: CGPoint(x: -availableSize.width / 2.0, y: 0.0), size: CGSize(width: availableSize.width * 2.0, height: availableSize.height))
if self.imageViews.isEmpty {
for icon in component.appIcons {
@ -68,6 +68,9 @@ final class AppIconsDemoComponent: Component {
let imageView = UIImageView(frame: CGRect(origin: .zero, size: CGSize(width: 90.0, height: 90.0)))
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 24.0
if #available(iOS 13.0, *) {
imageView.layer.cornerCurve = .continuous
}
imageView.image = image
self.containerView.addSubview(imageView)
@ -90,7 +93,7 @@ final class AppIconsDemoComponent: Component {
position = CGPoint(x: availableSize.width * 0.5, y: availableSize.height * 0.5)
}
view.center = position
view.center = position.offsetBy(dx: availableSize.width / 2.0, dy: 0.0)
i += 1
}
@ -105,10 +108,6 @@ final class AppIconsDemoComponent: Component {
}
if isDisplaying && !self.isVisible {
// var fast = false
// if let _ = transition.userData(DemoAnimateInTransition.self) {
// fast = true
// }
self.animateIn(availableSize: availableSize)
}
self.isVisible = isDisplaying
@ -126,10 +125,10 @@ final class AppIconsDemoComponent: Component {
from = CGPoint(x: -availableSize.width * 0.333, y: -availableSize.height * 0.8)
delay = 0.1
case 1:
from = CGPoint(x: -availableSize.width * 0.75, y: availableSize.height * 0.75)
from = CGPoint(x: -availableSize.width * 0.55, y: availableSize.height * 0.75)
delay = 0.15
case 2:
from = CGPoint(x: availableSize.width * 0.9, y: availableSize.height * 0.0)
from = CGPoint(x: availableSize.width * 0.9, y: availableSize.height * 0.75)
delay = 0.0
default:
from = CGPoint(x: availableSize.width * 0.5, y: availableSize.height * 0.5)

View File

@ -990,7 +990,11 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
switch perk {
case .doubleLimits:
let controller = PremimLimitsListScreen(context: accountContext, buttonText: isPremium ? strings.Common_OK : strings.Premium_SubscribeFor(state?.price ?? "").string, isPremium: isPremium)
controller.disposed = {
updateIsFocused(false)
}
present(controller)
updateIsFocused(true)
return
case .moreUpload:
demoSubject = .moreUpload
@ -1261,13 +1265,15 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
let source: PremiumSource
let updateInProgress: (Bool) -> Void
let present: (ViewController) -> Void
let push: (ViewController) -> Void
let completion: () -> Void
init(context: AccountContext, source: PremiumSource, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void) {
init(context: AccountContext, source: PremiumSource, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, push: @escaping (ViewController) -> Void, completion: @escaping () -> Void) {
self.context = context
self.source = source
self.updateInProgress = updateInProgress
self.present = present
self.push = push
self.completion = completion
}
@ -1284,6 +1290,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
final class State: ComponentState {
private let context: AccountContext
private let updateInProgress: (Bool) -> Void
private let present: (ViewController) -> Void
private let completion: () -> Void
var topContentOffset: CGFloat?
@ -1300,9 +1307,10 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
private var paymentDisposable = MetaDisposable()
private var activationDisposable = MetaDisposable()
init(context: AccountContext, source: PremiumSource, updateInProgress: @escaping (Bool) -> Void, completion: @escaping () -> Void) {
init(context: AccountContext, source: PremiumSource, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void) {
self.context = context
self.updateInProgress = updateInProgress
self.present = present
self.completion = completion
super.init()
@ -1356,7 +1364,11 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
self.updateInProgress(true)
self.updated(transition: .immediate)
self.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct, account: self.context.account)
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)
@ -1384,6 +1396,13 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
}
}
}))
} else {
strongSelf.inProgress = false
strongSelf.updateInProgress(false)
strongSelf.updated(transition: .immediate)
}
}
})
}
func updateIsFocused(_ isFocused: Bool) {
@ -1393,7 +1412,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
}
func makeState() -> State {
return State(context: self.context, source: self.source, updateInProgress: self.updateInProgress, completion: self.completion)
return State(context: self.context, source: self.source, updateInProgress: self.updateInProgress, present: self.present, completion: self.completion)
}
static var body: Body {
@ -1694,6 +1713,7 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer {
self.context = context
var updateInProgressImpl: ((Bool) -> Void)?
var pushImpl: ((ViewController) -> Void)?
var presentImpl: ((ViewController) -> Void)?
var completionImpl: (() -> Void)?
super.init(context: context, component: PremiumIntroScreenComponent(
@ -1705,6 +1725,9 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer {
present: { c in
presentImpl?(c)
},
push: { c in
pushImpl?(c)
},
completion: {
completionImpl?()
}
@ -1729,6 +1752,10 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer {
}
presentImpl = { [weak self] c in
self?.present(c, in: .window(.root))
}
pushImpl = { [weak self] c in
self?.push(c)
}

View File

@ -891,6 +891,8 @@ public class PremimLimitsListScreen: ViewController {
private let buttonText: String
private let buttonGloss: Bool
var disposed: () -> Void = {}
public convenience init(context: AccountContext, buttonText: String, isPremium: Bool) {
var expandImpl: (() -> Void)?
self.init(context: context, component: PremimLimitsListScreenComponent(context: context, expand: {
@ -935,6 +937,10 @@ public class PremimLimitsListScreen: ViewController {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.disposed()
}
@objc private func cancelPressed() {
self.dismiss(animated: true, completion: nil)
}

View File

@ -12,6 +12,7 @@ import AccountContext
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import ShimmerEffect
import StickerResources
final class StickersCarouselComponent: Component {
public typealias EnvironmentType = DemoPageEnvironment
@ -104,6 +105,7 @@ private class StickerNode: ASDisplayNode {
if file.isPremiumSticker {
let animationNode = AnimatedStickerNode()
animationNode.automaticallyLoadFirstFrame = true
self.animationNode = animationNode
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
@ -112,6 +114,8 @@ private class StickerNode: ASDisplayNode {
let pathPrefix = context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id)
animationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: file.resource, isVideo: file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, file: file, small: false, size: fittedDimensions))
self.disposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: .standalone(media: file), resource: file.resource).start())
if let effect = file.videoThumbnails.first {
@ -134,10 +138,9 @@ private class StickerNode: ASDisplayNode {
self.isUserInteractionEnabled = false
self.addSubnode(self.imageNode)
if let animationNode = self.animationNode {
self.addSubnode(animationNode)
} else {
self.addSubnode(self.imageNode)
}
if let additionalAnimationNode = self.additionalAnimationNode {
@ -254,7 +257,7 @@ private class StickerNode: ASDisplayNode {
}
}
let placeholderFrame = CGRect(origin: .zero, size: size)
let placeholderFrame = CGRect(origin: .zero, size: imageSize)
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
self.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: self.file.immediateThumbnailData, size: placeholderFrame.size, imageSize: thumbnailDimensions.cgSize)
self.placeholderNode.frame = placeholderFrame
@ -266,7 +269,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
private let context: AccountContext
private let stickers: [TelegramMediaFile]
private var itemContainerNodes: [ASDisplayNode] = []
private var itemNodes: [StickerNode] = []
private var itemNodes: [Int: StickerNode] = [:]
private let scrollNode: ASScrollNode
private let tapNode: ASDisplayNode
@ -299,7 +302,13 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
self.addSubnode(self.scrollNode)
self.scrollNode.addSubnode(self.tapNode)
self.setup()
for _ in self.stickers {
let containerNode = ASDisplayNode()
containerNode.isUserInteractionEnabled = false
self.addSubnode(containerNode)
self.itemContainerNodes.append(containerNode)
}
}
override func didLoad() {
@ -351,7 +360,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
}
func scrollTo(_ index: Int, playAnimation: Bool, duration: Double, clockwise: Bool? = nil) {
guard index >= 0 && index < self.itemNodes.count else {
guard index >= 0 && index < self.stickers.count else {
return
}
self.currentIndex = index
@ -411,19 +420,6 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
}
}
func setup() {
for sticker in self.stickers {
let containerNode = ASDisplayNode()
let itemNode = StickerNode(context: self.context, file: sticker)
containerNode.isUserInteractionEnabled = false
containerNode.addSubnode(itemNode)
self.addSubnode(containerNode)
self.itemContainerNodes.append(containerNode)
self.itemNodes.append(itemNode)
}
}
private var ignoreContentOffsetChange = false
private func resetScrollPosition() {
self.scrollStartPosition = nil
@ -434,14 +430,13 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
func playSelectedSticker() {
let delta = self.positionDelta
let index = max(0, Int(round(self.currentPosition / delta)) % self.itemNodes.count)
let index = max(0, Int(round(self.currentPosition / delta)) % self.stickers.count)
guard !self.playingIndices.contains(index) else {
return
}
for i in 0 ..< self.itemNodes.count {
let itemNode = self.itemNodes[i]
for (i, itemNode) in self.itemNodes {
let containerNode = self.itemContainerNodes[i]
let isCentral = i == index
itemNode.setCentral(isCentral)
@ -461,7 +456,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollStartPosition = (scrollView.contentOffset.y, self.currentPosition)
}
for itemNode in self.itemNodes {
for (_, itemNode) in self.itemNodes {
itemNode.setCentral(false)
}
}
@ -493,7 +488,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
self.currentPosition = updatedPosition
let indexDelta = self.positionDelta
let index = max(0, Int(round(self.currentPosition / indexDelta)) % self.itemNodes.count)
let index = max(0, Int(round(self.currentPosition / indexDelta)) % self.stickers.count)
if index != self.currentIndex {
self.currentIndex = index
if self.scrollNode.view.isTracking || self.scrollNode.view.isDecelerating {
@ -528,7 +523,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
self.resetScrollPosition()
let delta = self.positionDelta
let index = max(0, Int(round(self.currentPosition / delta)) % self.itemNodes.count)
let index = max(0, Int(round(self.currentPosition / delta)) % self.stickers.count)
self.scrollTo(index, playAnimation: true, duration: 0.2)
}
}
@ -555,8 +550,7 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
let bounds = CGRect(origin: .zero, size: size)
let areaSize = CGSize(width: floor(size.width * 4.0), height: size.height * 2.2)
for i in 0 ..< self.itemNodes.count {
let itemNode = self.itemNodes[i]
for i in 0 ..< self.stickers.count {
let containerNode = self.itemContainerNodes[i]
var angle = CGFloat.pi * 0.5 + CGFloat(i) * delta * CGFloat.pi * 2.0 - self.currentPosition * CGFloat.pi * 2.0 - CGFloat.pi * 0.5
@ -588,13 +582,28 @@ private class StickersCarouselNode: ASDisplayNode, UIScrollViewDelegate {
containerNode.position = CGPoint(x: itemFrame.midX, y: itemFrame.midY)
transition.updateTransformScale(node: containerNode, scale: 1.0 - distance * 0.75)
transition.updateAlpha(node: containerNode, alpha: 1.0 - distance * 0.6)
itemNode.updateAbsoluteRect(itemFrame, within: size)
let isVisible = self.visibility && itemFrame.intersects(bounds)
if isVisible {
let itemNode: StickerNode
if let current = self.itemNodes[i] {
itemNode = current
} else {
itemNode = StickerNode(context: self.context, file: self.stickers[i])
containerNode.addSubnode(itemNode)
self.itemNodes[i] = itemNode
}
itemNode.updateAbsoluteRect(itemFrame, within: size)
itemNode.setVisible(isVisible)
itemNode.frame = CGRect(origin: CGPoint(), size: itemFrame.size)
itemNode.updateLayout(size: itemFrame.size, transition: transition)
} else {
if let itemNode = self.itemNodes[i] {
itemNode.removeFromSupernode()
self.itemNodes[i] = nil
}
}
}
}
}

View File

@ -6256,6 +6256,21 @@ public extension Api.functions.payments {
})
}
}
public extension Api.functions.payments {
static func canPurchasePremium() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-1435856696)
return (FunctionDescription(name: "payments.canPurchasePremium", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.payments {
static func clearSavedInfo(flags: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
@ -6366,6 +6381,36 @@ public extension Api.functions.payments {
})
}
}
public extension Api.functions.payments {
static func restoreAppStoreReceipt(receipt: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(-2132923705)
serializeBytes(receipt, buffer: buffer, boxed: false)
return (FunctionDescription(name: "payments.restoreAppStoreReceipt", parameters: [("receipt", String(describing: receipt))]), 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 {
static func restorePlayMarketReceipt(receipt: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(-781917334)
serializeBytes(receipt, buffer: buffer, boxed: false)
return (FunctionDescription(name: "payments.restorePlayMarketReceipt", parameters: [("receipt", String(describing: receipt))]), 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 {
static func sendPaymentForm(flags: Int32, formId: Int64, invoice: Api.InputInvoice, requestedInfoId: String?, shippingOptionId: String?, credentials: Api.InputPaymentCredentials, tipAmount: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentResult>) {
let buffer = Buffer()

View File

@ -30,3 +30,18 @@ func _internal_assignAppStoreTransaction(account: Account, transactionId: String
}
}
}
func _internal_canPurchasePremium(account: Account) -> Signal<Bool, NoError> {
return account.network.request(Api.functions.payments.canPurchasePremium())
|> map { result -> Bool in
switch result {
case .boolTrue:
return true
case .boolFalse:
return false
}
}
|> `catch` { _ -> Signal<Bool, NoError> in
return.single(false)
}
}

View File

@ -40,5 +40,9 @@ public extension TelegramEngine {
public func assignAppStoreTransaction(transactionId: String) -> Signal<Never, AssignAppStoreTransactionError> {
return _internal_assignAppStoreTransaction(account: self.account, transactionId: transactionId)
}
public func canPurchasePremium() -> Signal<Bool, NoError> {
return _internal_canPurchasePremium(account: self.account)
}
}
}

View File

@ -6266,7 +6266,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
self.controller?.push(controller)
if let navigationController = context.sharedContext.mainWindow?.viewController as? NavigationController {
navigationController.pushViewController(controller)
}
} else {
self.context.sharedContext.beginNewAuth(testingEnvironment: self.context.account.testingEnvironment)
}