| /* |
| * 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 |
| * |
| * 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.wear.compose.material3 |
| |
| import androidx.compose.foundation.shape.CornerBasedShape |
| import androidx.compose.foundation.shape.CornerSize |
| import androidx.compose.foundation.shape.RoundedCornerShape |
| import androidx.compose.runtime.Composable |
| import androidx.compose.runtime.Immutable |
| import androidx.compose.runtime.ReadOnlyComposable |
| import androidx.compose.runtime.staticCompositionLocalOf |
| import androidx.compose.ui.graphics.Shape |
| import androidx.wear.compose.material3.tokens.ShapeKeyTokens |
| import androidx.wear.compose.material3.tokens.ShapeTokens |
| |
| /** |
| * Material surfaces can be displayed in different shapes. Shapes direct attention, identify |
| * components, communicate state, and express brand. |
| * |
| * The shape scale defines the style of container, offering a range of |
| * curved shapes (mostly polygonal). The default [Shapes] theme for Material3 is rounded rectangles, |
| * with various degrees of corner roundness: |
| * |
| * - Extra Small |
| * - Small |
| * - Medium |
| * - Large |
| * - Extra Large |
| * |
| * You can customize the shape system for all components in the [MaterialTheme] or you can do it |
| * on a per component basis by overriding the shape parameter for that |
| * component. For example, by default, buttons use the shape style "large". If your product requires |
| * a smaller amount of roundness, you can override the shape parameter with a different shape |
| * value like [Shapes.small]. |
| * |
| * TODO(b/273226734) Review documentation with references to components that use the shape themes. |
| * |
| * @param extraSmall By default, provides [ShapeDefaults.ExtraSmall], a [RoundedCornerShape] |
| * with 4dp [CornerSize] (used by bundled Cards). |
| * @param small By default, provides [ShapeDefaults.Small], a [RoundedCornerShape] |
| * with 8dp [CornerSize]. |
| * @param medium By default, provides [ShapeDefaults.Medium], a [RoundedCornerShape] with |
| * 16dp [CornerSize] (used by shape-shifting Buttons and rounded rectangle buttons). |
| * @param large By default, provides [ShapeDefaults.Large], a [RoundedCornerShape] |
| * with 24dp [CornerSize] (used by Cards). |
| * @param extraLarge By default, provides [ShapeDefaults.ExtraLarge], a |
| * [RoundedCornerShape] with 32dp [CornerSize]. |
| */ |
| @Immutable |
| class Shapes( |
| val extraSmall: CornerBasedShape = ShapeDefaults.ExtraSmall, |
| val small: CornerBasedShape = ShapeDefaults.Small, |
| val medium: CornerBasedShape = ShapeDefaults.Medium, |
| val large: CornerBasedShape = ShapeDefaults.Large, |
| val extraLarge: CornerBasedShape = ShapeDefaults.ExtraLarge, |
| ) { |
| /** Returns a copy of this Shapes, optionally overriding some of the values. */ |
| fun copy( |
| extraSmall: CornerBasedShape = this.extraSmall, |
| small: CornerBasedShape = this.small, |
| medium: CornerBasedShape = this.medium, |
| large: CornerBasedShape = this.large, |
| extraLarge: CornerBasedShape = this.extraLarge, |
| ): Shapes = Shapes( |
| extraSmall = extraSmall, |
| small = small, |
| medium = medium, |
| large = large, |
| extraLarge = extraLarge, |
| ) |
| |
| override fun equals(other: Any?): Boolean { |
| if (this === other) return true |
| if (other !is Shapes) return false |
| if (extraSmall != other.extraSmall) return false |
| if (small != other.small) return false |
| if (medium != other.medium) return false |
| if (large != other.large) return false |
| if (extraLarge != other.extraLarge) return false |
| return true |
| } |
| |
| override fun hashCode(): Int { |
| var result = extraSmall.hashCode() |
| result = 31 * result + small.hashCode() |
| result = 31 * result + medium.hashCode() |
| result = 31 * result + large.hashCode() |
| result = 31 * result + extraLarge.hashCode() |
| return result |
| } |
| |
| override fun toString(): String { |
| return "Shapes(" + |
| "extraSmall=$extraSmall, " + |
| "small=$small, " + |
| "medium=$medium, " + |
| "large=$large, " + |
| "extraLarge=$extraLarge)" |
| } |
| } |
| |
| /** |
| * Contains the default values used by [Shapes] |
| */ |
| object ShapeDefaults { |
| |
| /** Extra small sized corner shape */ |
| val ExtraSmall = ShapeTokens.CornerExtraSmall |
| |
| /** Small sized corner shape */ |
| val Small = ShapeTokens.CornerSmall |
| |
| /** Medium sized corner shape */ |
| val Medium = ShapeTokens.CornerMedium |
| |
| /** Large sized corner shape */ |
| val Large = ShapeTokens.CornerLarge |
| |
| /** Extra large sized corner shape */ |
| val ExtraLarge = ShapeTokens.CornerExtraLarge |
| } |
| |
| /** |
| * Helper function for component shape tokens. Here is an example on how to use component color |
| * tokens: |
| * ``MaterialTheme.shapes.fromToken(FabPrimarySmallTokens.ContainerShape)`` |
| */ |
| internal fun Shapes.fromToken(value: ShapeKeyTokens): Shape { |
| return when (value) { |
| ShapeKeyTokens.CornerExtraSmall -> extraSmall |
| ShapeKeyTokens.CornerSmall -> small |
| ShapeKeyTokens.CornerMedium -> medium |
| ShapeKeyTokens.CornerLarge -> large |
| ShapeKeyTokens.CornerExtraLarge -> extraLarge |
| ShapeKeyTokens.CornerFull -> ShapeTokens.CornerFull |
| ShapeKeyTokens.CornerNone -> ShapeTokens.CornerNone |
| } |
| } |
| |
| /** |
| * Converts a shape token key to the local shape provided by the theme |
| * The shape references the [LocalShapes]. |
| */ |
| internal val ShapeKeyTokens.value: Shape |
| @Composable |
| @ReadOnlyComposable |
| get() = MaterialTheme.shapes.fromToken(this) |
| |
| /** CompositionLocal used to specify the default shapes for the surfaces. */ |
| internal val LocalShapes = staticCompositionLocalOf { Shapes() } |