mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-10 21:09:40 +02:00
- Improves rendering of the QR Code elements
- Makes the QR bigger - Moves QR Code to rounder corners - Moves QR Screen to use the arrow icon instead of the close button
This commit is contained in:
parent
ceaa20fabf
commit
2b5e62aaf7
@ -108,11 +108,11 @@ fun FollowingIcon(modifier: Modifier) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ArrowBackIcon() {
|
||||
fun ArrowBackIcon(tint: Color = MaterialTheme.colorScheme.grayText) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = stringRes(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.grayText,
|
||||
tint = tint,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -26,10 +26,11 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.CornerRadius
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
@ -46,13 +47,16 @@ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
|
||||
import com.google.zxing.qrcode.encoder.ByteMatrix
|
||||
import com.google.zxing.qrcode.encoder.Encoder
|
||||
import com.google.zxing.qrcode.encoder.QRCode
|
||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||
|
||||
const val QR_MARGIN_PX = 100f
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun QrCodeDrawerPreview() {
|
||||
QrCodeDrawer("Test QR data")
|
||||
Box(Modifier.background(Color.Black).padding(10.dp)) {
|
||||
QrCodeDrawer("Test QR data")
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -62,19 +66,21 @@ fun QrCodeDrawer(
|
||||
) {
|
||||
val qrCode = remember(contents) { createQrCode(contents = contents) }
|
||||
|
||||
val foregroundColor = MaterialTheme.colorScheme.onSurface
|
||||
val foregroundColor = Color.Black
|
||||
|
||||
Box(
|
||||
modifier =
|
||||
modifier
|
||||
.clip(shape = QuoteBorder)
|
||||
.defaultMinSize(48.dp, 48.dp)
|
||||
.aspectRatio(1f)
|
||||
.background(MaterialTheme.colorScheme.background),
|
||||
.background(Color.White),
|
||||
) {
|
||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||
// Calculate the height and width of each column/row
|
||||
val rowHeight = (size.width - QR_MARGIN_PX * 2f) / qrCode.matrix.height
|
||||
val columnWidth = (size.width - QR_MARGIN_PX * 2f) / qrCode.matrix.width
|
||||
val radius = CornerRadius(20f)
|
||||
|
||||
// Draw all of the finder patterns required by the QR spec. Calculate the ratio
|
||||
// of the number of rows/columns to the width and height
|
||||
@ -86,6 +92,7 @@ fun QrCodeDrawer(
|
||||
height = rowHeight * FINDER_PATTERN_ROW_COUNT,
|
||||
),
|
||||
color = foregroundColor,
|
||||
cornerRadius = radius,
|
||||
)
|
||||
|
||||
// Draw data bits (encoded data part)
|
||||
@ -162,6 +169,7 @@ fun DrawScope.drawAllQrCodeDataBits(
|
||||
),
|
||||
),
|
||||
).forEach { section ->
|
||||
val newSize = Size(size.width + 0.5f, size.height + 0.5f)
|
||||
for (y in section.first.second until section.second.second) {
|
||||
for (x in section.first.first until section.second.first) {
|
||||
if (bytes[x, y] == 1.toByte()) {
|
||||
@ -177,7 +185,7 @@ fun DrawScope.drawAllQrCodeDataBits(
|
||||
x = QR_MARGIN_PX + x * size.width,
|
||||
y = QR_MARGIN_PX + y * size.height,
|
||||
),
|
||||
size = size,
|
||||
size = newSize,
|
||||
),
|
||||
)
|
||||
},
|
||||
@ -191,7 +199,7 @@ fun DrawScope.drawAllQrCodeDataBits(
|
||||
const val FINDER_PATTERN_ROW_COUNT = 7
|
||||
private const val INTERIOR_EXTERIOR_SHAPE_RATIO = 3f / FINDER_PATTERN_ROW_COUNT
|
||||
private const val INTERIOR_EXTERIOR_OFFSET_RATIO = 2f / FINDER_PATTERN_ROW_COUNT
|
||||
private const val INTERIOR_EXTERIOR_SHAPE_CORNER_RADIUS = 0.12f
|
||||
private const val INTERIOR_EXTERIOR_SHAPE_CORNER_RADIUS = 0.50f
|
||||
private const val INTERIOR_BACKGROUND_EXTERIOR_SHAPE_RATIO = 5f / FINDER_PATTERN_ROW_COUNT
|
||||
private const val INTERIOR_BACKGROUND_EXTERIOR_OFFSET_RATIO = 1f / FINDER_PATTERN_ROW_COUNT
|
||||
private const val INTERIOR_BACKGROUND_EXTERIOR_SHAPE_CORNER_RADIUS = 0.5f
|
||||
@ -206,6 +214,7 @@ private const val INTERIOR_BACKGROUND_EXTERIOR_SHAPE_CORNER_RADIUS = 0.5f
|
||||
internal fun DrawScope.drawQrCodeFinders(
|
||||
sideLength: Float,
|
||||
finderPatternSize: Size,
|
||||
cornerRadius: CornerRadius,
|
||||
color: Color,
|
||||
) {
|
||||
setOf(
|
||||
@ -219,7 +228,7 @@ internal fun DrawScope.drawQrCodeFinders(
|
||||
drawQrCodeFinder(
|
||||
topLeft = offset,
|
||||
finderPatternSize = finderPatternSize,
|
||||
cornerRadius = CornerRadius.Zero,
|
||||
cornerRadius = cornerRadius,
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
@ -54,14 +54,16 @@ import androidx.compose.ui.window.DialogProperties
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.FeatureSetType
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.actions.CloseButton
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.DisplayNIP05
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.components.nip05VerificationAsAState
|
||||
import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||
import com.vitorpamplona.quartz.events.UserMetadata
|
||||
|
||||
@ -87,6 +89,15 @@ fun ShowQRDialogPreview() {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BackButton(onPress: () -> Unit) {
|
||||
IconButton(
|
||||
onClick = onPress,
|
||||
) {
|
||||
ArrowBackIcon(MaterialTheme.colorScheme.onBackground)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowQRDialog(
|
||||
user: User,
|
||||
@ -107,7 +118,7 @@ fun ShowQRDialog(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
CloseButton(onPress = onClose)
|
||||
BackButton(onPress = onClose)
|
||||
}
|
||||
|
||||
Column(
|
||||
@ -126,23 +137,23 @@ fun ShowQRDialog(
|
||||
contentDescription = stringRes(R.string.profile_image),
|
||||
modifier =
|
||||
Modifier
|
||||
.width(100.dp)
|
||||
.height(100.dp)
|
||||
.width(120.dp)
|
||||
.height(120.dp)
|
||||
.clip(shape = CircleShape)
|
||||
.border(3.dp, MaterialTheme.colorScheme.background, CircleShape),
|
||||
.border(3.dp, MaterialTheme.colorScheme.onBackground, CircleShape),
|
||||
loadProfilePicture = accountViewModel.settings.showProfilePictures.value,
|
||||
loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 5.dp),
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 10.dp),
|
||||
) {
|
||||
CreateTextWithEmoji(
|
||||
text = user.info?.bestName() ?: "",
|
||||
tags = user.info?.tags,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 18.sp,
|
||||
fontSize = 20.sp,
|
||||
)
|
||||
}
|
||||
|
||||
@ -160,7 +171,7 @@ fun ShowQRDialog(
|
||||
} else {
|
||||
Text(
|
||||
text = user.pubkeyDisplayHex(),
|
||||
fontSize = 14.sp,
|
||||
fontSize = Font14SP,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
@ -170,20 +181,16 @@ fun ShowQRDialog(
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = Size35dp),
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = Size10dp),
|
||||
) {
|
||||
QrCodeDrawer(user.toNostrUri())
|
||||
}
|
||||
|
||||
Row(modifier = Modifier.padding(horizontal = 30.dp)) {
|
||||
Button(
|
||||
FilledTonalButton(
|
||||
onClick = { presenting = false },
|
||||
shape = RoundedCornerShape(Size35dp),
|
||||
modifier = Modifier.fillMaxWidth().height(50.dp),
|
||||
colors =
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
) {
|
||||
Text(text = stringRes(R.string.scan_qr))
|
||||
}
|
||||
|
@ -91,6 +91,16 @@ class Nip19Bech32Test {
|
||||
Assert.assertEquals(null, actual)
|
||||
}
|
||||
|
||||
@Test()
|
||||
fun uri_to_route_complete_nprofile_2() {
|
||||
val actual = Nip19Bech32.uriToRoute("nostr:nprofile1qqsyvrp9u6p0mfur9dfdru3d853tx9mdjuhkphxuxgfwmryja7zsvhqpzamhxue69uhhv6t5daezumn0wd68yvfwvdhk6tcpz9mhxue69uhkummnw3ezuamfdejj7qgwwaehxw309ahx7uewd3hkctcscpyug")
|
||||
|
||||
Assert.assertNotNull(actual)
|
||||
Assert.assertTrue(actual?.entity is Nip19Bech32.NProfile)
|
||||
Assert.assertEquals("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", (actual?.entity as? Nip19Bech32.NProfile)?.hex)
|
||||
Assert.assertEquals("wss://vitor.nostr1.com/", (actual?.entity as? Nip19Bech32.NProfile)?.relay?.first())
|
||||
}
|
||||
|
||||
@Test()
|
||||
fun uri_to_route_complete_nprofile() {
|
||||
val actual = Nip19Bech32.uriToRoute("nostr:nprofile1qy2hwumn8ghj7un9d3shjtnyv9kh2uewd9hj7qgwwaehxw309ahx7uewd3hkctcpr9mhxue69uhhyetvv9ujuumwdae8gtnnda3kjctv9uqzq9thu3vem5gvsc6f3l3uyz7c92h6lq56t9wws0zulzkrgc6nrvym5jfztf")
|
||||
|
Loading…
x
Reference in New Issue
Block a user