Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions .changeset/small-clouds-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@callstack/brownfield-navigation': minor
'@callstack/brownfield-cli': minor
---

feat: add support for callback and promise to brownfield navigation
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.os.Bundle
import android.widget.Toast
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
Expand Down Expand Up @@ -37,6 +38,8 @@ import com.callstack.nativebrownfieldnavigation.BrownfieldNavigationManager
import com.callstack.nativebrownfieldnavigation.UserType
import com.callstack.reactnativebrownfield.ReactNativeFragment
import com.callstack.reactnativebrownfield.constants.ReactNativeFragmentArgNames
import com.facebook.react.bridge.Callback
import com.facebook.react.bridge.Promise

class MainActivity : AppCompatActivity(), BrownfieldNavigationDelegate {
override fun onConfigurationChanged(newConfig: Configuration) {
Expand Down Expand Up @@ -108,6 +111,27 @@ class MainActivity : AppCompatActivity(), BrownfieldNavigationDelegate {
)
)
}

override fun requestNativeConfirmation(title: String, promise: Promise) {
runOnUiThread {
AlertDialog.Builder(this)
.setTitle(title)
.setPositiveButton("OK") { _, _ -> promise.resolve(true) }
.setNegativeButton("Cancel") { _, _ -> promise.resolve(false) }
.setCancelable(false)
.show()
}
}

override fun showNativeBanner(message: String, onDismiss: Callback) {
runOnUiThread {
AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("Dismiss") { _, _ -> onDismiss.invoke() }
.setCancelable(false)
.show()
}
}
}

@Composable
Expand All @@ -117,11 +141,11 @@ private fun MainScreen(modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally // center top bar content
) {
Spacer(modifier = Modifier.height(3.dp))
Spacer(modifier = Modifier.height(3.dp))

GreetingCard(
name = ReactNativeConstants.APP_NAME,
)
GreetingCard(
name = ReactNativeConstants.APP_NAME,
)

PostMessageCard()

Expand Down
44 changes: 44 additions & 0 deletions apps/AppleApp/Brownfield Apple App/BrownfieldAppleApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,50 @@ public class RNNavigationDelegate: BrownfieldNavigationDelegate {
present(ReferralsScreen(userId: userId))
}

public func requestNativeConfirmation(
_ title: String,
resolve: @escaping (Any?) -> Void,
reject: @escaping (String?, String?, (any Error)?) -> Void
) {
DispatchQueue.main.async {
guard let topController = UIApplication.shared.topMostViewController() else {
reject(
"no_view_controller",
"Could not find a view controller to present the confirmation.",
nil
)
return
}

let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
resolve(true)
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
resolve(false)
})
topController.present(alert, animated: true)
}
}

public func showNativeBanner(
_ message: String,
onDismiss onDismiss: @escaping ([Any]?) -> Void
) {
DispatchQueue.main.async {
guard let topController = UIApplication.shared.topMostViewController() else {
onDismiss([])
return
}

let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: .default) { _ in
onDismiss([])
})
topController.present(alert, animated: true)
}
}

