feat: add transaction filter for zaps vs non-zaps on wallet screen
Adds filter chips (All / Zaps / Non-Zaps) to the transactions list. Zap transactions are identified by having nostr metadata. The filter is applied client-side via a combined Flow in WalletViewModel. https://claude.ai/code/session_01CdNY7qYDRHJr1jhAFvVgzj
This commit is contained in:
+36
-1
@@ -40,6 +40,7 @@ import androidx.compose.material.icons.filled.ArrowUpward
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@@ -86,10 +87,11 @@ fun WalletTransactionsScreen(
|
||||
walletViewModel.fetchTransactions()
|
||||
}
|
||||
|
||||
val transactions by walletViewModel.transactions.collectAsState()
|
||||
val transactions by walletViewModel.filteredTransactions.collectAsState(emptyList())
|
||||
val isLoading by walletViewModel.isLoading.collectAsState()
|
||||
val isLoadingMore by walletViewModel.isLoadingMore.collectAsState()
|
||||
val hasMore by walletViewModel.hasMoreTransactions.collectAsState()
|
||||
val currentFilter by walletViewModel.transactionFilter.collectAsState()
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
@@ -166,6 +168,9 @@ fun WalletTransactionsScreen(
|
||||
modifier = Modifier.padding(padding),
|
||||
state = listState,
|
||||
) {
|
||||
item {
|
||||
TransactionFilterRow(currentFilter) { walletViewModel.setTransactionFilter(it) }
|
||||
}
|
||||
items(transactions) { tx ->
|
||||
TransactionItem(tx, accountViewModel, nav)
|
||||
HorizontalDivider()
|
||||
@@ -188,6 +193,36 @@ fun WalletTransactionsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransactionFilterRow(
|
||||
currentFilter: TransactionFilter,
|
||||
onFilterSelected: (TransactionFilter) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
FilterChip(
|
||||
selected = currentFilter == TransactionFilter.ALL,
|
||||
onClick = { onFilterSelected(TransactionFilter.ALL) },
|
||||
label = { Text(stringRes(R.string.wallet_filter_all)) },
|
||||
)
|
||||
FilterChip(
|
||||
selected = currentFilter == TransactionFilter.ZAPS,
|
||||
onClick = { onFilterSelected(TransactionFilter.ZAPS) },
|
||||
label = { Text(stringRes(R.string.wallet_filter_zaps)) },
|
||||
)
|
||||
FilterChip(
|
||||
selected = currentFilter == TransactionFilter.NON_ZAPS,
|
||||
onClick = { onFilterSelected(TransactionFilter.NON_ZAPS) },
|
||||
label = { Text(stringRes(R.string.wallet_filter_non_zaps)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransactionItem(
|
||||
tx: NwcTransaction,
|
||||
|
||||
+24
-1
@@ -39,6 +39,8 @@ import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceSuccessResponse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
sealed class SendState {
|
||||
@@ -70,6 +72,12 @@ sealed class ReceiveState {
|
||||
) : ReceiveState()
|
||||
}
|
||||
|
||||
enum class TransactionFilter {
|
||||
ALL,
|
||||
ZAPS,
|
||||
NON_ZAPS,
|
||||
}
|
||||
|
||||
class WalletViewModel : ViewModel() {
|
||||
private var account: Account? = null
|
||||
|
||||
@@ -83,7 +91,18 @@ class WalletViewModel : ViewModel() {
|
||||
val walletAlias = _walletAlias.asStateFlow()
|
||||
|
||||
private val _transactions = MutableStateFlow<List<NwcTransaction>>(emptyList())
|
||||
val transactions = _transactions.asStateFlow()
|
||||
|
||||
private val _transactionFilter = MutableStateFlow(TransactionFilter.ALL)
|
||||
val transactionFilter = _transactionFilter.asStateFlow()
|
||||
|
||||
val filteredTransactions =
|
||||
combine(_transactions, _transactionFilter) { txs, filter ->
|
||||
when (filter) {
|
||||
TransactionFilter.ALL -> txs
|
||||
TransactionFilter.ZAPS -> txs.filter { it.parsedMetadata()?.nostr != null }
|
||||
TransactionFilter.NON_ZAPS -> txs.filter { it.parsedMetadata()?.nostr == null }
|
||||
}
|
||||
}
|
||||
|
||||
private val _isLoading = MutableStateFlow(false)
|
||||
val isLoading = _isLoading.asStateFlow()
|
||||
@@ -336,4 +355,8 @@ class WalletViewModel : ViewModel() {
|
||||
fun clearError() {
|
||||
_error.value = null
|
||||
}
|
||||
|
||||
fun setTransactionFilter(filter: TransactionFilter) {
|
||||
_transactionFilter.value = filter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1260,6 +1260,9 @@
|
||||
<string name="wallet_incoming">Received</string>
|
||||
<string name="wallet_outgoing">Sent</string>
|
||||
<string name="wallet_refresh">Refresh</string>
|
||||
<string name="wallet_filter_all">All</string>
|
||||
<string name="wallet_filter_zaps">Zaps</string>
|
||||
<string name="wallet_filter_non_zaps">Non-Zaps</string>
|
||||
<string name="route_security_filters">Security Filters</string>
|
||||
<string name="route_import_follows">Import Follows</string>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user