1919@implementation RNScreensEventObserver {
2020 std::weak_ptr<const EventDispatcher> _eventDispatcher;
2121 std::shared_ptr<const EventListener> _eventListener;
22+ NSInteger _presenterScreenTag;
2223 NSMutableSet <NSNumber *> *_screenTags;
2324 __weak UIViewController *_presenterScreenController;
25+ __weak UIViewController *_parentScreenController;
26+ __weak UIWindow *_window;
2427 BOOL _dismissedByNavigation;
2528}
2629
2730- (instancetype )init {
2831 if (self = [super init ]) {
32+ _presenterScreenTag = 0 ;
2933 _screenTags = [NSMutableSet new ];
3034 _presenterScreenController = nil ;
35+ _parentScreenController = nil ;
36+ _window = nil ;
3137 }
3238 return self;
3339}
@@ -56,9 +62,11 @@ - (void)startObservingWithState:(const TrueSheetViewState &)state {
5662 Tag screenTag = family->getTag ();
5763
5864 if (event.type == " topWillDisappear" ) {
59- if ([strongSelf shouldDismissForScreenTag: screenTag]) {
60- strongSelf->_dismissedByNavigation = YES ;
61- [strongSelf.delegate presenterScreenWillDisappear ];
65+ if ([strongSelf->_screenTags containsObject: @(screenTag)]) {
66+ if ([strongSelf shouldDismissForScreenTag: screenTag]) {
67+ strongSelf->_dismissedByNavigation = YES ;
68+ [strongSelf.delegate presenterScreenWillDisappear ];
69+ }
6270 }
6371 } else if (event.type == " topWillAppear" ) {
6472 if ([strongSelf->_screenTags containsObject: @(screenTag)] && strongSelf->_dismissedByNavigation ) {
@@ -85,40 +93,68 @@ - (void)stopObserving {
8593}
8694
8795- (void )capturePresenterScreenFromView : (UIView *)view {
96+ _presenterScreenTag = 0 ;
8897 [_screenTags removeAllObjects ];
8998 _presenterScreenController = nil ;
99+ _parentScreenController = nil ;
100+ _window = view.window ;
90101
91102 for (UIView *current = view.superview ; current; current = current.superview ) {
92103 if ([NSStringFromClass ([current class ]) isEqualToString: @" RNSScreenView" ]) {
93104 [_screenTags addObject: @(current.tag)];
94105
95- // Capture the view controller from the first (immediate presenter) screen
96- if (!_presenterScreenController) {
97- for (UIResponder *r = current.nextResponder ; r; r = r.nextResponder ) {
98- if ([r isKindOfClass: [UIViewController class ]]) {
99- _presenterScreenController = (UIViewController *)r;
100- break ;
101- }
106+ UIViewController *screenVC = nil ;
107+ for (UIResponder *r = current.nextResponder ; r; r = r.nextResponder ) {
108+ if ([r isKindOfClass: [UIViewController class ]]) {
109+ screenVC = (UIViewController *)r;
110+ break ;
102111 }
103112 }
113+
114+ if (!_presenterScreenController) {
115+ _presenterScreenTag = current.tag ;
116+ _presenterScreenController = screenVC;
117+ } else if (!_parentScreenController && screenVC) {
118+ _parentScreenController = screenVC;
119+ }
104120 }
105121 }
106122}
107123
108124- (BOOL )shouldDismissForScreenTag : (NSInteger )screenTag {
109- if (![_screenTags containsObject: @(screenTag)]) {
125+ // For parent screens (not immediate presenter), check if the presenter screen is being removed
126+ // This handles nested stack removal case
127+ if (screenTag != _presenterScreenTag) {
128+ UINavigationController *parentNav = _parentScreenController.navigationController ;
129+
130+ // Modal case: parent's nav is presented -> let sheet dismiss naturally
131+ // Nested stack case: parent's nav is not presented (embedded) -> need to dismiss
132+ if (parentNav.presentingViewController != nil ) {
133+ return NO ;
134+ }
135+
136+ if (!_parentScreenController) {
137+ return NO ;
138+ }
139+
140+ // If presenter view is no longer in window, the nested stack is being removed
141+ UIView *presenterView = [_window viewWithTag: _presenterScreenTag];
142+ if (presenterView == nil || presenterView.window == nil ) {
143+ return YES ;
144+ }
145+
110146 return NO ;
111147 }
112148
149+ // For immediate presenter screen
113150 UINavigationController *navController = _presenterScreenController.navigationController ;
114151
115- // If nav controller is nil or being dismissed, dismiss the sheet
116152 if (!navController || navController.isBeingDismissed ) {
117153 return YES ;
118154 }
119155
120- // Skip if screen is still top of nav stack (e.g. modal dismiss - sheet dismisses naturally with modal )
121- // Dismiss if a new screen was pushed or popped
156+ // Dismiss if presenter is no longer top of nav stack (pushed/popped )
157+ // Skip if still top (e.g. modal dismiss - sheet dismisses naturally)
122158 return navController.topViewController != _presenterScreenController;
123159}
124160
0 commit comments