Improve sizing of shareable QR image.

This commit is contained in:
Alex Hart
2024-01-25 16:18:03 -04:00
committed by Nicholas Tinsley
parent c9e2162afc
commit 80c0e19692
2 changed files with 38 additions and 35 deletions

View File

@@ -217,16 +217,23 @@ class UsernameLinkSettingsViewModel : ViewModel() {
val qrCodeData: QrCodeData = state.qrCodeState.data val qrCodeData: QrCodeData = state.qrCodeState.data
val width = 424 val scaleFactor = 2
val height = 576 val width = 424 * scaleFactor
val backgroundPadHorizontal = 64f val height = 576 * scaleFactor
val backgroundPadVertical = 80f val backgroundPadHorizontal = 64f * scaleFactor
val backgroundPadVertical = 80f * scaleFactor
val qrBorderWidth = width - (backgroundPadHorizontal * 2) val qrBorderWidth = width - (backgroundPadHorizontal * 2)
val qrBorderHeight = 324f val qrBorderHeight = 324f * scaleFactor
val qrSize = 184f val qrBorderRadius = 30f * scaleFactor
val qrPadding = 16f val qrSize = 184f * scaleFactor
val borderSizeX = 40f val qrPadding = 16f * scaleFactor
val borderSizeY = 32f val borderSizeX = 40f * scaleFactor
val borderSizeY = 32f * scaleFactor
val helpTextHorizontalPad = 72 * scaleFactor
val helpTextVerticalPad = 444f * scaleFactor
val helpTextSize = 14f * scaleFactor
val usernameVerticalPad = 348f * scaleFactor
val usernameTextSize = 20f * scaleFactor
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).apply { val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).apply {
eraseColor(Color.TRANSPARENT) eraseColor(Color.TRANSPARENT)
@@ -241,7 +248,7 @@ class UsernameLinkSettingsViewModel : ViewModel() {
// QR Border // QR Border
androidCanvas.withTranslation(x = backgroundPadHorizontal, y = backgroundPadVertical) { androidCanvas.withTranslation(x = backgroundPadHorizontal, y = backgroundPadVertical) {
drawRoundRect(0f, 0f, qrBorderWidth, qrBorderHeight, 30f, 30f, Paint().apply { color = state.qrCodeColorScheme.borderColor.toArgb() }) drawRoundRect(0f, 0f, qrBorderWidth, qrBorderHeight, qrBorderRadius, qrBorderRadius, Paint().apply { color = state.qrCodeColorScheme.borderColor.toArgb() })
drawRoundRect(borderSizeX, borderSizeY, borderSizeX + qrSize + qrPadding * 2, borderSizeY + qrSize + qrPadding * 2, 15f, 15f, Paint().apply { color = Color.WHITE }) drawRoundRect(borderSizeX, borderSizeY, borderSizeX + qrSize + qrPadding * 2, borderSizeY + qrSize + qrPadding * 2, 15f, 15f, Paint().apply { color = Color.WHITE })
drawRoundRect( drawRoundRect(
@@ -249,8 +256,8 @@ class UsernameLinkSettingsViewModel : ViewModel() {
borderSizeY, borderSizeY,
borderSizeX + qrSize + qrPadding * 2, borderSizeX + qrSize + qrPadding * 2,
borderSizeY + qrSize + qrPadding * 2, borderSizeY + qrSize + qrPadding * 2,
15f, 15f * scaleFactor,
15f, 15f * scaleFactor,
Paint().apply { Paint().apply {
color = state.qrCodeColorScheme.outlineColor.toArgb() color = state.qrCodeColorScheme.outlineColor.toArgb()
style = Paint.Style.STROKE style = Paint.Style.STROKE
@@ -259,10 +266,9 @@ class UsernameLinkSettingsViewModel : ViewModel() {
) )
// Draw the QR code // Draw the QR code
composeCanvas.withSave {
composeCanvas.translate((qrBorderWidth / 2) - (qrSize / 2), borderSizeY + qrPadding) composeCanvas.translate((qrBorderWidth / 2) - (qrSize / 2), borderSizeY + qrPadding)
composeCanvas.withSave {
composeCanvas.scale(qrSize / 300f, qrSize / 300f)
canvasDrawScope.draw( canvasDrawScope.draw(
density = object : Density { density = object : Density {
override val density: Float = 1f override val density: Float = 1f
@@ -270,7 +276,7 @@ class UsernameLinkSettingsViewModel : ViewModel() {
}, },
layoutDirection = LayoutDirection.Ltr, layoutDirection = LayoutDirection.Ltr,
canvas = composeCanvas, canvas = composeCanvas,
size = Size(300f, 300f) size = Size(qrSize, qrSize)
) { ) {
drawQr( drawQr(
data = qrCodeData, data = qrCodeData,
@@ -281,8 +287,7 @@ class UsernameLinkSettingsViewModel : ViewModel() {
) )
} }
} }
}
composeCanvas.translate(-90f, -80f)
// Draw the signal logo -- unfortunately can't have the normal QR code drawing handle it because it requires a composable ImageBitmap // Draw the signal logo -- unfortunately can't have the normal QR code drawing handle it because it requires a composable ImageBitmap
BitmapFactory.decodeResource(ApplicationDependencies.getApplication().resources, R.drawable.qrcode_logo).also { logoBitmap -> BitmapFactory.decodeResource(ApplicationDependencies.getApplication().resources, R.drawable.qrcode_logo).also { logoBitmap ->
@@ -291,17 +296,17 @@ class UsernameLinkSettingsViewModel : ViewModel() {
} }
val sourceRect = Rect(0, 0, logoBitmap.width, logoBitmap.height) val sourceRect = Rect(0, 0, logoBitmap.width, logoBitmap.height)
val destLeft = qrBorderWidth / 2f + qrPadding val logoSize = 36f * scaleFactor
val destTop = destLeft - 10f val destLeft = (width / 2f) - (logoSize / 2f)
val destRect = RectF(destLeft, destTop, destLeft + 36f, destTop + 36f) val destTop = destLeft - (10f * scaleFactor) + (logoSize / 2f)
drawBitmap(logoBitmap, sourceRect, destRect, tintedPaint) val destRect = RectF(destLeft, destTop, destLeft + logoSize, destTop + logoSize)
} androidCanvas.drawBitmap(logoBitmap, sourceRect, destRect, tintedPaint)
} }
// Draw the username // Draw the username
val usernamePaint = Paint().apply { val usernamePaint = Paint().apply {
color = state.qrCodeColorScheme.textColor.toArgb() color = state.qrCodeColorScheme.textColor.toArgb()
textSize = 34f textSize = usernameTextSize
typeface = if (Build.VERSION.SDK_INT < 26) { typeface = if (Build.VERSION.SDK_INT < 26) {
Typeface.DEFAULT_BOLD Typeface.DEFAULT_BOLD
} else { } else {
@@ -314,13 +319,13 @@ class UsernameLinkSettingsViewModel : ViewModel() {
val usernameBounds = Rect() val usernameBounds = Rect()
usernamePaint.getTextBounds(state.username, 0, state.username.length, usernameBounds) usernamePaint.getTextBounds(state.username, 0, state.username.length, usernameBounds)
androidCanvas.drawText(state.username, (width / 2f) - (usernameBounds.width() / 2f), 348f + usernameBounds.height(), usernamePaint) androidCanvas.drawText(state.username, (width / 2f) - (usernameBounds.width() / 2f), usernameVerticalPad + usernameBounds.height(), usernamePaint)
// Draw the help text // Draw the help text
val helpTextPaint = TextPaint().apply { val helpTextPaint = TextPaint().apply {
isAntiAlias = true isAntiAlias = true
color = 0xFF3C3C43.toInt() color = 0xFF3C3C43.toInt()
textSize = 14f textSize = helpTextSize
typeface = if (Build.VERSION.SDK_INT < 26) { typeface = if (Build.VERSION.SDK_INT < 26) {
Typeface.DEFAULT Typeface.DEFAULT
} else { } else {
@@ -331,11 +336,10 @@ class UsernameLinkSettingsViewModel : ViewModel() {
} }
} }
val helpTextHorizontalPad = 72
val maxWidth = width - helpTextHorizontalPad * 2 val maxWidth = width - helpTextHorizontalPad * 2
val helpTextLayout = StaticLayout(helpText, helpTextPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1f, 0f, true) val helpTextLayout = StaticLayout(helpText, helpTextPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1f, 0f, true)
androidCanvas.withTranslation(x = helpTextHorizontalPad.toFloat(), y = 444f) { androidCanvas.withTranslation(x = helpTextHorizontalPad.toFloat(), y = helpTextVerticalPad) {
helpTextLayout.draw(androidCanvas) helpTextLayout.draw(androidCanvas)
} }

View File

@@ -5,7 +5,6 @@
package org.thoughtcrime.securesms.profiles.username package org.thoughtcrime.securesms.profiles.username
import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column