| /* |
| * Copyright 2021 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 |
| * |
| * http://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 androidx.glance.appwidget |
| |
| import androidx.annotation.RestrictTo |
| import androidx.compose.runtime.Composable |
| import androidx.glance.Emittable |
| import androidx.glance.EmittableCheckable |
| import androidx.glance.ExperimentalGlanceApi |
| import androidx.glance.GlanceModifier |
| import androidx.glance.GlanceNode |
| import androidx.glance.GlanceTheme |
| import androidx.glance.action.Action |
| import androidx.glance.action.ActionModifier |
| import androidx.glance.action.action |
| import androidx.glance.appwidget.action.CompoundButtonAction |
| import androidx.glance.appwidget.unit.CheckableColorProvider |
| import androidx.glance.appwidget.unit.CheckedUncheckedColorProvider.Companion.createCheckableColorProvider |
| import androidx.glance.appwidget.unit.ResourceCheckableColorProvider |
| import androidx.glance.color.DynamicThemeColorProviders |
| import androidx.glance.text.TextStyle |
| import androidx.glance.unit.ColorProvider |
| |
| /** Set of colors to apply to a Switch depending on the checked state. */ |
| sealed class SwitchColors { |
| internal abstract val thumb: CheckableColorProvider |
| internal abstract val track: CheckableColorProvider |
| } |
| |
| internal data class SwitchColorsImpl( |
| override val thumb: CheckableColorProvider, |
| override val track: CheckableColorProvider |
| ) : SwitchColors() |
| |
| /** |
| * Adds a switch view to the glance view. |
| * |
| * @param checked whether the switch is checked |
| * @param onCheckedChange the action to be run when the switch is clicked. The current value of |
| * checked is provided to this action in its ActionParameters, and can be retrieved using the |
| * [ToggleableStateKey]. If this action launches an activity, the current value of checked will be |
| * passed as an intent extra with the name [RemoteViews.EXTRA_CHECKED]. |
| * In order to allow the Launcher to provide this extra on Android version S and later, we use a |
| * mutable PendingIntent ([android.app.PendingIntent.FLAG_MUTABLE]) when this action is not a |
| * lambda. Before S, and for lambda actions, this will be an immutable PendingIntent. |
| * @param modifier the modifier to apply to the switch |
| * @param text the text to display to the end of the switch |
| * @param style the style to apply to [text] |
| * @param colors the tint colors for the thumb and track of the switch |
| * @param maxLines An optional maximum number of lines for the text to span, wrapping if |
| * necessary. If the text exceeds the given number of lines, it will be truncated. |
| */ |
| @Composable |
| fun Switch( |
| checked: Boolean, |
| onCheckedChange: Action?, |
| modifier: GlanceModifier = GlanceModifier, |
| text: String = "", |
| style: TextStyle? = null, |
| colors: SwitchColors = SwitchDefaults.colors(), |
| maxLines: Int = Int.MAX_VALUE, |
| ) = SwitchElement(checked, onCheckedChange, modifier, text, style, colors, maxLines) |
| |
| /** |
| * Adds a switch view to the glance view. |
| * |
| * @param checked whether the switch is checked |
| * @param onCheckedChange the action to be run when the switch is clicked |
| * @param modifier the modifier to apply to the switch |
| * @param text the text to display to the end of the switch |
| * @param style the style to apply to [text] |
| * @param colors the tint colors for the thumb and track of the switch |
| * @param maxLines An optional maximum number of lines for the text to span, wrapping if |
| * necessary. If the text exceeds the given number of lines, it will be truncated. |
| */ |
| @Composable |
| fun Switch( |
| checked: Boolean, |
| onCheckedChange: () -> Unit, |
| modifier: GlanceModifier = GlanceModifier, |
| text: String = "", |
| style: TextStyle? = null, |
| colors: SwitchColors = SwitchDefaults.colors(), |
| maxLines: Int = Int.MAX_VALUE, |
| ) = SwitchElement( |
| checked, |
| action(block = onCheckedChange), |
| modifier, |
| text, |
| style, |
| colors, |
| maxLines |
| ) |
| |
| /** |
| * Adds a switch view to the glance view. |
| * |
| * @param checked whether the switch is checked |
| * @param onCheckedChange the action to be run when the switch is clicked |
| * @param modifier the modifier to apply to the switch |
| * @param text the text to display to the end of the switch |
| * @param style the style to apply to [text] |
| * @param colors the tint colors for the thumb and track of the switch |
| * @param maxLines An optional maximum number of lines for the text to span, wrapping if |
| * necessary. If the text exceeds the given number of lines, it will be truncated. |
| * @param key A stable and unique key that identifies the action for this switch. This ensures |
| * that the correct action is triggered, especially in cases of items that change order. If not |
| * provided we use the key that is automatically generated by the Compose runtime, which is unique |
| * for every exact code location in the composition tree. |
| */ |
| @ExperimentalGlanceApi |
| @Composable |
| fun Switch( |
| checked: Boolean, |
| onCheckedChange: () -> Unit, |
| modifier: GlanceModifier = GlanceModifier, |
| text: String = "", |
| style: TextStyle? = null, |
| colors: SwitchColors = SwitchDefaults.colors(), |
| maxLines: Int = Int.MAX_VALUE, |
| key: String? = null, |
| ) = SwitchElement( |
| checked, |
| action(key, onCheckedChange), |
| modifier, |
| text, |
| style, |
| colors, |
| maxLines |
| ) |
| |
| /** |
| * Contains the default values used by [Switch]. |
| */ |
| object SwitchDefaults { |
| |
| /** |
| * SwitchColors to tint the thumb and track of the [Switch] according to the checked state. |
| * |
| * @param checkedThumbColor the tint to apply to the thumb of the switch when it is checked |
| * @param uncheckedThumbColor the tint to apply to the thumb of the switch when it is not |
| * checked |
| * @param checkedTrackColor the tint to apply to the track of the switch when it is checked |
| * @param uncheckedTrackColor the tint to apply to the track of the switch when it is not |
| * checked |
| */ |
| @Composable |
| fun colors( |
| checkedThumbColor: ColorProvider, |
| uncheckedThumbColor: ColorProvider, |
| checkedTrackColor: ColorProvider, |
| uncheckedTrackColor: ColorProvider, |
| ): SwitchColors = switchColors( |
| checkedThumbColor = checkedThumbColor, |
| uncheckedThumbColor = uncheckedThumbColor, |
| checkedTrackColor = checkedTrackColor, |
| uncheckedTrackColor = uncheckedTrackColor |
| ) |
| |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) |
| fun switchColors( |
| checkedThumbColor: ColorProvider, |
| uncheckedThumbColor: ColorProvider, |
| checkedTrackColor: ColorProvider, |
| uncheckedTrackColor: ColorProvider, |
| ): SwitchColors { |
| return SwitchColorsImpl( |
| thumb = createCheckableColorProvider( |
| source = "SwitchColors", |
| checked = checkedThumbColor, |
| unchecked = uncheckedThumbColor, |
| ), |
| track = createCheckableColorProvider( |
| source = "SwitchColors", |
| checked = checkedTrackColor, |
| unchecked = uncheckedTrackColor, |
| ) |
| ) |
| } |
| |
| /** |
| * |
| * SwitchColors to tint the thumb and track of the [Switch] according to the checked state. |
| * @return a default set of [SwitchColors]. |
| */ |
| @Composable |
| fun colors(): SwitchColors { |
| return if (GlanceTheme.colors == DynamicThemeColorProviders) { |
| SwitchColorsImpl( |
| thumb = ResourceCheckableColorProvider(R.color.glance_default_switch_thumb), |
| track = ResourceCheckableColorProvider(R.color.glance_default_switch_track) |
| ) |
| } else { |
| colors( |
| checkedThumbColor = GlanceTheme.colors.onPrimary, |
| uncheckedThumbColor = GlanceTheme.colors.outline, |
| checkedTrackColor = GlanceTheme.colors.primary, |
| uncheckedTrackColor = GlanceTheme.colors.surfaceVariant, |
| ) |
| } |
| } |
| } |
| |
| @Composable |
| private fun SwitchElement( |
| checked: Boolean, |
| onCheckedChange: Action?, |
| modifier: GlanceModifier = GlanceModifier, |
| text: String = "", |
| style: TextStyle? = null, |
| colors: SwitchColors = SwitchDefaults.colors(), |
| maxLines: Int = Int.MAX_VALUE, |
| ) { |
| val finalModifier = if (onCheckedChange != null) { |
| modifier.then(ActionModifier(CompoundButtonAction(onCheckedChange, checked))) |
| } else { |
| modifier |
| } |
| GlanceNode( |
| factory = { EmittableSwitch(colors) }, |
| update = { |
| this.set(checked) { this.checked = it } |
| this.set(text) { this.text = it } |
| this.set(finalModifier) { this.modifier = it } |
| this.set(style) { this.style = it } |
| this.set(colors) { this.colors = it } |
| this.set(maxLines) { this.maxLines = it } |
| }) |
| } |
| |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) |
| class EmittableSwitch( |
| var colors: SwitchColors |
| ) : EmittableCheckable() { |
| override var modifier: GlanceModifier = GlanceModifier |
| |
| override fun copy(): Emittable = EmittableSwitch(colors = colors).also { |
| it.modifier = modifier |
| it.checked = checked |
| it.text = text |
| it.style = style |
| it.maxLines = maxLines |
| } |
| |
| override fun toString(): String = "EmittableSwitch(" + |
| "$text, " + |
| "modifier=$modifier, " + |
| "checked=$checked, " + |
| "style=$style, " + |
| "colors=$colors, " + |
| "maxLines=$maxLines" + |
| ")" |
| } |