Skip to content

refactor: example app - #5053

Open
michalfedyna wants to merge 7 commits into
callstack:mainfrom
michalfedyna:refactor/example-app
Open

refactor: example app#5053
michalfedyna wants to merge 7 commits into
callstack:mainfrom
michalfedyna:refactor/example-app

Conversation

@michalfedyna

@michalfedyna michalfedyna commented Aug 17, 2026

Copy link
Copy Markdown

Motivation

PR improves example app. It adds:

  • Samples screen
  • 8 small and focused samples
  • Improved UI for preferences
  • Search for example usage list
Screen iOS Android
Samples list ios-01 android-01
Preferences ios-02 android-02
Examples list ios-03 android-03
Search ios-04 android-04
Sign up sample ios-05 android-05
Contacts sample ios-06 android-06
Article sample ios-07 android-07
Settings sample ios-08 android-08
Player sample ios-09 android-09
Orders sample ios-10 android-10
Help center sample ios-11 android-11
Workspace sample ios-12 android-12

Related issue

#4992

Test plan

yarn lint, yarn typecheck, yarn test and a visual check of provided screenshots

@MikitasK MikitasK left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

looks awesome! good job 👍
just a few points to address before merge:

Comment on lines +121 to +126
const resetPreferences = React.useCallback(async () => {
setShouldUseDynamicTheme(true);
setIsDarkMode(false);
setCustomFont(false);
setRippleEffectEnabled(true);
setPreferencesVisible(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

what about resetting RTL here as well? currently Reset clears stored preferences but leaves rtl unchanged, so the app can remain in RTL after resetting
I18nManager.forceRTL persists forced direction across restarts

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

That one was intentional, RTL in the app requires full app reload. I wanted to keep reset more responsive. That's why no RTL reset. I would keep it that way.

Comment thread example/src/SamplesList.tsx Outdated
keyExtractor={({ id }) => id}
contentContainerStyle={[
styles.content,
{ paddingBottom: safeArea.bottom + 16 },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

could we also include left & right safe-area insets in horizontal padding?
it's necessary to render list correctly in landscape mode (RN navigation docs)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed

@MikitasK MikitasK left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM 👍

Comment thread example/src/SamplesList.tsx Outdated

type SampleId = keyof typeof samples;

const data = (Object.keys(samples) as SampleId[]).map((id) => ({

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@typescript-eslint/no-unsafe-type-assertion is an error across example/ now, so this cast plus OrdersSample.tsx:95 and RootNavigator.tsx:22,68,92 all fail yarn lint after a rebase. Object.entries won't work here - it widens id to string and breaks navigate(item.id). main used eslint-disable where the cast is load-bearing.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed

Comment thread example/src/RootNavigator.tsx Outdated
Comment on lines +30 to +42
const searchAction = (
<Appbar.Action
icon="folder-search"
onPress={() => navigation.navigate('ExampleList')}
/>
);

return (
<Appbar.Header elevated>
{back ? (
<Appbar.BackAction onPress={() => navigation.goBack()} />
) : (
<Appbar.Action
icon="menu"
isLeading
onPress={() => drawerNavigation.openDrawer()}
/>
)}
<Appbar.Header>
{back ? backAction : isIOS ? searchAction : null}
<Appbar.Content title={options.title || route.name} />
{!isIOS && !back && searchAction}
<Appbar.Action icon="cog" onPress={togglePreferences} />

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Neither of these actions has an aria-label, and with the drawer gone they're the only way to reach the examples list and preferences. You labelled the Searchbar equivalents one file over in ExampleListHeader.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added accessibilityLabel

Comment thread example/src/RootNavigator.tsx Outdated
Comment on lines +30 to +35
const searchAction = (
<Appbar.Action
icon="folder-search"
onPress={() => navigation.navigate('ExampleList')}
/>
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Add isLeading here - on iOS this renders in the leading slot, and AppbarAction uses the prop to pick onSurface over onSurfaceVariant. main passed it on the leading menu action.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed, my idea was to have to Actions to the right of the Content on Android. Now it's back to Examples navigtiaon to the left on both platforms.

Comment thread example/src/Samples/WorkspaceSample.tsx Outdated
Comment on lines +105 to +107
React.useLayoutEffect(() => {
navigation.setOptions({ headerShown: false });
}, [navigation]);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Declare headerShown: false in the screen config instead of hiding it in a layout effect - as written, the stack header mounts and unmounts on the first frame. Add an optional options to SampleConfig and spread it in RootNavigator.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed, moved it into Config object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants