<@U0234N0QYSK> Is there a way to create two destin...
# compose-destinations
d
@Rafael Costa Is there a way to create two destinations for the same screen (with different arguments)?
r
Right now the answer is creating two Composable functions, each annotated with Destination. Then both would just call the same composable.
👍🏼 1
For v2, I have made @Destination repeatable. So you will be able to annotate the same Composable with Destination multiple times. Although in that case, you’ll have to specify the route in the second annotation, otherwise both destinations would use the same and that doesn’t work. This is enforced at compile time.
👍🏼 1
d
Thanks!
👍 1
r
I reserve the right to still revert this change on v2. I’m still debating if it’s worth it. 😜 The additional manual route is arguably almost worse than just making a second Composable. What do you think?
d
The truth is, that in my case, making a second composable might make more sense theoretically, but practically it comes out the same since I'm really using the info in the ViewModel... and whether it's two or one composable, I'd still have to put the
savedStateHandle.navArgs<...>()
in a runCatching and test for the other possibility... 🙈
If there was only a nice way to pass these to the view model...
r
You can have a sealed interface nav args annotated with @Serializable
Then your destination will be able to be navigated to with different arguments, the children of the sealed type.
And in the ViewModel you can use the navArgs method that will give you the sealed type, and you can cleanly deal with the multiple ways your destination gets navigated to
d
Wow, That could be a great idea! I'll try it out! I guess I'd loose the Destinations' invoke generation for the arg class's properties, I'd have to instantiate one of the child classes to pass it to navigate.
r
Yes the sealed type is one navigation argument, not the arguments delegate class
d
And I'd still need two composables, one for each Destination
r
So yes, to navigate you have to instantiate this type.
Hmm, I don’t think so. You would have one destination only
But that destination happens to accept one argument which can be of multiple types (as long as they extend the sealed type)
d
And in vanilla nav, I'd have to register two
composable { }
blocks
I wonder if the automatic nav would know to do that?
r
Not sure I’m following.. gotta go, be back later. Let me know how it goes
d
Nope
[ksp] com.ramcosta.composedestinations.codegen.commons.IllegalDestinationsSetup: There was an issue with 'navArgsDelegate' of composable 'DetailsScreen': make sure it is a class with a primary constructor.
r
Did you put the sealed type as a field of the delegate class?
Like I said, this will be a navigation argument, not the delegate itself
d
Yes
r
Can you show me the code here?
d
Oh, so two composables with two destinations and one navArgs (on the sealed interface) in the VM?
I can't really post it here... if need be I can maybe make an example
r
Just one Composable and one Destination, is my suggestion 🙂
One question: when coming from the deep link. Is the deep link created inside the app? Or is it external? In other words: do you control how the deep link URI is built?
d
Copy code
@Serializable
sealed interface FooBase {
   val id: SomeId
}

@Serializable
data class FooFromLinkArgs(
   val stringId: String
) {
  override id get() = ...
}

@Serializable
data class Foo(
  override val id: SomeId,
  val name: String,
...
)

@Destination(
   navArgsDelegate = FooBase::class
...
gives me the above error
Through a share button in the app, which makes an url.
r
Ok. So you’ll want to make FooBase not the delegate but a field inside the delegate. Think about the delegate just as a class we get nav arguments from. One field = one argument.
Copy code
data class YourScreenArgs(
    val arg: FooBase
)

@Destination(
    navArgsDelegate = YourScreenArgs::class
)
When navigating to this destination, you’ll be able to do
YourScreenDestination(Foo(id=…, name=…))
You might want to create a CustomSerializer to specify how you want the routes to be constructed for this type
FooBase
. Otherwise navigation lib won’t be able to automatically parse your URI format back into this class.
Obviously, this is a bit more work compared to having multiple Destinations. It’s up to you if it’s worth it
Using the runCatching is probably completely fine 😜
d
Yeah, but that's where it might have been nice to have navArgsOrNull to avoid the exception...?
r
Adding that API will encourage wrong approaches. I’d rather leave that to users if they really feel like it is ok on their specific use case
Do you have any practical issue with the runCatching?
d
Well, it's in my mind for exceptional cases, not something that's supposed to be "normal" usage. But what kind of wrong approaches would it encourage?