feat: colourblind friendly status indicators
This commit is contained in:
parent
667449fc0b
commit
4a51c7c212
|
|
@ -2,31 +2,37 @@ package chat.stoat.composables.generic
|
|||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.BlendMode
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.CompositingStrategy
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.stoat.R
|
||||
import chat.stoat.core.model.schemas.AutumnResource
|
||||
import chat.stoat.api.settings.LoadedSettings
|
||||
import chat.stoat.core.model.data.STOAT_BASE
|
||||
import chat.stoat.core.model.data.STOAT_FILES
|
||||
import chat.stoat.core.model.schemas.AutumnResource
|
||||
|
||||
enum class Presence {
|
||||
Online,
|
||||
|
|
@ -68,17 +74,61 @@ fun presenceColour(presence: Presence): Color {
|
|||
}
|
||||
}
|
||||
|
||||
private fun Presence.iconResource(): Int = when (this) {
|
||||
Presence.Online -> R.drawable.ic_circle_24dp__fill
|
||||
Presence.Idle -> R.drawable.ic_bedtime_24dp
|
||||
Presence.Dnd -> R.drawable.ic_do_not_disturb_on_24dp
|
||||
Presence.Focus -> R.drawable.ic_circle_circle_24dp
|
||||
Presence.Offline -> R.drawable.ic_circle_24dp
|
||||
}
|
||||
|
||||
private fun Presence.descriptionResource(): Int = when (this) {
|
||||
Presence.Online -> R.string.status_online
|
||||
Presence.Idle -> R.string.status_idle
|
||||
Presence.Dnd -> R.string.status_dnd
|
||||
Presence.Focus -> R.string.status_focus
|
||||
Presence.Offline -> R.string.status_offline
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PresenceBadge(presence: Presence, size: Dp = 16.dp) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(size)
|
||||
.clip(CircleShape)
|
||||
.border(2.dp, MaterialTheme.colorScheme.background, CircleShape)
|
||||
.background(presenceColour(presence))
|
||||
)
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.size(size)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(presence.iconResource()),
|
||||
contentDescription = stringResource(presence.descriptionResource()),
|
||||
tint = presenceColour(presence),
|
||||
modifier = Modifier
|
||||
.size((size - PresenceCutoutPadding * 2).coerceAtLeast(0.dp))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val PresenceCutoutPadding = 2.dp
|
||||
|
||||
private fun Modifier.presenceCutout(diameter: Dp): Modifier =
|
||||
graphicsLayer {
|
||||
compositingStrategy = CompositingStrategy.Offscreen
|
||||
}.drawWithCache {
|
||||
val radius = diameter.toPx() / 2
|
||||
val center = Offset(
|
||||
x = if (layoutDirection == LayoutDirection.Ltr) size.width - radius else radius,
|
||||
y = size.height - radius
|
||||
)
|
||||
|
||||
onDrawWithContent {
|
||||
drawContent()
|
||||
drawCircle(
|
||||
color = Color.Transparent,
|
||||
radius = radius,
|
||||
center = center,
|
||||
blendMode = BlendMode.Clear
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun UserAvatar(
|
||||
|
|
@ -109,6 +159,13 @@ fun UserAvatar(
|
|||
modifier = Modifier
|
||||
.clip(shape)
|
||||
.size(size)
|
||||
.then(
|
||||
if (presence != null) {
|
||||
Modifier.presenceCutout(presenceSize)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
.then(
|
||||
if (onLongClick != null || onClick != null) {
|
||||
Modifier
|
||||
|
|
@ -129,6 +186,13 @@ fun UserAvatar(
|
|||
modifier = Modifier
|
||||
.clip(shape)
|
||||
.size(size)
|
||||
.then(
|
||||
if (presence != null) {
|
||||
Modifier.presenceCutout(presenceSize)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
.then(
|
||||
if (onLongClick != null || onClick != null) {
|
||||
Modifier
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M565,565Q600,530 600,480Q600,430 565,395Q530,360 480,360Q430,360 395,395Q360,430 360,480Q360,530 395,565Q430,600 480,600Q530,600 565,565ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M484,880Q400,880 326.5,848Q253,816 198.5,761.5Q144,707 112,633.5Q80,560 80,476Q80,330 173,218.5Q266,107 410,80Q392,179 421,273.5Q450,368 521,439Q592,510 686.5,539Q781,568 880,550Q854,694 742,787Q630,880 484,880Z"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Q397,880 324,848.5ZM621.5,621.5Q680,563 680,480Q680,397 621.5,338.5Q563,280 480,280Q397,280 338.5,338.5Q280,397 280,480Q280,563 338.5,621.5Q397,680 480,680Q563,680 621.5,621.5Z"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M280,520L680,520L680,440L280,440L280,520ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
|
||||
</vector>
|
||||
Loading…
Reference in New Issue