From 80408a807cf8acd7d8b903810fe226d53a8069ad Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Thu, 14 Dec 2023 14:15:25 +0100 Subject: [PATCH] Fix mentions font weight and horizontal padding (#2025) * Fix mentions font weight and horizontal padding --------- Co-authored-by: ElementBot --- changelog.d/1449.bugfix | 1 + .../designsystem/text/TextSyleToTypeface.kt | 42 +++++++++++++++++++ .../textcomposer/mentions/MentionSpan.kt | 12 ++++-- .../mentions/MentionSpanProvider.kt | 30 ++++++++++++- ...ionSpan-Day-18_19_null,NEXUS_5,1.0,en].png | 4 +- ...nSpan-Night-18_20_null,NEXUS_5,1.0,en].png | 4 +- 6 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 changelog.d/1449.bugfix create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/text/TextSyleToTypeface.kt diff --git a/changelog.d/1449.bugfix b/changelog.d/1449.bugfix new file mode 100644 index 0000000000..adcca27f05 --- /dev/null +++ b/changelog.d/1449.bugfix @@ -0,0 +1 @@ +Adjust mention pills font weight and horizontal padding diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/text/TextSyleToTypeface.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/text/TextSyleToTypeface.kt new file mode 100644 index 0000000000..aa445a6c99 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/text/TextSyleToTypeface.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * 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 io.element.android.libraries.designsystem.text + +import android.graphics.Typeface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalFontFamilyResolver +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontSynthesis +import androidx.compose.ui.text.font.FontWeight + +@Composable +fun TextStyle.rememberTypeface(): State { + val resolver: FontFamily.Resolver = LocalFontFamilyResolver.current + @Suppress("UNCHECKED_CAST") + return remember(resolver, this) { + resolver.resolve( + fontFamily = fontFamily, + fontWeight = fontWeight ?: FontWeight.Normal, + fontStyle = fontStyle ?: FontStyle.Normal, + fontSynthesis = fontSynthesis ?: FontSynthesis.All, + ) + } as State +} diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt index 6876073d3b..ff93bb754a 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpan.kt @@ -19,6 +19,7 @@ package io.element.android.libraries.textcomposer.mentions import android.graphics.Canvas import android.graphics.Paint import android.graphics.RectF +import android.graphics.Typeface import android.text.style.ReplacementSpan import kotlin.math.roundToInt @@ -26,6 +27,9 @@ class MentionSpan( val type: Type, val backgroundColor: Int, val textColor: Int, + val startPadding: Int, + val endPadding: Int, + val typeface: Typeface = Typeface.DEFAULT, ) : ReplacementSpan() { override fun getSize(paint: Paint, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int { @@ -34,7 +38,8 @@ class MentionSpan( if (mentionText != text.toString()) { actualEnd = end + 1 } - return paint.measureText(mentionText, start, actualEnd).roundToInt() + 40 + paint.typeface = typeface + return paint.measureText(mentionText, start, actualEnd).roundToInt() + startPadding + endPadding } override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) { @@ -46,11 +51,12 @@ class MentionSpan( val textWidth = paint.measureText(mentionText, start, actualEnd) // Extra vertical space to add below the baseline (y). This helps us center the span vertically val extraVerticalSpace = y + paint.ascent() + paint.descent() - top - val rect = RectF(x, top.toFloat(), x + textWidth + 40, y.toFloat() + extraVerticalSpace) + val rect = RectF(x, top.toFloat(), x + textWidth + startPadding + endPadding, y.toFloat() + extraVerticalSpace) paint.color = backgroundColor canvas.drawRoundRect(rect, rect.height() / 2, rect.height() / 2, paint) paint.color = textColor - canvas.drawText(mentionText, start, actualEnd, x + 20, y.toFloat(), paint) + paint.typeface = typeface + canvas.drawText(mentionText, start, actualEnd, x + startPadding, y.toFloat(), paint) } private fun getActualText(text: CharSequence?, start: Int): String { diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt index 9fb459237c..f7b28d65e8 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/MentionSpanProvider.kt @@ -17,16 +17,24 @@ package io.element.android.libraries.textcomposer.mentions import android.graphics.Color +import android.graphics.Typeface import android.view.ViewGroup import android.widget.TextView +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.text.buildSpannedString +import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.text.rememberTypeface import io.element.android.libraries.designsystem.theme.currentUserMentionPillBackground import io.element.android.libraries.designsystem.theme.currentUserMentionPillText import io.element.android.libraries.designsystem.theme.mentionPillBackground @@ -34,7 +42,6 @@ import io.element.android.libraries.designsystem.theme.mentionPillText import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.permalink.PermalinkParser -import io.element.android.compound.theme.ElementTheme @Stable class MentionSpanProvider( @@ -44,6 +51,10 @@ class MentionSpanProvider( private var otherTextColor: Int = 0, private var otherBackgroundColor: Int = Color.WHITE, ) { + private val paddingValues = PaddingValues(start = 4.dp, end = 6.dp) + + private val paddingValuesPx = mutableStateOf(0 to 0) + private val typeface = mutableStateOf(Typeface.DEFAULT) @Suppress("ComposableNaming") @Composable @@ -52,10 +63,18 @@ class MentionSpanProvider( currentUserBackgroundColor = ElementTheme.colors.currentUserMentionPillBackground.toArgb() otherTextColor = ElementTheme.colors.mentionPillText.toArgb() otherBackgroundColor = ElementTheme.colors.mentionPillBackground.toArgb() + + typeface.value = ElementTheme.typography.fontBodyLgMedium.rememberTypeface().value + with(LocalDensity.current) { + val leftPadding = paddingValues.calculateLeftPadding(LocalLayoutDirection.current).roundToPx() + val rightPadding = paddingValues.calculateRightPadding(LocalLayoutDirection.current).roundToPx() + paddingValuesPx.value = leftPadding to rightPadding + } } fun getMentionSpanFor(text: String, url: String): MentionSpan { val permalinkData = PermalinkParser.parse(url) + val (startPaddingPx, endPaddingPx) = paddingValuesPx.value return when { permalinkData is PermalinkData.UserLink -> { val isCurrentUser = permalinkData.userId == currentSessionId.value @@ -63,6 +82,9 @@ class MentionSpanProvider( type = MentionSpan.Type.USER, backgroundColor = if (isCurrentUser) currentUserBackgroundColor else otherBackgroundColor, textColor = if (isCurrentUser) currentUserTextColor else otherTextColor, + startPadding = startPaddingPx, + endPadding = endPaddingPx, + typeface = typeface.value, ) } text == "@room" && permalinkData is PermalinkData.FallbackLink -> { @@ -70,6 +92,9 @@ class MentionSpanProvider( type = MentionSpan.Type.USER, backgroundColor = otherBackgroundColor, textColor = otherTextColor, + startPadding = startPaddingPx, + endPadding = endPaddingPx, + typeface = typeface.value, ) } else -> { @@ -77,6 +102,9 @@ class MentionSpanProvider( type = MentionSpan.Type.ROOM, backgroundColor = otherBackgroundColor, textColor = otherTextColor, + startPadding = startPaddingPx, + endPadding = endPaddingPx, + typeface = typeface.value, ) } } diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en].png index e681270fd2..c152a6cc4b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Day-18_19_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8819c4ceeb21f96ba6d584ee78e4aca1a9cf2c87412f70e8f00eff09de61abc8 -size 43788 +oid sha256:e541cfb32e9d3095d6499c4c25e4bb4158c10886d59accf6006290bda344e8b2 +size 43927 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en].png index 5005f06919..17f88d03b3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.mentions_MentionSpan_null_MentionSpan-Night-18_20_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffbb340bd78c7806dd52be9454057b5ed4a3f9831f9ecb1c99b10c0759ba7f85 -size 37091 +oid sha256:06cd8d611bf8149d3c86b8d9a4aa5613dc9f32f89156081472f98d6410e98c4d +size 37107