/*
* 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.wear.compose.material
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
/**
* Class holding typography definitions as defined by the Wear Material typography specification.
*
* The text styles in this typography are scaled according to the user's preferred font size in
* the system settings. Larger font sizes can be fixed if necessary in order to avoid pressure on
* screen space, because they are already sufficiently accessible.
* Here is an example of fixing the font size for Display1:
* @sample androidx.wear.compose.material.samples.FixedFontSize
*
* @property display1 Display1 is the largest headline. Displays are the largest text on the screen,
* reserved for short, important text or numerals.
*
* @property display2 Display2 is the second largest headline. Displays are the largest text on the
* screen, reserved for short, important text or numerals.
*
* @property display3 Display3 is the third largest headline. Displays are the largest text on the
* screen, reserved for short, important text or numerals.
*
* @property title1 Title1 is the largest title. Titles are smaller than Displays. They are
* typically reserved for medium-emphasis text that is shorter in length.
*
* @property title2 Title2 is the medium title. Titles are smaller than Displays. They are
* typically reserved for medium-emphasis text that is shorter in length.
*
* @property title3 Title3 is the smallest title. Titles are smaller than Displays. They are
* typically reserved for medium-emphasis text that is shorter in length.
*
* @property body1 Body1 is the largest body. Body texts are typically used for long-form writing as
* it works well for small text sizes. For longer sections of text, a serif or sans serif typeface
* is recommended.
*
* @property body2 Body2 is the smallest body. Body texts are typically used for long-form writing
* as it works well for small text sizes. For longer sections of text, a serif or sans serif
* typeface is recommended.
*
* @property button Button text is a call to action used in different types of buttons (such as
* text, outlined and contained buttons) and in tabs, dialogs, and cards. Button text is typically
* sans serif, using all caps text.
*
* @property caption1 Caption1 is the largest caption. Caption texts are the smallest font sizes.
* They are used on secondary content.
*
* @property caption2 Caption2 is the second largest caption. Caption texts are the smallest font
* sizes. They are used on secondary content.
*
* @property caption3 Caption3 is an exceptional small font size which is used for the extra
* long-form writing like legal texts.
*/
@Immutable
public class Typography internal constructor(
public val display1: TextStyle,
public val display2: TextStyle,
public val display3: TextStyle,
public val title1: TextStyle,
public val title2: TextStyle,
public val title3: TextStyle,
public val body1: TextStyle,
public val body2: TextStyle,
public val button: TextStyle,
public val caption1: TextStyle,
public val caption2: TextStyle,
public val caption3: TextStyle,
) {
public constructor (
defaultFontFamily: FontFamily = FontFamily.Default,
display1: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 40.sp,
lineHeight = 46.sp,
letterSpacing = 0.5.sp
),
display2: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 34.sp,
lineHeight = 40.sp,
letterSpacing = 1.sp
),
display3: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 30.sp,
lineHeight = 36.sp,
letterSpacing = 0.8.sp,
),
title1: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 24.sp,
lineHeight = 28.sp,
letterSpacing = 0.2.sp
),
title2: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 20.sp,
lineHeight = 24.sp,
letterSpacing = 0.2.sp
),
title3: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
lineHeight = 20.sp,
letterSpacing = 0.2.sp
),
body1: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 20.sp,
letterSpacing = 0.18.sp
),
body2: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 14.sp,
lineHeight = 18.sp,
letterSpacing = 0.2.sp
),
button: TextStyle = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 15.sp,
lineHeight = 19.sp,
letterSpacing = 0.38.sp
),
caption1: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
lineHeight = 18.sp,
letterSpacing = 0.1.sp
),
caption2: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 12.sp,
lineHeight = 16.sp,
letterSpacing = 0.1.sp
),
caption3: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 10.sp,
lineHeight = 14.sp,
letterSpacing = 0.1.sp
)
) : this(
display1 = display1.withDefaultFontFamily(defaultFontFamily),
display2 = display2.withDefaultFontFamily(defaultFontFamily),
display3 = display3.withDefaultFontFamily(defaultFontFamily),
title1 = title1.withDefaultFontFamily(defaultFontFamily),
title2 = title2.withDefaultFontFamily(defaultFontFamily),
title3 = title3.withDefaultFontFamily(defaultFontFamily),
body1 = body1.withDefaultFontFamily(defaultFontFamily),
body2 = body2.withDefaultFontFamily(defaultFontFamily),
button = button.withDefaultFontFamily(defaultFontFamily),
caption1 = caption1.withDefaultFontFamily(defaultFontFamily),
caption2 = caption2.withDefaultFontFamily(defaultFontFamily),
caption3 = caption3.withDefaultFontFamily(defaultFontFamily),
)
/**
* Returns a copy of this Typography, optionally overriding some of the values.
*/
public fun copy(
display1: TextStyle = this.display1,
display2: TextStyle = this.display2,
display3: TextStyle = this.display3,
title1: TextStyle = this.title1,
title2: TextStyle = this.title2,
title3: TextStyle = this.title3,
body1: TextStyle = this.body1,
body2: TextStyle = this.body2,
button: TextStyle = this.button,
caption1: TextStyle = this.caption1,
caption2: TextStyle = this.caption2,
caption3: TextStyle = this.caption3,
): Typography = Typography(
display1,
display2,
display3,
title1,
title2,
title3,
body1,
body2,
button,
caption1,
caption2,
caption3,
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Typography) return false
if (display1 != other.display1) return false
if (display2 != other.display2) return false
if (display3 != other.display3) return false
if (title1 != other.title1) return false
if (title2 != other.title2) return false
if (title3 != other.title3) return false
if (body1 != other.body1) return false
if (body2 != other.body2) return false
if (button != other.button) return false
if (caption1 != other.caption1) return false
if (caption2 != other.caption2) return false
if (caption3 != other.caption3) return false
return true
}
override fun hashCode(): Int {
var result = display1.hashCode()
result = 31 * result + display2.hashCode()
result = 31 * result + display3.hashCode()
result = 31 * result + title1.hashCode()
result = 31 * result + title2.hashCode()
result = 31 * result + title3.hashCode()
result = 31 * result + body1.hashCode()
result = 31 * result + body2.hashCode()
result = 31 * result + button.hashCode()
result = 31 * result + caption1.hashCode()
result = 31 * result + caption2.hashCode()
result = 31 * result + caption3.hashCode()
return result
}
override fun toString(): String {
return "Typography(display1=$display1, display2=$display2, display3=$display3, " +
"title1=$title1, title2=$title2, title3=$title3, body1=$body1, body2=$body2, " +
"button=$button, caption1=$caption1, caption2=$caption2, caption3=$caption3)"
}
}
/**
* @return [this] if there is a [FontFamily] defined, otherwise copies [this] with [default] as
* the [FontFamily].
*/
private fun TextStyle.withDefaultFontFamily(default: FontFamily): TextStyle {
return if (fontFamily != null) this else copy(fontFamily = default)
}
/**
* This Ambient holds on to the current definition of typography for this application as described
* by the Wear Material spec. You can read the values in it when creating custom components that
* want to use Wear Material types, as well as override the values when you want to re-style a part
* of your hierarchy. Material components related to text such as [Button] will use this Ambient
* to set values with which to style children text components.
*
* To access values within this ambient, use [MaterialTheme.typography].
*/
internal val LocalTypography = staticCompositionLocalOf { Typography() }