diff --git a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/screens/TransferScreen.kt b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/screens/TransferScreen.kt index cbb9020f..df319c68 100644 --- a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/screens/TransferScreen.kt +++ b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/screens/TransferScreen.kt @@ -23,10 +23,16 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import android.graphics.Bitmap +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.ui.graphics.asImageBitmap import com.durian.tssparty.domain.model.NetworkType import com.durian.tssparty.domain.model.SessionStatus import com.durian.tssparty.domain.model.ShareRecord import com.durian.tssparty.util.TransactionUtils +import com.google.zxing.BarcodeFormat +import com.google.zxing.qrcode.QRCodeWriter import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions import kotlinx.coroutines.launch @@ -650,20 +656,48 @@ private fun SigningScreen( Spacer(modifier = Modifier.height(24.dp)) - // Invite code (if waiting) + // Invite code with QR code (if waiting) if (sessionStatus == SessionStatus.WAITING && inviteCode != null) { Card( colors = CardDefaults.cardColors( containerColor = MaterialTheme.colorScheme.surfaceVariant ) ) { - Column(modifier = Modifier.padding(16.dp)) { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { Text( text = "邀请码", style = MaterialTheme.typography.labelMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.fillMaxWidth() ) - Spacer(modifier = Modifier.height(8.dp)) + + Spacer(modifier = Modifier.height(16.dp)) + + // QR Code for invite code + val qrBitmap = remember(inviteCode) { + generateInviteQRCode(inviteCode, 200) + } + qrBitmap?.let { bitmap -> + Box( + modifier = Modifier + .size(200.dp) + .background(Color.White), + contentAlignment = Alignment.Center + ) { + Image( + bitmap = bitmap.asImageBitmap(), + contentDescription = "邀请码二维码", + modifier = Modifier.size(200.dp) + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + // Invite code text with copy button Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, @@ -679,11 +713,15 @@ private fun SigningScreen( Text("复制") } } + Spacer(modifier = Modifier.height(8.dp)) + Text( - text = "将此邀请码分享给其他签名参与者", + text = "扫描二维码或分享邀请码给其他签名参与者", style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() ) } } @@ -1089,3 +1127,24 @@ private fun InfoRow(label: String, value: String) { ) } } + +/** + * Generate QR code bitmap for invite code + */ +private fun generateInviteQRCode(content: String, size: Int): Bitmap? { + return try { + val writer = QRCodeWriter() + val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size) + val width = bitMatrix.width + val height = bitMatrix.height + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) + for (x in 0 until width) { + for (y in 0 until height) { + bitmap.setPixel(x, y, if (bitMatrix[x, y]) android.graphics.Color.BLACK else android.graphics.Color.WHITE) + } + } + bitmap + } catch (e: Exception) { + null + } +} diff --git a/backend/mpc-system/services/service-party-app/src/pages/CoSignSession.tsx b/backend/mpc-system/services/service-party-app/src/pages/CoSignSession.tsx index db54abcf..0f4db156 100644 --- a/backend/mpc-system/services/service-party-app/src/pages/CoSignSession.tsx +++ b/backend/mpc-system/services/service-party-app/src/pages/CoSignSession.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; +import { QRCodeSVG } from 'qrcode.react'; import styles from './Session.module.css'; import { finalizeTransaction, @@ -346,6 +347,28 @@ export default function CoSignSession() { {session.inviteCode && session.status === 'waiting' && (

邀请码

+ + {/* QR Code */} +
+
+ +
+
+
{session.inviteCode}
-

- 将此邀请码分享给其他参与方,他们可以使用此码加入签名 +

+ 扫描二维码或分享邀请码给其他参与方加入签名

)}