https://kotlinlang.org logo
Title
e

Egor K.

11/29/2020, 10:28 AM
Hi! Can I ask a quastion?  How I can correctly display a dialog using Label without using a State? For instance. I check some condition in Executor in SimpleBootstrapper and according to result of the condition I decide to show user some dialog.
a

Arkadii Ivanov

11/29/2020, 10:35 AM
Hi! Are you asking how to emit labels from executor or how to receive labels in a view?
e

Egor K.

11/29/2020, 10:36 AM
second one) How to receive it in view
without using state. Just some dialogs, toasts and so on
a

Arkadii Ivanov

11/29/2020, 10:48 AM
Well, probably I need to describe this in the documentation. For now you can take the following general advice and adjust it for your needs. Define methods in view:
interface TodoListView : MviView<Model, Event> {
    fun showError(text: String)
    // Omitted code
}
Bind labels to view:
override fun onViewCreated(todoListView: TodoListView, viewLifecycle: Lifecycle) {
        bind(viewLifecycle, BinderLifecycleMode.START_STOP) {
            todoListStore.labels bindTo { todoListView.handleLabel(it) }
        }
    }

    private fun TodoListView.handleLabel(label: TodoListStore.Label): Unit =
        when (label) {
            is TodoListStore.Label.LoadingError -> showError(text = "Loading failed")
        }
Also you may prefer a separate sealed class in the view: Action. In this case you can write a mapper from Label to Action. Then you will just handle all Actions in the view. Both examples are exhaustive, so if you add one more Label the code won't compile unless you cover the new case.
e

Egor K.

11/29/2020, 11:06 AM
very detailed, thank you. But how do right if I have separate class TodoListBinder? I need to pass context of my “TodoListFragment” into the onViewCreated() and next in handleLabel() ? Like this (In separate TodoListBinder):
fun onViewCreated(todoListView: TodoListView, todoListfragment: TodoListFragment) {
        bind(viewLifecycle, BinderLifecycleMode.START_STOP) {
            todoListStore.labels bindTo { todoListView.handleLabel(it, todoListfragment) }
        }
}

private fun handleLabel(label: TodoListStore.Label, fragment: TodoListFragment) {
    when (label) {
        is TodoListStore.Label.LoadingError -> fragment.showDialog()
    }
In Fragment:
fun showDialog() {
	// some dialog?
}
a

Arkadii Ivanov

11/29/2020, 11:13 AM
Yes, you will need to pass the
Context
into
onViewCreated
.
private class ViewLabelHandler(
    private val view: TodoListView,
    private val context: Context
) : (TodoListStore.Label) -> Unit {
    override fun invoke(label: TodoListStore.Label) =
        when (label) {
            is TodoListStore.Label.LoadingError -> view.showError(text = context.getString(R.string.error_msg))
        }
}
override fun onViewCreated(todoListView: TodoListView, viewLifecycle: Lifecycle, context: Context) {
        bind(viewLifecycle, BinderLifecycleMode.START_STOP) {
            todoListStore.labels bindTo ViewLabelHandler(todoListView, context)
        }
    }
You may also want to improve unit testing by abstracting the
Context
with an interface:
interface Resources {
    val errorMsg: String
}
e

Egor K.

11/29/2020, 11:26 AM
thx a lot!) 🙏
👍 1