JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.24k stars 1.11k forks source link

navigation-compose in kmp/cmp sometimes flashes to next screen, or you can go back enough to get to white screen #4847

Closed ColtonIdle closed 1 month ago

ColtonIdle commented 1 month ago

Two distinct issues.

  1. When going to the next screen in my simple example app, you can see that sometimes you'll get a more noticeable flash when going to the next screen. At 20 seconds in, you can see an example of this flash. Same at about 24 seconds
  2. Now that you have a backstack full of items, you can mash on the back button in the sample, and you'll see that you can force yourself to go back past the start destination.

Description of Video: 1-15 seconds. showing happy path of going to next screens. then mashing back. everything works fine. 15-26: Trying to show the flashing that appears in issue 1 26-33: Showing that mashing back button sometimes leave you in a bad state

Code is pretty simple

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.ui.tooling.preview.Preview

@OptIn(ExperimentalResourceApi::class)
@Composable
@Preview
fun App() {
    MaterialTheme {
        val navController = rememberNavController()

        NavHost(navController = navController, startDestination = "a") {
            composable("a") {

                ScreenA(
                    { navController.navigate(route = "a") }, { navController.popBackStack() }
                )

            }
            composable("b") { ScreenB() }
        }
    }
}

@Composable
fun ScreenA(event: () -> Unit, backEvent: () -> Unit, viewModel: OrderViewModel = viewModel { OrderViewModel() }) {
    Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
        Column {

            Text("Screen A: Current $viewModel")
            Button({ event() }) {
                Text("Goto Screen B ${viewModel.asdf}")
            }
            Button({ backEvent() }) {
                Text("back")
            }

        }
    }
}

@Composable
fun ScreenB() {
    Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
        Text("Screen B")
    }
}

class OrderViewModel : ViewModel() {
    var asdf by mutableStateOf(0)

    init {
        viewModelScope.launch {
            while (true) {
                delay(10)
                asdf += 1
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
    }
}
[versions]
agp = "8.2.0"
android-compileSdk = "34"
android-minSdk = "24"
android-targetSdk = "34"
androidx-activityCompose = "1.9.0"
androidx-appcompat = "1.6.1"
androidx-constraintlayout = "2.1.4"
androidx-core-ktx = "1.13.0"
androidx-espresso-core = "3.5.1"
androidx-material = "1.11.0"
androidx-test-junit = "1.1.5"
compose = "1.6.7"
compose-plugin = "1.6.10-rc03"
junit = "4.13.2"
kotlin = "2.0.0-RC3"

androidx-lifecycle = "2.8.0-rc03"
androidx-navigation = "2.7.0-alpha06"

[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" }
androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-espresso-core" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" }
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
androidx-lifecycle-viewmodel-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
androidx-navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
androidLibrary = { id = "com.android.library", version.ref = "agp" }

jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }

Here is a video https://github.com/JetBrains/compose-multiplatform/assets/31751141/c176a65e-ffe2-4fa0-a66f-4697f7e65282

MatkovIvan commented 1 month ago

Hi @ColtonIdle,

I see that you deleted a template 😢, please don't do that. Based on the video, I'd say that it's an Android device emulator. LIke in Compose itself, we're using original Google binaries on Android, so it means that the issue is not in our fork and should be reported to Google issue tracker.

Regarding the reproduction itself. The content is still interactable during transaction animation (it's expected). You can add a check based on the lifecycle state to prevent this:

if (lifecycle.currentState < Lifecycle.State.RESUMED) {
    // Application is not in focus or navigation transition is in progress
    return
}
ColtonIdle commented 1 month ago

Sorry, for not going by the template. I wasn't sure where to put this ticket so I just wanted to get a feel for where it should go so I didn't want to spend the time filling in a bunch of details in case this was the wrong repo (first time trying to submit a bug for androidx/kmp stuff)

Seems like this might have been the right repo then? 😄

For what its worth... I submitted to android's issuetracker but it was closed as

Issues with org.jetbrains.androidx.navigation:navigation-compose" should be filed against the Jetbrains tracker, thanks!

See: https://issuetracker.google.com/issues/341973424

Please let me know what you think I should do next. The issue also happens on iOS. I can try to request for it to be re-opened on the Android side if that's what you think.

MatkovIvan commented 1 month ago

I can understand the confusion there, but I believe it was the right place. I'll discuss this with Google folks internally

Please let me know what you think I should do next. The issue also happens on iOS. I can try to request for it to be re-opened on the Android side if that's what you think.

Since the issue happens on Android, it's about the original library and can be reproduced without a multiplatform adoption. So you can add a reproduction with Google's only dependencies to that issue.

ColtonIdle commented 1 month ago

Got it. I will try! And my apologies... Was just trying to be helpful!

Sent from Proton Mail Android

-------- Original Message -------- On 5/23/24 4:15 AM, Ivan Matkov wrote:

I can understand the confusion there, but I believe it was the right place. I'll discuss this with Google folks internally

Please let me know what you think I should do next. The issue also happens on iOS. I can try to request for it to be re-opened on the Android side if that's what you think.

Since the issue happens on Android, it's about the original library and can be reproduced without a multiplatform adoption. So you can add a reproduction with Google's only dependencies to that issue.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>