better receive view but it freezes

This commit is contained in:
callebtc
2025-07-15 01:13:32 +02:00
parent 8d3b8e0765
commit aa12d8750e
4 changed files with 457 additions and 319 deletions
@@ -27,10 +27,11 @@ fun QRCodeCanvas(
size: Dp = 200.dp
) {
val density = LocalDensity.current
val sizePx = with(density) { size.toPx() }.toInt()
// Use a larger fixed size for better quality
val qrCodeBitMatrix = remember(text) {
try {
val sizePx = with(density) { 512.dp.toPx() }.toInt() // Fixed high resolution
val writer = QRCodeWriter()
writer.encode(text, BarcodeFormat.QR_CODE, sizePx, sizePx)
} catch (e: WriterException) {
@@ -40,20 +41,21 @@ fun QRCodeCanvas(
Canvas(
modifier = modifier
.size(size)
.background(Color.White)
) {
qrCodeBitMatrix?.let { bitMatrix ->
drawQRCode(bitMatrix, sizePx)
// Use the actual canvas size, not a calculated size
val canvasSize = minOf(this.size.width, this.size.height)
drawQRCode(bitMatrix, canvasSize)
}
}
}
private fun DrawScope.drawQRCode(
bitMatrix: com.google.zxing.common.BitMatrix,
sizePx: Int
sizePx: Float
) {
val cellSize = sizePx.toFloat() / bitMatrix.width
val cellSize = sizePx / bitMatrix.width
for (x in 0 until bitMatrix.width) {
for (y in 0 until bitMatrix.height) {
@@ -1,5 +1,6 @@
package com.bitchat.android.wallet.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -13,91 +14,113 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.bitchat.android.wallet.data.MintQuote
import com.bitchat.android.wallet.data.CashuToken
import com.bitchat.android.wallet.viewmodel.WalletViewModel
/**
* Receive dialog with options for Cashu tokens or Lightning invoices
* Full-screen receive view with options for Cashu tokens or Lightning invoices
*/
@Composable
fun ReceiveDialog(
fun ReceiveView(
viewModel: WalletViewModel,
onDismiss: () -> Unit
onNavigateBack: () -> Unit
) {
val receiveType by viewModel.receiveType.observeAsState(WalletViewModel.ReceiveType.CASHU)
val decodedToken by viewModel.decodedToken.observeAsState()
val currentMintQuote by viewModel.currentMintQuote.observeAsState()
val isLoading by viewModel.isLoading.observeAsState(false)
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
Card(
// Determine if we should show type selector
val showTypeSelector = decodedToken == null && currentMintQuote == null
Box(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFF1A1A1A))
.fillMaxSize()
.background(Color.Black)
) {
Column(
modifier = Modifier
.padding(24.dp)
.fillMaxSize()
.padding(16.dp)
.verticalScroll(rememberScrollState())
) {
// Header
// Header with back button
Row(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 24.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Receive",
color = Color.White,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
)
IconButton(onClick = onDismiss) {
IconButton(
onClick = onNavigateBack,
modifier = Modifier
.size(48.dp)
.clip(RoundedCornerShape(12.dp))
.background(Color(0xFF1A1A1A))
) {
Icon(
imageVector = Icons.Filled.Close,
contentDescription = "Close",
tint = Color.Gray
imageVector = Icons.Filled.ArrowBack,
contentDescription = "Back",
tint = Color.White,
modifier = Modifier.size(24.dp)
)
}
Text(
text = "RECEIVE",
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace,
letterSpacing = 2.sp
)
// Spacer to center the title
Spacer(modifier = Modifier.width(48.dp))
}
Spacer(modifier = Modifier.height(16.dp))
// Receive type selector
// Receive type selector (only show when not displaying QR code or token info)
if (showTypeSelector) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 24.dp),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFF1A1A1A))
) {
Row(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
FilterChip(
onClick = { viewModel.setReceiveType(WalletViewModel.ReceiveType.CASHU) },
label = {
Text(
text = "Cashu",
fontFamily = FontFamily.Monospace
text = "Cashu Token",
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Medium
)
},
selected = receiveType == WalletViewModel.ReceiveType.CASHU,
colors = FilterChipDefaults.filterChipColors(
selectedContainerColor = Color(0xFF00C851),
selectedLabelColor = Color.Black
selectedLabelColor = Color.Black,
containerColor = Color(0xFF2A2A2A),
labelColor = Color.White
),
modifier = Modifier.weight(1f)
)
@@ -106,20 +129,23 @@ fun ReceiveDialog(
onClick = { viewModel.setReceiveType(WalletViewModel.ReceiveType.LIGHTNING) },
label = {
Text(
text = "Lightning",
fontFamily = FontFamily.Monospace
text = "Lightning Invoice",
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Medium
)
},
selected = receiveType == WalletViewModel.ReceiveType.LIGHTNING,
colors = FilterChipDefaults.filterChipColors(
selectedContainerColor = Color(0xFF00C851),
selectedLabelColor = Color.Black
selectedLabelColor = Color.Black,
containerColor = Color(0xFF2A2A2A),
labelColor = Color.White
),
modifier = Modifier.weight(1f)
)
}
Spacer(modifier = Modifier.height(24.dp))
}
}
// Content based on receive type
when (receiveType) {
@@ -140,7 +166,6 @@ fun ReceiveDialog(
}
}
}
}
}
@Composable
@@ -154,116 +179,126 @@ private fun CashuReceiveContent(
if (decodedToken != null) {
// Show decoded token info and receive button
Column {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Token info card
Card(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 32.dp),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFF1A1A1A))
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Icon(
imageVector = Icons.Filled.Toll,
contentDescription = "Token",
tint = Color(0xFF00C851),
modifier = Modifier.size(48.dp)
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Cashu Token Details",
text = "CASHU TOKEN",
color = Color(0xFF00C851),
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace,
letterSpacing = 1.sp
)
Spacer(modifier = Modifier.height(24.dp))
// Amount
Text(
text = formatSats(decodedToken.amount.toLong()),
color = Color.White,
fontSize = 32.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
)
Spacer(modifier = Modifier.height(16.dp))
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFF2A2A2A))
) {
Column(modifier = Modifier.padding(16.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
// Mint info
Text(
text = "Amount:",
text = "From: ${decodedToken.mint.take(30)}${if (decodedToken.mint.length > 30) "..." else ""}",
color = Color.Gray,
fontFamily = FontFamily.Monospace
)
Text(
text = formatSats(decodedToken.amount.toLong()),
color = Color.White,
fontSize = 14.sp,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
textAlign = TextAlign.Center
)
}
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Mint:",
color = Color.Gray,
fontFamily = FontFamily.Monospace
)
Text(
text = decodedToken.mint.take(20) + if (decodedToken.mint.length > 20) "..." else "",
color = Color.White,
fontFamily = FontFamily.Monospace
)
}
if (!decodedToken.memo.isNullOrEmpty()) {
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Memo:",
text = "Memo: ${decodedToken.memo}",
color = Color.Gray,
fontFamily = FontFamily.Monospace
)
Text(
text = decodedToken.memo,
color = Color.White,
fontFamily = FontFamily.Monospace
fontSize = 14.sp,
fontFamily = FontFamily.Monospace,
textAlign = TextAlign.Center
)
}
}
}
}
Spacer(modifier = Modifier.height(24.dp))
// Receive button
Button(
onClick = {
viewModel.receiveCashuToken(decodedToken.token)
},
enabled = !isLoading,
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF00C851)
containerColor = Color(0xFF00C851),
disabledContainerColor = Color(0xFF2A2A2A)
),
shape = RoundedCornerShape(8.dp)
shape = RoundedCornerShape(16.dp)
) {
if (isLoading) {
CircularProgressIndicator(
color = Color.Black,
modifier = Modifier.size(16.dp)
modifier = Modifier.size(24.dp)
)
} else {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.Download,
contentDescription = "Receive",
tint = Color.Black
tint = Color.Black,
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Spacer(modifier = Modifier.width(12.dp))
Text(
text = "Receive Token",
text = "RECEIVE TOKEN",
color = Color.Black,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
fontFamily = FontFamily.Monospace,
letterSpacing = 1.sp
)
}
}
}
}
} else {
// Show token input
Column {
Column(
modifier = Modifier.fillMaxWidth()
) {
// Token input field
OutlinedTextField(
value = token,
onValueChange = {
@@ -288,11 +323,17 @@ private fun CashuReceiveContent(
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color(0xFF00C851),
focusedLabelColor = Color(0xFF00C851),
unfocusedBorderColor = Color(0xFF2A2A2A),
unfocusedLabelColor = Color.Gray,
unfocusedTextColor = Color.White,
focusedTextColor = Color.White
),
modifier = Modifier.fillMaxWidth(),
maxLines = 3,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 24.dp),
minLines = 3,
maxLines = 4,
shape = RoundedCornerShape(16.dp),
trailingIcon = {
IconButton(
onClick = {
@@ -300,7 +341,7 @@ private fun CashuReceiveContent(
}
) {
Icon(
imageVector = Icons.Filled.CameraAlt,
imageVector = Icons.Filled.QrCode,
contentDescription = "Scan QR",
tint = Color(0xFF00C851)
)
@@ -308,8 +349,7 @@ private fun CashuReceiveContent(
}
)
Spacer(modifier = Modifier.height(16.dp))
// Paste button
Button(
onClick = {
clipboardManager.getText()?.text?.let { clipText ->
@@ -319,31 +359,40 @@ private fun CashuReceiveContent(
}
}
},
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent
),
border = androidx.compose.foundation.BorderStroke(
1.dp,
2.dp,
Color(0xFF00C851)
),
shape = RoundedCornerShape(8.dp)
shape = RoundedCornerShape(16.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.ContentPaste,
contentDescription = "Paste",
tint = Color(0xFF00C851)
tint = Color(0xFF00C851),
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Spacer(modifier = Modifier.width(12.dp))
Text(
text = "Paste from clipboard",
text = "PASTE FROM CLIPBOARD",
color = Color(0xFF00C851),
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
fontFamily = FontFamily.Monospace,
letterSpacing = 1.sp
)
}
}
}
}
}
@Composable
@@ -358,29 +407,91 @@ private fun LightningReceiveContent(
if (currentMintQuote != null) {
// Show Lightning invoice QR code and details
Column {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Invoice header
Card(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 24.dp),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFF1A1A1A))
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Icon(
imageVector = Icons.Filled.FlashOn,
contentDescription = "Lightning",
tint = Color(0xFFFFB000),
modifier = Modifier.size(48.dp)
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Lightning Invoice",
color = Color(0xFF00C851),
text = "LIGHTNING INVOICE",
color = Color(0xFFFFB000),
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace,
letterSpacing = 1.sp
)
Spacer(modifier = Modifier.height(24.dp))
// Amount
Text(
text = formatSats(currentMintQuote.amount.toLong()),
color = Color.White,
fontSize = 32.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
)
Spacer(modifier = Modifier.height(16.dp))
// Status
Row(
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(12.dp)
.clip(RoundedCornerShape(6.dp))
.background(if (currentMintQuote.paid) Color(0xFF00C851) else Color(0xFFFFB000))
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = if (currentMintQuote.paid) "PAID" else "WAITING FOR PAYMENT",
color = if (currentMintQuote.paid) Color(0xFF00C851) else Color(0xFFFFB000),
fontSize = 14.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace,
letterSpacing = 1.sp
)
}
}
}
// QR Code
Card(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f),
shape = RoundedCornerShape(8.dp),
.aspectRatio(1f)
.padding(bottom = 24.dp),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
QRCodeCanvas(
@@ -390,85 +501,50 @@ private fun LightningReceiveContent(
}
}
Spacer(modifier = Modifier.height(16.dp))
// Invoice details
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFF2A2A2A))
) {
Column(modifier = Modifier.padding(16.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Amount:",
color = Color.Gray,
fontFamily = FontFamily.Monospace
)
Text(
text = formatSats(currentMintQuote.amount.toLong()),
color = Color.White,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
)
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Status:",
color = Color.Gray,
fontFamily = FontFamily.Monospace
)
Text(
text = if (currentMintQuote.paid) "Paid" else "Waiting...",
color = if (currentMintQuote.paid) Color(0xFF00C851) else Color.Yellow,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
// Copy invoice button
Button(
onClick = {
clipboardManager.setText(AnnotatedString(currentMintQuote.request))
},
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent
),
border = androidx.compose.foundation.BorderStroke(
1.dp,
Color(0xFF00C851)
2.dp,
Color(0xFFFFB000)
),
shape = RoundedCornerShape(8.dp)
shape = RoundedCornerShape(16.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.ContentCopy,
contentDescription = "Copy",
tint = Color(0xFF00C851)
tint = Color(0xFFFFB000),
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Spacer(modifier = Modifier.width(12.dp))
Text(
text = "Copy Invoice",
color = Color(0xFF00C851),
text = "COPY INVOICE",
color = Color(0xFFFFB000),
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
fontFamily = FontFamily.Monospace,
letterSpacing = 1.sp
)
}
}
}
} else {
// Show amount input
Column {
Column(
modifier = Modifier.fillMaxWidth()
) {
// Amount input
OutlinedTextField(
value = amount,
onValueChange = { amount = it },
@@ -482,14 +558,18 @@ private fun LightningReceiveContent(
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color(0xFF00C851),
focusedLabelColor = Color(0xFF00C851),
unfocusedBorderColor = Color(0xFF2A2A2A),
unfocusedLabelColor = Color.Gray,
unfocusedTextColor = Color.White,
focusedTextColor = Color.White
),
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
shape = RoundedCornerShape(16.dp)
)
Spacer(modifier = Modifier.height(16.dp))
// Description input
OutlinedTextField(
value = description,
onValueChange = { description = it },
@@ -502,14 +582,18 @@ private fun LightningReceiveContent(
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color(0xFF00C851),
focusedLabelColor = Color(0xFF00C851),
unfocusedBorderColor = Color(0xFF2A2A2A),
unfocusedLabelColor = Color.Gray,
unfocusedTextColor = Color.White,
focusedTextColor = Color.White
),
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 32.dp),
shape = RoundedCornerShape(16.dp)
)
Spacer(modifier = Modifier.height(24.dp))
// Create invoice button
Button(
onClick = {
amount.toLongOrNull()?.let { amountSats ->
@@ -517,34 +601,44 @@ private fun LightningReceiveContent(
}
},
enabled = !isLoading && amount.toLongOrNull()?.let { it > 0 } == true,
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF00C851)
containerColor = Color(0xFF00C851),
disabledContainerColor = Color(0xFF2A2A2A)
),
shape = RoundedCornerShape(8.dp)
shape = RoundedCornerShape(16.dp)
) {
if (isLoading) {
CircularProgressIndicator(
color = Color.Black,
modifier = Modifier.size(16.dp)
modifier = Modifier.size(24.dp)
)
} else {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.FlashOn,
contentDescription = "Create Invoice",
tint = Color.Black
tint = Color.Black,
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Spacer(modifier = Modifier.width(12.dp))
Text(
text = "Create Invoice",
text = "CREATE INVOICE",
color = Color.Black,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
fontFamily = FontFamily.Monospace,
letterSpacing = 1.sp
)
}
}
}
}
}
}
// Utility function to format sats
@@ -25,16 +25,35 @@ fun WalletScreen(
modifier: Modifier = Modifier
) {
var selectedTab by remember { mutableStateOf(0) }
var showReceiveView by remember { mutableStateOf(false) }
val showSendDialog by walletViewModel.showSendDialog.observeAsState(false)
val showReceiveDialog by walletViewModel.showReceiveDialog.observeAsState(false)
if (showReceiveView) {
// Full-screen ReceiveView
ReceiveView(
viewModel = walletViewModel,
onNavigateBack = {
showReceiveView = false
walletViewModel.hideReceiveDialog()
}
)
} else {
Column(modifier = modifier.fillMaxSize()) {
// Content
when (selectedTab) {
0 -> WalletOverview(viewModel = walletViewModel, modifier = Modifier.weight(1f))
1 -> TransactionHistory(
transactions = walletViewModel.getAllTransactions().observeAsState(initial = emptyList()).value,
modifier = Modifier.weight(1f)
modifier = Modifier.weight(1f),
onTransactionClick = { transaction ->
// For lightning receive transactions, open the receive view with the quote
if (transaction.type == com.bitchat.android.wallet.data.TransactionType.LIGHTNING_RECEIVE &&
transaction.quote != null) {
walletViewModel.setCurrentMintQuote(transaction.quote!!)
showReceiveView = true
}
}
)
2 -> MintsScreen(viewModel = walletViewModel, modifier = Modifier.weight(1f))
3 -> WalletSettings(
@@ -49,6 +68,7 @@ fun WalletScreen(
onTabSelected = { selectedTab = it }
)
}
}
// Dialogs
if (showSendDialog) {
@@ -59,10 +79,11 @@ fun WalletScreen(
}
if (showReceiveDialog) {
ReceiveDialog(
viewModel = walletViewModel,
onDismiss = { walletViewModel.hideReceiveDialog() }
)
LaunchedEffect(showReceiveDialog) {
if (showReceiveDialog) {
showReceiveView = true
}
}
}
}
@@ -274,6 +274,11 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
val updatedQuote = quote.copy(paid = true, state = MintQuoteState.PAID)
repository.saveMintQuote(updatedQuote)
// Update currentMintQuote if it's the same quote
if (_currentMintQuote.value?.id == quote.id) {
_currentMintQuote.value = updatedQuote
}
val transaction = WalletTransaction(
id = UUID.randomUUID().toString(),
type = TransactionType.LIGHTNING_RECEIVE,
@@ -372,6 +377,22 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
_errorMessage.value = null
}
/**
* Set a specific mint quote as current (for reopening from transaction list)
*/
fun setCurrentMintQuote(quoteId: String) {
viewModelScope.launch {
repository.getMintQuotes().onSuccess { quotes ->
val quote = quotes.find { it.id == quoteId }
if (quote != null) {
_currentMintQuote.value = quote
_receiveType.value = ReceiveType.LIGHTNING
showReceiveDialog()
}
}
}
}
// Wallet Operations
/**