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.63k stars 1.14k forks source link

rtl doesn't work on iOS #3997

Open chokokatana opened 8 months ago

chokokatana commented 8 months ago

Describe the bug iOS ignores arabic rtl layout/orientation. See attached screen where right side shows the arabic preview inside Android studio, and the left side shows the iOS simulator with that screen. Arabic rtl layout works fine on Android.

arabic

Affected platforms Select one of the platforms below:

Versions

Context

The code I use to create viewcontrollers is generic call to ComposeUIViewController plus some extra code to pass the UIViewController to my classes to be able to call native stuff. First, I tried to create a @Composable that logs the layout direction:

    val result = ComposeUIViewController {
        logDirection()
        WallaceTheme {
            BiomarkersHomeScreen(
                platform = platform,
                …
            )
        }
    }

…

@Composable
fun logDirection() {
    if (LocalLayoutDirection.current == LayoutDirection.Rtl) {
        println("DDDD direction is rtl")
    } else {
        println("DDDD direction is ltr")
    }
}

Running this code under iOS shows no surprises: the direction is LTR despite OS being set to RTL language. Then, I modified my platform class to contain a native swift test using the UIViewController returned from ComposeUIViewController:

    override func testDirection() {
        print("DDDD vc is \(vc)")
        if let direction = vc?.view.effectiveUserInterfaceLayoutDirection {
            if direction == .rightToLeft {
                print("DDDD iOS direction is right to left")
            } else {
                print("DDDD iOS direction is bad")
            }
        } else {
            print("DDDD no vc or view yet?")
        }
    }

Running this code on iOS will show that the direction is RTL. The actual log output I get is:

DDDD testing platform direction
DDDD vc is Optional(<ComposeWindow: 0x131c74910>)
DDDD iOS direction is right to left
DDDD direction is ltr

The third line is the swift code, and the fourth line is the kotlin composable.

Something is not connecting the RTL direction of the ComposeWindow.view with the LocalLayoutDirection.

Not being an iOS arabic user myself, I've been releasing this onto users without realising, and now I guess they are having fun navigating back through screens where some have the back arrow where expected, and some screens have the back arrow in the opposite place 🙈.

Is there any way for me to quickly patch this and force LocalLayoutDirection to have the right value outside of your bugfix release cycle?

chokokatana commented 8 months ago

Is there any way for me to quickly patch this and force LocalLayoutDirection to have the right value outside of your bugfix release cycle?

Ok, managed to patch it. My solution has been to implement the following code around the returned UIViewController:

    override func isNativeDirectionRtl() -> KotlinBoolean? {
        if let direction = vc?.view.effectiveUserInterfaceLayoutDirection {
            if direction == .rightToLeft {
                return KotlinBoolean(bool: true)
            } else {
                return KotlinBoolean(bool: false)
            }
        } else {
            return nil
        }
    }

Then, I add the following composable and wrap everything with it:

@Composable
fun overrideDirection(platform: BiomarkersHomePlatformIos, content: @Composable () -> Unit) {
    when (platform.isNativeDirectionRtl()) {
        true -> {
            CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
                content()
            }
        }

        false -> {
            CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
                content()
            }
        }

        null -> content()
    }
}

…

    val result = ComposeUIViewController {
        logDirection("first test")
        overrideDirection(platform) {
            logDirection("overriden test")
            WallaceTheme {
                BiomarkersHomeScreen(
…

With overrideDirection I finally get rendered everything in Arabic as intented.

mazunin-v-jb commented 8 months ago

Thank you for submitting the issue! It's a known problem, we linked this issue to #3096

okushnikov commented 3 weeks ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.