WinterGram/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/WinterGramGiftPickerScreen.swift

155 lines
6.5 KiB
Swift

import Foundation
import UIKit
import Display
import AsyncDisplayKit
import ComponentFlow
import SwiftSignalKit
import TelegramCore
import AccountContext
import TelegramPresentationData
import GiftItemComponent
// WinterGram: grid picker of regular star gifts for adding a non-unique gift to the profile.
public final class WinterGramGiftPickerScreen: ViewController {
private final class Node: ViewControllerTracingNode {
private weak var controller: WinterGramGiftPickerScreen?
private let context: AccountContext
private var presentationData: PresentationData
private let scrollNode: ASScrollNode
private var itemViews: [ComponentHostView<Empty>] = []
private var gifts: [StarGift] = []
private var disposable: Disposable?
private var keepUpdatedDisposable: Disposable?
private var validLayout: ContainerViewLayout?
init(controller: WinterGramGiftPickerScreen, context: AccountContext) {
self.controller = controller
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.scrollNode = ASScrollNode()
super.init()
self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor
self.scrollNode.view.alwaysBounceVertical = true
self.addSubnode(self.scrollNode)
// Ensure the gift catalog is cached so the picker is not empty on first open.
self.keepUpdatedDisposable = context.engine.payments.keepStarGiftsUpdated().startStrict()
self.disposable = (context.engine.payments.cachedStarGifts()
|> deliverOnMainQueue).start(next: { [weak self] gifts in
guard let self else {
return
}
self.gifts = (gifts ?? []).filter { gift in
if case .generic = gift {
return true
}
return false
}
if let layout = self.validLayout {
self.containerLayoutUpdated(layout: layout, transition: .immediate)
}
})
}
deinit {
self.disposable?.dispose()
self.keepUpdatedDisposable?.dispose()
}
func containerLayoutUpdated(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.validLayout = layout
let topInset = self.controller?.navigationLayout(layout: layout).navigationFrame.maxY ?? ((layout.statusBarHeight ?? 20.0) + 44.0)
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: .zero, size: layout.size))
let columns = 3
let sideInset = layout.safeInsets.left + 12.0
let spacing: CGFloat = 10.0
let availableWidth = layout.size.width - sideInset * 2.0
let itemWidth = floor((availableWidth - spacing * CGFloat(columns - 1)) / CGFloat(columns))
let itemHeight = itemWidth + 34.0
while self.itemViews.count < self.gifts.count {
let view = ComponentHostView<Empty>()
self.scrollNode.view.addSubview(view)
self.itemViews.append(view)
}
while self.itemViews.count > self.gifts.count {
self.itemViews.removeLast().removeFromSuperview()
}
for (index, gift) in self.gifts.enumerated() {
guard case let .generic(genericGift) = gift else {
continue
}
let column = index % columns
let row = index / columns
let x = sideInset + CGFloat(column) * (itemWidth + spacing)
let y = topInset + 8.0 + CGFloat(row) * (itemHeight + spacing)
let view = self.itemViews[index]
let _ = view.update(
transition: .immediate,
component: AnyComponent(GiftItemComponent(
context: self.context,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
subject: .starGift(gift: genericGift, price: "\(genericGift.price)"),
isSoldOut: genericGift.soldOut != nil,
action: { [weak self] in
self?.controller?.selectGift(gift)
}
)),
environment: {},
containerSize: CGSize(width: itemWidth, height: itemHeight)
)
view.frame = CGRect(origin: CGPoint(x: x, y: y), size: CGSize(width: itemWidth, height: itemHeight))
}
let rows = self.gifts.isEmpty ? 0 : (self.gifts.count + columns - 1) / columns
let contentHeight = topInset + 8.0 + CGFloat(rows) * (itemHeight + spacing) + layout.intrinsicInsets.bottom + 16.0
self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: max(layout.size.height, contentHeight))
}
}
private let context: AccountContext
private let completion: (StarGift) -> Void
public init(context: AccountContext, completion: @escaping (StarGift) -> Void) {
self.context = context
self.completion = completion
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
self.title = presentationData.strings.WinterGram_AddVisualGift
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func cancelPressed() {
self.dismiss()
}
fileprivate func selectGift(_ gift: StarGift) {
self.completion(gift)
self.dismiss()
}
override public func loadDisplayNode() {
self.displayNode = Node(controller: self, context: self.context)
self.displayNodeDidLoad()
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, transition: transition)
}
}