diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index 46107c4f0..73e3acfbd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -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, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt index a030c4dd2..126971dc7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeDrawer.kt @@ -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, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt index e5a332b5b..524170355 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt @@ -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)) } diff --git a/quartz/src/test/java/com/vitorpamplona/quartz/encoders/Nip19Bech32Test.kt b/quartz/src/test/java/com/vitorpamplona/quartz/encoders/Nip19Bech32Test.kt index 7d1cce5eb..5c9a0ecf6 100644 --- a/quartz/src/test/java/com/vitorpamplona/quartz/encoders/Nip19Bech32Test.kt +++ b/quartz/src/test/java/com/vitorpamplona/quartz/encoders/Nip19Bech32Test.kt @@ -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")