/*
* Copyright 2019 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.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
/**
* <a href="https://material.io/design/typography/the-type-system.html#type-scale" class="external" target="_blank">Material Design type scale</a>.
*
* The Material Design type scale includes a range of contrasting styles that support the needs of
* your product and its content.
*
* The type scale is a combination of thirteen styles that are supported by the type system. It
* contains reusable categories of text, each with an intended application and meaning.
*
* ![Typography image](https://developer.android.com/images/reference/androidx/compose/material/typography.png)
*
* @property h1 h1 is the largest headline, reserved for short, important text or numerals.
* For headlines, you can choose an expressive font, such as a display, handwritten, or script
* style. These unconventional font designs have details and intricacy that help attract the eye.
* @property h2 h2 is the second largest headline, reserved for short, important text or numerals.
* For headlines, you can choose an expressive font, such as a display, handwritten, or script
* style. These unconventional font designs have details and intricacy that help attract the eye.
* @property h3 h3 is the third largest headline, reserved for short, important text or numerals.
* For headlines, you can choose an expressive font, such as a display, handwritten, or script
* style. These unconventional font designs have details and intricacy that help attract the eye.
* @property h4 h4 is the fourth largest headline, reserved for short, important text or numerals.
* For headlines, you can choose an expressive font, such as a display, handwritten, or script
* style. These unconventional font designs have details and intricacy that help attract the eye.
* @property h5 h5 is the fifth largest headline, reserved for short, important text or numerals.
* For headlines, you can choose an expressive font, such as a display, handwritten, or script
* style. These unconventional font designs have details and intricacy that help attract the eye.
* @property h6 h6 is the sixth largest headline, reserved for short, important text or numerals.
* For headlines, you can choose an expressive font, such as a display, handwritten, or script
* style. These unconventional font designs have details and intricacy that help attract the eye.
* @property subtitle1 subtitle1 is the largest subtitle, and is typically reserved for
* medium-emphasis text that is shorter in length. Serif or sans serif typefaces work well for
* subtitles.
* @property subtitle2 subtitle2 is the smallest subtitle, and is typically reserved for
* medium-emphasis text that is shorter in length. Serif or sans serif typefaces work well for
* subtitles.
* @property body1 body1 is the largest body, and is 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, and is 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 caption caption is one of the smallest font sizes. It is used sparingly to
* annotate imagery or to introduce a headline.
* @property overline overline is one of the smallest font sizes. It is used sparingly to
* annotate imagery or to introduce a headline.
*/
@Immutable
class Typography internal constructor(
val h1: TextStyle,
val h2: TextStyle,
val h3: TextStyle,
val h4: TextStyle,
val h5: TextStyle,
val h6: TextStyle,
val subtitle1: TextStyle,
val subtitle2: TextStyle,
val body1: TextStyle,
val body2: TextStyle,
val button: TextStyle,
val caption: TextStyle,
val overline: TextStyle
) {
/**
* Constructor to create a [Typography]. For information on the types of style defined in
* this constructor, see the property documentation for [Typography].
*
* @param defaultFontFamily the default [FontFamily] to be used for [TextStyle]s provided in
* this constructor. This default will be used if the [FontFamily] on the [TextStyle] is `null`.
* @param h1 h1 is the largest headline, reserved for short, important text or numerals.
* @param h2 h2 is the second largest headline, reserved for short, important text or numerals.
* @param h3 h3 is the third largest headline, reserved for short, important text or numerals.
* @param h4 h4 is the fourth largest headline, reserved for short, important text or numerals.
* @param h5 h5 is the fifth largest headline, reserved for short, important text or numerals.
* @param h6 h6 is the sixth largest headline, reserved for short, important text or numerals.
* @param subtitle1 subtitle1 is the largest subtitle, and is typically reserved for
* medium-emphasis text that is shorter in length.
* @param subtitle2 subtitle2 is the smallest subtitle, and is typically reserved for
* medium-emphasis text that is shorter in length.
* @param body1 body1 is the largest body, and is typically used for long-form writing as it
* works well for small text sizes.
* @param body2 body2 is the smallest body, and is typically used for long-form writing as it
* works well for small text sizes.
* @param 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.
* @param caption caption is one of the smallest font sizes. It is used sparingly to annotate
* imagery or to introduce a headline.
* @param overline overline is one of the smallest font sizes. It is used sparingly to annotate
* imagery or to introduce a headline.
*/
constructor(
defaultFontFamily: FontFamily = FontFamily.Default,
h1: TextStyle = TextStyle(
fontWeight = FontWeight.Light,
fontSize = 96.sp,
letterSpacing = (-1.5).sp
),
h2: TextStyle = TextStyle(
fontWeight = FontWeight.Light,
fontSize = 60.sp,
letterSpacing = (-0.5).sp
),
h3: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 48.sp,
letterSpacing = 0.sp
),
h4: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 34.sp,
letterSpacing = 0.25.sp
),
h5: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 24.sp,
letterSpacing = 0.sp
),
h6: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 20.sp,
letterSpacing = 0.15.sp
),
subtitle1: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
letterSpacing = 0.15.sp
),
subtitle2: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
letterSpacing = 0.1.sp
),
body1: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
letterSpacing = 0.5.sp
),
body2: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 14.sp,
letterSpacing = 0.25.sp
),
button: TextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
letterSpacing = 1.25.sp
),
caption: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 12.sp,
letterSpacing = 0.4.sp
),
overline: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 10.sp,
letterSpacing = 1.5.sp
)
) : this(
h1 = h1.withDefaultFontFamily(defaultFontFamily),
h2 = h2.withDefaultFontFamily(defaultFontFamily),
h3 = h3.withDefaultFontFamily(defaultFontFamily),
h4 = h4.withDefaultFontFamily(defaultFontFamily),
h5 = h5.withDefaultFontFamily(defaultFontFamily),
h6 = h6.withDefaultFontFamily(defaultFontFamily),
subtitle1 = subtitle1.withDefaultFontFamily(defaultFontFamily),
subtitle2 = subtitle2.withDefaultFontFamily(defaultFontFamily),
body1 = body1.withDefaultFontFamily(defaultFontFamily),
body2 = body2.withDefaultFontFamily(defaultFontFamily),
button = button.withDefaultFontFamily(defaultFontFamily),
caption = caption.withDefaultFontFamily(defaultFontFamily),
overline = overline.withDefaultFontFamily(defaultFontFamily)
)
/**
* Returns a copy of this Typography, optionally overriding some of the values.
*/
fun copy(
h1: TextStyle = this.h1,
h2: TextStyle = this.h2,
h3: TextStyle = this.h3,
h4: TextStyle = this.h4,
h5: TextStyle = this.h5,
h6: TextStyle = this.h6,
subtitle1: TextStyle = this.subtitle1,
subtitle2: TextStyle = this.subtitle2,
body1: TextStyle = this.body1,
body2: TextStyle = this.body2,
button: TextStyle = this.button,
caption: TextStyle = this.caption,
overline: TextStyle = this.overline
): Typography = Typography(
h1 = h1,
h2 = h2,
h3 = h3,
h4 = h4,
h5 = h5,
h6 = h6,
subtitle1 = subtitle1,
subtitle2 = subtitle2,
body1 = body1,
body2 = body2,
button = button,
caption = caption,
overline = overline
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Typography) return false
if (h1 != other.h1) return false
if (h2 != other.h2) return false
if (h3 != other.h3) return false
if (h4 != other.h4) return false
if (h5 != other.h5) return false
if (h6 != other.h6) return false
if (subtitle1 != other.subtitle1) return false
if (subtitle2 != other.subtitle2) return false
if (body1 != other.body1) return false
if (body2 != other.body2) return false
if (button != other.button) return false
if (caption != other.caption) return false
if (overline != other.overline) return false
return true
}
override fun hashCode(): Int {
var result = h1.hashCode()
result = 31 * result + h2.hashCode()
result = 31 * result + h3.hashCode()
result = 31 * result + h4.hashCode()
result = 31 * result + h5.hashCode()
result = 31 * result + h6.hashCode()
result = 31 * result + subtitle1.hashCode()
result = 31 * result + subtitle2.hashCode()
result = 31 * result + body1.hashCode()
result = 31 * result + body2.hashCode()
result = 31 * result + button.hashCode()
result = 31 * result + caption.hashCode()
result = 31 * result + overline.hashCode()
return result
}
override fun toString(): String {
return "Typography(h1=$h1, h2=$h2, h3=$h3, h4=$h4, h5=$h5, h6=$h6, " +
"subtitle1=$subtitle1, subtitle2=$subtitle2, body1=$body1, " +
"body2=$body2, button=$button, caption=$caption, overline=$overline)"
}
}
/**
* @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 CompositionLocal holds on to the current definition of typography for this application as
* described by the Material spec. You can read the values in it when creating custom components
* that want to use 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
* CompositionLocal to set values with which to style children text components.
*
* To access values within this CompositionLocal, use [MaterialTheme.typography].
*/
internal val LocalTypography = staticCompositionLocalOf { Typography() }