
Pairel
Conversation List Item
package com.composables.pairel.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import com.composables.compose.ripple.rememberRippleIndication
import com.composables.pairel.theme.ProvideContentColor
import com.composables.pairel.theme.ProvideTextStyle
import com.composables.pairel.theme.Theme
@Composable
fun ConversationListItem(
onClick: () -> Unit,
avatar: @Composable () -> Unit,
name: @Composable () -> Unit,
message: @Composable () -> Unit,
time: @Composable () -> Unit,
modifier: Modifier = Modifier,
unread: Boolean = false,
onClickLabel: String? = null,
) {
Row(
modifier =
modifier
.fillMaxWidth()
.clip(Theme.shapes.small)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRippleIndication(color = Theme.colors.onBackground),
onClickLabel = onClickLabel,
onClick = onClick,
)
.padding(horizontal = 20.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
avatar()
Spacer(Modifier.width(14.dp))
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
ProvideTextStyle(Theme.typography.label, name)
ProvideContentColor(Theme.colors.onBackgroundMuted, message)
}
Spacer(Modifier.width(8.dp))
Column(horizontalAlignment = Alignment.End) {
ProvideContentColor(Theme.colors.onBackgroundMuted) {
ProvideTextStyle(Theme.typography.caption, time)
}
if (unread) {
Spacer(Modifier.height(8.dp))
Box(Modifier.size(8.dp).clip(CircleShape).background(Theme.colors.primary))
}
}
}
}
package com.composables.pairel.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.*
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.*
import androidx.compose.ui.unit.*
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.composables.googlefonts.rememberGoogleFontFamily
@Immutable
data class ThemeColors(
val `background`: Color = Color(0xFFF8F5EF),
val `onBackground`: Color = Color(0xFF173D3A),
val `surface`: Color = Color(0xFFFFFFFF),
val `onSurface`: Color = Color(0xFF173D3A),
val `surfaceVariant`: Color = Color(0xFFECE8DD),
val `onSurfaceVariant`: Color = Color(0xFF173D3A),
val `primary`: Color = Color(0xFFF58C76),
val `onPrimary`: Color = Color(0xFF173D3A),
val `accent`: Color = Color(0xFF24675D),
val `onAccent`: Color = Color(0xFFF8F5EF),
val `textSelection`: Color = Color(0x6624675D),
val `onBackgroundMuted`: Color = Color(0xFF5A6B67),
val `onSurfaceInactive`: Color = Color(0xFF5A6B67),
val `border`: Color = Color(0xFFDCDDD4),
val `destructive`: Color = Color(0xFFB42318),
)
@Immutable
data class ThemeTypography(
val `display`: TextStyle =
TextStyle(
fontFamily = FontFamily.SansSerif,
fontSize = 46.sp,
lineHeight = 52.sp,
fontWeight = FontWeight(700),
),
val `headline`: TextStyle =
TextStyle(
fontFamily = FontFamily.SansSerif,
fontSize = 32.sp,
lineHeight = 38.sp,
fontWeight = FontWeight(700),
),
val `title`: TextStyle =
TextStyle(
fontFamily = FontFamily.SansSerif,
fontSize = 22.sp,
lineHeight = 28.sp,
fontWeight = FontWeight(700),
),
val `quote`: TextStyle =
TextStyle(
fontFamily = FontFamily.SansSerif,
fontSize = 23.sp,
lineHeight = 31.sp,
fontWeight = FontWeight(400),
),
val `body`: TextStyle =
TextStyle(
fontFamily = FontFamily.SansSerif,
fontSize = 16.sp,
lineHeight = 24.sp,
fontWeight = FontWeight(400),
),
val `label`: TextStyle =
TextStyle(
fontFamily = FontFamily.SansSerif,
fontSize = 16.sp,
lineHeight = 20.sp,
fontWeight = FontWeight(700),
),
val `caption`: TextStyle =
TextStyle(
fontFamily = FontFamily.SansSerif,
fontSize = 12.sp,
lineHeight = 16.sp,
fontWeight = FontWeight(700),
),
)
@Immutable
data class ThemeShapes(
val `small`: Shape = RoundedCornerShape(12.dp),
val `large`: Shape = RoundedCornerShape(24.dp),
val `fullyRounded`: Shape = RoundedCornerShape(50),
)
fun themeColors(dark: Boolean = false): ThemeColors = ThemeColors()
@Composable
fun resolveThemeTypography(typography: ThemeTypography = ThemeTypography()): ThemeTypography {
val font0 = rememberGoogleFontFamily("Fraunces", weights = intArrayOf(400, 700))
val font1 = rememberGoogleFontFamily("DM Sans", weights = intArrayOf(400, 700))
return typography.copy(
`display` = typography.`display`.copy(fontFamily = font0),
`headline` = typography.`headline`.copy(fontFamily = font1),
`title` = typography.`title`.copy(fontFamily = font1),
`quote` = typography.`quote`.copy(fontFamily = font0),
`body` = typography.`body`.copy(fontFamily = font1),
`label` = typography.`label`.copy(fontFamily = font1),
`caption` = typography.`caption`.copy(fontFamily = font1),
)
}
private val LocalColors = staticCompositionLocalOf<ThemeColors> { error("Theme is missing") }
private val LocalTypography =
staticCompositionLocalOf<ThemeTypography> { error("Theme is missing") }
private val LocalSpace = staticCompositionLocalOf { 4.dp }
private val LocalShapes = staticCompositionLocalOf<ThemeShapes> { error("Theme is missing") }
val LocalContentColor = compositionLocalOf<Color> { error("Theme is missing") }
val LocalTextStyle = compositionLocalOf<TextStyle> { error("Theme is missing") }
object Theme {
val colors: ThemeColors
@Composable get() = LocalColors.current
val typography: ThemeTypography
@Composable get() = LocalTypography.current
val shapes: ThemeShapes
@Composable get() = LocalShapes.current
}
val Space: Dp
@Composable get() = LocalSpace.current
@Composable
fun PairelTheme(
colors: ThemeColors = themeColors(isSystemInDarkTheme()),
typography: ThemeTypography = resolveThemeTypography(),
space: Dp = 4.dp,
shapes: ThemeShapes = ThemeShapes(),
contentColor: Color = colors.onBackground,
textStyle: TextStyle = typography.body,
content: @Composable () -> Unit,
) {
CompositionLocalProvider(
LocalColors provides colors,
LocalTypography provides typography,
LocalSpace provides space,
LocalShapes provides shapes,
LocalContentColor provides contentColor,
LocalTextStyle provides textStyle,
LocalTextSelectionColors provides
TextSelectionColors(
handleColor = colors.accent,
backgroundColor = colors.textSelection,
),
content = content,
)
}
@Composable
fun ProvideContentColor(color: Color, content: @Composable () -> Unit) {
CompositionLocalProvider(LocalContentColor provides color, content = content)
}
@Composable
fun ProvideTextStyle(style: TextStyle, content: @Composable () -> Unit) {
CompositionLocalProvider(
LocalTextStyle provides LocalTextStyle.current.merge(style),
content = content,
)
}


























