Zoltan Demant
07/19/2022, 11:46 AMcolor = contentColor.copy(alpha = 1f)
and then use CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha)
to provide the actual alpha just mere lines later?juliocbcotta
07/19/2022, 12:37 PMmattinger
07/19/2022, 1:20 PMKwok Wong
07/19/2022, 1:28 PMLazyColumn
and have been managed to follow the example here to implement the drag-and-drop operation for the list items.
In a compose UI test, we want to test the drag-and-drop behaviours using code below:
onNodeWithContentDescription("itemDesription", substring = true)
.onChild()
.performTouchInput {
down(bottomCenter)
moveTo(percentOffset(0.5f, -0.7f), delayMillis = 1000L)
up()
}
What the code would do:
1. Select an item from list (long-click)
2. Move the item one position up
However, the operation always fails with the step moveTo
So, we are wondering whether we are using the moveTo API properly.
Any suggestions?
Regards,Can Korkmaz
07/19/2022, 1:58 PMVivek Modi
07/19/2022, 4:34 PMviewModelScope.launch
so when I call in my compose function, should I use any thing else? I am reading Side-effects using LunchEffect and DispoableEffect. Is this neccessary in my composable function? If yes can someone guide me, bcoz I unable to understand this concept. Thanks
class MainActivityViewModel(private val resultRepository: ResultRepository) : ViewModel() {
init {
getSportResult()
}
fun getSportResult() {
viewModelScope.launch {
val response = resultRepository.getSportResult()
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SetupView(viewModel :MainActivityViewModel = koinViewModel()) {
Scaffold(topBar = {
TopAppBar(
title = { Text(text = stringResource(id = R.string.app_name)) },
)
}, content = { padding ->
Column(
modifier = Modifier
.fillMaxSize()
) {
Button(onClick = { /*TODO*/ }) {
Text(text = stringResource(id = R.string.get_result))
}
}
})
}
Thanks guys..Nat Strangerweather
07/19/2022, 5:26 PMDropDownMenu
but both Material 2 and Material 3 are leaking in Compose. Do you just put up with the memory leak or is there a workaround?raghunandan
07/20/2022, 3:40 AMjasu
07/20/2022, 4:11 AMKonyaco
07/20/2022, 6:05 AMKonyaco
07/20/2022, 6:17 AMste
07/20/2022, 7:36 AMCanvas
? Given the dark blue rect and the black text, how should I blend them? I tried every single BlendMode
, but none of them gave the desired result. I need to whiten the part of the text that overlaps the rect (or, alternatively, clear the part or the rect the text would overlap)Slackbot
07/20/2022, 10:51 AMLukasz Kalnik
07/20/2022, 12:39 PMLazyVerticalGrid
with items containing some Coil `AsyncImage`s and the scroll is stuttering very hard. Is this a known problem?Vivek Modi
07/20/2022, 2:34 PMA
screen. Inside that I have Button
. When I click I am calling api and getting data. In this whole process I am passing UI state event i.e. IsLoading
, OnSuccess
and OnError
. So when I press the Button
the IsLoading
is trigger and when I get data without any problem, I trigger`OnSuccess` with data. So question is
1. When IsLoading
happening I want to called A
screen -> B
Screen.
Note:- we are standing on B
screen
2. When I get OnSuccess
with data, A
screen pass to B
Screen again.
Is it possible to do that through navigation compose or something else?Mohan manu
07/20/2022, 4:58 PMVikas Singh
07/20/2022, 6:26 PMandrew
07/20/2022, 6:34 PMJasmin Fajkic
07/20/2022, 8:12 PMSean Proctor
07/20/2022, 9:01 PMandroidx.compose.ui.input.key.Key
?Colton Idle
07/20/2022, 10:28 PM1.7.10
Colton Idle
07/20/2022, 10:52 PMK Merle
07/21/2022, 8:26 AMsystem
theme?Kulwinder Singh
07/21/2022, 9:31 AMloloof64
07/21/2022, 9:55 AMSurface
with solid background color, and a Button
.
2. When the user clicks on the button, the expected behaviour is that the square changes its color.
3. In this experiment, things are a bit more complicated : I'm using a ColorSquareState
class, with a method chooseNextColor
, and I'm storing a `mutableState`on an instance of this class.
But when the `chooseNextColor`is called, it does not force recomposition. Why ? Is there a simple workaround keeping the use of `ColorSquareState`as long as method chooseNextColor
?Jasmin Fajkic
07/21/2022, 12:00 PMLisandro Di Meo
07/21/2022, 2:27 PMval isLoginError by loginViewModel.loginError.observeAsState()
val context = LocalContext.current
LaunchedEffect(isLoginError){
when (isLoginError) {
true -> {
Toast.makeText(context, "Error", Toast.LENGTH_SHORT).show()
}
false -> navHostController.navigate(Paths.HOME_PATH)
null -> { // blah }
}
}
LoginScreen(loginViewModel)
Joseph Hawkes-Cates
07/21/2022, 4:13 PMVivek Modi
07/21/2022, 4:42 PMprivate const val NEAREST_RESULT_JSON = "nearestResultJson"
@Composable
internal fun NavigationGraph() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = ScreenRoute.Home.route) {
composable(ScreenRoute.Home.route) {
SetupMainActivityView { nearestResult ->
val nearestResultJson = Uri.encode(Gson().toJson(nearestResult))
navController.navigate(ScreenRoute.Result.route + "/{$nearestResultJson}")
}
}
composable(
ScreenRoute.Result.route + "/{$NEAREST_RESULT_JSON}",
arguments = listOf(
navArgument(NEAREST_RESULT_JSON) { type = NearestResultParamType() }
)
) { backStackEntry ->
ResultScreen(backStackEntry.arguments?.getParcelableArrayList(NEAREST_RESULT_JSON))
}
}
}
dimsuz
07/21/2022, 5:16 PMFlow<State>
which then gets collected and rendered.
When TextField
emits a value change request — this too is considered a source of change and gets mapped/processed and then ends up in this state flow with actual text
value calculated → rendered. Example usecase: "user inputs foo
, ViewModel receives this request, merges it with some flags and decides to send foo-bar
back to render in the text field".
The thing is: if calculating "foo-bar" value consumes some time, then TextField state gets completely messed up, because it emits faster than it renders.
In the attached video I simply press and hold the 1
key while in code I add some delay before sending it back to the TextField
. See 🧵 for a minimum sample code.
Is this something that can be done correctly?dimsuz
07/21/2022, 5:16 PMFlow<State>
which then gets collected and rendered.
When TextField
emits a value change request — this too is considered a source of change and gets mapped/processed and then ends up in this state flow with actual text
value calculated → rendered. Example usecase: "user inputs foo
, ViewModel receives this request, merges it with some flags and decides to send foo-bar
back to render in the text field".
The thing is: if calculating "foo-bar" value consumes some time, then TextField state gets completely messed up, because it emits faster than it renders.
In the attached video I simply press and hold the 1
key while in code I add some delay before sending it back to the TextField
. See 🧵 for a minimum sample code.
Is this something that can be done correctly?var state by remember { mutableStateOf(TextFieldValue()) }
val changeRequests = remember {
MutableSharedFlow<TextFieldValue>(extraBufferCapacity = 50)
}
LaunchedEffect(Unit) {
changeRequests.onEach { delay(100); state = it }.collect()
}
TextField(value = state, onValueChange = { changeRequests.tryEmit(it) })
Ale Stamato
07/21/2022, 6:08 PMdimsuz
07/21/2022, 6:16 PMString
, but here I use only the one with TextFieldValue
— does it still has those 3 copies? (is this down to the BasicTextField
?)Ale Stamato
07/21/2022, 6:41 PMinput.copy(text = input.text.filter { !it.isDigit() })
. For other cases in which you have to, for example, launch a coroutine and “hold the state” youre bound to have an issuedimsuz
07/21/2022, 10:42 PMFlow<>
(as I've described).
This is quite flexible and reactive, but it seems that this "merging" itself sometimes can create enough delay to drive TextField out of sync.
Thank you for explanation! If there will be some plans about improving this situation, I'd be interested to read more through whichever medium 🙂Joost Klitsie
07/22/2022, 11:23 AMdimsuz
07/22/2022, 11:41 AMdelay(...)
is to model what happens, of course I'm not having it in my code 🙂 The transformation or merging effect sometimes can create delay, see my last message above. Of course you can say "should happen without delay", but the reality is that delays can happen due to slow hardware or software.Alexander Ivanov
07/22/2022, 11:42 AMThis should never be delayed, if you want to transform this then the transformation should happen without delayReal world example would be some sort of validation which happens on Dispatcher other than Dispatchers.Main. Even without validation using Dispatchers.Default to reduce the state (e.g. in ViewModel) is enough to cause such a delay.
Joost Klitsie
07/22/2022, 11:45 AM// in ViewModel
val someText = MutableStateFlow("")
init {
viewModelScope.launch {
someText.collectLatest {
formatter.format(it).also { formattedText ->
someText.update { formattedText }
}
}
}
}
fun updateText(text: String) { someText.update { text } }
// in composable
val someState by someText.collectAsState()
Text(value = someState, onValueChange = { viewModel.updateText(it) })
someText.debounce(100).collectLatest { <--format-->}
dimsuz
07/22/2022, 11:51 AMflow1: Flow<NetworkResponse>
• flow2: Flow<UserInput>
(strings)
And I want to update field whenever I receive response in additiion to user input. User doesn't type, response comes → field is updated. So I roughly do this:
val text by remember { merge(flow1.map { it.responseText } ,flow2.map { it.text}) }.collectAsState()
TextField(text, onValueChange = { flow2.emit(it) })
That merge
above can already cause slight delays depending on the device.Joost Klitsie
07/22/2022, 11:52 AMdimsuz
07/22/2022, 11:55 AMmain.immediate
, but not on main
. And I'd really like to launch flow1 on Dispatchers.IO 🙂Sean McQuillan [G]
08/12/2022, 4:20 PMdimsuz
08/12/2022, 6:38 PMPresenter
) which contains all the logic, no android deps, while Compose only does rendering.
This ViewModel
holds the data class ViewState(text: String, whateverElse: Int)
for the whole screen and it also has val state: StateFlow<ViewState>
for the renderer (Compose) to consume.
On the Compose side we feed viewState.text
to the TextField
and onValueChange
reports changed text to the ViewModel
→ it updates ViewState
and renders it. Cycle is complete.
But ViewModel
is also subscribed to other sources for text changes, let's say network request or some other system event can change it.
So the ViewModel
has something like this (in pseudo-code):
merge(textFieldChangeFlow, networkTextFlow, systemTextFlow).collect { newText ->
state.update { it.copy(text = newText)
}
// other actions coming from UI can update text too
validateButtonClickFlow.collect {
state.update { it.copy(text = validateAndUpdate(it.text) }
}
The crucial thing here is that we want this ViewState
in VM to be the single source of truth for the screen, including the text field. So that screen logic in VM always works with the latest state and can update and render it at any time.
So whenever text changes in Сompose, we want not only set it to the text field, but update it in VM (which in turn can cause it to render). Or VM even can decide not to update state with the new text value: this way we can implement filters and masks in VM. While also keeping logic of working with other streams there, in one place (!).
But if we have the requirement that TextField
must receive text asap, then we have to use additional remember { }
on the compose side and onValueChanged
should update that MutableState and then also send it to the VM. And this leaves us with two sources of truth: local mutable state in compose and ViewState consumed from VM, and while they should be in-sync most of the time, often something does cause them to go out of sync very badly when fast-typing or fast-deleting the text in the field. Perhaps it's those Flow operator roundtrips or the fact that some flows can execute on different dispatchers before being merged on Dispatchers.Main, I am not 100% sure right now. Also this case excludes ability to implement filtering/masking on VM.
In my original post here I have tried to reproduce this "out-of-sync" problem with large delays, but I'm not sure that this is actually what happens, but at least it looks very similar, while not depicting out actual setup 100%.Sean McQuillan [G]
08/15/2022, 3:55 PMmutex(ON_MAIN_THREAD)
if(getText() == expected) setText(...)