Skip to content

Commit

Permalink
Implement ToggleButton (#1476)
Browse files Browse the repository at this point in the history
  • Loading branch information
luizgrp authored Jul 7, 2023
1 parent 245eabf commit 3a4f3e3
Show file tree
Hide file tree
Showing 29 changed files with 834 additions and 8 deletions.
10 changes: 10 additions & 0 deletions compose-material/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ package com.google.android.horologist.compose.material {
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void Title(String text, optional androidx.compose.ui.Modifier modifier);
}

public final class ToggleButtonDefaults {
method @androidx.compose.runtime.Composable public androidx.wear.compose.material.ToggleButtonColors iconOnlyColors();
field public static final com.google.android.horologist.compose.material.ToggleButtonDefaults INSTANCE;
}

public final class ToggleButtonKt {
method @androidx.compose.runtime.Composable public static void ToggleButton(String text, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChanged, optional androidx.compose.ui.Modifier modifier, optional boolean checked, optional boolean enabled, optional androidx.wear.compose.material.ToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional int role, optional boolean smallSize);
method @androidx.compose.runtime.Composable public static void ToggleButton(Object checkedIcon, Object notCheckedIcon, String contentDescription, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChanged, optional androidx.compose.ui.Modifier modifier, optional boolean checked, optional boolean enabled, optional androidx.wear.compose.material.ToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional int role, optional com.google.android.horologist.compose.material.IconRtlMode iconRtlMode, optional boolean smallSize);
}

public final class ToggleChipKt {
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void ToggleChip(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChanged, String label, com.google.android.horologist.compose.material.ToggleChipToggleControl toggleControl, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.vector.ImageVector? icon, optional com.google.android.horologist.compose.material.IconRtlMode iconRtlMode, optional String? secondaryLabel, optional androidx.wear.compose.material.ToggleChipColors colors, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.horologist.compose.material

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AirplanemodeActive
import androidx.compose.material.icons.filled.AirplanemodeInactive
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreview() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {}
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewNotChecked() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {},
checked = false
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewDisabled() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {},
enabled = false
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewNotCheckedDisabled() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {},
checked = false,
enabled = false
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewText() {
ToggleButton(
text = "Monday",
onCheckedChanged = {}
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewTextNotChecked() {
ToggleButton(
text = "Monday",
onCheckedChanged = {},
checked = false
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewSmall() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {},
smallSize = true
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewSmallNotChecked() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {},
checked = false,
smallSize = true
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewIconOnly() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {},
colors = ToggleButtonDefaults.iconOnlyColors(),
smallSize = true
)
}

@Preview(
backgroundColor = 0xff000000,
showBackground = true
)
@Composable
fun ToggleButtonPreviewIconOnlyNotChecked() {
ToggleButton(
checkedIcon = Icons.Filled.AirplanemodeActive,
notCheckedIcon = Icons.Filled.AirplanemodeInactive,
contentDescription = "contentDescription",
onCheckedChanged = {},
checked = false,
colors = ToggleButtonDefaults.iconOnlyColors(),
smallSize = true
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ public fun SplitToggleChip(
val toggleControlParam: (@Composable BoxScope.() -> Unit) = {
val stateDescriptionSemantics = stringResource(
if (checked) {
R.string.horologist_split_toggle_chip_on_content_description
R.string.horologist_split_toggle_chip_on_state_description
} else {
R.string.horologist_split_toggle_chip_off_content_description
R.string.horologist_split_toggle_chip_off_state_description
}
)
Icon(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.horologist.compose.material

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.wear.compose.material.ContentAlpha
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.Text
import androidx.wear.compose.material.ToggleButton
import androidx.wear.compose.material.ToggleButtonColors
import androidx.wear.compose.material.ToggleButtonDefaults
import androidx.wear.compose.material.contentColorFor

/**
* This component is an alternative to [ToggleButton], providing the following:
* - a convenient way of providing text;
*/
@Composable
public fun ToggleButton(
text: String,
onCheckedChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier,
checked: Boolean = true,
enabled: Boolean = true,
colors: ToggleButtonColors = ToggleButtonDefaults.toggleButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = CircleShape,
role: Role = ToggleButtonDefaults.DefaultRole,
smallSize: Boolean = false
) {
val stateDescriptionSemantics = stringResource(
if (checked) {
R.string.horologist_toggle_button_on_state_description
} else {
R.string.horologist_toggle_button_off_state_description
}
)

val newModifier = if (smallSize) {
modifier.size(ToggleButtonDefaults.SmallToggleButtonSize)
} else {
modifier
}.semantics { stateDescription = stateDescriptionSemantics }

ToggleButton(
checked = checked,
onCheckedChange = onCheckedChanged,
modifier = newModifier,
enabled = enabled,
colors = colors,
interactionSource = interactionSource,
shape = shape,
role = role
) {
Text(text = text.take(3))
}
}

/*
* This component is an alternative to [ToggleButton], providing the following:
* - a convenient way of providing a icons for the checked and not checked states;
*/
@Composable
public fun ToggleButton(
checkedIcon: Any,
notCheckedIcon: Any,
contentDescription: String,
onCheckedChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier,
checked: Boolean = true,
enabled: Boolean = true,
colors: ToggleButtonColors = ToggleButtonDefaults.toggleButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = CircleShape,
role: Role = ToggleButtonDefaults.DefaultRole,
iconRtlMode: IconRtlMode = IconRtlMode.Default,
smallSize: Boolean = false
) {
val stateDescriptionSemantics = stringResource(
if (checked) {
R.string.horologist_toggle_button_on_state_description
} else {
R.string.horologist_toggle_button_off_state_description
}
)

val newModifier = if (smallSize) {
modifier.size(ToggleButtonDefaults.SmallToggleButtonSize)
} else {
modifier
}.semantics { stateDescription = stateDescriptionSemantics }

ToggleButton(
checked = checked,
onCheckedChange = onCheckedChanged,
modifier = newModifier,
enabled = enabled,
colors = colors,
interactionSource = interactionSource,
shape = shape,
role = role
) {
Icon(
icon = if (checked) {
checkedIcon
} else {
notCheckedIcon
},
modifier = modifier,
contentDescription = contentDescription,
rtlMode = iconRtlMode
)
}
}

/**
* Contains the default values used by [ToggleButton].
*/
public object ToggleButtonDefaults {

/**
* Creates a [ToggleButtonColors] that represents the content colors for an icon-only
* [ToggleButton].
*/
@Composable
public fun iconOnlyColors(): ToggleButtonColors {
return ToggleButtonDefaults.toggleButtonColors(
checkedBackgroundColor = Color.Transparent,
uncheckedBackgroundColor = Color.Transparent,
disabledCheckedContentColor = contentColorFor(MaterialTheme.colors.surface).copy(alpha = ContentAlpha.disabled)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ public fun ToggleChip(

val stateDescriptionSemantics = stringResource(
if (checked) {
R.string.horologist_toggle_chip_on_content_description
R.string.horologist_toggle_chip_on_state_description
} else {
R.string.horologist_toggle_chip_off_content_description
R.string.horologist_toggle_chip_off_state_description
}
)
ToggleChip(
Expand Down
10 changes: 6 additions & 4 deletions compose-material/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
-->

<resources>
<string description="Content description of the ToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_toggle_chip_on_content_description">On</string>
<string description="Content description of the ToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_toggle_chip_off_content_description">Off</string>
<string description="Content description of the SplitToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_split_toggle_chip_on_content_description">On</string>
<string description="Content description of the SplitToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_split_toggle_chip_off_content_description">Off</string>
<string description="State description of the ToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_toggle_chip_on_state_description">On</string>
<string description="State description of the ToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_toggle_chip_off_state_description">Off</string>
<string description="State description of the SplitToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_split_toggle_chip_on_state_description">On</string>
<string description="State description of the SplitToggleChip. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_split_toggle_chip_off_state_description">Off</string>
<string description="State description of the ToggleButton. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_toggle_button_on_state_description">On</string>
<string description="State description of the ToggleButton. It lets the user know if the toggle is checked or not. [CHAR_LIMIT=NONE]" name="horologist_toggle_button_off_state_description">Off</string>
</resources>
Loading

0 comments on commit 3a4f3e3

Please sign in to comment.