Skip to content

Commit e8f7981

Browse files
committed
Complete implementing and fix the segmented button components
ref: https://developer.android.com/develop/ui/compose/components/segmented-button
1 parent 71d9287 commit e8f7981

File tree

4 files changed

+102
-78
lines changed

4 files changed

+102
-78
lines changed

demo/src/commonMain/kotlin/com/huanshankeji/compose/material/demo/Material3.kt

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -376,29 +376,25 @@ fun Material3(/*modifier: Modifier = Modifier*/
376376
// Segmented Buttons - Single select with Selection enum
377377
var selectedSegment by remember { mutableStateOf(Selection.A) }
378378
SingleChoiceSegmentedButtonRow {
379-
Selection.entries.forEach { selection ->
379+
Selection.entries.forEachIndexed { index, selection ->
380380
SegmentedButton(
381-
selected = selectedSegment == selection,
382-
onClick = { selectedSegment = selection },
383-
label = { Text(selection.name) }
381+
selectedSegment == selection,
382+
{ selectedSegment = selection },
383+
SegmentedButtonDefaultShapeArgs(index, Selection.entries.size),
384+
label = selection.name
384385
)
385386
}
386387
}
387388

388389
// Segmented Buttons - Multi-select
389-
var selectedOptions by remember { mutableStateOf(setOf<Selection>()) }
390+
val isIndexSelected = remember { mutableStateListOf(false, false, false) }
390391
MultiChoiceSegmentedButtonRow {
391-
Selection.entries.forEach { selection ->
392+
Selection.entries.forEachIndexed { index, selection ->
392393
SegmentedButton(
393-
selected = selection in selectedOptions,
394-
onClick = {
395-
selectedOptions = if (selection in selectedOptions) {
396-
selectedOptions - selection
397-
} else {
398-
selectedOptions + selection
399-
}
400-
},
401-
label = { Text(selection.name) }
394+
isIndexSelected[index],
395+
{ isIndexSelected[index] = it },
396+
SegmentedButtonDefaultShapeArgs(index, Selection.entries.size),
397+
label = selection.name
402398
)
403399
}
404400
}

material3/src/commonMain/kotlin/com/huanshankeji/compose/material3/SegmentedButton.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,16 @@ expect fun MultiChoiceSegmentedButtonRow(
4444
content: @Composable MultiChoiceSegmentedButtonRowScope.() -> Unit
4545
)
4646

47+
/**
48+
* For `SegmentedButtonDefaults.itemShape` on Compose UI.
49+
*/
50+
class SegmentedButtonDefaultShapeArgs(val index: Int, val count: Int)
51+
4752
/**
4853
* Scope for the content of a single-choice segmented button row.
4954
*/
5055
expect class SingleChoiceSegmentedButtonRowScope {
56+
5157
/**
5258
* Material Design segmented button.
5359
*
@@ -64,10 +70,11 @@ expect class SingleChoiceSegmentedButtonRowScope {
6470
fun SegmentedButton(
6571
selected: Boolean,
6672
onClick: () -> Unit,
73+
defaultShapeArgs: SegmentedButtonDefaultShapeArgs,
6774
modifier: Modifier = Modifier,
6875
enabled: Boolean = true,
6976
icon: @Composable (() -> Unit)? = null,
70-
label: @Composable () -> Unit
77+
label: String //@Composable () -> Unit
7178
)
7279
}
7380

@@ -77,11 +84,12 @@ expect class SingleChoiceSegmentedButtonRowScope {
7784
expect class MultiChoiceSegmentedButtonRowScope {
7885
@Composable
7986
fun SegmentedButton(
80-
selected: Boolean,
81-
onClick: () -> Unit,
87+
checked: Boolean,
88+
onCheckedChange: (Boolean) -> Unit,
89+
defaultShapeArgs: SegmentedButtonDefaultShapeArgs,
8290
modifier: Modifier = Modifier,
8391
enabled: Boolean = true,
8492
icon: @Composable (() -> Unit)? = null,
85-
label: @Composable () -> Unit
93+
label: String //@Composable () -> Unit
8694
)
8795
}

material3/src/composeUiMain/kotlin/com/huanshankeji/compose/material3/SegmentedButton.composeUi.kt

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package com.huanshankeji.compose.material3
22

33
import androidx.compose.material3.SegmentedButton
44
import androidx.compose.material3.SegmentedButtonDefaults
5+
import androidx.compose.material3.Text
56
import androidx.compose.runtime.Composable
67
import androidx.compose.ui.unit.Dp
7-
import com.huanshankeji.compose.foundation.layout.Row
88
import com.huanshankeji.compose.ui.Modifier
99

1010
@Composable
@@ -24,43 +24,61 @@ actual fun MultiChoiceSegmentedButtonRow(
2424
space: Dp?,
2525
content: @Composable MultiChoiceSegmentedButtonRowScope.() -> Unit
2626
) =
27-
Row(modifier = modifier) {
28-
MultiChoiceSegmentedButtonRowScope().content()
27+
androidx.compose.material3.MultiChoiceSegmentedButtonRow(
28+
modifier.platformModifier,
29+
space ?: SegmentedButtonDefaults.BorderWidth
30+
) {
31+
MultiChoiceSegmentedButtonRowScope(this).content()
2932
}
3033

3134
actual class SingleChoiceSegmentedButtonRowScope(val platformScope: androidx.compose.material3.SingleChoiceSegmentedButtonRowScope) {
3235
@Composable
3336
actual fun SegmentedButton(
3437
selected: Boolean,
3538
onClick: () -> Unit,
39+
defaultShapeArgs: SegmentedButtonDefaultShapeArgs,
3640
modifier: Modifier,
3741
enabled: Boolean,
3842
icon: @Composable (() -> Unit)?,
39-
label: @Composable () -> Unit
43+
label: String //@Composable () -> Unit
4044
) =
4145
platformScope.SegmentedButton(
4246
selected,
4347
onClick,
4448
SegmentedButtonDefaults.itemShape(
45-
index = TODO(),
46-
count = TODO()
49+
defaultShapeArgs.index,
50+
defaultShapeArgs.count
4751
),
4852
modifier.platformModifier,
4953
enabled,
50-
icon = TODO(),
51-
label = label
52-
)
54+
icon = icon ?: { SegmentedButtonDefaults.Icon(selected) },
55+
) {
56+
Text(label)
57+
}
5358
}
5459

55-
actual class MultiChoiceSegmentedButtonRowScope {
60+
actual class MultiChoiceSegmentedButtonRowScope(val platformScope: androidx.compose.material3.MultiChoiceSegmentedButtonRowScope) {
5661
@Composable
5762
actual fun SegmentedButton(
58-
selected: Boolean,
59-
onClick: () -> Unit,
63+
checked: Boolean,
64+
onCheckedChange: (Boolean) -> Unit,
65+
defaultShapeArgs: SegmentedButtonDefaultShapeArgs,
6066
modifier: Modifier,
6167
enabled: Boolean,
6268
icon: @Composable (() -> Unit)?,
63-
label: @Composable () -> Unit
69+
label: String //@Composable () -> Unit
6470
) =
65-
TODO() as Unit
71+
platformScope.SegmentedButton(
72+
checked,
73+
onCheckedChange,
74+
SegmentedButtonDefaults.itemShape(
75+
defaultShapeArgs.index,
76+
defaultShapeArgs.count
77+
),
78+
modifier.platformModifier,
79+
enabled,
80+
icon = icon ?: { SegmentedButtonDefaults.Icon(checked) },
81+
) {
82+
Text(label)
83+
}
6684
}

material3/src/jsMain/kotlin/com/huanshankeji/compose/material3/SegmentedButton.js.kt

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import androidx.compose.ui.unit.Dp
55
import com.huanshankeji.compose.html.material3.MaterialWebLabsApi
66
import com.huanshankeji.compose.html.material3.MdOutlinedSegmentedButton
77
import com.huanshankeji.compose.html.material3.MdOutlinedSegmentedButtonSet
8-
import com.huanshankeji.compose.html.material3.MdSegmentedButtonScope
98
import com.huanshankeji.compose.html.material3.MdSegmentedButtonScope.Slot
109
import com.huanshankeji.compose.ui.Modifier
1110
import com.huanshankeji.compose.ui.toAttrs
@@ -37,67 +36,70 @@ actual fun MultiChoiceSegmentedButtonRow(
3736
MultiChoiceSegmentedButtonRowScope(this).content()
3837
}
3938

40-
// TODO check their implementations and consider unifying their duplicate implementations
39+
@MaterialWebLabsApi
40+
@Composable
41+
private fun CommonSegmentedButton(
42+
selected: Boolean,
43+
onClick: () -> Unit,
44+
defaultShapeArgs: SegmentedButtonDefaultShapeArgs, // not used here
45+
modifier: Modifier,
46+
enabled: Boolean,
47+
icon: @Composable (() -> Unit)?,
48+
label: String //@Composable () -> Unit
49+
) {
50+
val hasIcon = (icon != null).isTrueOrNull()
51+
MdOutlinedSegmentedButton(
52+
enabled.isFalseOrNull(),
53+
selected.isTrueOrNull(),
54+
label,
55+
hasIcon,
56+
hasIcon,
57+
modifier.toAttrs {
58+
onClick { onClick() }
59+
}
60+
) {
61+
icon?.let { iconContent ->
62+
Div({ slot(Slot.Icon) }) {
63+
iconContent()
64+
}
65+
}
66+
/*
67+
// For `label: @Composable () -> Unit` by Copilot. Might not work.
68+
// Render label in the default slot
69+
label()
70+
*/
71+
}
72+
}
4173

4274
actual class SingleChoiceSegmentedButtonRowScope(val elementScope: ElementScope<HTMLElement>) {
4375
@MaterialWebLabsApi
4476
@Composable
4577
actual fun SegmentedButton(
4678
selected: Boolean,
4779
onClick: () -> Unit,
80+
defaultShapeArgs: SegmentedButtonDefaultShapeArgs, // not used here
4881
modifier: Modifier,
4982
enabled: Boolean,
5083
icon: @Composable (() -> Unit)?,
51-
label: @Composable () -> Unit
52-
) {
53-
MdOutlinedSegmentedButton(
54-
disabled = enabled.isFalseOrNull(),
55-
selected = selected.isTrueOrNull(),
56-
hasIcon = (icon != null).isTrueOrNull(),
57-
attrs = modifier.toAttrs {
58-
this.onClick { onClick() }
59-
}
60-
) {
61-
icon?.let { iconContent ->
62-
Div({
63-
slot(Slot.Icon)
64-
}) {
65-
iconContent()
66-
}
67-
}
68-
// Render label in the default slot
69-
label()
70-
}
71-
}
84+
label: String //@Composable () -> Unit
85+
) =
86+
CommonSegmentedButton(selected, onClick, defaultShapeArgs, modifier, enabled, icon, label)
7287
}
7388

7489
actual class MultiChoiceSegmentedButtonRowScope(val elementScope: ElementScope<HTMLElement>) {
7590
@MaterialWebLabsApi
7691
@Composable
7792
actual fun SegmentedButton(
78-
selected: Boolean,
79-
onClick: () -> Unit,
93+
checked: Boolean,
94+
onCheckedChange: (Boolean) -> Unit,
95+
defaultShapeArgs: SegmentedButtonDefaultShapeArgs, // not used here
8096
modifier: Modifier,
8197
enabled: Boolean,
8298
icon: @Composable (() -> Unit)?,
83-
label: @Composable () -> Unit
84-
) {
85-
MdOutlinedSegmentedButton(
86-
disabled = enabled.isFalseOrNull(),
87-
selected = selected.isTrueOrNull(),
88-
hasIcon = (icon != null).isTrueOrNull(),
89-
attrs = modifier.toAttrs {
90-
this.onClick { onClick() }
91-
}
92-
) {
93-
icon?.let { iconContent ->
94-
Div({
95-
slot(Slot.Icon)
96-
}) {
97-
iconContent()
98-
}
99-
}
100-
label()
101-
}
102-
}
99+
label: String //@Composable () -> Unit
100+
) =
101+
CommonSegmentedButton(
102+
checked, { onCheckedChange(!checked) },
103+
defaultShapeArgs, modifier, enabled, icon, label
104+
)
103105
}

0 commit comments

Comments
 (0)