2 years ago

#51446

test-img

Joe Vienneau

Is there a way to reuse "common" things like DropdownMenu in Compose Multiplatform Project?

For the desktop, DropdownMenu is supplied by Gradle: org.jetbrains.compose.material:material-desktop:1.0.1-rc2; for Android it's in Gradle: androidx.compose.material:material:1.1.0-beta04@aar

I would have thought there would be a common API that both implemented.

I know that I could define my own interface/adapter and then plug in the device specific version, but I'm wondering if there is a clever idiomatic Kotlin way to do this.

I tried using 'expect' and 'actual', but I could figure out the syntax. (DropdownMenu doesn't have a simple signature like in the examples of expect/actual usage).

Here's an example of a Menu I'm using... the Android and Desktop versions look identical:

// TODO is there way that this can be moved to Common
@Composable
fun BellSoundMenu(model: SessionViewModel, files: List<SoundFile>) {
    val selectedIndex = remember { mutableStateOf(0) }
    DropdownMenu(
        expanded = model.isBellMenuExpanded.value,
        ...
    ) {
        files.forEachIndexed { index, sound: SoundFile ->
            DropdownMenuItem(onClick = {
                selectedIndex.value = index
                ...
            }) {
                Row {
                    val isSelected = sound == model.getBellFile()
                    Icon(
                        ...
                    )
                    Text(
                        ...
                    )
                }
            }
        }
    }
}

I'm looking for a way to move this to the Common folder and not duplicate code.

I ended up doing this; I created an interface:

interface MyDropdown {
    @Composable
    fun Menu(
        expanded: Boolean,
        onDismissRequest: () -> Unit,
        modifier: Modifier,
        content: @Composable (androidx.compose.foundation.layout.ColumnScope.() -> Unit)
    )

    @Composable
    fun MenuItem(
        onClick: () -> Unit,
        content: @Composable (androidx.compose.foundation.layout.RowScope.() -> Unit)
    )
}

And then a small object to do the forwarding:

val AndroidDropdown = object : MyDropdown {
    @Composable
    override fun Menu(
        expanded: Boolean,
        onDismissRequest: () -> Unit,
        modifier: Modifier,
        content: @Composable (androidx.compose.foundation.layout.ColumnScope.() -> Unit)
    ) {
        return DropdownMenu(
            expanded = expanded, onDismissRequest = onDismissRequest, modifier = modifier, content = content
        )
    }

    @Composable
    override fun MenuItem(
        onClick: () -> Unit, content: @Composable RowScope.() -> Unit
    ) {
        return DropdownMenuItem(onClick = onClick, content = content)
    }
}

I'm still curious if there's a more Kotlin-esque way of doing it :)

kotlin

android-jetpack-compose

kotlin-multiplatform

compose-multiplatform

0 Answers

Your Answer

Accepted video resources