import Foundation import UIKit import Display import ComponentFlow import ViewControllerComponent import AccountContext import SheetComponent import ButtonComponent import LottieComponent import MultilineTextComponent import BalancedTextComponent import Markdown import TelegramStringFormatting import BundleIconComponent private final class BalanceNeededSheetContentComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let action: () -> Void let dismiss: () -> Void init( action: @escaping () -> Void, dismiss: @escaping () -> Void ) { self.action = action self.dismiss = dismiss } static func ==(lhs: BalanceNeededSheetContentComponent, rhs: BalanceNeededSheetContentComponent) -> Bool { return true } final class View: UIView { private let icon = ComponentView() private let title = ComponentView() private let text = ComponentView() private let button = ComponentView() private var cancelButton: ComponentView? private var component: BalanceNeededSheetContentComponent? private weak var state: EmptyComponentState? override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { } func update(component: BalanceNeededSheetContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { self.component = component self.state = state let environment = environment[EnvironmentType.self].value let sideInset: CGFloat = 16.0 let cancelButton: ComponentView if let current = self.cancelButton { cancelButton = current } else { cancelButton = ComponentView() self.cancelButton = cancelButton } let cancelButtonSize = cancelButton.update( transition: transition, component: AnyComponent(Button( content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: environment.theme.list.itemAccentColor)), action: { [weak self] in guard let self, let component = self.component else { return } component.dismiss() } ).minSize(CGSize(width: 8.0, height: 44.0))), environment: {}, containerSize: CGSize(width: 200.0, height: 100.0) ) if let cancelButtonView = cancelButton.view { if cancelButtonView.superview == nil { self.addSubview(cancelButtonView) } transition.setFrame(view: cancelButtonView, frame: CGRect(origin: CGPoint(x: 16.0, y: 6.0), size: cancelButtonSize)) } var contentHeight: CGFloat = 0.0 contentHeight += 32.0 let iconSize = self.icon.update( transition: transition, component: AnyComponent(LottieComponent( content: LottieComponent.AppBundleContent(name: "StoryUpgradeSheet"), color: nil, startingPosition: .begin, size: CGSize(width: 100.0, height: 100.0) )), environment: {}, containerSize: CGSize(width: 100.0, height: 100.0) ) if let iconView = self.icon.view { if iconView.superview == nil { self.addSubview(iconView) } transition.setFrame(view: iconView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: 42.0), size: iconSize)) } contentHeight += 138.0 let titleSize = self.title.update( transition: transition, component: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString(string: environment.strings.Story_UpgradeQuality_Title, font: Font.semibold(20.0), textColor: environment.theme.list.itemPrimaryTextColor)), horizontalAlignment: .center, maximumNumberOfLines: 0 )), environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) ) if let titleView = self.title.view { if titleView.superview == nil { self.addSubview(titleView) } transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: contentHeight), size: titleSize)) } contentHeight += titleSize.height contentHeight += 14.0 let textSize = self.text.update( transition: transition, component: AnyComponent(BalancedTextComponent( text: .plain(NSAttributedString(string: environment.strings.Story_UpgradeQuality_Text, font: Font.regular(14.0), textColor: environment.theme.list.itemSecondaryTextColor)), horizontalAlignment: .center, maximumNumberOfLines: 0, lineSpacing: 0.18 )), environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) ) if let textView = self.text.view { if textView.superview == nil { self.addSubview(textView) } transition.setFrame(view: textView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - textSize.width) * 0.5), y: contentHeight), size: textSize)) } contentHeight += textSize.height contentHeight += 12.0 contentHeight += 32.0 let buttonSize = self.button.update( transition: transition, component: AnyComponent(ButtonComponent( background: ButtonComponent.Background( color: environment.theme.list.itemCheckColors.fillColor, foreground: environment.theme.list.itemCheckColors.foregroundColor, pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8) ), content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString(string: "Add Funds via Fragment")) ))), isEnabled: true, allowActionWhenDisabled: true, displaysProgress: false, action: { [weak self] in guard let self, let component = self.component else { return } component.action() } )), environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0) ) let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: buttonSize) if let buttonView = self.button.view { if buttonView.superview == nil { self.addSubview(buttonView) } transition.setFrame(view: buttonView, frame: buttonFrame) } contentHeight += buttonSize.height if environment.safeInsets.bottom.isZero { contentHeight += 16.0 } else { contentHeight += environment.safeInsets.bottom + 14.0 } return CGSize(width: availableSize.width, height: contentHeight) } } func makeView() -> View { return View(frame: CGRect()) } func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } } private final class BalanceNeededScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext let buttonAction: (() -> Void)? init( context: AccountContext, buttonAction: (() -> Void)? ) { self.context = context self.buttonAction = buttonAction } static func ==(lhs: BalanceNeededScreenComponent, rhs: BalanceNeededScreenComponent) -> Bool { if lhs.context !== rhs.context { return false } return true } final class View: UIView { private let sheet = ComponentView<(ViewControllerComponentContainer.Environment, SheetComponentEnvironment)>() private let sheetAnimateOut = ActionSlot>() private var component: BalanceNeededScreenComponent? private var environment: EnvironmentType? override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func update(component: BalanceNeededScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { self.component = component let environment = environment[ViewControllerComponentContainer.Environment.self].value self.environment = environment let sheetEnvironment = SheetComponentEnvironment( isDisplaying: environment.isVisible, isCentered: environment.metrics.widthClass == .regular, hasInputHeight: !environment.inputHeight.isZero, regularMetricsSize: CGSize(width: 430.0, height: 900.0), dismiss: { [weak self] _ in guard let self, let environment = self.environment else { return } self.sheetAnimateOut.invoke(Action { _ in if let controller = environment.controller() { controller.dismiss(completion: nil) } }) } ) let _ = self.sheet.update( transition: transition, component: AnyComponent(SheetComponent( content: AnyComponent(BalanceNeededSheetContentComponent( action: { [weak self] in guard let self else { return } self.sheetAnimateOut.invoke(Action { [weak self] _ in if let controller = environment.controller() { controller.dismiss(completion: nil) } guard let self else { return } self.component?.buttonAction?() }) }, dismiss: { self.sheetAnimateOut.invoke(Action { _ in if let controller = environment.controller() { controller.dismiss(completion: nil) } }) } )), backgroundColor: .color(environment.theme.overallDarkAppearance ? environment.theme.list.itemBlocksBackgroundColor : environment.theme.list.blocksBackgroundColor), animateOut: self.sheetAnimateOut )), environment: { environment sheetEnvironment }, containerSize: availableSize ) if let sheetView = self.sheet.view { if sheetView.superview == nil { self.addSubview(sheetView) } transition.setFrame(view: sheetView, frame: CGRect(origin: CGPoint(), size: availableSize)) } return availableSize } } func makeView() -> View { return View(frame: CGRect()) } func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } } public class BalanceNeededScreen: ViewControllerComponentContainer { public init( context: AccountContext, buttonAction: (() -> Void)? = nil ) { super.init(context: context, component: BalanceNeededScreenComponent( context: context, buttonAction: buttonAction ), navigationBarAppearance: .none) self.statusBar.statusBarStyle = .Ignore self.navigationPresentation = .flatModal self.blocksBackgroundWhenInOverlay = true } required public init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) } override public func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.view.disablesInteractiveModalDismiss = true } override public func dismiss(completion: (() -> Void)? = nil) { super.dismiss(completion: { completion?() }) self.wasDismissed?() } }