https://kotlinlang.org logo
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
orbit-mvi
  • b

    Benoît

    11/16/2021, 10:22 AM
    Hi everyone, using Orbit's testing framework, is there a way to ensure that no more states/effects are emitted? I need to make sure that my container stays in a particular state after a particular intent has been fired
    m
    • 2
    • 39
  • r

    Rak

    11/28/2021, 11:01 PM
    Hi, I have a more MVI-related question. In my app I have a number of logically related screens such as a questionnaire where multiple screens are displayed with questions and then finally a result screen is shown. These screens share a view model (which seems the correct thing to do). The issue arises where state needs to be kept across screens (but not necessarily displayed). So for example, a flow of screens is started with some important information at the beginning (say the questionnaire was started in beginner or advanced mode and this is needed at the last step to talk to some api. I could store the information as an instance field in the view model but you have to be careful about making sure fields are set before using and then reset as view models can outlive the screens. I was wondering could I put this state into the view state class? Or is this not a good idea?
    m
    b
    • 3
    • 8
  • r

    Rak

    12/01/2021, 9:41 AM
    Hi, if you have a button that triggers a navigation event, is it worth passing through the VM?
    m
    a
    b
    • 4
    • 7
  • r

    Rak

    12/01/2021, 8:35 PM
    Hi, the state objects i define end up containing a lot of nulls. The examples I’ve seen usually use numerics or lists which are easy to initialise to non-null values. But what about strings or complex data structures? I attempted to make my state object a sealed class hierarchy but I couldnt work out how to reduce it. I guess I am looking for validation that I’m doing it correctly (as I can’t find any complex examples to learn from)
    m
    a
    +2
    • 5
    • 9
  • r

    Rak

    12/03/2021, 11:29 AM
    Hi, I have a main screen that shows your status. You go off to other screens that update your status and then you return to the main screen. Problem is that I am not sure how to best refresh the status? No intents are firing on return (I think the last State is displayed but its no longer valid).
    a
    • 2
    • 2
  • m

    miqbaldc

    12/07/2021, 6:08 PM
    What do you folks thought about https://square.github.io/workflow/?
    o
    b
    • 3
    • 2
  • r

    Rak

    12/12/2021, 6:46 PM
    Hi, I am trying to add a
    delay
    but I dont know how to do this as i get the error about not being in a suspend function when inside an `intent`block.
    m
    a
    • 3
    • 6
  • c

    Cedric Dupin

    12/14/2021, 4:49 PM
    Hi all ! How do you handle your TextFiled and their values in your ContainerHost/State ? I tried everything I found online but I keep having this issue : https://github.com/orbit-mvi/orbit-mvi/issues/82
    a
    • 2
    • 1
  • m

    miqbaldc

    12/22/2021, 12:36 PM
    Any references/guidances when to define States or SideEffect for this usecase? 1. Initial State 2. Get User 3. Upload Photo Profile 4. Update User Profile 5. Get User (to update preferences) This is our current implementation in 🧵
    b
    • 2
    • 5
  • o

    Oleksii Malovanyi

    12/22/2021, 4:06 PM
    Question regarding new androidx lifecycle (2.4.0) and the article https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda Isn’t the proper way to bound to the lifecycle is like?
    @Composable
    fun <STATE : Any, SIDE_EFFECT : Any> ContainerHost<STATE, SIDE_EFFECT>.collectAsState(
        minActiveState: Lifecycle.State = Lifecycle.State.STARTED
    ): State<STATE> {
        val lifecycleOwner = LocalLifecycleOwner.current
        val lifecycleAwareStateFlow = remember(this, lifecycleOwner) {
            container.stateFlow.flowWithLifecycle(lifecycleOwner.lifecycle, minActiveState)
        }
        return lifecycleAwareStateFlow.collectAsState(currentState)
    }
    ➕ 1
    k
    • 2
    • 4
  • o

    Oleksii Malovanyi

    12/23/2021, 9:14 AM
    Do you think it is possible to move the project to new coroutines lib? I wonder what side effects it could bring 🤔 https://blog.jetbrains.com/kotlin/2021/12/introducing-kotlinx-coroutines-1-6-0/#kotlinx-coroutines-test-update
    ➕ 1
    a
    • 2
    • 1
  • b

    Benoît

    12/23/2021, 2:03 PM
    Hey guys, is there a chance someone could have a look at that PR? https://github.com/orbit-mvi/orbit-mvi/pull/97 It's to support the new Macbook M1
    ➕ 1
    a
    m
    • 3
    • 6
  • m

    miqbaldc

    01/03/2022, 3:03 PM
    Any recommendation to pass a
    State
    &
    Side-Effect
    to a Composable screen, instead of passing the
    ViewModel
    ?
    ViewModel
    ref based on: https://github.com/orbit-mvi/orbit-sample-stocklist-jetpack-compose/blob/main/app/[…]otlin/org/orbitmvi/orbit/sample/stocklist/list/ui/ListScreen.kt Code in 🧵 1️⃣ , 2️⃣ or 3️⃣ ?
    b
    a
    • 3
    • 9
  • r

    Ravi

    01/05/2022, 2:01 PM
    Any recommendation for this question https://stackoverflow.com/questions/68483347/android-mvi-using-stateflow-and-paging-3 ?
    a
    • 2
    • 1
  • r

    Rak

    01/05/2022, 5:19 PM
    Hi, I am trying to write my first unit test for my viewmodel but it doesnt work
    m
    a
    m
    • 4
    • 8
  • r

    Rak

    01/10/2022, 4:43 PM
    Hi, is the reason that I have to pass a
    State
    to the
    test
    method in my unit tests so that I can fast forward to any point in the state machine? Its just strange passing it in when the viewmodel should do the initial state. Would it not be better as an optional parameter for when you do want to skip the initial state?
    ➕ 1
    m
    • 2
    • 1
  • r

    Rak

    01/12/2022, 4:46 PM
    Hi, can someone explain the
    runOnCreate
    method? Is it always required? I am writing tests for my viewmodels on android.
    a
    b
    • 3
    • 3
  • r

    Rak

    01/17/2022, 9:42 AM
    Hi, a couple of bugs on GitHub have had no responses, one of them is preventing me from testing an important screen in my app. Any idea when someone will look at them?
    m
    • 2
    • 3
  • b

    Benoît

    01/17/2022, 11:37 AM
    Hey guys, I'm trying to do something with Orbit's testing framework and basically the test finishes too early and so my assertion fails. I'm trying to simulate an empty state in a Repository's Flow that should trigger a refresh, here's the code:
    class MyContainerHost(
        scope: CoroutineScope,
        val repositoryFlow: Flow<String?>, // Flow representing repository state
        val requestRefresh: () -> Unit
    ) :
        ContainerHost<String, String> {
        override val container: Container<String, String> =
            scope.container("initial") {
                // When creating the container, listen for update on the Repository flow
                scope.launch {
                    repositoryFlow.collect { newState ->
                        intent {
                            // When no state in flow, refresh it
                            if (newState != null) {
                                reduce { newState }
                            } else {
                                requestRefresh()
                            }
                        }
                    }
                }
            }
    }
    The thing is when I write a unit test for that, the test returns before being able to get into my
    collect{}
    block. How would you deal with that? Thanks
    m
    r
    • 3
    • 17
  • t

    Tim Rösler

    01/20/2022, 12:59 PM
    Hi All, I'm currently facing some issues with my code and Orbit-MVI and don't fully get why this happens and how to fix. I'm using a Android Jetpack Compose function with following code:
    @Composable
    fun MyComposeApp(modifier: Modifier = Modifier, viewModel: MyAppViewModel = getStateViewModel()) {
    ...
    ConstraintLayout(modifier = modifier
            .pointerInput(Unit) {
                detectTapGestures(
                    onLongPress = {
                        Log.d("xxx","TabGestures: longPress recognized")
                        viewModel.switchToEditMode(true)
                    })
            }
    My state class look like this:
    data class MyAppState(
        ...
        val editMode: Boolean = false,
    MyAppViewModel:
    class MyAppViewModel(
        private val repository: MyAppRepository,
        private val savedState: SavedStateHandle
    ) : ContainerHost<MyAppState, Nothing>, ViewModel() {
    
        override val container = container<MyAppState, Nothing>(
            MyAppState(...)
        ) {
            ...
        }
    
        fun switchToEditMode(editMode: Boolean) {
            Log.d("xxx","1 switchToEditMode: $editMode")
    
            intent {
                Log.d("xxx","2 switchToEditMode")
    
                reduce {
                    state.copy(
                        editMode = editMode,
                        ...
                    )
                }
                Log.d("xxx","3 switchToEditMode")
            }
        }
    My code is embedded in some Fragment pages with a pager implementation. The Compose code is rendered on one of those Fragments. Due to some legacy code and extended Drag&Drop functionality I was not able to use Compose for the rest of the Fragment pages. On that legacy Fragment pages (Kotlin code) I'm using Drag&Drop functionality enabled by long-press. This code and all the relevant classes are separated from the Compose code (see above). So there shouldn't be any interference. The only code they share is the whole fragment pager logic. But the content of this single compose ui is embedded like this:
    class MyComposeFragment : Fragment() {
    
        val myAppViewModel: MyAppViewModel by viewModel()
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            return ComposeView(requireContext()).apply {
                setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
                setContent {
                    HomeTheme {
                        MyComposeApp(Modifier.fillMaxSize(), MyAppViewModel)
                    }
                }
            }
        }
    }
    Bug scenario: As long as I do not perform any drag&drop on those legacy code pages, the Compose impl. and Orbit code works like charm. Then I perform a drag&drop gesture on those non Compose code pages and swipe back to my Fragment using the Compose code above. The Compose code on longpress calls:
    viewModel.switchToEditMode(true)
    and the Log is printed. This now leads to my viewModel where the following function is called:
    fun switchToEditMode(editMode: Boolean) {
            Log.d("xxx","1 switchToEditMode: $editMode")
    ...
    This log is printed as well but it seems that the complete intent { } block is not going to be executed anymore. At least I cannot see my logs in there. NOTE: Clicks on the Compose UI are still possible and show a result and also the long-press gesture seems to be recognized correctly. It's just that the intent block is not executed anymore. Can anybody give a hint or explain to me why and in what situations the intent {} block will not be executed anymore? How can I fix or work-around? Help is highly appreciated.
    o
    • 2
    • 3
  • r

    Ravi

    01/20/2022, 5:43 PM
    Whats the correct way to check state property ensuring thread safety. For example
    data class MviState(val isChecked: Boolean)
    
    Inside ViewModel ...
    
    fun doSomething = intent {
       if(mviState.isChecked) {  --------------> how to ensure its thread safe here. (reduce block is thread safe) 
          postSideEffect(SideEffect.Something)
       }   
    }
    b
    • 2
    • 2
  • r

    Ramzi Eljabali

    01/20/2022, 10:47 PM
    Hey all, I saw that iOS is in Alpha stage. Is there any documentation to be able to use it? Gradle doesn’t sync in common main in adding mvi-orbit project.
    b
    • 2
    • 2
  • b

    Benoît

    01/25/2022, 10:44 AM
    Is there anything in the Orbit Testing library that prevents an intent from throwing an Exception and crashing? One of my
    intent
    blocks has to throw an Exception to signify that the test has failed, I can see the Exception being passed to my
    CoroutineExceptionHandler
    where I throw it, but the test somehow still passes
    m
    m
    • 3
    • 9
  • b

    Benoît

    01/28/2022, 2:24 PM
    Hey guys, when do you plan on making a release with this? https://github.com/orbit-mvi/orbit-mvi/pull/100
    a
    m
    • 3
    • 2
  • c

    Clemens Tögel

    01/30/2022, 5:10 PM
    Hi, I want to use the orbit-core for a multiplatform app targeting also js. Would it be possible to simply add a js target to the orbit-core module which implements the Blocking.kt mechanism just like the jvm target? I am also wondering why the
    runBlocking
    function is even an expected declaration in the common module when it is implemented the same way in jvm and ios? Thanks in advance.
    m
    b
    • 3
    • 3
  • m

    miqbaldc

    02/03/2022, 5:58 AM
    Looking into a sample code from
    orbit-mvi/orbit-mvi
    , compose effect are wrapped with
    LaunchedEffect
    Strangely in our case, we were unable to observe same sideEffect twice tho Does it compose
    LaunchedEffect
    are not meant to observe same sideEffect, or maybe any other alternative?
    🆙 1
    m
    • 2
    • 16
  • r

    Ravi

    02/03/2022, 3:42 PM
    Hi, I’m showing countdown timer on ui served from viewModel .
    MVI state
    data class VideoState(val currentTime: Long, 
                          val totalTime: Long,
                          val title: String)
    UI (Fragment)
    renderData(state: VideoState) {
     binding.timerTextView.text = "$state.currentTime"
     binding.durationTextView.text = "$state.totalTime"
     binding.title = "$state.title"
    }
    only
    timerTextView
    will update but
    durationTextView
    &
    title
    will remain same still
    renderData
    will set everything. Is there any performance again if we want to update part of the view? If so whats the better to do that? Hoping for a
    onBindViewHolder
    with
    payload
    kind of approach
    • 1
    • 1
  • a

    appmattus

    02/04/2022, 7:46 AM
    Orbit v4.3.1 is released https://github.com/orbit-mvi/orbit-mvi/releases/tag/4.3.1 This is a minor release with the following features: Features • Support for Apple Silicon simulators • Updated to Kotlin 1.6.10 and coroutines 1.6.0 Fixes • Minor documentation fixes • Add package to compose utility functions • Fix smart casting in reducers As always, massive thank you to our community for the suggestions, discussions and contribution 🙇 cc @Benoît
    👯‍♂️ 2
    🥳 2
    :party-parrot: 2
    🤘 4
    ❤️ 10
    😮rbit-mvi: 3
    :bored-party-parrot: 2
    b
    • 2
    • 1
  • r

    Rak

    02/08/2022, 2:17 PM
    How do I test what was emitted from the view model?
    m
    • 2
    • 4
  • r

    Rak

    02/08/2022, 2:18 PM
    btw, the view model is meant to set the state based on what it finds in shared prefs, I haven’t written that logic yet as I wanted to write the test first.
    • 1
    • 4
Powered by Linen
Title
r

Rak

02/08/2022, 2:18 PM
btw, the view model is meant to set the state based on what it finds in shared prefs, I haven’t written that logic yet as I wanted to write the test first.
So I can’t work out how to test the initial state is correct so I am passing a “dummy” initial state that I can ignore and then use the create method to do the real work to test the state. Here’s my logic and the test.
class AnalyticsConsentViewModel(val prefs: Preferences) : ViewModel(),
    ContainerHost<AnalyticsConsentState, NavigationEvent> {
    override val container: Container<AnalyticsConsentState, NavigationEvent> =
        container(AnalyticsConsentState()) {
            getInitialState()
        }

    private fun getInitialState() = intent {
        val hasAnalyticsConsentGiven = prefs.hasAnalyticsConsentGiven()
        if (hasAnalyticsConsentGiven == null || hasAnalyticsConsentGiven) {
            reduce {
                state.copy(consentGivenChecked = true)
            }
        } else {
            reduce {
                state.copy(consentGivenChecked = false)
            }
        }
    }
}

data class AnalyticsConsentState(
    val consentGivenChecked: Boolean? = null
)
and the tests
@Test
    fun `nothing in shared prefs so asking during registration`() = runTest {
        // given
        val initialState = AnalyticsConsentState()
        every { prefs.hasAnalyticsConsentGiven() } returns null
        val viewModel = AnalyticsConsentViewModel(prefs).test(initialState)

        // when
        viewModel.runOnCreate()

        // then
        viewModel.assert(initialState) {
            states(
                { copy(consentGivenChecked = true) }
            )
        }
    }

    @Test
    fun `analytics consent given`() = runTest {
        // given
        val initialState = AnalyticsConsentState()
        every { prefs.hasAnalyticsConsentGiven() } returns true
        val viewModel = AnalyticsConsentViewModel(prefs).test(initialState)

        // when
        viewModel.runOnCreate()

        // then
        viewModel.assert(initialState) {
            states(
                { copy(consentGivenChecked = true) }
            )
        }
    }

    @Test
    fun `analytics consent denied`() = runTest {
        // given
        val initialState = AnalyticsConsentState()
        every { prefs.hasAnalyticsConsentGiven() } returns false
        val viewModel = AnalyticsConsentViewModel(prefs).test(initialState)

        // when
        viewModel.runOnCreate()

        // then
        viewModel.assert(initialState) {
            states(
                { copy(consentGivenChecked = false) }
            )
        }
    }
View count: 7