diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt index 3dede2f18..9a1407eb9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt @@ -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, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt index 0de7e1a58..ceb1fbd77 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt @@ -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>(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 + } } diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index d2ae0d724..32a8e479e 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -1260,6 +1260,9 @@ Received Sent Refresh + All + Zaps + Non-Zaps Security Filters Import Follows