Benoît
11/16/2021, 10:22 AMRak
11/28/2021, 11:01 PMRak
12/01/2021, 9:41 AMRak
12/01/2021, 8:35 PMRak
12/03/2021, 11:29 AMmiqbaldc
12/07/2021, 6:08 PMRak
12/12/2021, 6:46 PMdelay
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.Cedric Dupin
12/14/2021, 4:49 PMmiqbaldc
12/22/2021, 12:36 PMOleksii Malovanyi
12/22/2021, 4:06 PM@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)
}
Oleksii Malovanyi
12/23/2021, 9:14 AMBenoît
12/23/2021, 2:03 PMmiqbaldc
01/03/2022, 3:03 PMState
& 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️⃣ ?Ravi
01/05/2022, 2:01 PMRak
01/05/2022, 5:19 PMRak
01/10/2022, 4:43 PMState
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?Rak
01/12/2022, 4:46 PMrunOnCreate
method? Is it always required? I am writing tests for my viewmodels on android.Rak
01/17/2022, 9:42 AMBenoît
01/17/2022, 11:37 AMclass 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?
ThanksTim Rösler
01/20/2022, 12:59 PM@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.Ravi
01/20/2022, 5:43 PMdata 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)
}
}
Ramzi Eljabali
01/20/2022, 10:47 PMBenoît
01/25/2022, 10:44 AMintent
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 passesBenoît
01/28/2022, 2:24 PMClemens Tögel
01/30/2022, 5:10 PMrunBlocking
function is even an expected declaration in the common module when it is implemented the same way in jvm and ios?
Thanks in advance.miqbaldc
02/03/2022, 5:58 AMorbit-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?Ravi
02/03/2022, 3:42 PMMVI 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 approachappmattus
02/04/2022, 7:46 AMRak
02/08/2022, 2:17 PMRak
02/08/2022, 2:18 PM