1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#import "ABI48_0_0RCTWrapperViewControllerHostingView.h"
9
10#import <ABI48_0_0React/ABI48_0_0UIView+React.h>
11
12#pragma mark - UIViewController+Children
13
14@interface UIViewController (Children)
15
16@property (nonatomic, readonly) BOOL isAttached;
17- (void)attachChildViewController:(UIViewController *)childViewController toContainerView:(UIView *)containerView;
18- (void)detachChildViewController:(UIViewController *)childViewController;
19
20@end
21
22@implementation UIViewController (Children)
23
24- (BOOL)isAttached
25{
26  return self.parentViewController != nil;
27}
28
29- (void)attachChildViewController:(UIViewController *)childViewController toContainerView:(UIView *)containerView
30{
31  [self addChildViewController:childViewController];
32  // `[childViewController willMoveToParentViewController:self]` is calling automatically
33  [containerView addSubview:childViewController.view];
34  childViewController.view.frame = containerView.bounds;
35  childViewController.view.translatesAutoresizingMaskIntoConstraints = YES;
36  childViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
37  [childViewController didMoveToParentViewController:self];
38
39  [childViewController beginAppearanceTransition:true animated:false];
40  [childViewController endAppearanceTransition];
41}
42
43- (void)detachChildViewController:(UIViewController *)childViewController
44{
45  [childViewController beginAppearanceTransition:false animated:false];
46  [childViewController endAppearanceTransition];
47
48  [childViewController willMoveToParentViewController:nil];
49  [childViewController.view removeFromSuperview];
50  [childViewController removeFromParentViewController];
51  // `[childViewController didMoveToParentViewController:nil]` is calling automatically
52}
53
54@end
55
56@implementation ABI48_0_0RCTWrapperViewControllerHostingView {
57  UIViewController *_Nullable _contentViewController;
58}
59
60#pragma mark - `contentViewController`
61
62- (nullable UIViewController *)contentViewController
63{
64  return _contentViewController;
65}
66
67- (void)setContentViewController:(UIViewController *)contentViewController
68{
69  if (_contentViewController) {
70    [self detachContentViewControllerIfNeeded];
71  }
72
73  _contentViewController = contentViewController;
74
75  if (_contentViewController) {
76    [self attachContentViewControllerIfNeeded];
77  }
78}
79
80#pragma mark - Attaching and Detaching
81
82- (void)attachContentViewControllerIfNeeded
83{
84  if (self.contentViewController.isAttached) {
85    return;
86  }
87
88  [self.ABI48_0_0ReactViewController attachChildViewController:self.contentViewController toContainerView:self];
89}
90
91- (void)detachContentViewControllerIfNeeded
92{
93  if (!self.contentViewController.isAttached) {
94    return;
95  }
96
97  [self.ABI48_0_0ReactViewController detachChildViewController:self.contentViewController];
98}
99
100#pragma mark - Life cycle
101
102- (void)willMoveToWindow:(UIWindow *)newWindow
103{
104  if (newWindow == nil) {
105    [self detachContentViewControllerIfNeeded];
106  }
107}
108
109- (void)didMoveToWindow
110{
111  [super didMoveToWindow];
112  [self attachContentViewControllerIfNeeded];
113}
114
115#pragma mark - Layout
116
117- (void)setNeedsLayout
118{
119  [super setNeedsLayout];
120  [self.superview setNeedsLayout];
121}
122
123- (CGSize)intrinsicContentSize
124{
125  return self.contentViewController.view.intrinsicContentSize;
126}
127
128- (CGSize)sizeThatFits:(CGSize)size
129{
130  return [self.contentViewController.view sizeThatFits:size];
131}
132
133@end
134