My business layer doesn't include Compose, but I'd...
# compose
d
My business layer doesn't include Compose, but I'd like a method in it to suspend while waiting for the user to respond to a dialog. Showing the dialog uses
@Composable
, which doesn't exist in the business layer. Any patterns on how to structure that? I'll put what I have so far in the thread.
Business module
Copy code
suspend fun installFromUnknownSource(
        promptUserToReplaceExistingFolder: suspend (modInfo: ModInfo) -> Boolean
    )
Dialog
Copy code
@Composable
suspend fun DuplicateModAlertDialog(modInfo: ModInfo): Boolean {
    return suspendCoroutine { cont ->
      // stuff
      cont.resume(...)
   }
}
Usage (the part that doesn't compile due to lacking Composable)
Copy code
installFromUnknownSource(
    promptUserToReplaceExistingFolder = { modInfo ->
        DuplicateModAlertDialog(modInfo)
    })
can't tell if i'm being dumb or trying to do something that shouldn't be done (not mutually exclusive)
a
You might be interested in how
SnackbarHostState
publishes data for composables to display. It uses a suspend function to show a notification and get a return value for whether the snackbar was dismissed or if the user pressed a button for that message https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/src/commonMain/kotlin/androidx/compose/material/SnackbarHost.kt;l=60?q=SnackbarHostState&sq=
d
Very interesting, thank you! Took me a bit to get a chance to look. So it essentially decouples the Snackbar from the listener. Calling
showSnackbar
creates a new (observable) state that contains a continuation, then suspends. The Snackbar is then created/shown in response to the newly created state and invokes the continuation when the user interacts with it.
Having that "singleton" state variable is the decoupling that's needed to allow the communication between the layer without Composable and the layer with
a
right. And since it's state, it can be presented in 0-N places simultaneously if the situation calls for it
nothing is "consumed" unless it's acted on, and it doesn't particularly matter which presentation is acted on
and if the caller of
showSnackbar
no longer cares, it can cancel its call and it will be removed from the queue; if it was currently being shown it will move on to the next one
d
canceling the suspending call with invoke
Copy code
finally {
            currentSnackbarData = null
        }
?
and from there the next suspending call, which was waiting for the Mutex, will start, creating a new toast
a
Yep