https://kotlinlang.org logo
Join SlackCommunities
Powered by
# mvikotlin
  • p

    Pragnesh Meniya

    08/21/2023, 5:02 AM
    I want hit progress on every api calling. Progrss bar is common created the Top of jetpack compose-view. I am using the MVIkotlin & decompose libs in my project. How to achieve above thing? Trigger Progress bar BaseStoreFactory to ContentView
    a
    • 2
    • 5
  • s

    Seth Madison

    09/06/2023, 5:36 AM
    It seems like there is no way to know when a
    binding
    has started collecting. I have code along the lines of:
    Copy code
    binder = bind {
        renderer.events.map { it.toIntent() } bindTo store
    }.apply { start() }
    But I have no way to know when it is safe to call
    renderer.dispatch
    because the call to
    start()
    is asynchronous, and non-blocking. It would be nice to provide an API similar to
    stateIn
    , which offers a default implementation that launches a job to start sharing, and a secondary suspending
    stateIn()
    function that blocks until the sharing has begun. In MVIKotlin we could offer suspending
    start()
    that would block until the flows are all actively collecting. Thoughts? Am I missing something?
    a
    • 2
    • 18
  • s

    Shabinder Singh

    09/08/2023, 8:59 PM
    I have a hierarchy of Component and respective Store, building on top of similar functionality. So at lower most I have a StoreFactory with a BaseExecutor extending from
    CoroutineExecutor
    and StoreFactories in upper levels extend this
    BaseExecutor
    My use case is, I want to do some logic process whenever a
    BaseMsg
    is dispatched, My first thought was to override the
    dispatch method
    in
    BaseExecutor
    and do processing by having a check in there. but the dispatch of CoroutineExecutor is not marked as Open. Is there a better way designed to support this use case or should I open a ticket suggesting marking dispatch as open ?
    a
    • 2
    • 4
  • n

    Nacho Ruiz Martin

    09/18/2023, 6:16 AM
    Hey 👋 Using the experimental API, how do you retrieve the
    CoroutineScope
    of the executor inside
    coroutineExecutorFactory
    or
    onIntent
    ? I’d like to use the same mechanism as with the previous API for my flows to be automatically cancelled when the scope is disposed.
    ✅ 1
    a
    • 2
    • 3
  • t

    Tung97 Hl

    10/13/2023, 4:17 AM
    Hi anyone can provide me some use cases of labels. I don't know why we need it. Thanks.
    a
    • 2
    • 2
  • a

    Arkadii Ivanov

    11/04/2023, 9:05 PM
    Apparently, MVIKotlin and Kotlin Multiplatform Mobile plugin work pretty well together. https://twitter.com/arkann1985/status/1720906252618723681
    🔥 1
  • a

    Arkadii Ivanov

    11/04/2023, 11:14 PM
    MVIKotlin
    3.3.0
    is released! 👉 Updated Kotlin to
    1.9.20
    and other dependencies 👉 Removed the support of the legacy memory model Release notes: https://github.com/arkivanov/MVIKotlin/releases/tag/3.3.0
    K 2
  • n

    Nacho Ruiz Martin

    11/18/2023, 7:15 AM
    Hey @Arkadii Ivanov, WDYT of adding a built-in way of mapping states out of the store when using
    stateFlow
    extension? I’ve found that if you map it with:
    Copy code
    store.stateFlow.map(::mapper).stateIn(scope, SharingStarted.Eagerly, store.state.mapper())
    you fall into the everlasting problem of textfield states. I’ve been thinking of adding an optional mapping function inside
    stateFlow
    . This would help users of
    MviKotlin
    +
    Decompose
    that want to use
    Coroutines
    all the way down.
    a
    • 2
    • 6
  • a

    Arkadii Ivanov

    11/19/2023, 10:03 PM
    An interesting update of Essenty has been released:
    1.3.0-beta01
    . - Added Lifecycle extensions for Coroutines - Added Lifecycle extensions for Reaktive - Added convenience extensions for LifecycleOwner - Call doOnDestroy callback if Lifecycle is already destroyed Release notes: https://github.com/arkivanov/Essenty/releases/tag/1.3.0-beta01 Slack Conversation
  • a

    Arkadii Ivanov

    12/02/2023, 4:02 PM
    MVIKotlin 4.0.0-alpha01 is released! - Updated Reaktive in
    mvikotlin-extensions-reaktive
    module to version
    2.0.0
    - Updated Essenty to
    1.3.0
    - Deleted all deprecated code - Merged
    rx
    ,
    rx-internal
    and
    utils-internal
    modules into
    mvikotlin
    module - Updated Kotlin to
    1.9.21
    - Disabled debug artifact publications for Android - Support sending Actions from Executors - Replaced
    getState
    argument function in Executors and
    state
    property in DSL with
    state()
    function Release notes: https://github.com/arkivanov/MVIKotlin/releases/tag/4.0.0-alpha01
    z
    • 2
    • 1
  • e

    electrolobzik

    12/31/2023, 2:09 PM
    @Arkadii Ivanov Is there any approach to use the DSL (coroutineExecutorFactory) and keep the exhaustive nature of
    when
    block of the regular Executor for Intents?
    a
    • 2
    • 10
  • e

    electrolobzik

    01/04/2024, 2:41 PM
    @Arkadii Ivanov I am searching for some convenient approach for decomposition of a store into smaller parts. For example I have a SignIn flow with 4 screens. 2 screens are basically dialogs and don’t have any UI logic, but 2 other screens for entering a phone number and an OTP code have it’s own validation. I have a SignInStore which now contain: 1. Validation of the phone number 2. Validation of the OTP code 3. Actual logic of requesting OTP code from the backend 4. Actual logic of sending the OTP code to the backend, getting session or error and the corresponding error handling I already tried 2 approaches: 1. I have one single SignInStore and a single decompose SignInComponent, which is attached in the compose with 4 different screens and passes UI events as intents to the store and maps the store state to the UI state. a. pros: All sign-in logic in one place, low amount of boilerplate code in components b. cons: If we have just one component for all screens we also have just one fat UiModel which is passed to the compose screens. As a workaround in a single component we can create 4 separate UiModels for each screen. 2. I have one single SignInStore, one SignInRoot component and several decompose child components (one for each screen). a. pros: Not much, just a separation of UiModels inside child components. Potentially some logic could also be done in the child components, but it will probably overcomplicate the system, because we already have another source of truth: the store. b. cons: A lot of boilerplate, because all child components have at least 2 files and all they do is passing events directly to the store the same way as it will work in case1. Now potentially I would like to be able to break the SignInStore into 3 parts: a. The parent store, which does the communication with the backend and handles the flow b. The phone number store, which just contains UI logic for phone validation (actually it also will load countries list etc) c. The OTP code validation store, which contains UI logic for OTP screen. Right now I didn’t find a good approach for performing such decomposition. The most complicated part is the communication between the parent store and 2 child store with UI logic. By communication I mean mainly propagation of the state from parent to children (we don’t want to have several sources of truth, right?), and the Intents from children to parent, etc. In this particular case this could not look worth the efforts, but it is just an example. I already had a similar case, but with much more complex screens with their own logic and the general logic of the flow, when each state used some part of the bigger flow state. That case we handled with MVICore by moving child stores inside the parent store and delegating some parts of the parent state to this children. It was complicated and hard to debug, but still better than monolithic store. I expected that decompose should help to solve this task, but I don’t realise yet how this should look in general. I can move validation logic into the child components instead of child stores, but it doesn’t help much with synchronization and communication. At least it creates 3 separate states (in store and in 2 child components) which I don’t understand how to sync. Did you ever tried to do anything similar?
    a
    • 2
    • 26
  • a

    Arkadii Ivanov

    01/16/2024, 9:10 AM
    MVIKotlin
    4.0.0-alpha02
    is released! 👉 Support
    wasmJs
    target Release notes: https://github.com/arkivanov/MVIKotlin/releases/tag/4.0.0-alpha02
    🔥 2
    🎉 2
  • z

    Zsolt.bertalan

    02/29/2024, 2:03 PM
    I finally got around to test the alpha versions, with an eye on the debug/android artifact publications. I can gladly report that this is now working well, also for Decompose and Essenty. For clarity, the dependency analysis plugin suggested using debug and android artifacts, that had no value. A link to the plugin: https://github.com/autonomousapps/dependency-analysis-gradle-plugin I have a question about the MVIKotlin-Decompose interaction in the thread:
    a
    • 2
    • 4
  • r

    Robert Munro

    03/29/2024, 2:13 PM
    hiya, I have some controller and stores that i want to reuse for a desktop app. and i have made a single
    UiComponent
    interface with
    create()
    and
    destory()
    methods. So now i want to create an essenty lifecycle object that i can pass to my Controller and i can manually call state changes from the create and destroy methods. Is there some prebuilt object in essenty that I can use for this or how would i implement one?
    a
    • 2
    • 4
  • a

    Arkadii Ivanov

    04/05/2024, 8:51 PM
    MVIKotlin
    4.0.0-beta01
    is released! 👉 Updated Kotlin to
    1.9.23
    , Essenty to
    2.0.0-beta01
    , coroutines to
    1.8.0
    , Reaktive to
    2.1.0
    Release notes: https://github.com/arkivanov/MVIKotlin/releases/tag/4.0.0-beta01
    🎉 2
  • a

    Arkadii Ivanov

    04/27/2024, 9:33 PM
    🔥 MVIKotlin
    4.0.0
    is released!
    Changes since version
    4.0.0-beta01
    👉 Updated Essenty to
    2.0.0
    👉 Promoted Executor
    onAction
    and
    forward
    methods to stable 👉 Promoted DSL APIs to stable Full release notes and migration guides: https://github.com/arkivanov/MVIKotlin/releases/tag/4.0.0
    🎉 2
    👍 1
  • t

    Tung97 Hl

    05/02/2024, 11:16 AM
    Hi, I have a question about the latest release. Can I use a variable inside the coroutineExecutorFactory to change logic inside the executor under some conditions? In the 3.x version it's ok because the ExecutorImpl is a class. Now in the 4.x version dsl I'm not sure.
    a
    • 2
    • 7
  • f

    Francis Mariano

    05/17/2024, 5:21 PM
    Hello everyone. How are you? I have two components (A and B) each one with its store. In Store A, I have a stateFlow collect which is launched in onAction. So I navigate to component B via push, in this way store A is not disposed (even component A calls onStop). Once store A is not disposed, the stateFlow continues collecting. What is the better approach to cancel the collect and resume it when the store A come back visible again??
    a
    • 2
    • 20
  • p

    Pavel S

    05/22/2024, 7:24 AM
    Is there a reason why one is not supposed to create a
    store
    by calling
    storeFactory.create
    and instead is supposed to create some factory class with a function returning
    object : Store<…> by storeFactory.create(…)
    ?
    a
    • 2
    • 9
  • p

    Pavel S

    05/31/2024, 8:01 AM
    Is communication between stores via labels a viable solution? For example, a component listens to labels of one store and on a certain label it passes a corresponding intent to another store
    a
    • 2
    • 1
  • p

    Pavel S

    06/02/2024, 4:16 PM
    I have a problem with a label value being skipped if using coroutines extension
    labels
    when the label is published immediately on store startup. I’ve modified my previous sample to illustrate the issue. I expect to see “a” in the first text and “bb” in the second text.
    AStore
    dispatches an
    Action.PublishLabel
    in the bootstrapper, and the action handler publishes
    Label.LabelPublished
    . I subscribe to
    labels
    in the init block of
    DefaultWelcomeComponent
    but the label event is never received. But if you add a
    delay(<long>)
    call before the
    publish
    call, the label event is received. I initially thought this had something to do with the order of initialization of all the objects, but it seems that wasn’t the case, since if you use
    labels(observer: Observer<Label>): Disposable
    the label event is still received. How would you suggest to deal with this?
    a
    • 2
    • 9
  • a

    Arkadii Ivanov

    06/07/2024, 1:05 PM
    MVIKotlin
    4.1.0
    is released! 👉 Use
    typeOf
    as key instead of
    KClass
    in
    InstanceKeeper#getStore
    👉 Updated Kotlin to
    2.0.0
    , Essenty to
    2.1.0
    and other dependencies Full release notes: https://github.com/arkivanov/MVIKotlin/releases/tag/4.1.0
    🎉 4
  • c

    CXwudi

    06/25/2024, 8:47 PM
    Hi, I am doing a practice project involving Decompose and MVIKotlin, and I got a design question about the proper way to call a callback from a`Store` . So I have a
    ScreenAComponent
    that receive a callback to navigate to screen B like the following:
    Copy code
    interface ScreenAComponent {
      val state: Value<ScreenAState>
      fun sendIntent(intent: ScreenAIntent)
    }
    
    class DefaultScreenAComponent(
      private val componentContext: ComponentContext,
      private val storeFactory: StoreFactory,
      val onScreenBNavigate: (String) -> Unit
    ) : ScreenAComponent, ComponentContext by componentContext
    The
    DefaultScreenAComponent
    is created by the root component which basically just does the stack navigation, and the
    onScreenBNavigate
    callback passed into
    ScreenAComponent
    is basically just
    stackNavigation.push()
    function call. Now, I don't know which is the right place to call
    onScreenBNavigate
    , should I do it by subscribing the labels? Or should I call it in Reducer? Or in Executor? Or create a dedicated state for representing that the callback should be called?
    a
    • 2
    • 2
  • c

    CXwudi

    07/25/2024, 10:07 PM
    Hi there, I am trying to test the label dispatching from Store, and I am not sure if this is a deadlock bug in MVIKotlin, or it is my own issue. So please let me explain what I have observed. I have a store like this:
    Copy code
    onIntent<LandingPageIntent.ToNextPage> {
      launch {
         ... some other suspend fun call
         publish(LandingPageToNextPageLabel)
         log.d { "Label sent" }
      }
    Now I have two test cases in kotlintest. One has deadlock, another one doesn't. Here is the one with the deadlock:
    Copy code
    @Test
      fun normalFlowStucked() = runTest {
        // the labels Flow way will be stuck if running in single-threaded env like JS or single-threaded Dispatcher
        // However, from debugging, the label is actually dispatched, but for some reason, we can't receive it
        val job = launch {
          landingPageStore.labels.stateIn(CoroutineScope(coroutineContext)).collect {
            log.d { "Received $it" }
            assertEquals(LandingPageToNextPageLabel, it)
          }
        }
    
        landingPageStore.accept(LandingPageIntent.TextChanged("a change"))
        assertEquals("a change", landingPageStore.state.url)
        landingPageStore.accept(LandingPageIntent.ToNextPage)
    
        job.join()
      }
    The test case can still print
    "Label sent"
    , but not
    "Received LandingPageToNextPageLabel"
    . This only happens if running in
    jsTest
    or in Android platform without specifying the
    Dispatchers.Default
    . Now here is another test case that uses
    Channel
    instead of `Flow`:
    Copy code
    @Test
      fun testNormalFlow1() = runTest {
        // Can't make Store.labels Flow way working in single-threaded env like JS or single-threaded Dispatcher
        val channel = Channel<LandingPageToNextPageLabel>()
        val scope = CoroutineScope(coroutineContext)
    
        landingPageStore.labels(observer {
          scope.launch {
            channel.send(it)
            log.d { "Received $it" }
          }
        })
    
        landingPageStore.accept(LandingPageIntent.TextChanged("a change"))
        assertEquals("a change", landingPageStore.state.url)
        landingPageStore.accept(LandingPageIntent.ToNextPage)
    
        val label = channel.receive()
        assertEquals(label, LandingPageToNextPageLabel)
    
        channel.close()
      }
    This one runs successfully, no deadlock. The actual codes are open sourced at [here](https://github.com/CXwudi/realworld-compose-http4k-example-app/blob/master/conduit[…]onduit/frontend/logic/component/landing/LandingPageStoreTest.kt) and [here](https://github.com/CXwudi/realworld-compose-http4k-example-app/blob/master/conduit[…]uit/frontend/logic/component/landing/LandingPageStoreFactory.kt) for references So here are my questions: 1. Is the deadlock expected for the first test case? 2. Is the second test case a good way to test labels dispatching? If not, then what are some good way to test it?
    a
    • 2
    • 2
  • a

    Arkadii Ivanov

    08/08/2024, 11:06 PM
    MVIKotlin
    4.2.0
    is released! 👉 Added
    Store.labelsChannel(...): ReceiveChannel<Label>
    extension function 👉 Updated Kotlin to
    2.0.10
    Release notes: https://github.com/arkivanov/MVIKotlin/releases/tag/4.2.0
    😯 1
  • c

    CXwudi

    10/04/2024, 6:26 PM
    Hi @Arkadii Ivanov, for the
    labelsChannel()
    , I have some improvement idea in the comment section
    a
    • 2
    • 7
  • s

    Seth Madison

    10/29/2024, 5:49 PM
    Is there any reason not to kick off a coroutine in a renderer so that we can do the rendering work on a background thread? (cc @Casey Morris)
    a
    • 2
    • 5
  • m

    Mark Rebhan

    12/06/2024, 3:24 PM
    For Android targets, if we enable
    LoggingStoreFactory
    , the Android app eventually crashes due to a JNI global reference table overflow. This crash goes away if we don't use the logging store 🤔. I'm trying to figure out if it's an issue with the library or system print.
    a
    • 2
    • 9
  • a

    Arkadii Ivanov

    01/16/2025, 4:32 PM
    MVIKotlin
    4.3.0
    is released! 👉 Updated Kotlin to
    2.1.0
    and other deps 👉 Added
    Store#stateFlow(Lifecycle)
    and
    Store#labelsChannel(Lifecycle)
    API, promoted to stable Release notes: https://github.com/arkivanov/MVIKotlin/releases/tag/4.3.0
    K 1