Alexander Maryanovsky
06/14/2022, 2:03 PMval value by stateFlow.collectAsState()
println("Value: $value")
Text(
text = value
)
and a new value is getting printed, but the old value is displayed until something else in the window is redrawn.Dima Avdeev
06/19/2022, 12:13 PMAlexander Maryanovsky
06/19/2022, 2:04 PMDouble
Alexander Maryanovsky
06/19/2022, 2:06 PMDouble
that is converted to String
like this:
val value by stateFlow.collectAsState()
println("Value: $value")
Text(
text = "Value: ${value.roundToInt()}"
)
Alexander Maryanovsky
06/19/2022, 2:06 PMroundToInt()
changes tooDima Avdeev
06/19/2022, 2:11 PMAlexander Maryanovsky
06/19/2022, 2:12 PMAlexander Maryanovsky
06/19/2022, 2:12 PMValue: 647.3730582038996
Value: 647.3730582038996
Value: 664.5584672349289
and the UI shows 647Alexander Maryanovsky
06/19/2022, 2:13 PMAlexander Maryanovsky
06/19/2022, 2:15 PMAlexander Maryanovsky
06/19/2022, 2:16 PMDima Avdeev
06/19/2022, 2:18 PMDima Avdeev
06/19/2022, 3:14 PMval value by stateFlow.collectAsState()
println("Value: $value")
val derivedValue by derivedStateOf { "Value: ${value.roundToInt()}" }
Text(
text = derivedValue
)
Alexander Maryanovsky
06/19/2022, 6:38 PMclass Flows{
private val v1 = MutableStateFlow(0.0)
private val v2 = MutableStateFlow(0.0)
private val valuesFlow = MutableStateFlow(
listOf(v1.asStateFlow(), v2.asStateFlow()),
).asStateFlow()
@OptIn(ExperimentalCoroutinesApi::class)
val combination = valuesFlow.flatMapLatest { items ->
combine(
items,
Array<Double>::sum
)
}
val _generation = MutableStateFlow(0)
val generation = _generation.asStateFlow()
suspend fun next(){
v1.value = v1.value + 1
delay(1)
v2.value = v2.value + 1
_generation.value += 1
}
suspend fun prev(){
v1.value = v1.value - 1
delay(1)
v2.value = v2.value - 1
_generation.value -= 1
}
}
@Composable
fun DisplayFlows(flows: Flows){
val coroutineScope = rememberCoroutineScope()
val value by remember(flows.combination){
flows.combination.stateIn(
scope = coroutineScope,
started = SharingStarted.WhileSubscribed(),
initialValue = 0.0
)
}.collectAsState()
println("Value: $value")
Text(
text = "Value: ${value.roundToInt()}"
)
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ModifyFlows(flows: Flows){
val focusRequester = remember{ FocusRequester() }
val coroutineScope = rememberCoroutineScope()
Box(
modifier = Modifier
.size(120.dp, 100.dp)
.background(Color.LightGray)
.focusRequester(focusRequester)
.focusable()
.focusTarget()
.onKeyEvent {
if (it.type == KeyEventType.KeyUp){
if (it.key == Key.DirectionLeft){
coroutineScope.launch {
flows.prev()
}
}
else if (it.key == Key.DirectionRight){
coroutineScope.launch {
flows.next()
}
}
}
true
}
){
val generation by flows.generation.collectAsState()
Text(
text = "Press left or right\nGeneration: $generation",
modifier = Modifier.align(Alignment.Center)
)
}
LaunchedEffect(Unit){
focusRequester.requestFocus()
}
}
fun main() {
singleWindowApplication(
title = "Test",
state = WindowState(
width = 400.dp,
height = 600.dp,
)
) {
val flows = remember{ Flows() }
Column(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
DisplayFlows(flows)
ModifyFlows(flows)
Button(
onClick = {}
){
Text("Move mouse over me\nto repaint value")
}
}
}
}
Alexander Maryanovsky
06/19/2022, 6:42 PMAlexander Maryanovsky
06/19/2022, 6:53 PMflatMapLatest
2. Don’t show the generation
3. Remove the delay(1)
Dima Avdeev
06/19/2022, 6:53 PMDima Avdeev
06/19/2022, 6:55 PMAlexander Maryanovsky
06/19/2022, 6:55 PMDima Avdeev
06/19/2022, 6:55 PMAlexander Maryanovsky
06/19/2022, 6:55 PMplugins {
kotlin("jvm") version "1.6.10"
id("org.jetbrains.compose") version "1.1.1"
}
Alexander Maryanovsky
06/19/2022, 7:03 PMAlexander Maryanovsky
06/19/2022, 7:05 PMplugins {
kotlin("jvm") version "1.6.21"
id("org.jetbrains.compose") version "1.2.0-alpha01-dev716"
}
for meAlexander Maryanovsky
06/19/2022, 7:05 PMfocusTarget()
)Alexander Maryanovsky
06/19/2022, 7:06 PMAlexander Maryanovsky
06/19/2022, 7:08 PMInt
as well.Dima Avdeev
06/19/2022, 7:08 PMDima Avdeev
06/19/2022, 7:08 PMDima Avdeev
06/19/2022, 7:09 PMAlexander Maryanovsky
06/19/2022, 7:09 PMAlexander Maryanovsky
06/19/2022, 7:11 PMAlexander Maryanovsky
06/19/2022, 7:12 PMDima Avdeev
06/20/2022, 7:54 AMAlexander Maryanovsky
06/20/2022, 11:01 AMDima Avdeev
06/20/2022, 11:42 AMRyan Mitchener
06/22/2022, 2:35 AMDima Avdeev
06/22/2022, 5:00 AMRyan Mitchener
06/22/2022, 1:30 PMDima Avdeev
06/22/2022, 1:52 PMRyan Mitchener
06/22/2022, 2:18 PMAlexander Maryanovsky
06/22/2022, 4:19 PMAlexander Maryanovsky
06/22/2022, 4:24 PMAlexander Maryanovsky
06/22/2022, 4:27 PMDima Avdeev
06/28/2022, 2:23 PMAlexander Maryanovsky
07/21/2022, 2:49 PMAlexander Maryanovsky
07/21/2022, 3:33 PMTextDelegate
, but it’s not seen on the screen. That makes me think it’s a skiko issue, or the way it’s called from compose.Alexander Maryanovsky
07/21/2022, 4:00 PMSystem.setProperty("skiko.renderApi", "SOFTWARE_COMPAT")
Alexander Maryanovsky
07/21/2022, 4:01 PMDima Avdeev
07/21/2022, 4:44 PMAlexander Maryanovsky
07/23/2022, 8:24 AMSkiaLayer
and dumps its screenshot into a file:
val skiaLayer = (window.contentPane.components[0] as JLayeredPane).components[0] as SkiaLayer
ImageIO.write(skiaLayer.screenshot()?.toBufferedImage(), "png", File("$home/Desktop/compose.png"))
then I reproduce the issue (screen showing wrong value) and click the button. The screenshot shows the correct values.Dima Avdeev
07/23/2022, 8:27 AMAlexander Maryanovsky
07/23/2022, 8:28 AMAlexander Maryanovsky
07/23/2022, 8:48 AMscreenshot()
draws is the same Picture that was last drawn by MetalContextHandler
on a Surface too. There’s nothing going on between the last draw to the screen and the screenshot.Alexander Maryanovsky
07/24/2022, 5:27 PMorg.jetbrains.skia.Surface
has the right thing drawn on it. I screenshotted it via Surface.readPixels
. So it looks like the problem is further down, maybe in native code.