Last active
March 10, 2025 22:48
-
-
Save vRallev/7885592b09dce14d891cd85089475130 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Used to process events returned by the UI layer in the scope that runs our presenters, which | |
| * usually is `PresenterCoroutineScope`. Without this wrapper events would be processed on the | |
| * main thread and could potentially block the UI or cause lag. | |
| * | |
| * Furthermore, the returned lambda is remembered as state within the composable, which allows | |
| * to make [BaseModel] implementations data classes. Without remembering every [BaseModel] instance | |
| * would not equal another instance, since different lambda instances are never equal to each | |
| * other. | |
| * | |
| * A common pattern looks as follows: | |
| * ``` | |
| * @Inject | |
| * class LoginPresenter(..) : MoleculePresenter<Unit, Model> { | |
| * | |
| * @Composable | |
| * override fun present(input: Unit): Model { | |
| * // ... | |
| * return Model( | |
| * name = .. | |
| * onEvent = onEvent { | |
| * when (it) { | |
| * is Event.OnNameClick -> ... | |
| * is Event.Login -> ... | |
| * } | |
| * } | |
| * ) | |
| * } | |
| * | |
| * data class Model( | |
| * val name: String, | |
| * val onEvent: (Event) -> Unit | |
| * ) : BaseModel | |
| * | |
| * sealed interface Event { | |
| * object OnNameClick : Event | |
| * class Login(val userName: String) : Event | |
| * } | |
| * } | |
| * ``` | |
| */ | |
| @Suppress("unused", "UnusedReceiverParameter") | |
| @Composable | |
| fun <EventT : Any> MoleculePresenter<*, *>.onEvent( | |
| handler: @DisallowComposableCalls suspend (EventT) -> Unit, | |
| ): (EventT) -> Unit { | |
| // This function creates, remembers and returns a separate lambda from the the `handler` | |
| // argument. The newly created lambda forwards events to the last `handler` lambda this | |
| // function was called with. | |
| val scope = rememberCoroutineScope() | |
| val lambdaReference = remember { AtomicRefWrapper(handler) } | |
| lambdaReference.value = handler | |
| DisposableEffect(Unit) { | |
| onDispose { | |
| // Release the lambda | |
| lambdaReference.value = null | |
| } | |
| } | |
| return remember { | |
| { event -> | |
| // Launch a coroutine in this scope so that we process the event on the | |
| // PresenterCoroutineScope. | |
| scope.launch { | |
| lambdaReference.value?.invoke(event) | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment