Skip to content

Commit

Permalink
Add highlighted text in the title to the upload progress screen
Browse files Browse the repository at this point in the history
  • Loading branch information
LunarX committed Nov 8, 2024
1 parent c809b93 commit e1bd3ca
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* Infomaniak SwissTransfer - Android
* Copyright (C) 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.swisstransfer.ui.components

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import com.infomaniak.swisstransfer.R
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import com.infomaniak.swisstransfer.ui.utils.PreviewLightAndDark
import kotlin.math.cos
import kotlin.math.sin

@Composable
fun HighlighterText(
templateRes: Int,
argumentRes: Int,
style: TextStyle,
verticalPadding: Float = 2f, // TODO
horizontalPadding: Float = 24f, // TODO
angleDegrees: Float = -3f, // TODO
) {
val template = stringResource(templateRes)
val argument = stringResource(argumentRes)
val text = String.format(template, argument)

val highlighterColor = SwissTransferTheme.colors.highlighterColor

var highlighterPath by remember { mutableStateOf<Path?>(null) }

Text(
text = text,
style = style,
onTextLayout = { layoutResult ->
val boundingBoxes = layoutResult.getArgumentBoundingBoxes(text, argument)
highlighterPath = boundingBoxes.transformForHighlighterStyle(verticalPadding, horizontalPadding, angleDegrees)
},
modifier = Modifier.drawBehind {
highlighterPath?.let {
drawPath(it, style = Fill, color = highlighterColor)
}
}
)
}

private fun TextLayoutResult.getArgumentBoundingBoxes(text: String, argument: String): List<Rect> {
val startIndex = text.indexOf(argument)
return getBoundingBoxesForRange(start = startIndex, end = startIndex + argument.count())
}

private fun List<Rect>.transformForHighlighterStyle(
verticalPadding: Float,
horizontalPadding: Float,
angleDegrees: Float,
): Path = Path().apply {
forEach { boundingBox ->
addPath(boundingBox.transformForHighlighterStyle(verticalPadding, horizontalPadding, angleDegrees))
}
}

private fun Rect.transformForHighlighterStyle(verticalPadding: Float, horizontalPadding: Float, angleDegrees: Float): Path {
return getRotatedRectanglePath(
Rect(
left = left - horizontalPadding,
top = top - verticalPadding,
right = right + horizontalPadding,
bottom = bottom + verticalPadding,
),
angleDegrees = angleDegrees,
)
}

private fun getRotatedRectanglePath(rect: Rect, angleDegrees: Float): Path {
val centerX = rect.left + (rect.width / 2)
val centerY = rect.top + (rect.height / 2)

val angleRadians = Math.toRadians(angleDegrees.toDouble())

// Function to rotate a point around the center
fun rotatePoint(x: Float, y: Float, centerX: Float, centerY: Float, angleRadians: Double): Offset {
val dx = x - centerX
val dy = y - centerY
val cosAngle = cos(angleRadians)
val sinAngle = sin(angleRadians)
val newX = (dx * cosAngle - dy * sinAngle + centerX).toFloat()
val newY = (dx * sinAngle + dy * cosAngle + centerY).toFloat()
return Offset(newX, newY)
}

val topLeft = rotatePoint(rect.left, rect.top, centerX, centerY, angleRadians)
val topRight = rotatePoint(rect.right, rect.top, centerX, centerY, angleRadians)
val bottomRight = rotatePoint(rect.right, rect.bottom, centerX, centerY, angleRadians)
val bottomLeft = rotatePoint(rect.left, rect.bottom, centerX, centerY, angleRadians)

return Path().apply {
moveTo(topLeft.x, topLeft.y)
lineTo(topRight.x, topRight.y)
lineTo(bottomRight.x, bottomRight.y)
lineTo(bottomLeft.x, bottomLeft.y)
close()
}
}

private fun TextLayoutResult.getBoundingBoxesForRange(start: Int, end: Int): List<Rect> {
var previousRect: Rect? = null
var firstLineCharRect: Rect? = null
val boundingBoxes = mutableListOf<Rect>()

for (index in start..end) {
val rect = getBoundingBox(index)
val isLastRect = index == end

// Single char case
if (isLastRect && firstLineCharRect == null) {
firstLineCharRect = rect
previousRect = rect
}

// `rect.right` is zero for the last space in each line
// Might be an issue: https://issuetracker.google.com/issues/197146630
if (!isLastRect && rect.right == 0f) continue

if (firstLineCharRect == null) {
firstLineCharRect = rect
} else if (previousRect != null) {
if (previousRect.bottom != rect.bottom || isLastRect) {
boundingBoxes.add(
firstLineCharRect.copy(right = previousRect.right)
)
firstLineCharRect = rect
}
}
previousRect = rect
}
return boundingBoxes
}


