mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Various improvements
This commit is contained in:
@@ -16,6 +16,7 @@ import OpenInExternalAppUI
|
||||
import MultilineTextComponent
|
||||
import MinimizedContainer
|
||||
import InstantPageUI
|
||||
import NavigationStackComponent
|
||||
|
||||
private let settingsTag = GenericComponentViewTag()
|
||||
|
||||
@@ -26,6 +27,7 @@ private final class BrowserScreenComponent: CombinedComponent {
|
||||
let contentState: BrowserContentState?
|
||||
let presentationState: BrowserPresentationState
|
||||
let performAction: ActionSlot<BrowserScreen.Action>
|
||||
let performHoldAction: (UIView, ContextGesture?, BrowserScreen.Action) -> Void
|
||||
let panelCollapseFraction: CGFloat
|
||||
|
||||
init(
|
||||
@@ -33,12 +35,14 @@ private final class BrowserScreenComponent: CombinedComponent {
|
||||
contentState: BrowserContentState?,
|
||||
presentationState: BrowserPresentationState,
|
||||
performAction: ActionSlot<BrowserScreen.Action>,
|
||||
performHoldAction: @escaping (UIView, ContextGesture?, BrowserScreen.Action) -> Void,
|
||||
panelCollapseFraction: CGFloat
|
||||
) {
|
||||
self.context = context
|
||||
self.contentState = contentState
|
||||
self.presentationState = presentationState
|
||||
self.performAction = performAction
|
||||
self.performHoldAction = performHoldAction
|
||||
self.panelCollapseFraction = panelCollapseFraction
|
||||
}
|
||||
|
||||
@@ -72,7 +76,8 @@ private final class BrowserScreenComponent: CombinedComponent {
|
||||
return { context in
|
||||
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
|
||||
let performAction = context.component.performAction
|
||||
|
||||
let performHoldAction = context.component.performHoldAction
|
||||
|
||||
let navigationContent: AnyComponentWithIdentity<Empty>?
|
||||
var navigationLeftItems: [AnyComponentWithIdentity<Empty>]
|
||||
var navigationRightItems: [AnyComponentWithIdentity<Empty>]
|
||||
@@ -172,7 +177,7 @@ private final class BrowserScreenComponent: CombinedComponent {
|
||||
leftItems: navigationLeftItems,
|
||||
rightItems: navigationRightItems,
|
||||
centerItem: navigationContent,
|
||||
readingProgress: 0.0,
|
||||
readingProgress: context.component.contentState?.readingProgress ?? 0.0,
|
||||
loadingProgress: context.component.contentState?.estimatedProgress,
|
||||
collapseFraction: collapseFraction
|
||||
),
|
||||
@@ -206,7 +211,8 @@ private final class BrowserScreenComponent: CombinedComponent {
|
||||
textColor: environment.theme.rootController.navigationBar.primaryTextColor,
|
||||
canGoBack: context.component.contentState?.canGoBack ?? false,
|
||||
canGoForward: context.component.contentState?.canGoForward ?? false,
|
||||
performAction: performAction
|
||||
performAction: performAction,
|
||||
performHoldAction: performHoldAction
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -275,17 +281,18 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
private weak var controller: BrowserScreen?
|
||||
private let context: AccountContext
|
||||
|
||||
private let contentContainerView: UIView
|
||||
fileprivate var content: BrowserContent?
|
||||
private let contentContainerView = UIView()
|
||||
fileprivate let contentNavigationContainer = ComponentView<Empty>()
|
||||
fileprivate var content: [BrowserContent] = []
|
||||
|
||||
private var contentState: BrowserContentState?
|
||||
private var contentStateDisposable: Disposable?
|
||||
fileprivate var contentState: BrowserContentState?
|
||||
private var contentStateDisposable = MetaDisposable()
|
||||
|
||||
private var presentationState: BrowserPresentationState
|
||||
|
||||
private let performAction: ActionSlot<BrowserScreen.Action>
|
||||
private let performAction = ActionSlot<BrowserScreen.Action>()
|
||||
|
||||
fileprivate let componentHost: ComponentView<ViewControllerComponentContainer.Environment>
|
||||
fileprivate let componentHost = ComponentView<ViewControllerComponentContainer.Environment>()
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
@@ -296,41 +303,13 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.presentationState = BrowserPresentationState(fontSize: 100, fontIsSerif: false, isSearching: false, searchResultIndex: 0, searchResultCount: 0, searchQueryIsEmpty: true)
|
||||
|
||||
self.performAction = ActionSlot()
|
||||
|
||||
self.contentContainerView = UIView()
|
||||
self.contentContainerView.clipsToBounds = true
|
||||
|
||||
self.componentHost = ComponentView<ViewControllerComponentContainer.Environment>()
|
||||
|
||||
|
||||
super.init()
|
||||
|
||||
let content: BrowserContent
|
||||
switch controller.subject {
|
||||
case let .webPage(url):
|
||||
content = BrowserWebContent(context: controller.context, url: url)
|
||||
case let .instantPage(webPage, sourceLocation):
|
||||
content = BrowserInstantPageContent(context: controller.context, webPage: webPage, url: webPage.content.url ?? "", sourceLocation: sourceLocation)
|
||||
}
|
||||
|
||||
self.content = content
|
||||
self.contentStateDisposable = (content.state
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.controller?.title = state.title
|
||||
strongSelf.contentState = state
|
||||
strongSelf.requestLayout(transition: .easeInOut(duration: 0.25))
|
||||
}).strict()
|
||||
|
||||
self.content?.onScrollingUpdate = { [weak self] update in
|
||||
self?.onContentScrollingUpdate(update)
|
||||
}
|
||||
|
||||
self.pushContent(controller.subject, transition: .immediate)
|
||||
|
||||
self.performAction.connect { [weak self] action in
|
||||
guard let self, let content = self.content, let url = self.contentState?.url else {
|
||||
guard let self, let content = self.content.last, let url = self.contentState?.url else {
|
||||
return
|
||||
}
|
||||
switch action {
|
||||
@@ -341,7 +320,11 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
case .stop:
|
||||
content.stop()
|
||||
case .navigateBack:
|
||||
content.navigateBack()
|
||||
if content.currentState.canGoBack {
|
||||
content.navigateBack()
|
||||
} else {
|
||||
self.popContent(transition: .spring(duration: 0.4))
|
||||
}
|
||||
case .navigateForward:
|
||||
content.navigateForward()
|
||||
case .share:
|
||||
@@ -458,22 +441,139 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.contentStateDisposable?.dispose()
|
||||
self.contentStateDisposable.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.contentContainerView.clipsToBounds = true
|
||||
self.view.addSubview(self.contentContainerView)
|
||||
if let content = self.content {
|
||||
self.contentContainerView.addSubview(content)
|
||||
}
|
||||
}
|
||||
|
||||
func updatePresentationState(animated: Bool = false, _ f: (BrowserPresentationState) -> BrowserPresentationState) {
|
||||
self.presentationState = f(self.presentationState)
|
||||
self.requestLayout(transition: animated ? .easeInOut(duration: 0.2) : .immediate)
|
||||
}
|
||||
|
||||
func pushContent(_ content: BrowserScreen.Subject, transition: ComponentTransition) {
|
||||
let browserContent: BrowserContent
|
||||
switch content {
|
||||
case let .webPage(url):
|
||||
browserContent = BrowserWebContent(context: self.context, url: url)
|
||||
case let .instantPage(webPage, anchor, sourceLocation):
|
||||
let instantPageContent = BrowserInstantPageContent(context: self.context, webPage: webPage, anchor: anchor, url: webPage.content.url ?? "", sourceLocation: sourceLocation)
|
||||
instantPageContent.openPeer = { [weak self] peer in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.openPeer(peer)
|
||||
}
|
||||
browserContent = instantPageContent
|
||||
}
|
||||
browserContent.pushContent = { [weak self] content in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.pushContent(content, transition: .spring(duration: 0.4))
|
||||
}
|
||||
browserContent.present = { [weak self] c, a in
|
||||
guard let self, let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
controller.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
browserContent.presentInGlobalOverlay = { [weak self] c in
|
||||
guard let self, let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
controller.presentInGlobalOverlay(c)
|
||||
}
|
||||
browserContent.getNavigationController = { [weak self] in
|
||||
return self?.controller?.navigationController as? NavigationController
|
||||
}
|
||||
browserContent.minimize = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.minimize()
|
||||
}
|
||||
|
||||
self.content.append(browserContent)
|
||||
self.requestLayout(transition: transition)
|
||||
|
||||
self.setupContentStateUpdates()
|
||||
}
|
||||
|
||||
func popContent(transition: ComponentTransition) {
|
||||
self.content.removeLast()
|
||||
self.requestLayout(transition: transition)
|
||||
|
||||
self.setupContentStateUpdates()
|
||||
}
|
||||
|
||||
func openPeer(_ peer: EnginePeer) {
|
||||
guard let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
self.minimize()
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), animated: true))
|
||||
}
|
||||
|
||||
private func setupContentStateUpdates() {
|
||||
for content in self.content {
|
||||
content.onScrollingUpdate = { _ in }
|
||||
}
|
||||
|
||||
guard let content = self.content.last else {
|
||||
self.controller?.title = ""
|
||||
self.contentState = nil
|
||||
self.contentStateDisposable.set(nil)
|
||||
self.requestLayout(transition: .easeInOut(duration: 0.25))
|
||||
return
|
||||
}
|
||||
|
||||
var previousState = BrowserContentState(title: "", url: "", estimatedProgress: 1.0, readingProgress: 0.0, contentType: .webPage, canGoBack: false, canGoForward: false, backList: [], forwardList: [])
|
||||
if self.content.count > 1 {
|
||||
for content in self.content.prefix(upTo: self.content.count - 1) {
|
||||
var backList = previousState.backList
|
||||
backList.append(BrowserContentState.HistoryItem(url: content.currentState.url, title: content.currentState.title, uuid: content.uuid))
|
||||
previousState = previousState.withUpdatedBackList(backList)
|
||||
}
|
||||
}
|
||||
|
||||
self.contentStateDisposable.set((content.state
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] state in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var backList = state.backList
|
||||
backList.insert(contentsOf: previousState.backList, at: 0)
|
||||
|
||||
var canGoBack = state.canGoBack
|
||||
if !backList.isEmpty {
|
||||
canGoBack = true
|
||||
}
|
||||
|
||||
let previousState = self.contentState
|
||||
let state = state.withUpdatedCanGoBack(canGoBack).withUpdatedBackList(backList)
|
||||
self.controller?.title = state.title
|
||||
self.contentState = state
|
||||
|
||||
let transition: ComponentTransition
|
||||
if let previousState, previousState.withUpdatedReadingProgress(state.readingProgress) == state {
|
||||
transition = .immediate
|
||||
} else {
|
||||
transition = .easeInOut(duration: 0.25)
|
||||
}
|
||||
|
||||
self.requestLayout(transition: transition)
|
||||
}))
|
||||
|
||||
content.onScrollingUpdate = { [weak self] update in
|
||||
self?.onContentScrollingUpdate(update)
|
||||
}
|
||||
}
|
||||
|
||||
func minimize() {
|
||||
guard let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
@@ -598,7 +698,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
if result == self.componentHost.view, let content = self.content {
|
||||
if result == self.componentHost.view, let content = self.content.last {
|
||||
return content.hitTest(self.view.convert(point, to: content), with: event)
|
||||
}
|
||||
return result
|
||||
@@ -654,6 +754,51 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
}
|
||||
}
|
||||
|
||||
func navigateTo(_ item: BrowserContentState.HistoryItem) {
|
||||
if let _ = item.webItem {
|
||||
if let last = self.content.last {
|
||||
last.navigateTo(historyItem: item)
|
||||
}
|
||||
} else if let uuid = item.uuid {
|
||||
var newContent = self.content
|
||||
while newContent.last?.uuid != uuid {
|
||||
newContent.removeLast()
|
||||
}
|
||||
self.content = newContent
|
||||
self.requestLayout(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
|
||||
func performHoldAction(view: UIView, gesture: ContextGesture?, action: BrowserScreen.Action) {
|
||||
guard let controller = self.controller, let contentState = self.contentState else {
|
||||
return
|
||||
}
|
||||
|
||||
let source: ContextContentSource = .reference(BrowserReferenceContentSource(controller: controller, sourceView: view))
|
||||
var items: [ContextMenuItem] = []
|
||||
switch action {
|
||||
case .navigateBack:
|
||||
for item in contentState.backList {
|
||||
items.append(.action(ContextMenuActionItem(text: item.title, textLayout: .secondLineWithValue(item.url), icon: { _ in return nil }, action: { [weak self] (_, action) in
|
||||
self?.navigateTo(item)
|
||||
action(.default)
|
||||
})))
|
||||
}
|
||||
case .navigateForward:
|
||||
for item in contentState.forwardList {
|
||||
items.append(.action(ContextMenuActionItem(text: item.title, textLayout: .secondLineWithValue(item.url), icon: { _ in return nil }, action: { [weak self] (_, action) in
|
||||
self?.navigateTo(item)
|
||||
action(.default)
|
||||
})))
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
let contextController = ContextController(presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))))
|
||||
self.controller?.present(contextController, in: .window(.root))
|
||||
}
|
||||
|
||||
func requestLayout(transition: ComponentTransition) {
|
||||
if let (layout, navigationBarHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
@@ -694,6 +839,11 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
contentState: self.contentState,
|
||||
presentationState: self.presentationState,
|
||||
performAction: self.performAction,
|
||||
performHoldAction: { [weak self] view, gesture, action in
|
||||
if let self {
|
||||
self.performHoldAction(view: view, gesture: gesture, action: action)
|
||||
}
|
||||
},
|
||||
panelCollapseFraction: self.scrollingPanelOffsetFraction
|
||||
)
|
||||
),
|
||||
@@ -711,12 +861,48 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
transition.setFrame(view: componentView, frame: CGRect(origin: .zero, size: componentSize))
|
||||
}
|
||||
transition.setFrame(view: self.contentContainerView, frame: CGRect(origin: .zero, size: layout.size))
|
||||
if let content = self.content {
|
||||
let collapsedHeight: CGFloat = 24.0
|
||||
let topInset: CGFloat = environment.statusBarHeight + navigationBarHeight * (1.0 - self.scrollingPanelOffsetFraction) + collapsedHeight * self.scrollingPanelOffsetFraction
|
||||
let bottomInset = 49.0 + layout.intrinsicInsets.bottom
|
||||
content.updateLayout(size: layout.size, insets: UIEdgeInsets(top: topInset, left: layout.safeInsets.left, bottom: bottomInset, right: layout.safeInsets.right), transition: transition)
|
||||
transition.setFrame(view: content, frame: CGRect(origin: .zero, size: layout.size))
|
||||
|
||||
var items: [AnyComponentWithIdentity<Empty>] = []
|
||||
for content in self.content {
|
||||
items.append(
|
||||
AnyComponentWithIdentity(id: content.uuid, component: AnyComponent(
|
||||
BrowserContentComponent(
|
||||
content: content,
|
||||
insets: UIEdgeInsets(
|
||||
top: environment.statusBarHeight,
|
||||
left: layout.safeInsets.left,
|
||||
bottom: layout.intrinsicInsets.bottom,
|
||||
right: layout.safeInsets.right
|
||||
),
|
||||
navigationBarHeight: navigationBarHeight,
|
||||
scrollingPanelOffsetFraction: self.scrollingPanelOffsetFraction
|
||||
)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
let _ = self.contentNavigationContainer.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(
|
||||
NavigationStackComponent(
|
||||
items: items,
|
||||
requestPop: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.popContent(transition: .spring(duration: 0.4))
|
||||
}
|
||||
)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: layout.size
|
||||
)
|
||||
let navigationFrame = CGRect(origin: .zero, size: layout.size)
|
||||
if let view = self.contentNavigationContainer.view {
|
||||
if view.superview == nil {
|
||||
self.contentContainerView.addSubview(view)
|
||||
}
|
||||
transition.setFrame(view: view, frame: navigationFrame)
|
||||
}
|
||||
|
||||
self.navigationBarHeight = environment.navigationHeight
|
||||
@@ -726,7 +912,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
|
||||
public enum Subject {
|
||||
case webPage(url: String)
|
||||
case instantPage(webPage: TelegramMediaWebpage, sourceLocation: InstantPageSourceLocation)
|
||||
case instantPage(webPage: TelegramMediaWebpage, anchor: String?, sourceLocation: InstantPageSourceLocation)
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
@@ -743,7 +929,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .allButUpsideDown)
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
(self?.displayNode as? Node)?.content?.scrollToTop()
|
||||
self?.node.content.last?.scrollToTop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,6 +937,10 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
private var node: Node {
|
||||
return self.displayNode as! Node
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = Node(controller: self)
|
||||
|
||||
@@ -760,11 +950,30 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.height, transition: ComponentTransition(transition))
|
||||
self.node.containerLayoutUpdated(layout: layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.height, transition: ComponentTransition(transition))
|
||||
}
|
||||
|
||||
public var isMinimized = false
|
||||
public var isMinimizable = true
|
||||
|
||||
public var minimizedIcon: UIImage? {
|
||||
if let contentState = self.node.contentState {
|
||||
switch contentState.contentType {
|
||||
case .webPage:
|
||||
return contentState.favicon
|
||||
case .instantPage:
|
||||
return UIImage(bundleImageName: "Chat/Message/AttachedContentInstantIcon")?.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public var minimizedProgress: Float? {
|
||||
if let contentState = self.node.contentState {
|
||||
return Float(contentState.readingProgress)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private final class BrowserReferenceContentSource: ContextReferenceContentSource {
|
||||
@@ -780,3 +989,70 @@ private final class BrowserReferenceContentSource: ContextReferenceContentSource
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
private final class BrowserContentComponent: Component {
|
||||
let content: BrowserContent
|
||||
let insets: UIEdgeInsets
|
||||
let navigationBarHeight: CGFloat
|
||||
let scrollingPanelOffsetFraction: CGFloat
|
||||
|
||||
init(
|
||||
content: BrowserContent,
|
||||
insets: UIEdgeInsets,
|
||||
navigationBarHeight: CGFloat,
|
||||
scrollingPanelOffsetFraction: CGFloat
|
||||
) {
|
||||
self.content = content
|
||||
self.insets = insets
|
||||
self.navigationBarHeight = navigationBarHeight
|
||||
self.scrollingPanelOffsetFraction = scrollingPanelOffsetFraction
|
||||
}
|
||||
|
||||
static func ==(lhs: BrowserContentComponent, rhs: BrowserContentComponent) -> Bool {
|
||||
if lhs.content.uuid != rhs.content.uuid {
|
||||
return false
|
||||
}
|
||||
if lhs.insets != rhs.insets {
|
||||
return false
|
||||
}
|
||||
if lhs.navigationBarHeight != rhs.navigationBarHeight {
|
||||
return false
|
||||
}
|
||||
if lhs.scrollingPanelOffsetFraction != rhs.scrollingPanelOffsetFraction {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
final class View: UIView {
|
||||
init() {
|
||||
super.init(frame: CGRect())
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
func update(component: BrowserContentComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
|
||||
if component.content.superview !== self {
|
||||
self.addSubview(component.content)
|
||||
}
|
||||
|
||||
let collapsedHeight: CGFloat = 24.0
|
||||
let topInset: CGFloat = component.insets.top + component.navigationBarHeight * (1.0 - component.scrollingPanelOffsetFraction) + collapsedHeight * component.scrollingPanelOffsetFraction
|
||||
let bottomInset = 49.0 + component.insets.bottom
|
||||
component.content.updateLayout(size: availableSize, insets: UIEdgeInsets(top: topInset, left: component.insets.left, bottom: bottomInset, right: component.insets.right), transition: transition)
|
||||
transition.setFrame(view: component.content, frame: CGRect(origin: .zero, size: availableSize))
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
return View()
|
||||
}
|
||||
|
||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user