Files
divkit/client/ios/DivKitPlayground/UI/DivView/DivViewController.swift
T
2023-03-28 12:17:21 +03:00

153 lines
4.0 KiB
Swift

import SwiftUI
import UIKit
import CommonCorePublic
import DivKit
import DivKitExtensions
import LayoutKit
struct DivView: UIViewControllerRepresentable {
let blockProvider: DivBlockProvider
let divKitComponents: DivKitComponents
func makeUIViewController(context _: Context) -> UIViewController {
DivViewController(
blockProvider: blockProvider,
divKitComponents: divKitComponents
)
}
func updateUIViewController(_: UIViewController, context _: Context) {}
}
open class DivViewController: UIViewController {
private let blockProvider: DivBlockProvider
private let divKitComponents: DivKitComponents
private let disposePool = AutodisposePool()
private let cardView = VisibilityTrackingCardView()
private let scrollView = VisibilityTrackingScrollView()
private var lastBounds = CGRect.zero
private var blockView: BlockView! {
didSet {
oldValue?.removeFromSuperview()
scrollView.addSubview(blockView)
}
}
init(
blockProvider: DivBlockProvider,
divKitComponents: DivKitComponents
) {
self.blockProvider = blockProvider
self.divKitComponents = divKitComponents
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
public required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func loadView() {
scrollView.backgroundColor = .white
scrollView.cardView = cardView
blockProvider.parentScrollView = scrollView
view = scrollView
}
public override func viewDidLoad() {
super.viewDidLoad()
let pinchToZoomExtensionHandler = PinchToZoomExtensionHandler(overlayView: view)
divKitComponents.extensionHandlers = divKitComponents.extensionHandlers.filter {
$0.id != pinchToZoomExtensionHandler.id
}
divKitComponents.extensionHandlers.append(pinchToZoomExtensionHandler)
}
public override func viewWillAppear(_: Bool) {
blockProvider.$block
.currentAndNewValues
.addObserver(updateBlockView)
.dispose(in: disposePool)
}
public override func viewDidAppear(_: Bool) {
onVisibleBoundsChanged(to: scrollView.bounds)
}
public override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let blockSize = blockProvider.block.size(forResizableBlockSize: view.bounds.size)
cardView.frame = CGRect(origin: .zero, size: blockSize)
blockView.frame = cardView.bounds
scrollView.contentSize = blockSize
onVisibleBoundsChanged(to: scrollView.bounds)
}
public override func viewDidDisappear(_: Bool) {
disposePool.drain()
onVisibleBoundsChanged(to: .zero)
}
open func onViewUpdated() {}
private func updateBlockView(block: Block) {
let elementStateObserver = self
if let blockView = blockView, block.canConfigureBlockView(blockView) {
block.configureBlockView(
blockView,
observer: elementStateObserver,
overscrollDelegate: nil,
renderingDelegate: nil
)
} else {
blockView = block.makeBlockView(observer: elementStateObserver)
cardView.blockView = blockView
}
view.setNeedsLayout()
onViewUpdated()
}
private func onVisibleBoundsChanged(to: CGRect) {
let from = lastBounds
lastBounds = to
scrollView.onVisibleBoundsChanged(from: from, to: to)
}
}
extension DivViewController: ElementStateObserver {
public func elementStateChanged(_ state: ElementState, forPath path: UIElementPath) {
divKitComponents.blockStateStorage.elementStateChanged(state, forPath: path)
blockProvider.update(withStates: [path: state])
}
}
extension DivViewController: UIActionEventPerforming {
public func perform(uiActionEvent event: UIActionEvent, from _: AnyObject) {
handle(event.payload)
}
private func handle(_ payload: UserInterfaceAction.Payload) {
switch payload {
case .composite, .empty, .json, .url:
break
case let .menu(menu):
showMenu(menu, actionPerformer: self)
case let .divAction(params):
divKitComponents.handleActions(params: params)
}
}
}