Implemented doing the same transfer again or transfer money to the recipient when long pressing a TransactionListItem

This commit is contained in:
dankito 2024-09-06 01:05:47 +02:00
parent ac308700c0
commit 418c188eb6
7 changed files with 74 additions and 21 deletions

View File

@ -23,6 +23,7 @@ import net.codinux.banking.ui.composables.NavigationMenuItem
import net.codinux.banking.ui.composables.settings.UiSettings
import net.codinux.banking.ui.config.Colors
import net.codinux.banking.ui.config.DI
import net.codinux.banking.ui.model.ShowTransferMoneyDialogData
import org.jetbrains.compose.resources.imageResource
private val uiState = DI.uiState
@ -99,7 +100,7 @@ fun SideMenuContent() {
NavigationMenuItem(itemModifier, "Neue Überweisung", textColor, horizontalPadding = ItemHorizontalPadding,
icon = { Icon(Icons.Filled.Add, "Konto hinzufügen", Modifier.size(iconSize), tint = textColor) }) {
uiState.showTransferMoneyDialog.value = true
uiState.showTransferMoneyDialogData.value = ShowTransferMoneyDialogData()
coroutineScope.launch {
drawerState.close()

View File

@ -14,7 +14,7 @@ private val formatUtil = DI.formatUtil
@Composable
fun StateHandler(uiState: UiState, snackbarHostState: SnackbarHostState) {
val showAddAccountDialog by uiState.showAddAccountDialog.collectAsState()
val showTransferMoneyDialog by uiState.showTransferMoneyDialog.collectAsState()
val showTransferMoneyDialogData by uiState.showTransferMoneyDialogData.collectAsState()
val showExportScreen by uiState.showExportScreen.collectAsState()
val tanChallengeReceived by uiState.tanChallengeReceived.collectAsState()
@ -28,8 +28,8 @@ fun StateHandler(uiState: UiState, snackbarHostState: SnackbarHostState) {
AddAccountDialog { uiState.showAddAccountDialog.value = false }
}
if (showTransferMoneyDialog) {
TransferMoneyDialog { uiState.showTransferMoneyDialog.value = false }
showTransferMoneyDialogData?.let { data ->
TransferMoneyDialog(data) { uiState.showTransferMoneyDialogData.value = null }
}
if (showExportScreen) {

View File

@ -1,22 +1,23 @@
package net.codinux.banking.ui.composables.transactions
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.*
import androidx.compose.material.Divider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import net.codinux.banking.client.model.UserAccount
import net.codinux.banking.ui.composables.BankIcon
import net.codinux.banking.ui.config.Colors
import net.codinux.banking.ui.config.DI
import net.codinux.banking.ui.model.AccountTransactionViewModel
import net.codinux.banking.ui.model.ShowTransferMoneyDialogData
private val uiSettings = DI.uiSettings
@ -32,9 +33,35 @@ fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransacti
val backgroundColor = if (zebraStripes && itemIndex % 2 == 1) Colors.Zinc100_50 else Color.White
val bottomPadding = 56.dp
var showMenuAt by remember { mutableStateOf<DpOffset?>(null) }
fun newMoneyTransferToOtherParty(withSameData: Boolean) {
showMenuAt = null
DI.uiState.showTransferMoneyDialogData.value = ShowTransferMoneyDialogData(
DI.uiState.userAccounts.value.firstNotNullOf { it.accounts.firstOrNull { it.id == transaction.bankAccountId } },
transaction.otherPartyName,
if (withSameData) transaction.amount else null,
if (withSameData) transaction.reference else null
)
}
Row(
modifier = Modifier.fillMaxWidth()
.background(color = backgroundColor)
.pointerInput(Unit) {
detectTapGestures(
onLongPress = {
if (transaction.otherPartyName != null) { // TODO: also check if IBAN is set
showMenuAt = DpOffset(it.x.dp, it.y.dp - bottomPadding)
}
}
)
}
.padding(horizontal = 6.dp, vertical = 6.dp)
) {
Column(Modifier.weight(1f)) {
@ -61,7 +88,7 @@ fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransacti
)
}
Spacer(Modifier.width(6.dp).background(Color.Yellow))
Spacer(Modifier.width(6.dp))
Column(Modifier.width(90.dp), horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.Center) {
Text(
@ -75,6 +102,18 @@ fun TransactionListItem(userAccount: UserAccount?, transaction: AccountTransacti
text = formatUtil.formatDate(transaction.valueDate)
)
}
DropdownMenu(showMenuAt != null, { showMenuAt = null }, Modifier.widthIn(min = 350.dp),
offset = showMenuAt ?: DpOffset.Zero,
) {
DropdownMenuItem({ newMoneyTransferToOtherParty(false) }) {
Text("Neue Überweisung an ${transaction.otherPartyName} ...")
}
DropdownMenuItem({ newMoneyTransferToOtherParty(true) }) {
Text("Neue Überweisung mit gleichen Daten ...")
}
}
}
if (itemIndex < countItems - 1) {

View File

@ -24,6 +24,7 @@ import net.codinux.banking.ui.config.DI
import net.codinux.banking.ui.forms.AutocompleteTextField
import net.codinux.banking.ui.forms.OutlinedTextField
import net.codinux.banking.ui.forms.Select
import net.codinux.banking.ui.model.ShowTransferMoneyDialogData
import net.codinux.banking.ui.model.error.ErroneousAction
import net.codinux.banking.ui.service.RecipientFinder
@ -35,6 +36,7 @@ private val formatUtil = DI.formatUtil
@Composable
fun TransferMoneyDialog(
data: ShowTransferMoneyDialogData,
onDismiss: () -> Unit,
) {
val userAccounts = uiState.userAccounts.value
@ -51,12 +53,12 @@ fun TransferMoneyDialog(
}
var senderAccount by remember { mutableStateOf(accountsSupportingTransferringMoney.first()) }
var senderAccount by remember { mutableStateOf(data.senderAccount ?: accountsSupportingTransferringMoney.first()) }
var recipientName by remember { mutableStateOf("") }
var recipientName by remember { mutableStateOf(data.recipientName ?: "") }
var recipientAccountIdentifier by remember { mutableStateOf("") }
var amount by remember { mutableStateOf("") }
var paymentReference by remember { mutableStateOf("") }
var amount by remember { mutableStateOf(data.amount?.amount ?: "") }
var paymentReference by remember { mutableStateOf(data.reference ?: "") }
val accountSupportsInstantTransfer by remember(senderAccount) { derivedStateOf { senderAccount.supportsAnyFeature(BankAccountFeatures.InstantPayment) } }
var instantTransfer by remember { mutableStateOf(false) }
@ -134,6 +136,7 @@ fun TransferMoneyDialog(
Column(Modifier.padding(top = verticalSpace)) {
AutocompleteTextField(
"Name des Empfängers / der Empfängerin",
recipientName,
dropdownMaxHeight = 350.dp,
minTextLengthForSearch = 0,
onEnteredTextChanged = { recipientName = it },
@ -194,6 +197,7 @@ fun TransferMoneyDialog(
AutocompleteTextField(
"Verwendungszweck (optional)",
paymentReference,
dropdownMaxHeight = 250.dp,
minTextLengthForSearch = 0,
getItemTitle = { suggestion -> suggestion.reference },

View File

@ -19,6 +19,7 @@ import net.codinux.banking.ui.config.Colors
@Composable
fun <T> AutocompleteTextField(
label: String,
initialValue: String? = null,
onSelectedItemChanged: (T?) -> Unit,
onEnteredTextChanged: ((String) -> Unit)? = null,
minTextLengthForSearch: Int = 1,
@ -29,7 +30,7 @@ fun <T> AutocompleteTextField(
fetchSuggestions: suspend (query: String) -> Collection<T> = { emptyList() },
suggestionContent: @Composable (T) -> Unit
) {
var searchQuery by remember { mutableStateOf("") }
var searchQuery by remember { mutableStateOf(initialValue ?: "") }
var expanded by remember { mutableStateOf(false) }
var isLoading by remember { mutableStateOf(false) }
var suggestions by remember { mutableStateOf<Collection<T>>(emptyList()) }

View File

@ -0,0 +1,12 @@
package net.codinux.banking.ui.model
import net.codinux.banking.client.model.Amount
import net.codinux.banking.dataaccess.entities.BankAccountEntity
data class ShowTransferMoneyDialogData(
val senderAccount: BankAccountEntity? = null,
val recipientName: String? = null,
// TODO: add recipient account identifier
val amount: Amount? = null,
val reference: String? = null
)

View File

@ -3,14 +3,10 @@ package net.codinux.banking.ui.state
import androidx.compose.material.DrawerState
import androidx.compose.material.DrawerValue
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import net.codinux.banking.dataaccess.entities.UserAccountEntity
import net.codinux.banking.ui.model.AccountTransactionViewModel
import net.codinux.banking.ui.model.AccountTransactionsFilter
import net.codinux.banking.ui.model.TanChallengeReceived
import net.codinux.banking.ui.model.*
import net.codinux.banking.ui.model.error.ApplicationError
import net.codinux.banking.ui.model.error.BankingClientError
import net.codinux.banking.ui.model.error.ErroneousAction
@ -45,7 +41,7 @@ class UiState : ViewModel() {
val showAddAccountDialog = MutableStateFlow(false)
val showTransferMoneyDialog = MutableStateFlow(false)
val showTransferMoneyDialogData = MutableStateFlow<ShowTransferMoneyDialogData?>(null)
val showExportScreen = MutableStateFlow(false)