private func present<Content: View>(_ view: Content) {
DispatchQueue.main.async {
let hostingController = UIHostingController(rootView: view)
Expand Down
52 changes: 37 additions & 15 deletions apps/ExpoApp55/RNApp.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import { SafeAreaView } from 'react-native-safe-area-context';
import { Button, StyleSheet, Text, View } from 'react-native';
import { useEffect } from 'react';
import BrownfieldNavigation from '@callstack/brownfield-navigation';
import {
syncBrownfieldE2EModeFromRootProps,
type BrownfieldRootProps,
} from '@callstack/brownfield-example-shared-tests/runtime';
import { checkAndFetchUpdate } from './src/utils/expo-rn-updates';

import Counter from './src/components/counter';

type RNAppProps = BrownfieldRootProps;
type RNAppProps = {
nativeOsVersionLabel?: string;
};

export default function RNApp({
nativeOsVersionLabel,
brownfieldE2E,
}: RNAppProps) {
useEffect(() => {
syncBrownfieldE2EModeFromRootProps(brownfieldE2E);
return () => syncBrownfieldE2EModeFromRootProps(undefined);
}, [brownfieldE2E]);
export default function RNApp({ nativeOsVersionLabel }: RNAppProps) {
const requestNativeConfirmation = async () => {
try {
await BrownfieldNavigation.requestNativeConfirmation(
'Are you sure you want to continue?'
);
} catch (error) {
console.error(`Native confirmation failed: ${error}`, 'native');
}
};

const showNativeBanner = () => {
BrownfieldNavigation.showNativeBanner('Hello from React Native!', () => {
console.log('Native banner dismissed');
});
};

return (
<SafeAreaView style={styles.container}>
Expand All @@ -39,12 +44,29 @@ export default function RNApp({

<Button
title="Navigate to Settings"
onPress={() => BrownfieldNavigation.navigateToSettings()}
onPress={() =>
BrownfieldNavigation.navigateToSettings({
id: 'expo-user-123',
name: 'Expo User',
flags: ['expo56'],
ids: ['expo-user-123'],
})
}
/>
<Button
title="Navigate to Referrals"
onPress={() => BrownfieldNavigation.navigateToReferrals('123')}
/>
<Button
onPress={requestNativeConfirmation}
title="Request native confirmation"
/>

<Button
onPress={showNativeBanner}
title="Show native banner"
/>

<Button title="Fetch Update" onPress={checkAndFetchUpdate} />
</View>
</SafeAreaView>
Expand Down
10 changes: 10 additions & 0 deletions apps/ExpoApp55/brownfield.navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,14 @@ export interface BrownfieldNavigationSpec {
* @param userId - The user's unique identifier
*/
navigateToReferrals(userId: string): void;

/**
* Ask the native host to confirm an action. Resolves with the user's choice.
*/
requestNativeConfirmation(title: string): Promise<boolean>;

/**
* Show a native banner. The native host calls onDismiss when the banner is dismissed.
*/
showNativeBanner(message: string, onDismiss: () => void): void;
}
26 changes: 26 additions & 0 deletions apps/ExpoApp56/RNApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ type RNAppProps = {
};

export default function RNApp({ nativeOsVersionLabel }: RNAppProps) {
const requestNativeConfirmation = async () => {
try {
await BrownfieldNavigation.requestNativeConfirmation(
'Are you sure you want to continue?'
);
} catch (error) {
console.error(`Native confirmation failed: ${error}`, 'native');
}
};

const showNativeBanner = () => {
BrownfieldNavigation.showNativeBanner('Hello from React Native!', () => {
console.log('Native banner dismissed');
});
};

return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>Expo React Native Brownfield</Text>
Expand Down Expand Up @@ -41,6 +57,16 @@ export default function RNApp({ nativeOsVersionLabel }: RNAppProps) {
title="Navigate to Referrals"
onPress={() => BrownfieldNavigation.navigateToReferrals('123')}
/>
<Button
onPress={requestNativeConfirmation}
title="Request native confirmation"
/>

<Button
onPress={showNativeBanner}
title="Show native banner"
/>

<Button title="Fetch Update" onPress={checkAndFetchUpdate} />
</View>
</SafeAreaView>
Expand Down
10 changes: 10 additions & 0 deletions apps/ExpoApp56/brownfield.navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,14 @@ export interface BrownfieldNavigationSpec {
* @param userId - The user's unique identifier
*/
navigateToReferrals(userId: string): void;

/**
* Ask the native host to confirm an action. Resolves with the user's choice.
*/
requestNativeConfirmation(title: string): Promise<boolean>;

/**
* Show a native banner. The native host calls onDismiss when the banner is dismissed.
*/
showNativeBanner(message: string, onDismiss: () => void): void;
}
10 changes: 10 additions & 0 deletions apps/RNApp/brownfield.navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,14 @@ export interface BrownfieldNavigationSpec {
* @param userId - The user's unique identifier
*/
navigateToReferrals(userId: string): void;

/**
* Ask the native host to confirm an action. Resolves with the user's choice.
*/
requestNativeConfirmation(title: string): Promise<boolean>;

/**
* Show a native banner. The native host calls onDismiss when the banner is dismissed.
*/
showNativeBanner(message: string, onDismiss: () => void): void;
}
18 changes: 9 additions & 9 deletions apps/RNApp/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- BrownfieldNavigation (3.13.2):
- BrownfieldNavigation (4.0.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
Expand All @@ -21,7 +21,7 @@ PODS:
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- Brownie (3.13.2):
- Brownie (4.0.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
Expand Down Expand Up @@ -1803,7 +1803,7 @@ PODS:
- ReactNativeDependencies
- ReactAppDependencyProvider (0.85.0):
- ReactCodegen
- ReactBrownfield (3.13.2):
- ReactBrownfield (4.0.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
Expand Down Expand Up @@ -2174,10 +2174,10 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"

SPEC CHECKSUMS:
BrownfieldNavigation: 8146f96f66306e94c36d7e2f8f1d67a686a25051
Brownie: d670f2a9208c9aff2f99dd6b466877b2011a229f
BrownfieldNavigation: 0a734000e2fe9210273593910edb6aa0ec582fe2
Brownie: 5264215957fd935ea3bb1744d3c88ad9ab148b2e
FBLazyVector: c00c20551d40126351a6783c47ce75f5b374851b
hermes-engine: 05cd56ea9fb0e7f74219230acf32a6f31d86b3c8
hermes-engine: 133acc7688f66a6db232bff7de874c7129b01e1e
RCTDeprecation: 3bb167081b134461cfeb875ff7ae1945f8635257
RCTRequired: 74839f55d5058a133a0bc4569b0afec750957f64
RCTSwiftUI: 87a316382f3eab4dd13d2a0d0fd2adcce917361a
Expand All @@ -2186,7 +2186,7 @@ SPEC CHECKSUMS:
React: 1b1536b9099195944034e65b1830f463caaa8390
React-callinvoker: 6dff6d17d1d6cc8fdf85468a649bafed473c65f5
React-Core: 00faa4d038298089a1d5a5b21dde8660c4f0820d
React-Core-prebuilt: 6cbf1ad263d444d15cebe62c2bf64507712f4653
React-Core-prebuilt: 46fad9d85d53619a69cbd91fa8703ce085c73c29
React-CoreModules: a17807f849bfd86045b0b9a75ec8c19373b482f6
React-cxxreact: c7b53ace5827be54048288bce5c55f337c41e95f
React-debug: 1f20c32441d0090cf67e6b966895f4ccd929d84c
Expand Down Expand Up @@ -2246,10 +2246,10 @@ SPEC CHECKSUMS:
React-utils: f747ea9fa3f4b293533ec4ef7976d1e37f004ef8
React-webperformancenativemodule: cf676ba871cc4b6ae175f75b92e8c689960c4141
ReactAppDependencyProvider: 5787b37b8e2e51dfeab697ec031cc7c4080dcea2
ReactBrownfield: a4c75a93524a50336ef486b799a73b95fe039fa5
ReactBrownfield: 0c4d52841657d406cd55a673bf17ef7ead244e7a
ReactCodegen: d9ba64702c846111b3eeb157ea2e15aa5bb2ea55
ReactCommon: fe2a3af8975e63efa60f95fca8c34dc85deee360
ReactNativeDependencies: 3112b1660fc53efb9f3670b66f4384aa879c8090
ReactNativeDependencies: bf5d16ce034aaabeeb0f7102f7db739529a3b910
RNScreens: 85c533985720c563272c6f6dd19e1278dfd0f5d4
Yoga: ce94692032f0a4e4ca7ed9e52a284cb208fcdbbb

Expand Down
Loading
Loading