Files
Ilya Laktyushin e97422e333 Various fixes
2026-04-27 04:40:29 +02:00

842 lines
32 KiB
Swift

import Foundation
import UIKit
import Display
import TelegramCore
import SwiftSignalKit
import AccountContext
import TelegramPresentationData
import PresentationDataUtils
import TelegramStringFormatting
import ComponentFlow
import ViewControllerComponent
import SheetComponent
import ButtonComponent
import BundleIconComponent
import GlassBarButtonComponent
public enum ChatTimerScreenStyle {
case `default`
case media
}
public enum ChatTimerScreenMode {
case sendTimer
case autoremove
case mute
}
private protocol TimerPickerView: UIView {
}
private class TimerCustomPickerView: UIPickerView, TimerPickerView {
var selectorColor: UIColor? = nil {
didSet {
for subview in self.subviews {
if subview.bounds.height <= 1.0 {
subview.backgroundColor = self.selectorColor
}
}
}
}
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
if let selectorColor = self.selectorColor {
if subview.bounds.height <= 1.0 {
subview.backgroundColor = selectorColor
}
}
}
override func didMoveToWindow() {
super.didMoveToWindow()
if let selectorColor = self.selectorColor {
for subview in self.subviews {
if subview.bounds.height <= 1.0 {
subview.backgroundColor = selectorColor
}
}
}
}
}
private class TimerDatePickerView: UIDatePicker, TimerPickerView {
var selectorColor: UIColor? = nil {
didSet {
for subview in self.subviews {
if subview.bounds.height <= 1.0 {
subview.backgroundColor = self.selectorColor
}
}
}
}
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
if let selectorColor = self.selectorColor {
if subview.bounds.height <= 1.0 {
subview.backgroundColor = selectorColor
}
}
}
override func didMoveToWindow() {
super.didMoveToWindow()
if let selectorColor = self.selectorColor {
for subview in self.subviews {
if subview.bounds.height <= 1.0 {
subview.backgroundColor = selectorColor
}
}
}
}
}
private let digitsCharacterSet = CharacterSet(charactersIn: "0123456789")
private let nondigitsCharacterSet = CharacterSet(charactersIn: "0123456789").inverted
private class TimerPickerItemView: UIView {
let valueLabel = UILabel()
let unitLabel = UILabel()
var textColor: UIColor? = nil {
didSet {
self.valueLabel.textColor = self.textColor
self.unitLabel.textColor = self.textColor
}
}
var value: (Int32, String)? {
didSet {
if let (value, string) = self.value {
let components = string.components(separatedBy: " ")
if value == viewOnceTimeout {
self.valueLabel.text = string
self.unitLabel.text = ""
} else if components.count > 1 {
self.valueLabel.text = components[0]
self.unitLabel.text = components[1]
} else {
self.valueLabel.text = string.trimmingCharacters(in: nondigitsCharacterSet)
self.unitLabel.text = string.trimmingCharacters(in: digitsCharacterSet)
}
}
self.setNeedsLayout()
}
}
override init(frame: CGRect) {
self.valueLabel.backgroundColor = nil
self.valueLabel.isOpaque = false
self.valueLabel.font = Font.regular(24.0)
self.unitLabel.backgroundColor = nil
self.unitLabel.isOpaque = false
self.unitLabel.font = Font.medium(16.0)
super.init(frame: frame)
self.addSubview(self.valueLabel)
self.addSubview(self.unitLabel)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
self.valueLabel.sizeToFit()
self.unitLabel.sizeToFit()
if let (value, _) = self.value, value == viewOnceTimeout {
self.valueLabel.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((self.frame.width - self.valueLabel.frame.size.width) / 2.0), y: floor((self.frame.height - self.valueLabel.frame.height) / 2.0)), size: self.valueLabel.frame.size)
} else {
self.valueLabel.frame = CGRect(origin: CGPoint(x: self.frame.width / 2.0 - 28.0 - self.valueLabel.frame.size.width, y: floor((self.frame.height - self.valueLabel.frame.height) / 2.0)), size: self.valueLabel.frame.size)
self.unitLabel.frame = CGRect(origin: CGPoint(x: self.frame.width / 2.0 - 20.0, y: floor((self.frame.height - self.unitLabel.frame.height) / 2.0) + 2.0), size: self.unitLabel.frame.size)
}
}
}
private var timerValues: [Int32] = {
var values: [Int32] = []
for i in 1 ..< 20 {
values.append(Int32(i))
}
for i in 0 ..< 9 {
values.append(Int32(20 + i * 5))
}
return values
}()
private let autoremoveTimerValues: [Int32] = [
1 * 24 * 60 * 60 as Int32,
2 * 24 * 60 * 60 as Int32,
3 * 24 * 60 * 60 as Int32,
4 * 24 * 60 * 60 as Int32,
5 * 24 * 60 * 60 as Int32,
6 * 24 * 60 * 60 as Int32,
1 * 7 * 24 * 60 * 60 as Int32,
2 * 7 * 24 * 60 * 60 as Int32,
3 * 7 * 24 * 60 * 60 as Int32,
1 * 31 * 24 * 60 * 60 as Int32,
2 * 30 * 24 * 60 * 60 as Int32,
3 * 31 * 24 * 60 * 60 as Int32,
4 * 30 * 24 * 60 * 60 as Int32,
5 * 31 * 24 * 60 * 60 as Int32,
6 * 30 * 24 * 60 * 60 as Int32,
365 * 24 * 60 * 60 as Int32
]
private final class ChatTimerSheetContentComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let style: ChatTimerScreenStyle
let mode: ChatTimerScreenMode
let currentTime: Int32?
let dismiss: () -> Void
init(
style: ChatTimerScreenStyle,
mode: ChatTimerScreenMode,
currentTime: Int32?,
dismiss: @escaping () -> Void
) {
self.style = style
self.mode = mode
self.currentTime = currentTime
self.dismiss = dismiss
}
static func ==(lhs: ChatTimerSheetContentComponent, rhs: ChatTimerSheetContentComponent) -> Bool {
if lhs.style != rhs.style {
return false
}
if lhs.mode != rhs.mode {
return false
}
if lhs.currentTime != rhs.currentTime {
return false
}
return true
}
final class View: UIView, UIPickerViewDataSource, UIPickerViewDelegate {
private let closeButton = ComponentView<Empty>()
private let title = ComponentView<Empty>()
private let primaryButton = ComponentView<Empty>()
private let secondaryButton = ComponentView<Empty>()
private var component: ChatTimerSheetContentComponent?
private var environment: EnvironmentType?
private weak var state: EmptyComponentState?
private var pickerView: TimerPickerView?
private var isCompleting = false
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func selectedValue() -> Int32? {
guard let component = self.component, let pickerView = self.pickerView else {
return nil
}
if let pickerView = pickerView as? TimerCustomPickerView {
switch component.mode {
case .sendTimer:
let row = pickerView.selectedRow(inComponent: 0)
if row == 0 {
return viewOnceTimeout
} else {
return timerValues[row - 1]
}
case .autoremove:
return autoremoveTimerValues[pickerView.selectedRow(inComponent: 0)]
case .mute:
return nil
}
} else if let pickerView = pickerView as? TimerDatePickerView {
return Int32(pickerView.date.timeIntervalSince1970)
} else {
return nil
}
}
private func pickerTextColor(component: ChatTimerSheetContentComponent, environment: EnvironmentType) -> UIColor {
switch component.mode {
case .sendTimer:
return .white
case .autoremove:
if case .media = component.style {
return .white
} else {
return environment.theme.list.itemPrimaryTextColor
}
case .mute:
if case .media = component.style {
return .white
} else {
return environment.theme.list.itemPrimaryTextColor
}
}
}
private func selectAutoremoveValue(_ value: Int32, in pickerView: TimerCustomPickerView) {
var selectedRowIndex = 0
for i in 0 ..< autoremoveTimerValues.count {
if autoremoveTimerValues[i] <= value {
selectedRowIndex = i
}
}
pickerView.selectRow(selectedRowIndex, inComponent: 0, animated: false)
}
private func setupPickerView(component: ChatTimerSheetContentComponent, environment: EnvironmentType) {
let previousSelectedValue = self.selectedValue()
let previousDate = (self.pickerView as? TimerDatePickerView)?.date
if let pickerView = self.pickerView {
pickerView.removeFromSuperview()
}
switch component.mode {
case .sendTimer:
let pickerView = TimerCustomPickerView()
pickerView.selectorColor = UIColor(rgb: 0xffffff, alpha: 0.18)
pickerView.dataSource = self
pickerView.delegate = self
self.addSubview(pickerView)
self.pickerView = pickerView
if let previousSelectedValue {
if previousSelectedValue == viewOnceTimeout {
pickerView.selectRow(0, inComponent: 0, animated: false)
} else if let index = timerValues.firstIndex(of: previousSelectedValue) {
pickerView.selectRow(index + 1, inComponent: 0, animated: false)
}
}
case .autoremove:
let pickerView = TimerCustomPickerView()
pickerView.dataSource = self
pickerView.delegate = self
pickerView.selectorColor = self.pickerTextColor(component: component, environment: environment).withMultipliedAlpha(0.18)
self.addSubview(pickerView)
self.pickerView = pickerView
if let previousSelectedValue {
self.selectAutoremoveValue(previousSelectedValue, in: pickerView)
} else if let currentTime = component.currentTime {
self.selectAutoremoveValue(currentTime, in: pickerView)
}
case .mute:
let pickerView = TimerDatePickerView()
pickerView.locale = localeWithStrings(environment.strings)
pickerView.datePickerMode = .dateAndTime
pickerView.minimumDate = Date()
if #available(iOS 13.4, *) {
pickerView.preferredDatePickerStyle = .wheels
}
pickerView.setValue(self.pickerTextColor(component: component, environment: environment), forKey: "textColor")
pickerView.setValue(false, forKey: "highlightsToday")
pickerView.selectorColor = UIColor(rgb: 0xffffff, alpha: 0.18)
pickerView.addTarget(self, action: #selector(self.datePickerChanged), for: .valueChanged)
if let previousDate {
pickerView.date = max(previousDate, Date())
}
self.addSubview(pickerView)
self.pickerView = pickerView
}
}
@objc private func datePickerChanged() {
self.state?.updated(transition: .immediate)
}
private func title(strings: PresentationStrings) -> String {
guard let component = self.component else {
return ""
}
switch component.mode {
case .sendTimer:
return strings.Conversation_Timer_Title
case .autoremove:
return strings.Conversation_DeleteTimer_SetupTitle
case .mute:
return strings.Conversation_Mute_SetupTitle
}
}
private func primaryButtonTitle(component: ChatTimerSheetContentComponent, environment: EnvironmentType) -> String {
switch component.mode {
case .sendTimer:
return environment.strings.Conversation_Timer_Send
case .autoremove:
return environment.strings.Conversation_DeleteTimer_Apply
case .mute:
if let pickerView = self.pickerView as? TimerDatePickerView {
let now = Int32(Date().timeIntervalSince1970)
let timeInterval = max(0, Int32(pickerView.date.timeIntervalSince1970) - now)
if timeInterval > 0 {
let timeString = stringForPreciseRelativeTimestamp(strings: environment.strings, relativeTimestamp: Int32(pickerView.date.timeIntervalSince1970), relativeTo: now, dateTimeFormat: environment.dateTimeFormat)
return environment.strings.Conversation_Mute_ApplyMuteUntil(timeString).string
} else {
return environment.strings.Common_Close
}
} else {
return environment.strings.Common_Close
}
}
}
private func complete(value: Int32) {
guard !self.isCompleting else {
return
}
self.isCompleting = true
if let controller = self.environment?.controller() as? ChatTimerScreen {
controller.completion(value)
}
self.component?.dismiss()
}
private func completeWithPickerValue() {
guard let component = self.component, let pickerView = self.pickerView else {
return
}
if let pickerView = pickerView as? TimerCustomPickerView {
switch component.mode {
case .sendTimer:
let row = pickerView.selectedRow(inComponent: 0)
let value: Int32
if row == 0 {
value = viewOnceTimeout
} else {
value = timerValues[row - 1]
}
self.complete(value: value)
case .autoremove:
self.complete(value: autoremoveTimerValues[pickerView.selectedRow(inComponent: 0)])
case .mute:
break
}
} else if let pickerView = pickerView as? TimerDatePickerView {
switch component.mode {
case .mute:
let timeInterval = max(0, Int32(pickerView.date.timeIntervalSince1970) - Int32(Date().timeIntervalSince1970))
self.complete(value: timeInterval)
default:
break
}
}
}
func update(component: ChatTimerSheetContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
let environment = environment[EnvironmentType.self].value
let previousComponent = self.component
let previousEnvironment = self.environment
let themeUpdated: Bool
let stringsUpdated: Bool
if let previousEnvironment {
themeUpdated = previousEnvironment.theme !== environment.theme
stringsUpdated = previousEnvironment.strings !== environment.strings
} else {
themeUpdated = false
stringsUpdated = false
}
self.component = component
self.environment = environment
self.state = state
if self.pickerView == nil || previousComponent?.mode != component.mode || previousComponent?.style != component.style || themeUpdated || stringsUpdated {
self.setupPickerView(component: component, environment: environment)
}
let titleColor: UIColor
switch component.style {
case .default:
titleColor = environment.theme.actionSheet.primaryTextColor
case .media:
titleColor = .white
}
let barButtonSize = CGSize(width: 44.0, height: 44.0)
let closeButtonSize = self.closeButton.update(
transition: transition,
component: AnyComponent(
GlassBarButtonComponent(
size: barButtonSize,
backgroundColor: nil,
isDark: environment.theme.overallDarkAppearance,
state: .glass,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: environment.theme.chat.inputPanel.panelControlColor
)
)),
action: { [weak self] _ in
self?.component?.dismiss()
}
)
),
environment: {},
containerSize: barButtonSize
)
if let closeButtonView = self.closeButton.view {
if closeButtonView.superview == nil {
self.addSubview(closeButtonView)
}
transition.setFrame(view: closeButtonView, frame: CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: closeButtonSize))
}
let titleSize = self.title.update(
transition: transition,
component: AnyComponent(
Text(text: self.title(strings: environment.strings), font: Font.semibold(17.0), color: titleColor)
),
environment: {},
containerSize: CGSize(width: availableSize.width - 120.0, height: 44.0)
)
if let titleView = self.title.view {
if titleView.superview == nil {
self.addSubview(titleView)
}
transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - titleSize.width) / 2.0), y: floorToScreenPixels(16.0 + (barButtonSize.height - titleSize.height) / 2.0)), size: titleSize))
}
var contentHeight: CGFloat = 68.0
let pickerHeight: CGFloat = 216.0
if let pickerView = self.pickerView {
transition.setFrame(view: pickerView as UIView, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: availableSize.width, height: pickerHeight)))
}
contentHeight += pickerHeight
contentHeight += 17.0
let buttonSideInset: CGFloat = 30.0
let primaryButtonTitle = self.primaryButtonTitle(component: component, environment: environment)
let primaryButtonSize = self.primaryButton.update(
transition: transition,
component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
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(primaryButtonTitle), component: AnyComponent(
Text(text: primaryButtonTitle, font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor)
)),
isEnabled: true,
displaysProgress: false,
action: { [weak self] in
self?.completeWithPickerValue()
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - buttonSideInset * 2.0, height: 52.0)
)
if let primaryButtonView = self.primaryButton.view {
if primaryButtonView.superview == nil {
self.addSubview(primaryButtonView)
}
transition.setFrame(view: primaryButtonView, frame: CGRect(origin: CGPoint(x: buttonSideInset, y: contentHeight), size: primaryButtonSize))
}
contentHeight += primaryButtonSize.height
if case .autoremove = component.mode, component.currentTime != nil {
contentHeight += 8.0
let secondaryButtonTitle = environment.strings.Conversation_DeleteTimer_Disable
let secondaryButtonSize = self.secondaryButton.update(
transition: transition,
component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: environment.theme.list.itemDestructiveColor.withMultipliedAlpha(0.1),
foreground: environment.theme.list.itemDestructiveColor,
pressedColor: environment.theme.list.itemDestructiveColor.withMultipliedAlpha(0.8)
),
content: AnyComponentWithIdentity(id: AnyHashable(secondaryButtonTitle), component: AnyComponent(
Text(text: secondaryButtonTitle, font: Font.semibold(17.0), color: environment.theme.list.itemDestructiveColor)
)),
isEnabled: true,
displaysProgress: false,
action: { [weak self] in
self?.complete(value: 0)
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - buttonSideInset * 2.0, height: 52.0)
)
if let secondaryButtonView = self.secondaryButton.view {
if secondaryButtonView.superview == nil {
self.addSubview(secondaryButtonView)
}
transition.setFrame(view: secondaryButtonView, frame: CGRect(origin: CGPoint(x: buttonSideInset, y: contentHeight), size: secondaryButtonSize))
}
contentHeight += secondaryButtonSize.height
} else if let secondaryButtonView = self.secondaryButton.view, secondaryButtonView.superview != nil {
secondaryButtonView.removeFromSuperview()
}
let bottomInset: CGFloat = environment.safeInsets.bottom > 0.0 ? environment.safeInsets.bottom + 5.0 : 15.0
contentHeight += bottomInset
return CGSize(width: availableSize.width, height: contentHeight)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
guard let component = self.component else {
return 0
}
switch component.mode {
case .sendTimer:
return timerValues.count + 1
case .autoremove:
return autoremoveTimerValues.count
case .mute:
return 0
}
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent componentIndex: Int, reusing view: UIView?) -> UIView {
guard let component = self.component, let environment = self.environment else {
return UIView()
}
let itemView: TimerPickerItemView
if let current = view as? TimerPickerItemView {
itemView = current
} else {
itemView = TimerPickerItemView()
}
itemView.textColor = self.pickerTextColor(component: component, environment: environment)
switch component.mode {
case .sendTimer:
if row == 0 {
let string = environment.strings.MediaPicker_Timer_ViewOnce
itemView.value = (viewOnceTimeout, string)
} else {
let value = timerValues[row - 1]
let string = timeIntervalString(strings: environment.strings, value: value)
itemView.value = (value, string)
}
case .autoremove:
let value = autoremoveTimerValues[row]
let string = timeIntervalString(strings: environment.strings, value: value)
itemView.value = (value, string)
case .mute:
preconditionFailure()
}
return itemView
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.state?.updated(transition: .immediate)
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
private final class ChatTimerSheetComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let style: ChatTimerScreenStyle
let mode: ChatTimerScreenMode
let currentTime: Int32?
init(
style: ChatTimerScreenStyle,
mode: ChatTimerScreenMode,
currentTime: Int32?
) {
self.style = style
self.mode = mode
self.currentTime = currentTime
}
static func ==(lhs: ChatTimerSheetComponent, rhs: ChatTimerSheetComponent) -> Bool {
if lhs.style != rhs.style {
return false
}
if lhs.mode != rhs.mode {
return false
}
if lhs.currentTime != rhs.currentTime {
return false
}
return true
}
final class View: UIView {
private let sheet = ComponentView<(ViewControllerComponentContainer.Environment, SheetComponentEnvironment)>()
private let sheetAnimateOut = ActionSlot<Action<Void>>()
private var component: ChatTimerSheetComponent?
private var environment: EnvironmentType?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func dismiss() {
self.sheetAnimateOut.invoke(Action { [weak self] _ in
guard let self, let controller = self.environment?.controller() else {
return
}
controller.dismiss(completion: nil)
})
}
func update(component: ChatTimerSheetComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
self.component = component
let environment = environment[ViewControllerComponentContainer.Environment.self].value
self.environment = environment
let sheetEnvironment = SheetComponentEnvironment(
metrics: environment.metrics,
deviceMetrics: environment.deviceMetrics,
isDisplaying: environment.isVisible,
isCentered: environment.metrics.widthClass == .regular,
hasInputHeight: !environment.inputHeight.isZero,
regularMetricsSize: CGSize(width: 430.0, height: 900.0),
dismiss: { [weak self] _ in
self?.dismiss()
}
)
let backgroundColor: UIColor
switch component.style {
case .default:
backgroundColor = environment.theme.actionSheet.opaqueItemBackgroundColor
case .media:
backgroundColor = UIColor(rgb: 0x1c1c1e)
}
let _ = self.sheet.update(
transition: transition,
component: AnyComponent(SheetComponent(
content: AnyComponent(ChatTimerSheetContentComponent(
style: component.style,
mode: component.mode,
currentTime: component.currentTime,
dismiss: { [weak self] in
self?.dismiss()
}
)),
style: .glass,
backgroundColor: .color(backgroundColor),
followContentSizeChanges: true,
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<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
public final class ChatTimerScreen: ViewControllerComponentContainer {
fileprivate let completion: (Int32) -> Void
public init(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
style: ChatTimerScreenStyle,
mode: ChatTimerScreenMode = .sendTimer,
currentTime: Int32? = nil,
completion: @escaping (Int32) -> Void
) {
self.completion = completion
super.init(
context: context,
component: ChatTimerSheetComponent(
style: style,
mode: mode,
currentTime: currentTime
),
navigationBarAppearance: .none,
statusBarStyle: .ignore,
theme: style == .media ? .dark : .default,
updatedPresentationData: updatedPresentationData
)
self.statusBar.statusBarStyle = .Ignore
self.navigationPresentation = .flatModal
self.blocksBackgroundWhenInOverlay = true
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.view.disablesInteractiveModalDismiss = true
}
public func dismissAnimated() {
if let view = self.node.hostView.findTaggedView(tag: SheetComponent<ViewControllerComponentContainer.Environment>.View.Tag()) as? SheetComponent<ViewControllerComponentContainer.Environment>.View {
view.dismissAnimated()
}
}
}