@PreviewLightAndDark
@Composable
private fun Preview() {
SwissTransferTheme {
Surface {
Box(modifier = Modifier.padding(20.dp)) {
HighlighterText(
templateRes = R.string.uploadProgressTitleTemplate,
argumentRes = R.string.uploadProgressTitleArgument,
style = SwissTransferTheme.typography.bodyMedium
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private fun getShowPasswordButton(shouldShowPassword: Boolean, onClick: () -> Un

@Composable
@Preview
fun Preview() {
private fun Preview() {
SwissTransferTheme {
Surface {
Column(Modifier.padding(Margin.Medium)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import com.infomaniak.swisstransfer.R
import com.infomaniak.swisstransfer.ui.components.HighlighterText
import com.infomaniak.swisstransfer.ui.screen.newtransfer.upload.UploadProgressAdType
import com.infomaniak.swisstransfer.ui.theme.Dimens
import com.infomaniak.swisstransfer.ui.theme.Margin
Expand All @@ -45,7 +46,13 @@ fun ColumnScope.AdHeader(adScreenType: UploadProgressAdType) {
horizontalAlignment = Alignment.CenterHorizontally,
) {
Spacer(modifier = Modifier.height(Margin.Giant))
Text(stringResource(R.string.uploadSuccessTitle), style = SwissTransferTheme.typography.bodyMedium)

HighlighterText(
templateRes = R.string.uploadProgressTitleTemplate,
argumentRes = R.string.uploadProgressTitleArgument,
style = SwissTransferTheme.typography.bodyMedium,
)

Spacer(modifier = Modifier.height(Margin.Huge))
Text(
text = adScreenType.description(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,5 @@ val CustomDarkColorScheme = CustomColorScheme(
transferFilePreviewOverflow = Color(dark3),
onTransferFilePreviewOverflow = Color(green_main),
transferListStroke = Color(green_main),
highlighterColor = Color(green_dark),
)
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,5 @@ val CustomLightColorScheme = CustomColorScheme(
transferFilePreviewOverflow = Color(green_dark),
onTransferFilePreviewOverflow = Color(green_contrast),
transferListStroke = Color(green_dark),
highlighterColor = Color(green_secondary),
)
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ data class CustomColorScheme(
val transferFilePreviewOverflow: Color = Color.Unspecified,
val onTransferFilePreviewOverflow: Color = Color.Unspecified,
val transferListStroke: Color = Color.Unspecified,
val highlighterColor: Color = Color.Unspecified,
)

private val Shapes = Shapes(
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@
<string name="uploadProgressDescriptionTemplateIndependence">Wir entwickeln %s Ohne Kompromisse bei Ökologie, Privatsphäre und Menschen.</string>
<string name="uploadErrorDescription">Die Übertragung hat nicht funktioniert, gib ihr noch eine Chance. Wenn das Problem weiterhin besteht, wende dich an unseren Support.</string>
<string name="uploadErrorTitle">Was ist das denn?</string>
<string name="uploadProgressTitleArgument">zeichnet uns aus</string>
<string name="uploadProgressTitleTemplate">Was %s?</string>
<plurals name="uploadSuccessEmailDescription">
<item quantity="one">Der Download-Link wurde erfolgreich an den folgenden Empfänger gesendet:</item>
<item quantity="other">Der Download-Link wurde an die folgenden Empfänger gesendet:</item>
Expand All @@ -134,7 +136,6 @@
<string name="uploadSuccessLinkDescription">Lass diesen QR-Code in deiner Umgebung scannen, um deine Dateien weiterzugeben, oder kopiere den untenstehenden Link.</string>
<string name="uploadSuccessLinkTitle">Deine Überweisung ist fertig!</string>
<string name="uploadSuccessQrTitle">Dein QR-Code ist fertig!</string>
<string name="uploadSuccessTitle">Was zeichnet uns aus?</string>
<string name="uploadSuccessTransferInProgress">Transfer wird durchgeführt…</string>
<string name="urlAbout">https://www.infomaniak.com/de/about</string>
<string name="urlUserReportAndroid">https://feedback.userreport.com/9abc7665-a78e-4fd2-aa41-a47a8b867fcd/#ideas/popular</string>
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@
<string name="uploadProgressDescriptionTemplateIndependence">Desarrollamos %s Sin comprometer la ecología, la privacidad ni a las personas.</string>
<string name="uploadErrorDescription">La transferencia no ha funcionado, dale otra oportunidad. Si el problema persiste, ponte en contacto con nuestro equipo de asistencia.</string>
<string name="uploadErrorTitle">¿Pero qué, qué?</string>
<string name="uploadProgressTitleArgument">diferencia</string>
<string name="uploadProgressTitleTemplate">¿Qué nos %s?</string>
<plurals name="uploadSuccessEmailDescription">
<item quantity="one">El enlace de descarga se ha enviado al siguiente destinatario:</item>
<item quantity="other">El enlace de descarga se ha enviado a los siguientes destinatarios:</item>
Expand All @@ -134,7 +136,6 @@
<string name="uploadSuccessLinkDescription">Escanea este código QR a tu alrededor para compartir tus archivos o copia el enlace que aparece a continuación.</string>
<string name="uploadSuccessLinkTitle">Su transferencia está lista</string>
<string name="uploadSuccessQrTitle">Su código QR está listo</string>
<string name="uploadSuccessTitle">¿Qué nos diferencia?</string>
<string name="uploadSuccessTransferInProgress">Transferencia en curso…</string>
<string name="urlAbout">https://www.infomaniak.com/es/about</string>
<string name="urlUserReportAndroid">https://feedback.userreport.com/1c462a20-7559-415e-a6e0-4b624dc38877/#ideas/popular</string>
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@
<string name="uploadProgressDescriptionTemplateIndependence">Nous développons %s Sans compromis sur l’écologie,
la vie privée et l’humain.</string>
<string name="uploadErrorDescription">Le transfert n’a pas fonctionné, donnes-lui une autre chance. Si le problème persiste, contacte notre support.</string>
<string name="uploadErrorTitle">Qu’est-ce que quoi ?</string>
<string name="uploadProgressTitleArgument">différent</string>
<string name="uploadProgressTitleTemplate">Ce qui nous rend %s ?</string>
<plurals name="uploadSuccessEmailDescription">
<item quantity="one">Le lien de téléchargement a bien été envoyé au destinataire suivant :</item>
<item quantity="other">Le lien de téléchargement a été envoyé aux destinataires suivants :</item>
Expand All @@ -136,7 +138,6 @@
<string name="uploadSuccessLinkDescription">Fais scanner ce QR code autour de toi pour partager tes fichiers ou copie le lien ci-dessous.</string>
<string name="uploadSuccessLinkTitle">Ton transfert est prêt !</string>
<string name="uploadSuccessQrTitle">Ton QR code est prêt !</string>
<string name="uploadSuccessTitle">Ce qui nous rend différent ?</string>
<string name="uploadSuccessTransferInProgress">Transfert en cours…</string>
<string name="urlAbout">https://www.infomaniak.com/fr/a-propos</string>
<string name="urlUserReportAndroid">https://feedback.userreport.com/1c462a20-7559-415e-a6e0-4b624dc38877/#ideas/popular</string>
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values-it/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@
<string name="uploadProgressDescriptionTemplateIndependence">Stiamo sviluppando %s Senza compromettere l’ecologia, la privacy e le persone.</string>
<string name="uploadErrorDescription">Il trasferimento non ha funzionato, da un’altra possibilità. Se il problema persiste, contatta il nostro team di assistenza.</string>
<string name="uploadErrorTitle">Che cosa che… cosa?</string>
<string name="uploadProgressTitleArgument">diversi</string>
<string name="uploadProgressTitleTemplate">Cosa ci rende %s?</string>
<plurals name="uploadSuccessEmailDescription">
<item quantity="one">Il link per il download è stato inviato al seguente destinatario:</item>
<item quantity="other">Il link per il download è stato inviato ai seguenti destinatari:</item>
Expand All @@ -134,7 +136,6 @@
<string name="uploadSuccessLinkDescription">Scansiona questo codice QR intorno a voi per condividere i vostri file o copiate il link qui sotto.</string>
<string name="uploadSuccessLinkTitle">Il trasferimento è pronto!</string>
<string name="uploadSuccessQrTitle">Il codice QR è pronto!</string>
<string name="uploadSuccessTitle">Cosa ci differenzia?</string>
<string name="uploadSuccessTransferInProgress">Trasferimento in corso…</string>
<string name="urlAbout">https://www.infomaniak.com/it/about</string>
<string name="urlUserReportAndroid">https://feedback.userreport.com/c85aa792-0f76-4923-8fe2-fae976cac9c2/#ideas/popular</string>
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
<string name="uploadProgressDescriptionTemplateIndependence">We develop %s Without compromising on ecology, privacy and people.</string>
<string name="uploadErrorDescription">The transfer didn’t work, give it another chance. If the problem persists, contact our support team.</string>
<string name="uploadErrorTitle">Wait, what just happened?</string>
<string name="uploadProgressTitleArgument">apart</string>
<string name="uploadProgressTitleTemplate">What sets us %s?</string>
<plurals name="uploadSuccessEmailDescription">
<item quantity="one">The download link has been sent to the following recipient:</item>
<item quantity="other">The download link has been sent to the following recipients:</item>
Expand All @@ -139,7 +141,6 @@
<string name="uploadSuccessLinkDescription">Scan this QR code around you to share your files, or copy the link below.</string>
<string name="uploadSuccessLinkTitle">Your transfer is ready!</string>
<string name="uploadSuccessQrTitle">Your QR code is ready!</string>
<string name="uploadSuccessTitle">What sets us apart?</string>
<string name="uploadSuccessTransferInProgress">Transfer in progress…</string>
<string name="urlAbout">https://www.infomaniak.com/en/about</string>
<string name="urlUserReportAndroid">https://feedback.userreport.com/f12466ad-db5b-4f5c-b24c-a54b0a5117ca/#ideas/popular</string>
Expand Down

0 comments on commit e1bd3ca

Please sign in to comment.