1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.material
18 
19 import androidx.annotation.FloatRange
20 import androidx.compose.runtime.Composable
21 import androidx.compose.runtime.compositionLocalOf
22 import androidx.compose.ui.graphics.luminance
23 
24 /**
25  * Default alpha levels used by Material components.
26  *
27  * See [LocalContentAlpha].
28  */
29 object ContentAlpha {
30     /**
31      * A high level of content alpha, used to represent high emphasis text such as input text in a
32      * selected [TextField].
33      */
34     val high: Float
35         @Composable
36         get() =
37             contentAlpha(
38                 highContrastAlpha = HighContrastContentAlpha.high,
39                 lowContrastAlpha = LowContrastContentAlpha.high
40             )
41 
42     /**
43      * A medium level of content alpha, used to represent medium emphasis text such as placeholder
44      * text in a [TextField].
45      */
46     val medium: Float
47         @Composable
48         get() =
49             contentAlpha(
50                 highContrastAlpha = HighContrastContentAlpha.medium,
51                 lowContrastAlpha = LowContrastContentAlpha.medium
52             )
53 
54     /**
55      * A low level of content alpha used to represent disabled components, such as text in a
56      * disabled [Button].
57      */
58     val disabled: Float
59         @Composable
60         get() =
61             contentAlpha(
62                 highContrastAlpha = HighContrastContentAlpha.disabled,
63                 lowContrastAlpha = LowContrastContentAlpha.disabled
64             )
65 
66     /**
67      * This default implementation uses separate alpha levels depending on the luminance of the
68      * incoming color, and whether the theme is light or dark. This is to ensure correct contrast
69      * and accessibility on all surfaces.
70      *
71      * See [HighContrastContentAlpha] and [LowContrastContentAlpha] for what the levels are used
72      * for, and under what circumstances.
73      */
74     @Composable
contentAlphanull75     private fun contentAlpha(
76         @FloatRange(from = 0.0, to = 1.0) highContrastAlpha: Float,
77         @FloatRange(from = 0.0, to = 1.0) lowContrastAlpha: Float
78     ): Float {
79         val contentColor = LocalContentColor.current
80         val lightTheme = MaterialTheme.colors.isLight
81         return if (lightTheme) {
82             if (contentColor.luminance() > 0.5) highContrastAlpha else lowContrastAlpha
83         } else {
84             if (contentColor.luminance() < 0.5) highContrastAlpha else lowContrastAlpha
85         }
86     }
87 }
88 
89 /**
90  * CompositionLocal containing the preferred content alpha for a given position in the hierarchy.
91  * This alpha is used for text and iconography ([Text] and [Icon]) to emphasize / de-emphasize
92  * different parts of a component. See the Material guide on
93  * [Text Legibility](https://material.io/design/color/text-legibility.html) for more information on
94  * alpha levels used by text and iconography.
95  *
96  * See [ContentAlpha] for the default levels used by most Material components.
97  *
98  * [MaterialTheme] sets this to [ContentAlpha.high] by default, as this is the default alpha for
99  * body text.
100  *
101  * @sample androidx.compose.material.samples.ContentAlphaSample
102  */
<lambda>null103 val LocalContentAlpha = compositionLocalOf { 1f }
104 
105 /**
106  * Alpha levels for high luminance content in light theme, or low luminance content in dark theme.
107  *
108  * This content will typically be placed on colored surfaces, so it is important that the contrast
109  * here is higher to meet accessibility standards, and increase legibility.
110  *
111  * These levels are typically used for text / iconography in primary colored tabs / bottom
112  * navigation / etc.
113  */
114 private object HighContrastContentAlpha {
115     const val high: Float = 1.00f
116     const val medium: Float = 0.74f
117     const val disabled: Float = 0.38f
118 }
119 
120 /**
121  * Alpha levels for low luminance content in light theme, or high luminance content in dark theme.
122  *
123  * This content will typically be placed on grayscale surfaces, so the contrast here can be lower
124  * without sacrificing accessibility and legibility.
125  *
126  * These levels are typically used for body text on the main surface (white in light theme, grey in
127  * dark theme) and text / iconography in surface colored tabs / bottom navigation / etc.
128  */
129 private object LowContrastContentAlpha {
130     const val high: Float = 0.87f
131     const val medium: Float = 0.60f
132     const val disabled: Float = 0.38f
133 }
134