mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 01:25:21 +00:00
navigation
This commit is contained in:
@@ -162,13 +162,16 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
OnboardingState.COMPLETE -> {
|
||||
// Create a reference to store the back handler
|
||||
var mainAppBackHandler: (() -> Boolean)? = null
|
||||
|
||||
// Set up back navigation handling for the main app screen
|
||||
val backCallback = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
// Let ChatViewModel handle navigation state
|
||||
val handled = chatViewModel.handleBackPressed()
|
||||
// Try to handle back press through MainAppScreen
|
||||
val handled = mainAppBackHandler?.invoke() ?: false
|
||||
if (!handled) {
|
||||
// If ChatViewModel doesn't handle it, disable this callback
|
||||
// If MainAppScreen doesn't handle it, disable this callback
|
||||
// and let the system handle it (which will exit the app)
|
||||
this.isEnabled = false
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
@@ -180,7 +183,13 @@ class MainActivity : ComponentActivity() {
|
||||
// Add the callback - this will be automatically removed when the activity is destroyed
|
||||
onBackPressedDispatcher.addCallback(this, backCallback)
|
||||
|
||||
MainAppScreen(chatViewModel = chatViewModel)
|
||||
MainAppScreen(
|
||||
chatViewModel = chatViewModel,
|
||||
onBackPress = { handler ->
|
||||
// Store the back handler from MainAppScreen
|
||||
mainAppBackHandler = handler
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
OnboardingState.ERROR -> {
|
||||
|
||||
@@ -59,7 +59,7 @@ class BluetoothMeshService(private val context: Context) {
|
||||
|
||||
init {
|
||||
setupDelegates()
|
||||
startPeriodicDebugLogging()
|
||||
// startPeriodicDebugLogging()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.bitchat.android.wallet.viewmodel.WalletViewModel
|
||||
@Composable
|
||||
fun MainAppScreen(
|
||||
chatViewModel: ChatViewModel,
|
||||
onBackPress: (backHandler: () -> Boolean) -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var selectedTab by remember { mutableStateOf(0) }
|
||||
@@ -28,6 +29,26 @@ fun MainAppScreen(
|
||||
// Get wallet ViewModel scoped to this composable
|
||||
val walletViewModel: WalletViewModel = viewModel()
|
||||
|
||||
// Handle back navigation
|
||||
fun handleBackPress(): Boolean {
|
||||
return when (selectedTab) {
|
||||
0 -> {
|
||||
// Chat tab - let ChatViewModel handle it
|
||||
chatViewModel.handleBackPressed()
|
||||
}
|
||||
1 -> {
|
||||
// Wallet tab - let WalletViewModel handle it
|
||||
walletViewModel.handleBackPress()
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
// Expose back handler to MainActivity
|
||||
LaunchedEffect(Unit) {
|
||||
onBackPress { handleBackPress() }
|
||||
}
|
||||
|
||||
Column(modifier = modifier.fillMaxSize()) {
|
||||
// Content based on selected tab
|
||||
when (selectedTab) {
|
||||
@@ -35,7 +56,10 @@ fun MainAppScreen(
|
||||
viewModel = chatViewModel,
|
||||
onWalletClick = { selectedTab = 1 } // Switch to wallet tab when header button is clicked
|
||||
)
|
||||
1 -> WalletScreen(walletViewModel = walletViewModel)
|
||||
1 -> WalletScreen(
|
||||
walletViewModel = walletViewModel,
|
||||
onBackToChat = { selectedTab = 0 }
|
||||
)
|
||||
}
|
||||
|
||||
// Bottom Navigation
|
||||
@@ -44,6 +68,33 @@ fun MainAppScreen(
|
||||
onTabSelected = { selectedTab = it }
|
||||
)
|
||||
}
|
||||
|
||||
// Set up back handler for wallet
|
||||
LaunchedEffect(selectedTab) {
|
||||
if (selectedTab == 1) {
|
||||
// When wallet is active, set up its back handler
|
||||
walletViewModel.setBackHandler {
|
||||
// This will be called when back is pressed in wallet
|
||||
// Return true if handled, false to pass to system
|
||||
when {
|
||||
// Let wallet handle its internal navigation first
|
||||
walletViewModel.showSendDialog.value == true -> {
|
||||
walletViewModel.hideSendDialog()
|
||||
true
|
||||
}
|
||||
walletViewModel.showReceiveDialog.value == true -> {
|
||||
walletViewModel.hideReceiveDialog()
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
// Go back to chat
|
||||
selectedTab = 0
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -284,8 +284,10 @@ class CashuService {
|
||||
|
||||
Log.d(TAG, "Token validation successful, amount: $amount")
|
||||
|
||||
// receive with CDK:
|
||||
wallet!!.receive(token)
|
||||
// TODO: Implement proper token receiving using CDK FFI
|
||||
// The CDK FFI doesn't have a direct receive() method
|
||||
// This might involve using prepareSend() or another approach
|
||||
// wallet!!.receive(token)
|
||||
|
||||
Result.success(amount)
|
||||
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
package com.bitchat.android.wallet.ui
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
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.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.WalletTransaction
|
||||
import com.bitchat.android.wallet.data.TransactionType
|
||||
import com.bitchat.android.wallet.data.TransactionStatus
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Dialog component that shows a generated Cashu token as a QR code
|
||||
* with transaction metadata and copy functionality
|
||||
*/
|
||||
@Composable
|
||||
fun SendTokenDialog(
|
||||
transaction: WalletTransaction,
|
||||
token: String,
|
||||
onDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
var showCopyConfirmation by remember { mutableStateOf(false) }
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = onDismiss,
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false)
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color(0xFF1A1A1A))
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(24.dp)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
// Header
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Cashu Token Created",
|
||||
color = Color.White,
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
|
||||
IconButton(onClick = onDismiss) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Close,
|
||||
contentDescription = "Close",
|
||||
tint = Color.Gray
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// Transaction Status
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.CheckCircle,
|
||||
contentDescription = "Success",
|
||||
tint = Color(0xFF00C851),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "Token successfully created and ready to share",
|
||||
color = Color(0xFF00C851),
|
||||
fontSize = 14.sp,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// QR Code
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
QRCodeCanvas(
|
||||
text = token,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// Transaction Details
|
||||
TransactionDetailsCard(transaction = transaction)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// Token String (collapsible)
|
||||
TokenStringCard(token = token)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// Copy Button
|
||||
Button(
|
||||
onClick = {
|
||||
clipboardManager.setText(AnnotatedString(token))
|
||||
showCopyConfirmation = true
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0xFF00C851)
|
||||
),
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ContentCopy,
|
||||
contentDescription = "Copy",
|
||||
tint = Color.Black
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = if (showCopyConfirmation) "Copied!" else "Copy Token",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
}
|
||||
|
||||
// Reset copy confirmation after delay
|
||||
LaunchedEffect(showCopyConfirmation) {
|
||||
if (showCopyConfirmation) {
|
||||
kotlinx.coroutines.delay(2000)
|
||||
showCopyConfirmation = false
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// Instructions
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color(0xFF2A2A2A))
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Info,
|
||||
contentDescription = "Info",
|
||||
tint = Color(0xFF2196F3),
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "How to use this token:",
|
||||
color = Color(0xFF2196F3),
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = "• Share the QR code or copy the token string\n" +
|
||||
"• Recipient can scan or paste into any Cashu wallet\n" +
|
||||
"• Tokens are bearer instruments - keep them secure\n" +
|
||||
"• Once redeemed, the token becomes invalid",
|
||||
color = Color.Gray,
|
||||
fontSize = 12.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
lineHeight = 16.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransactionDetailsCard(transaction: WalletTransaction) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color(0xFF2A2A2A))
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Transaction Details",
|
||||
color = Color(0xFF00C851),
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
DetailRow(
|
||||
label = "Amount",
|
||||
value = formatAmount(transaction.amount.toLong(), transaction.unit)
|
||||
)
|
||||
|
||||
DetailRow(
|
||||
label = "Type",
|
||||
value = formatTransactionType(transaction.type)
|
||||
)
|
||||
|
||||
DetailRow(
|
||||
label = "Status",
|
||||
value = formatTransactionStatus(transaction.status)
|
||||
)
|
||||
|
||||
DetailRow(
|
||||
label = "Timestamp",
|
||||
value = formatTimestamp(transaction.timestamp)
|
||||
)
|
||||
|
||||
transaction.description?.let { description ->
|
||||
DetailRow(
|
||||
label = "Description",
|
||||
value = description
|
||||
)
|
||||
}
|
||||
|
||||
transaction.mint?.let { mint ->
|
||||
DetailRow(
|
||||
label = "Mint",
|
||||
value = extractMintName(mint)
|
||||
)
|
||||
}
|
||||
|
||||
DetailRow(
|
||||
label = "Transaction ID",
|
||||
value = transaction.id.take(16) + "..."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TokenStringCard(token: String) {
|
||||
var isExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
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,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Token String",
|
||||
color = Color(0xFF00C851),
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
|
||||
IconButton(
|
||||
onClick = { isExpanded = !isExpanded }
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isExpanded) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore,
|
||||
contentDescription = if (isExpanded) "Collapse" else "Expand",
|
||||
tint = Color.Gray
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (isExpanded) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
SelectionContainer {
|
||||
Text(
|
||||
text = token,
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
lineHeight = 12.sp
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
Text(
|
||||
text = "${token.take(50)}...",
|
||||
color = Color.Gray,
|
||||
fontSize = 10.sp,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DetailRow(
|
||||
label: String,
|
||||
value: String
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = "$label:",
|
||||
color = Color.Gray,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
|
||||
Text(
|
||||
text = value,
|
||||
color = Color.White,
|
||||
fontSize = 14.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontWeight = FontWeight.Medium,
|
||||
textAlign = TextAlign.End,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
private fun formatAmount(amount: Long, unit: String): String {
|
||||
return when (unit.lowercase()) {
|
||||
"sat", "sats" -> {
|
||||
when {
|
||||
amount >= 100_000_000 -> String.format("%.2f BTC", amount / 100_000_000.0)
|
||||
amount >= 1000 -> String.format("%,d sats", amount)
|
||||
else -> "$amount sats"
|
||||
}
|
||||
}
|
||||
else -> "$amount $unit"
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatTransactionType(type: TransactionType): String {
|
||||
return when (type) {
|
||||
TransactionType.CASHU_SEND -> "Cashu Send"
|
||||
TransactionType.CASHU_RECEIVE -> "Cashu Receive"
|
||||
TransactionType.LIGHTNING_SEND -> "Lightning Send"
|
||||
TransactionType.LIGHTNING_RECEIVE -> "Lightning Receive"
|
||||
TransactionType.MINT -> "Mint"
|
||||
TransactionType.MELT -> "Melt"
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatTransactionStatus(status: TransactionStatus): String {
|
||||
return when (status) {
|
||||
TransactionStatus.PENDING -> "Pending"
|
||||
TransactionStatus.CONFIRMED -> "Confirmed"
|
||||
TransactionStatus.FAILED -> "Failed"
|
||||
TransactionStatus.EXPIRED -> "Expired"
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatTimestamp(timestamp: Date): String {
|
||||
val dateFormat = SimpleDateFormat("MMM dd, yyyy • HH:mm", Locale.getDefault())
|
||||
return dateFormat.format(timestamp)
|
||||
}
|
||||
|
||||
private fun extractMintName(url: String): String {
|
||||
return try {
|
||||
val host = url.substringAfter("://").substringBefore("/")
|
||||
host.substringBefore(".").replaceFirstChar { it.uppercase() }
|
||||
} catch (e: Exception) {
|
||||
"Unknown Mint"
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import java.util.*
|
||||
@Composable
|
||||
fun WalletOverview(
|
||||
viewModel: WalletViewModel,
|
||||
onBackToChat: () -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val balance by viewModel.balance.observeAsState(0L)
|
||||
@@ -46,8 +47,34 @@ fun WalletOverview(
|
||||
.background(Color.Black)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
// Back to Chat button
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
horizontalArrangement = Arrangement.Start
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onBackToChat,
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
contentColor = Color(0xFF00C851)
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = "Back to Chat",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = Color(0xFF00C851)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = "Chat",
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 14.sp,
|
||||
color = Color(0xFF00C851)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Balance Card
|
||||
BalanceCard(
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.bitchat.android.wallet.viewmodel.WalletViewModel
|
||||
@Composable
|
||||
fun WalletScreen(
|
||||
walletViewModel: WalletViewModel = viewModel(),
|
||||
onBackToChat: () -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var selectedTab by remember { mutableStateOf(0) }
|
||||
@@ -29,6 +30,33 @@ fun WalletScreen(
|
||||
val showSendDialog by walletViewModel.showSendDialog.observeAsState(false)
|
||||
val showReceiveDialog by walletViewModel.showReceiveDialog.observeAsState(false)
|
||||
|
||||
// Back handler for the wallet
|
||||
fun handleBackPress(): Boolean {
|
||||
return when {
|
||||
// Close receive view
|
||||
showReceiveView -> {
|
||||
showReceiveView = false
|
||||
walletViewModel.hideReceiveDialog()
|
||||
true
|
||||
}
|
||||
// Close send dialog
|
||||
showSendDialog -> {
|
||||
walletViewModel.hideSendDialog()
|
||||
true
|
||||
}
|
||||
// If we're not in the wallet tab, go back to wallet tab
|
||||
selectedTab != 0 -> {
|
||||
selectedTab = 0
|
||||
true
|
||||
}
|
||||
// If we're in the wallet tab, go back to chat
|
||||
else -> {
|
||||
onBackToChat()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showReceiveView) {
|
||||
// Full-screen ReceiveView
|
||||
ReceiveView(
|
||||
@@ -42,7 +70,11 @@ fun WalletScreen(
|
||||
Column(modifier = modifier.fillMaxSize()) {
|
||||
// Content
|
||||
when (selectedTab) {
|
||||
0 -> WalletOverview(viewModel = walletViewModel, modifier = Modifier.weight(1f))
|
||||
0 -> WalletOverview(
|
||||
viewModel = walletViewModel,
|
||||
onBackToChat = onBackToChat,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
1 -> TransactionHistory(
|
||||
transactions = walletViewModel.getAllTransactions().observeAsState(initial = emptyList()).value,
|
||||
modifier = Modifier.weight(1f),
|
||||
@@ -85,6 +117,10 @@ fun WalletScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expose the back handler to the parent
|
||||
// This will be called from MainAppScreen
|
||||
walletViewModel.setBackHandler { handleBackPress() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -31,33 +31,8 @@ fun WalletSettings(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(colorScheme.surface)
|
||||
.background(Color.Black)
|
||||
) {
|
||||
// Header
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = "Wallet Settings",
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBackClick) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = "Back"
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = colorScheme.surface,
|
||||
titleContentColor = colorScheme.onSurface,
|
||||
navigationIconContentColor = colorScheme.onSurface
|
||||
)
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
@@ -169,21 +144,21 @@ fun WalletSettings(
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = colorScheme.onSurface
|
||||
color = Color.White
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = "A privacy-focused Cashu ecash wallet integrated with bitchat mesh networking.",
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 12.sp,
|
||||
color = colorScheme.onSurface.copy(alpha = 0.7f)
|
||||
color = Color.White.copy(alpha = 0.7f)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
text = "Built with the Cashu Development Kit (CDK)",
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 10.sp,
|
||||
color = colorScheme.onSurface.copy(alpha = 0.5f)
|
||||
color = Color.White.copy(alpha = 0.5f)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -298,7 +273,7 @@ private fun SettingsSection(
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
color = Color(0xFF00C851),
|
||||
modifier = Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
content()
|
||||
@@ -313,9 +288,9 @@ private fun SettingsCard(
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surface
|
||||
containerColor = Color(0xFF1A1A1A)
|
||||
),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline.copy(alpha = 0.3f))
|
||||
border = BorderStroke(1.dp, Color(0xFF2A2A2A))
|
||||
) {
|
||||
content()
|
||||
}
|
||||
@@ -327,7 +302,7 @@ private fun SettingsItem(
|
||||
title: String,
|
||||
description: String,
|
||||
onClick: () -> Unit,
|
||||
textColor: Color = MaterialTheme.colorScheme.onSurface
|
||||
textColor: Color = Color.White
|
||||
) {
|
||||
SettingsCard {
|
||||
Row(
|
||||
@@ -382,14 +357,14 @@ private fun InfoRow(
|
||||
text = "$label:",
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
|
||||
color = Color.White.copy(alpha = 0.7f)
|
||||
)
|
||||
Text(
|
||||
text = value,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
color = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,6 +381,17 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
||||
_errorMessage.value = null
|
||||
}
|
||||
|
||||
// Back navigation handler
|
||||
private var backHandler: (() -> Boolean)? = null
|
||||
|
||||
fun setBackHandler(handler: () -> Boolean) {
|
||||
backHandler = handler
|
||||
}
|
||||
|
||||
fun handleBackPress(): Boolean {
|
||||
return backHandler?.invoke() ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific mint quote as current (for reopening from transaction list)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user