Skip to content

Commit

Permalink
Measure tag's actual width to know when to ellipsize or not
Browse files Browse the repository at this point in the history
  • Loading branch information
LunarX committed Feb 21, 2024
1 parent 197f2d7 commit eef7adf
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ class ThreadListAdapter @Inject constructor(
tag = thread.folderName,
tagColor = TagColor(R.color.folderTagBackground, R.color.folderTagTextColor),
ellipsizeConfiguration = SubjectFormatter.EllipsizeConfiguration(
maxWidth = context.resources.getDimension(R.dimen.folderNameTagMaxSize).toInt(),
maxWidth = context.resources.getDimension(R.dimen.folderNameTagMaxSize),
truncateAt = TruncateAt.END,
),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Infomaniak Mail - Android
* Copyright (C) 2023 Infomaniak Network SA
* Copyright (C) 2023-2024 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -95,5 +95,7 @@ class RoundedBackgroundSpan(
private const val LEFT_MARGIN = 4
private const val PADDING = 16
private const val VERTICAL_OFFSET = 4

fun getTotalHorizontalSpace(): Int = PADDING * 2 + LEFT_MARGIN
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package com.infomaniak.mail.ui.main.thread

import android.content.Context
import android.content.res.Resources
import android.graphics.Paint
import android.text.StaticLayout
import android.text.TextPaint
Expand All @@ -29,20 +28,21 @@ import com.infomaniak.mail.MatomoMail.trackExternalEvent
import com.infomaniak.mail.R
import com.infomaniak.mail.data.models.thread.Thread
import com.infomaniak.mail.utils.ExternalUtils.findExternalRecipients
import com.infomaniak.mail.utils.Utils
import com.infomaniak.mail.utils.extensions.MergedContactDictionary
import com.infomaniak.mail.utils.extensions.formatSubject
import com.infomaniak.mail.utils.extensions.postfixWithTag
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class SubjectFormatter @Inject constructor(private val context: Context) {
class SubjectFormatter @Inject constructor(private val appContext: Context) {

fun generateSubjectContent(
subjectData: SubjectData,
onExternalClicked: (String) -> Unit,
): Pair<String, CharSequence> = with(subjectData) {
val subject = context.formatSubject(thread.subject)
val subject = appContext.formatSubject(thread.subject)

val spannedSubjectWithExternal = handleExternals(subject, onExternalClicked)
val spannedSubjectWithFolder = handleFolders(spannedSubjectWithExternal)
Expand All @@ -67,14 +67,14 @@ class SubjectFormatter @Inject constructor(private val context: Context) {
externalRecipientQuantity: Int,
externalRecipientEmail: String?,
onExternalClicked: (String) -> Unit,
) = context.postfixWithTag(
) = appContext.postfixWithTag(
previousContent,
R.string.externalTag,
TagColor(R.color.externalTagBackground, R.color.externalTagOnBackground),
) {
context.trackExternalEvent("threadTag")
appContext.trackExternalEvent("threadTag")

val description = context.resources.getQuantityString(
val description = appContext.resources.getQuantityString(
R.plurals.externalDialogDescriptionExpeditor,
externalRecipientQuantity,
externalRecipientEmail,
Expand All @@ -94,7 +94,7 @@ class SubjectFormatter @Inject constructor(private val context: Context) {
previousContent: CharSequence,
folderName: String,
ellipsizeConfiguration: EllipsizeConfiguration?,
) = context.postfixWithTag(
) = appContext.postfixWithTag(
previousContent,
folderName,
TagColor(R.color.folderTagBackground, R.color.folderTagTextColor),
Expand All @@ -104,14 +104,29 @@ class SubjectFormatter @Inject constructor(private val context: Context) {
private fun getFolderName(thread: Thread) = if (thread.messages.size > 1) "" else thread.folderName

private fun getEllipsizeConfiguration(tag: String): EllipsizeConfiguration? {
val paddingsInPixels = (context.resources.getDimension(R.dimen.threadHorizontalMargin) * 2).toInt()
val widthInPixels = Resources.getSystem().displayMetrics.widthPixels - paddingsInPixels
val paddingsInPixels = (appContext.resources.getDimension(R.dimen.threadHorizontalMargin) * 2).toInt()
val containerWidth = appContext.resources.displayMetrics.widthPixels - paddingsInPixels

val tagTextPaint = getTagsPaint(context)
val layoutWithTag = StaticLayout.Builder.obtain(tag, 0, tag.length, tagTextPaint, widthInPixels).build()

return layoutWithTag.takeIf { it.lineCount > 1 }?.let {
EllipsizeConfiguration(widthInPixels, TruncateAt.MIDDLE, withNewLine = true)
// spannedTagForMeasurement only contains the tag's text itself and its formatting, nothing more nothing less
val spannedTagForMeasurement = with(postFixWithFolder("", tag, null)) {
subSequence(Utils.TAG_SEPARATOR.length, length)
}
val layout = StaticLayout.Builder.obtain(
spannedTagForMeasurement,
0,
spannedTagForMeasurement.length,
TextPaint(Paint.ANTI_ALIAS_FLAG),
containerWidth,
).build()
val tagWidth = layout.getLineWidth(0)

return if (tagWidth >= containerWidth) {
val roundedBackgroundSpanHorizontalSpace = RoundedBackgroundSpan.getTotalHorizontalSpace()
val tagAvailableWidth = (containerWidth - roundedBackgroundSpanHorizontalSpace).toFloat()

EllipsizeConfiguration(tagAvailableWidth, TruncateAt.MIDDLE)
} else {
null
}
}

Expand All @@ -123,9 +138,8 @@ class SubjectFormatter @Inject constructor(private val context: Context) {
)

data class EllipsizeConfiguration(
val maxWidth: Int,
val maxWidth: Float,
val truncateAt: TruncateAt = TruncateAt.MIDDLE,
val withNewLine: Boolean = false,
)

data class TagColor(@ColorRes val backgroundColorRes: Int, @ColorRes val textColorRes: Int)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -515,31 +515,29 @@ fun Context.postfixWithTag(
*/
fun Context.postfixWithTag(
original: CharSequence = "",
tag: CharSequence,
tag: String,
tagColor: TagColor,
ellipsizeConfiguration: EllipsizeConfiguration? = null,
onClicked: (() -> Unit)? = null,
): Spannable {

fun getEllipsizedTag(): CharSequence {
val baseTag = "$TAG_SEPARATOR$tag"
fun getEllipsizedTagContent(): String {
return ellipsizeConfiguration?.let {
val modifiedTag = if (ellipsizeConfiguration.withNewLine) "\n$baseTag" else baseTag
TextUtils.ellipsize(
modifiedTag,
tag,
getTagsPaint(this),
ellipsizeConfiguration.maxWidth.toFloat(),
ellipsizeConfiguration.maxWidth,
ellipsizeConfiguration.truncateAt
)
} ?: baseTag
).toString()
} ?: tag
}

val ellipsizedTag = getEllipsizedTag()
val postFixed = TextUtils.concat(original, ellipsizedTag)
val ellipsizedTagContent = getEllipsizedTagContent()
val postFixed = TextUtils.concat(original, TAG_SEPARATOR, ellipsizedTagContent)

return postFixed.toSpannable().apply {
val startIndex = original.length + TAG_SEPARATOR.length
val endIndex = startIndex + ellipsizedTag.length - TAG_SEPARATOR.length
val endIndex = startIndex + ellipsizedTagContent.length

with(tagColor) {
setTagSpan(this@postfixWithTag, startIndex, endIndex, backgroundColorRes, textColorRes)
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/layout/fragment_thread.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@
tools:text="@tools:sample/lorem[7]" />

</com.google.android.material.appbar.CollapsingToolbarLayout>

</com.google.android.material.appbar.AppBarLayout>

<androidx.core.widget.NestedScrollView
Expand Down

0 comments on commit eef7adf

Please sign in to comment.