I have a dialog composable for which I created a s...
# compose
p
I have a dialog composable for which I created a state holder, because it has some internal variables and logic which is better to manage and group it outside the composable. Now, that composable can do some more extra logic for example calling share intents for opening the browser, seding an email etc... That logic will only be executed by this complex composable which requires a state holder... should that logic be written in the state holder and called like this:
stateHolder.doExtraLogic()
?
We do that with viewmodels (
vm.doExtraLogic()
), but I'm not sure if that is a good practice also with composable state holders. I want this composable to be very portable. I mean that moving it to another project is simply to copy and paste the .kt file and using it, so will be a benefit to have that extra logic functions in the state holder. Is it a good practice to do this?
z
It's common to have extra logic on more complex state holders. I would think about whether you consider your state holder to be part of the view layer or presentation layer (e.g. if it's remembered inside a composable, it's view layer, if it's created and owned by a view model somewhere else, then not). The bigger question is whether anything in the view layer should be responsible for sending intents out to the OS.
The idea is that you should be able to write tests for your views and mock out the calls that do things like send intents.
p
now I'm using a Util singleton for that. It haves some logic functions that are bing used in various parts of the app: • sendEmail • openGooglePlayLink • etc and I'm doing Util.sendEmail() etc...
probably will be more clean to inject that Util class with Koin, but for this simple functions I did using that singleton directly, seems to be simpler
a
I would pass those functions into the Composable as parameters, something like this:
Copy code
@Composable
fun Dialog(
    sendEmail: (String) -> Boolean,
    shareStuff: () -> Unit,
    ...
): {
    ...
    Button(onClick = { sendEmail(text) }, ...)
    ...
}
That way you would be able to reuse that Composable more easily, and for tests, specify those lambdas as empty lambdas, with maybe a Boolean set to true. Also, this enables `@Preview`s of the Composable, just pass empty lambdas in there.
z
Yea you need to inject/pass them into something at some point if you want your view code to be testable. Whether that’s as separate functions or as a single view model/state holder thing is up to you, but hard-coding them is gonna make testing much harder for yourself than it needs to be.