ResultDestination with sealed interface as result acting unpredictably
Closed this issue · 5 comments
I have the following destination/result setup:
@Serializable
data class AddItem(
val listUrlLocator: ListUrlLocator,
) : ListDestinations, ResultDestination<AddItem.Created> {
@Serializable
data object Created
}
@Serializable
data class EditItem(
val listUrlLocator: ListUrlLocator,
val itemUrlLocator: ItemUrlLocator,
) : ListDestinations, ResultDestination<EditItem.Result> {
sealed interface Result {
@Serializable
data class Updated(
val itemUrlLocator: ItemUrlLocator,
) : Result
@Serializable
data object Deleted : Result
@Serializable
data class Archived(val itemUrlLocator: ItemUrlLocator) : Result
}
}
and the effect side:
ComposableResultEffect<ListDestinations.AddItem.Created>(
navController = navController,
block = {
dispatch(ListDetailEvents.ItemAdded)
},
)
ComposableResultEffect<ListDestinations.EditItem.Result>(
navController = navController,
block = {
Timber.d("$it")
when (it) {
is ListDestinations.EditItem.Result.Updated -> {
dispatch(ListDetailEvents.ItemUpdated(it.itemUrlLocator))
}
is ListDestinations.EditItem.Result.Deleted -> {
dispatch(ListDetailEvents.ItemDeleted)
}
is ListDestinations.EditItem.Result.Archived -> {
dispatch(ListDetailEvents.ItemArchived(it.itemUrlLocator))
}
}
},
)
Graph setup:
addItem(
onItemCreated = { listUrlLocator ->
navController.setResult(ListDestinations.AddItem.Created)
navController.popBackStack()
},
)
editItem(
onItemEdited = {
navController.setResult(ListDestinations.EditItem.Result.Updated(it))
navController.popBackStack()
},
onItemDeleted = {
navController.setResult(ListDestinations.EditItem.Result.Deleted)
navController.popBackStack()
},
onItemArchived = { listUrlLocator: ListUrlLocator, itemUrlLocator: ItemUrlLocator ->
navController.setResult(ListDestinations.EditItem.Result.Archived(itemUrlLocator))
navController.popBackStack()
},
)
The effect for ListDestinations.AddItem.Created
fires without issue every time. The effect for ListDestinations.EditItem.Result
sometimes fires, often times not. Unfortunately, attaching the debugger seems to make the effect consistently fire 😅. Not sure whats happening here.
Also just to confirm: I switched to using a non-sealed interface and just testing with the Updated
result and its working as intended.
Workaround for now seems to be:
@Serializable
data class EditItem(
val listUrlLocator: ListUrlLocator,
val itemUrlLocator: ItemUrlLocator,
) : ListDestinations, ResultDestination<EditItem.Result> {
@Serializable
data class Result(val operation: Operation) {
@Serializable
sealed class Operation {
@Serializable
data class Updated(val itemUrlLocator: ItemUrlLocator) : Operation()
@Serializable
data object Deleted : Operation()
@Serializable
data class Archived(val itemUrlLocator: ItemUrlLocator) : Operation()
}
}
}
That's the problem of KotlinX.Serialization and its limitation on polymorphism. There are two options:
A:
navController.setResult<ListDestinations.AddItem.Result>(ListDestinations.AddItem.Created)
or B:
you found it - #133 (comment) - which is probably the better way as it is less error-prone.
AFAIK: there are no solutions, I spent hours finding something.
maybe it would be worthwhile to add an example to the result sharing part of the readme? either way this can be closed :)