Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bc2274d
Create a separate folder for new implementation
kmichalikk Mar 17, 2026
aa39e1f
Add RNSStackOperation
kmichalikk Mar 17, 2026
bf9b68f
Simplify StackHost & add operation coordinator
kmichalikk Mar 17, 2026
a765d55
Use operation coordinator in host
kmichalikk Mar 17, 2026
8be5479
Execute stack operations on navigation controller
kmichalikk Mar 17, 2026
8ba3ed3
Rewrite screen controller to obj-c and integrate with new implementation
kmichalikk Mar 17, 2026
341be5f
move stack-queue to stack
kmichalikk Mar 17, 2026
37fe3c1
Make queue operations work
kmichalikk Mar 17, 2026
5997ca6
refactor
kmichalikk Mar 17, 2026
33951f7
add logs & refactor
kmichalikk Mar 18, 2026
d8f1fb1
Move isNativelyDismissed, refactor log
kmichalikk Mar 18, 2026
83d0702
Revert App.tsx
kmichalikk Mar 18, 2026
81446b4
Add asserts for correct screen type
kmichalikk Mar 18, 2026
4f3ea97
Move RNSStackOperation implementation to correct dir
kmichalikk Mar 18, 2026
e69ed78
Fix Copilot catches
kmichalikk Mar 18, 2026
7f15694
simplify sorting
kmichalikk Apr 8, 2026
1e8d43e
fix nonull, noop and RNSLog
kmichalikk Apr 8, 2026
2571b25
Change logged tags, remove unnecessary code
kmichalikk Apr 8, 2026
83d747c
Add assertion in `reactAddControllerToClosestParent`
kkafar Apr 14, 2026
afdfc5d
Fix for the issue with pushing screens that are mid-dismissal
kkafar Apr 14, 2026
1b0a8db
Add nonnill assertion
kkafar Apr 14, 2026
86346d0
fix(ios): add assertion for unexpected activityMode in stack host
kkafar Apr 14, 2026
69e32cf
refactor(ios): reorganize stack host methods into pragma sections
kkafar Apr 14, 2026
d62f256
refactor(ios): replace RNSStackOperation protocol with base class
kkafar Apr 14, 2026
26d29e6
fix: prevent pop action on non-top attached screen
kkafar Apr 14, 2026
ce86bd2
Add simple navigation scenario to test the changes
kkafar Apr 14, 2026
433bab4
refactor(ios): move isNativelyDismissed to public interface
kkafar Apr 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type StackRouteConfig = {
export type StackRoute = StackRouteConfig & {
activityMode: StackScreenProps['activityMode'];
routeKey: StackScreenProps['screenKey'];
isMarkedForDismissal: Boolean, // whether this route is during or after dismissal process
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
isMarkedForDismissal: Boolean, // whether this route is during or after dismissal process
isMarkedForDismissal: boolean, // whether this route is during or after dismissal process

};

/// StackContainer props
Expand Down
14 changes: 12 additions & 2 deletions apps/src/shared/gamma/containers/stack/reducer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function navigationActionPushHandler(
const stack = state.stack;
const renderedRouteIndex = stack.findIndex(
route =>
route.name === action.routeName && route.activityMode === 'detached',
route.name === action.routeName && route.activityMode === 'detached' && !route.isMarkedForDismissal,
);

if (renderedRouteIndex !== NOT_FOUND_INDEX) {
Expand Down Expand Up @@ -161,12 +161,21 @@ function navigationActionPopHandler(
return state;
}

// Pop operation on not-top screen is forbidden and might crash.
const topAttachedRouteIndex = state.stack.findLastIndex(r => r.activityMode === 'attached');

if (topAttachedRouteIndex > routeIndex) {
console.warn(`[Stack] Can not perform pop action on route: ${action.routeKey} - not a top screen`);
return state;
}

const newStack = [...stack];
// NOTE: This modifies existing state, possibly impacting calculations done before new state is updated.
// Consider doing deep copy of the state here.
// EDIT: not sure really whether this is really a problem or not, since the updates are queued
// and the original state won't be immediatelly affected.
route.activityMode = 'detached';
route.isMarkedForDismissal = true;

return stateWithStack(state, newStack);
}
Expand Down Expand Up @@ -266,6 +275,7 @@ function createRouteFromConfig(
...config,
activityMode,
routeKey: generateRouteKeyForRouteName(config.name),
isMarkedForDismissal: false,
};
}

Expand Down Expand Up @@ -312,7 +322,7 @@ function applyPush(state: StackState, newRoute: StackRoute): StackState {
route => route.activityMode === 'attached',
);

if (lastAttachedIndex === -1) {
if (lastAttachedIndex === NOT_FOUND_INDEX) {
throw new Error(
`[Stack] Invalid stack state: there should be at least one attached route on the stack.`,
);
Expand Down
2 changes: 2 additions & 0 deletions apps/src/tests/single-feature-tests/stack-v5/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import PreventNativeDismissSingleStack from './prevent-native-dismiss-single-sta
import PreventNativeDismissNestedStack from './prevent-native-dismiss-nested-stack';
import AnimationAndroid from './test-animation-android';
import TestStackHeaderModes from './test-stack-header-modes';
import TestStackSimpleNav from './test-stack-simple-nav';

const scenarios = {
PreventNativeDismissSingleStack,
PreventNativeDismissNestedStack,
AnimationAndroid,
TestStackHeaderModes,
TestStackSimpleNav,
};

const StackScenarioGroup: ScenarioGroup<keyof typeof scenarios> = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import type { Scenario } from '@apps/tests/shared/helpers';
import { StyleSheet, Text, View } from 'react-native';
import {
StackContainer,
useStackNavigationContext,
} from '@apps/shared/gamma/containers/stack';
import { CenteredLayoutView } from '@apps/shared/CenteredLayoutView';
import Colors from '@apps/shared/styling/Colors';
import { StackNavigationButtons } from '@apps/tests/shared/components/stack-v5/StackNavigationButtons';

const SCENARIO: Scenario = {
name: 'Simple navigation scenario',
key: 'test-stack-simple-nav',
details:
'Test simple push and pop operations',
platforms: ['android', 'ios'],
AppComponent: App,
};

export default SCENARIO;

export function App() {
return (
<StackSetup />
);
}

function StackSetup() {
return (
<StackContainer
routeConfigs={[
{
name: 'Home',
Component: HomeScreen,
options: {},
},
{
name: 'A',
Component: AScreen,
options: {},
},
{
name: 'B',
Component: BScreen,
options: {},
},
]}
/>
);
}

function HomeScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.BlueLight40 }}>
<RouteInformation routeName="Home" />
<StackNavigationButtons isPopEnabled={false} routeNames={['A', 'B']} />
</CenteredLayoutView>
);
}

function AScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.YellowLight40 }}>
<RouteInformation routeName="A" />
<StackNavigationButtons isPopEnabled={true} routeNames={['A', 'B']} />
</CenteredLayoutView>
);
}

function BScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.GreenLight100 }}>
<RouteInformation routeName="B" />
<StackNavigationButtons isPopEnabled={true} routeNames={['A', 'B']} />
</CenteredLayoutView>
);
}

function RouteInformation(props: { routeName: string }) {
const routeKey = useStackNavigationContext().routeKey;

return (
<View>
<Text style={styles.routeInformation}>Name: {props.routeName}</Text>
<Text style={styles.routeInformation}>Key: {routeKey}</Text>
</View>
);
}

const styles = StyleSheet.create({
routeInformation: {
color: 'black',
fontSize: 20,
fontWeight: 'bold',
},
});
65 changes: 0 additions & 65 deletions ios/gamma/stack/host/RNSStackController.swift

This file was deleted.

8 changes: 1 addition & 7 deletions ios/gamma/stack/host/RNSStackHostComponentView.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
#pragma once

#import "RNSReactBaseView.h"

@class RNSStackController;
@class RNSStackScreenComponentView;
#import "RNSStackScreenComponentView.h"

NS_ASSUME_NONNULL_BEGIN

@interface RNSStackHostComponentView : RNSReactBaseView

@property (nonatomic, nonnull, strong, readonly) RNSStackController *stackController;

- (nonnull NSMutableArray<RNSStackScreenComponentView *> *)reactSubviews;

Comment on lines -12 to -15
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These weren't used outside the implementation or anywhere

@end

#pragma mark - Communication with StackScreen
Expand Down
Loading
Loading