fix(#207): dynamic contrast adjustments for chat bubbles legibility
This commit is contained in:
1 parent
7ce19cd52c
commit
315e1097b2
1 file changed
+46
-13
@@ -50,6 +50,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.luminance
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.platform.LocalClipboardManager
|
import androidx.compose.ui.platform.LocalClipboardManager
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
@@ -167,6 +168,23 @@ private fun UserBubble(
|
|||||||
MaterialTheme.colorScheme.secondary,
|
MaterialTheme.colorScheme.secondary,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
val primary = MaterialTheme.colorScheme.primary
|
||||||
|
val secondary = MaterialTheme.colorScheme.secondary
|
||||||
|
val avgLuminance = (primary.luminance() + secondary.luminance()) / 2f
|
||||||
|
val userBubbleTextColor =
|
||||||
|
if (avgLuminance > 0.5f) {
|
||||||
|
if (MaterialTheme.colorScheme.onPrimary.luminance() < 0.5f) {
|
||||||
|
MaterialTheme.colorScheme.onPrimary
|
||||||
|
} else {
|
||||||
|
Color(0xFF1A1A24)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (MaterialTheme.colorScheme.onPrimary.luminance() > 0.5f) {
|
||||||
|
MaterialTheme.colorScheme.onPrimary
|
||||||
|
} else {
|
||||||
|
Color.White
|
||||||
|
}
|
||||||
|
}
|
||||||
Box {
|
Box {
|
||||||
Surface(
|
Surface(
|
||||||
modifier =
|
modifier =
|
||||||
@@ -194,19 +212,21 @@ private fun UserBubble(
|
|||||||
SelectionContainer {
|
SelectionContainer {
|
||||||
Text(
|
Text(
|
||||||
text = highlightedText,
|
text = highlightedText,
|
||||||
color = Color.White,
|
color = userBubbleTextColor,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(
|
if (!message.isStreaming) {
|
||||||
text = formatTimestamp(message.timestamp),
|
Text(
|
||||||
color = Color.White.copy(alpha = 0.7f),
|
text = formatTimestamp(message.timestamp),
|
||||||
style = MaterialTheme.typography.labelSmall,
|
color = userBubbleTextColor.copy(alpha = 0.6f),
|
||||||
modifier =
|
style = MaterialTheme.typography.labelSmall,
|
||||||
Modifier
|
modifier =
|
||||||
.align(Alignment.End)
|
Modifier
|
||||||
.padding(top = 4.dp),
|
.align(Alignment.End)
|
||||||
)
|
.padding(top = 4.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +275,20 @@ private fun AssistantBubble(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val bubbleColor = if (isDarkTheme) AssistantBubble else AssistantBubbleLight
|
val bubbleColor = if (isDarkTheme) AssistantBubble else AssistantBubbleLight
|
||||||
val textColor = MaterialTheme.colorScheme.onSurface
|
val textColor =
|
||||||
|
if (bubbleColor.luminance() > 0.5f) {
|
||||||
|
if (MaterialTheme.colorScheme.onSurface.luminance() < 0.5f) {
|
||||||
|
MaterialTheme.colorScheme.onSurface
|
||||||
|
} else {
|
||||||
|
Color(0xFF1A1A24)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (MaterialTheme.colorScheme.onSurface.luminance() > 0.5f) {
|
||||||
|
MaterialTheme.colorScheme.onSurface
|
||||||
|
} else {
|
||||||
|
Color(0xFFE8E6EE)
|
||||||
|
}
|
||||||
|
}
|
||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
var showCopyButton by remember { mutableStateOf(false) }
|
var showCopyButton by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
@@ -786,7 +819,7 @@ private fun RichText(
|
|||||||
// Search match highlight
|
// Search match highlight
|
||||||
searchQuery.isNotEmpty() &&
|
searchQuery.isNotEmpty() &&
|
||||||
src.regionMatches(i, searchQuery, 0, searchQuery.length, ignoreCase = true) -> {
|
src.regionMatches(i, searchQuery, 0, searchQuery.length, ignoreCase = true) -> {
|
||||||
withStyle(SpanStyle(background = searchHighlightColor)) {
|
withStyle(SpanStyle(background = searchHighlightColor, color = Color(0xFF1A1A24))) {
|
||||||
append(src.substring(i, i + searchQuery.length))
|
append(src.substring(i, i + searchQuery.length))
|
||||||
}
|
}
|
||||||
i += searchQuery.length
|
i += searchQuery.length
|
||||||
@@ -843,7 +876,7 @@ private fun buildHighlightedString(
|
|||||||
append(text.substring(i, matchEnd))
|
append(text.substring(i, matchEnd))
|
||||||
}
|
}
|
||||||
// Append the match highlighted
|
// Append the match highlighted
|
||||||
withStyle(SpanStyle(background = highlightColor)) {
|
withStyle(SpanStyle(background = highlightColor, color = Color(0xFF1A1A24))) {
|
||||||
append(text.substring(matchEnd, matchEnd + query.length))
|
append(text.substring(matchEnd, matchEnd + query.length))
|
||||||
}
|
}
|
||||||
i = matchEnd + query.length
|
i = matchEnd + query.length
|
||||||
|
|||||||
Reference in new issue
Block a user