Skip to content

Commit 1ea3373

Browse files
committed
docs: updates readme with result navigation
1 parent be1eb6e commit 1ea3373

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

README.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Nibel supports both **single-module** and **multi-module** navigation out-of-the
1515
- [Installation](#installation)
1616
- [Basic usage](#basic-usage)
1717
- [Multi-module navigation](#multi-module-navigation)
18+
- [Result-based navigation](#result-based-navigation)
1819
- [Sample app](#sample-app)
1920

2021
## Materials
@@ -244,6 +245,177 @@ val args = ThirdScreenArgs(...)
244245
navigator.navigateTo(ThirdScreenDestination(args))
245246
```
246247

248+
## Result-based navigation
249+
250+
Nibel supports result-based navigation that allows screens to return typed data to the previous screen. This feature integrates with Android's Activity Result API pattern while maintaining Nibel's type-safe approach.
251+
252+
### Declaring a result screen
253+
254+
To create a screen that can return a result, specify the `result` parameter in your annotation with a `Parcelable` result type:
255+
256+
```kotlin
257+
@Parcelize
258+
data class PhotoResult(
259+
val photoUrl: String,
260+
val photoName: String,
261+
val timestamp: Long = System.currentTimeMillis()
262+
) : Parcelable
263+
264+
@UiEntry(
265+
type = ImplementationType.Composable,
266+
args = PhotoArgs::class,
267+
result = PhotoResult::class // This screen can return PhotoResult
268+
)
269+
@Composable
270+
fun PhotoPickerScreen(
271+
args: PhotoArgs,
272+
navigator: NavigationController
273+
) {
274+
// Your screen content
275+
Button(onClick = {
276+
val selectedPhoto = PhotoResult("url", "name")
277+
navigator.setResultAndNavigateBack(selectedPhoto)
278+
}) {
279+
Text("Select Photo")
280+
}
281+
282+
// Or cancel without result
283+
Button(onClick = {
284+
navigator.cancelResultAndNavigateBack()
285+
}) {
286+
Text("Cancel")
287+
}
288+
}
289+
```
290+
291+
When you build the code, the generated entry class will implement both `ComposableEntry` and `ResultEntry<PhotoResult>` interfaces.
292+
293+
### Navigating for a result
294+
295+
To navigate to a result-returning screen and receive the result:
296+
297+
```kotlin
298+
@UiEntry(type = ImplementationType.Composable)
299+
@Composable
300+
fun HomeScreen(navigator: NavigationController) {
301+
var selectedPhoto by remember { mutableStateOf<PhotoResult?>(null) }
302+
303+
Button(onClick = {
304+
navigator.navigateForResult(
305+
entry = PhotoPickerScreenEntry.newInstance(PhotoArgs()),
306+
callback = { result: PhotoResult? ->
307+
// Handle the result - null if cancelled
308+
selectedPhoto = result
309+
}
310+
)
311+
}) {
312+
Text("Pick Photo")
313+
}
314+
315+
// Display result
316+
selectedPhoto?.let { photo ->
317+
Text("Selected: ${photo.photoName}")
318+
}
319+
}
320+
```
321+
322+
### Multi-module result navigation
323+
324+
For cross-module result navigation, use external destinations with the `result` parameter:
325+
326+
```kotlin
327+
// In navigation module
328+
@Parcelize
329+
data class UserSelectionResult(
330+
val userId: String,
331+
val userName: String
332+
) : Parcelable
333+
334+
data class UserPickerDestination(
335+
override val args: UserPickerArgs
336+
) : DestinationWithArgs<UserPickerArgs>
337+
```
338+
339+
```kotlin
340+
// In feature module
341+
@UiExternalEntry(
342+
type = ImplementationType.Composable,
343+
destination = UserPickerDestination::class,
344+
result = UserSelectionResult::class
345+
)
346+
@Composable
347+
fun UserPickerScreen(
348+
args: UserPickerArgs,
349+
navigator: NavigationController
350+
) {
351+
// Implementation
352+
Button(onClick = {
353+
navigator.setResultAndNavigateBack(
354+
UserSelectionResult("123", "John Doe")
355+
)
356+
}) {
357+
Text("Select User")
358+
}
359+
}
360+
```
361+
362+
```kotlin
363+
// Navigate from another module
364+
navigator.navigateForResult(
365+
destination = UserPickerDestination(UserPickerArgs()),
366+
callback = { result: UserSelectionResult? ->
367+
result?.let { user ->
368+
// Use the selected user
369+
println("Selected user: ${user.userName}")
370+
}
371+
}
372+
)
373+
```
374+
375+
### Type safety and error handling
376+
377+
Nibel ensures compile-time type safety for result navigation:
378+
379+
- **Result types** must be `Parcelable` data classes or objects
380+
- **Factory methods** return `ResultEntry<R>` instead of generic entries
381+
- **Callbacks** are strongly typed to the expected result type
382+
- **Runtime errors** occur if destinations don't implement `ResultEntry`
383+
384+
### Edge cases handled
385+
386+
The result navigation system handles several important scenarios:
387+
388+
- **Configuration changes**: Results survive device rotation and process death
389+
- **Multiple requests**: Each navigation request gets a unique callback key
390+
- **Lifecycle management**: Callbacks are automatically cleaned up
391+
- **Cancellation**: Users can cancel without providing a result (`null` callback)
392+
393+
### Best practices
394+
395+
- **Keep results simple**: Use lightweight `Parcelable` data classes
396+
- **Handle null results**: Always check if the result is null (cancelled)
397+
- **Cleanup resources**: The framework handles callback lifecycle automatically
398+
- **Test thoroughly**: Verify both success and cancellation paths
399+
400+
### Migration from existing patterns
401+
402+
If you're migrating from Fragment result APIs or other patterns:
403+
404+
```kotlin
405+
// Before (Fragment)
406+
setFragmentResultListener("photo_key") { _, bundle ->
407+
val result = bundle.getParcelable<PhotoResult>("photo_data")
408+
// handle result
409+
}
410+
411+
// After (Nibel)
412+
navigator.navigateForResult(
413+
entry = PhotoPickerScreenEntry.newInstance(args)
414+
) { result: PhotoResult? ->
415+
// handle result - automatically typed and null-safe
416+
}
417+
```
418+
247419
## Sample app
248420

249421
Check out a [sample app](sample) for demonstration of various scenarios of using Nibel in practice.

0 commit comments

Comments
 (0)