package com.bitcointxoko.gudariwallet.ui import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ContentPaste import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.fragment.app.FragmentActivity import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.bitcointxoko.gudariwallet.ui.send.Bolt11ConfirmCard import com.bitcointxoko.gudariwallet.ui.send.LnurlInvoiceConfirmCard import com.bitcointxoko.gudariwallet.ui.send.LnurlPayForm import com.bitcointxoko.gudariwallet.util.SendInputDetector import com.bitcointxoko.gudariwallet.util.feePpm import kotlinx.coroutines.launch @Composable fun SendScreen(vm: WalletViewModel) { val sendState: SendState by vm.sendState.collectAsStateWithLifecycle() var input by remember { mutableStateOf("") } val context = LocalContext.current val activity = context as FragmentActivity val clipboard = LocalClipboard.current val scope = rememberCoroutineScope() // Read rate directly from VM cache — same source HomeTab uses. // Both are null when no currency is selected; fiat display is suppressed. val fiatRate = vm.fiatRate // Double? val fiatCurrency = vm.fiatCurrency // String? DisposableEffect(Unit) { onDispose { vm.resetSendState() } } Column( modifier = Modifier .fillMaxSize() .verticalScroll(rememberScrollState()) .padding(24.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top ) { Spacer(Modifier.height(16.dp)) Text("Send", style = MaterialTheme.typography.headlineSmall) Spacer(Modifier.height(24.dp)) if (sendState !is SendState.PaymentSent) { OutlinedTextField( value = input, onValueChange = { input = SendInputDetector.normalize(it) }, label = { Text("Invoice, LNURL, or Lightning Address") }, placeholder = { Text("lnbc… / lnurl1… / user@domain.com") }, modifier = Modifier.fillMaxWidth(), enabled = sendState is SendState.Idle || sendState is SendState.Error, singleLine = false, maxLines = 4, textStyle = MaterialTheme.typography.bodySmall.copy(fontFamily = FontFamily.Monospace), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Uri, imeAction = ImeAction.Go ), keyboardActions = KeyboardActions( onGo = { if (input.isNotBlank()) vm.scan(input) } ), ) Spacer(Modifier.height(8.dp)) } when (val state = sendState) { is SendState.Idle -> { Button( onClick = { scope.launch { val text = clipboard.getClipEntry() ?.clipData ?.getItemAt(0) ?.text ?.toString() if (!text.isNullOrBlank()) { input = SendInputDetector.normalize(text) vm.scan(text) } } }, modifier = Modifier.fillMaxWidth() ) { Icon( imageVector = Icons.Filled.ContentPaste, contentDescription = null, modifier = Modifier.size(18.dp) ) Spacer(Modifier.width(8.dp)) Text("Paste") } Spacer(Modifier.height(8.dp)) OutlinedButton( onClick = { if (input.isNotBlank()) vm.scan(input) }, enabled = input.isNotBlank(), modifier = Modifier.fillMaxWidth() ) { Text("Continue") } } is SendState.Scanning -> { Spacer(Modifier.height(16.dp)) CircularProgressIndicator() Spacer(Modifier.height(8.dp)) Text("Resolving…") } is SendState.Bolt11Decoded -> { Bolt11ConfirmCard( state = state, activity = activity, vm = vm, fiatRate = fiatRate, fiatCurrency = fiatCurrency ) } is SendState.LnurlReady -> { LnurlPayForm( state = state, vm = vm, fiatRate = fiatRate, fiatCurrency = fiatCurrency ) } is SendState.LnurlInvoiceReady -> { LnurlInvoiceConfirmCard( state = state, activity = activity, vm = vm, fiatRate = fiatRate, fiatCurrency = fiatCurrency ) } is SendState.Paying -> { Spacer(Modifier.height(16.dp)) CircularProgressIndicator() Spacer(Modifier.height(8.dp)) Text("Sending payment…") } is SendState.PaymentSent -> { Spacer(Modifier.height(32.dp)) Text( text = "✓", style = MaterialTheme.typography.displayLarge, color = MaterialTheme.colorScheme.primary ) Spacer(Modifier.height(8.dp)) Text("Payment sent!", style = MaterialTheme.typography.headlineSmall) Spacer(Modifier.height(4.dp)) Text( text = "${state.amountSats} sats", color = MaterialTheme.colorScheme.onSurfaceVariant ) Spacer(Modifier.height(4.dp)) val feeText = when { state.feeSats == null || state.feeSats == 0L -> "No fees" else -> { val ppm = feePpm( amountMsat = state.amountSats * 1_000L, feeMsat = state.feeSats * 1_000L ) val ppmSuffix = if (ppm != null) " (${ppm} ppm)" else "" "Routing fee: ${state.feeSats} sat${if (state.feeSats == 1L) "" else "s"}$ppmSuffix" } } Text( text = feeText, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant ) Spacer(Modifier.height(32.dp)) Button( onClick = { vm.resetSendState(); input = "" }, modifier = Modifier.fillMaxWidth() ) { Text("Send Another") } } is SendState.Error -> { Spacer(Modifier.height(8.dp)) Text( text = state.message, color = MaterialTheme.colorScheme.error, textAlign = TextAlign.Center ) Spacer(Modifier.height(12.dp)) Button( onClick = { if (input.isNotBlank()) vm.scan(input) }, enabled = input.isNotBlank(), modifier = Modifier.fillMaxWidth() ) { Text("Try Again") } Spacer(Modifier.height(8.dp)) OutlinedButton( onClick = { vm.resetSendState(); input = "" }, modifier = Modifier.fillMaxWidth() ) { Text("Clear") } } } } }