Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

Delete account 2nd and 3rd confirmation #2641

Merged
2 changes: 2 additions & 0 deletions ivy-resources/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
<string name="no_transactions_for_period">You don\'t have any transactions for %1$s.\nYou can add one by scrolling down and tapping "Add income" or "Add expense" button at the top.</string>
<string name="account_confirm_deletion_description">Note: Deleting this account will remove it permanently and delete all associated transactions with it.</string>
<string name="category_confirm_deletion_description">Note: Deleting this category will remove it permanently.</string>
<string name="account_confirm_deletion_description2" translatable="false">Once you delete this account you cannot get it back and all the transactions associated with the account will be removed.</string>
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
<string name="account_confirm_deletion_type_account_name" translatable="false">Please type \"%s\" in order to delete your account.</string>
<string name="edit">Edit</string>
<string name="transactions">transactions</string>
<string name="home">Home</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
Expand Down Expand Up @@ -74,6 +75,7 @@ import com.ivy.wallet.ui.theme.findContrastTextColor
import com.ivy.wallet.ui.theme.isDarkColor
import com.ivy.wallet.ui.theme.modal.ChoosePeriodModal
import com.ivy.wallet.ui.theme.modal.ChoosePeriodModalData
import com.ivy.wallet.ui.theme.modal.DeleteConfirmationModal
import com.ivy.wallet.ui.theme.modal.DeleteModal
import com.ivy.wallet.ui.theme.modal.edit.AccountModal
import com.ivy.wallet.ui.theme.modal.edit.AccountModalData
Expand Down Expand Up @@ -196,7 +198,10 @@ fun BoxWithConstraintsScope.ItemStatisticScreen(screen: ItemStatisticScreen) {
},
onSkipAllTransactions = { transactions ->
viewModel.skipTransactions(screen, transactions)
}
},
accountNameConfirmation = viewModel.accountNameConfirmation,
updateAccountNameConfirmation = viewModel::updateAccountDeletionState,
enableDeletionButton = viewModel.enableDeletionButton
)
}

Expand All @@ -209,6 +214,10 @@ private fun BoxWithConstraintsScope.UI(
account: Account?,
category: Category?,

accountNameConfirmation: TextFieldValue,
updateAccountNameConfirmation: (String) -> Unit,
enableDeletionButton: Boolean,

categories: ImmutableList<Category>,
accounts: ImmutableList<Account>,

Expand Down Expand Up @@ -247,7 +256,9 @@ private fun BoxWithConstraintsScope.UI(
val ivyContext = ivyWalletCtx()
val itemColor = (account?.color ?: category?.color)?.toComposeColor() ?: Gray

var deleteModalVisible by remember { mutableStateOf(false) }
var deleteModal1Visible by remember { mutableStateOf(false) }
var deleteModal2Visible by remember { mutableStateOf(false) }
var deleteModal3Visible by remember { mutableStateOf(false) }
var skipAllModalVisible by remember { mutableStateOf(false) }
var categoryModalData: CategoryModalData? by remember { mutableStateOf(null) }
var accountModalData: AccountModalData? by remember { mutableStateOf(null) }
Expand Down Expand Up @@ -298,7 +309,7 @@ private fun BoxWithConstraintsScope.UI(
treatTransfersAsIncomeExpense = treatTransfersAsIncomeExpense,

onDelete = {
deleteModalVisible = true
deleteModal1Visible = true
},
onEdit = {
when {
Expand Down Expand Up @@ -422,16 +433,53 @@ private fun BoxWithConstraintsScope.UI(
}

DeleteModal(
visible = deleteModalVisible,
visible = deleteModal1Visible,
title = stringResource(R.string.confirm_deletion),
description = if (account != null) {
stringResource(R.string.account_confirm_deletion_description)
} else {
stringResource(R.string.category_confirm_deletion_description)
},
dismiss = { deleteModalVisible = false }
dismiss = { deleteModal1Visible = false }
) {
deleteModal2Visible = true
}

DeleteModal(
visible = deleteModal2Visible,
title = stringResource(R.string.confirm_deletion),
description = if (account != null) {
stringResource(R.string.account_confirm_deletion_description2)
} else {
stringResource(R.string.category_confirm_deletion_description)
},
dismiss = {
deleteModal2Visible = false
deleteModal1Visible = false
}
) {
deleteModal3Visible = true
}

DeleteConfirmationModal(
visible = deleteModal3Visible,
title = stringResource(id = R.string.confirm_deletion),
description = stringResource(
id = R.string.account_confirm_deletion_type_account_name,
account?.name ?: ""
),
accountName = accountNameConfirmation,
onAccountNameChange = updateAccountNameConfirmation,
enableDeletionButton = enableDeletionButton,
dismiss = {
updateAccountNameConfirmation("")
deleteModal3Visible = false
deleteModal2Visible = false
deleteModal1Visible = false
}
) {
onDelete()
updateAccountNameConfirmation("")
}

DeleteModal(
Expand Down Expand Up @@ -739,7 +787,10 @@ private fun Preview_empty() {
onNextMonth = {},
onDelete = {},
onEditAccount = { _, _ -> },
onEditCategory = {}
onEditCategory = {},
accountNameConfirmation = TextFieldValue(),
updateAccountNameConfirmation = {},
enableDeletionButton = true
)
}
}
Expand Down Expand Up @@ -776,7 +827,10 @@ private fun Preview_crypto() {
onNextMonth = {},
onDelete = {},
onEditAccount = { _, _ -> },
onEditCategory = {}
onEditCategory = {},
accountNameConfirmation = TextFieldValue(),
updateAccountNameConfirmation = {},
enableDeletionButton = true
)
}
}
Expand Down Expand Up @@ -811,7 +865,10 @@ private fun Preview_empty_upcoming() {
onEditCategory = {},
upcoming = persistentListOf(
Transaction(UUID(1L, 2L), TransactionType.EXPENSE, BigDecimal.valueOf(10L))
)
),
accountNameConfirmation = TextFieldValue(),
updateAccountNameConfirmation = {},
enableDeletionButton = true
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.ivy.transactions

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.toArgb
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
Expand Down Expand Up @@ -28,6 +31,7 @@ import com.ivy.legacy.utils.dateNowUTC
import com.ivy.legacy.utils.ioThread
import com.ivy.legacy.utils.isNotNullOrBlank
import com.ivy.legacy.utils.readOnly
import com.ivy.legacy.utils.selectEndTextFieldValue
import com.ivy.navigation.ItemStatisticScreen
import com.ivy.navigation.Navigation
import com.ivy.resources.R
Expand Down Expand Up @@ -152,6 +156,11 @@ class ItemStatisticViewModel @Inject constructor(
private val _treatTransfersAsIncomeExpense = MutableStateFlow(false)
val treatTransfersAsIncomeExpense = _treatTransfersAsIncomeExpense.readOnly()

var accountNameConfirmation by mutableStateOf(selectEndTextFieldValue(""))
private set
var enableDeletionButton by mutableStateOf(false)
private set

fun start(
screen: ItemStatisticScreen,
period: TimePeriod? = ivyContext.selectedPeriod,
Expand Down Expand Up @@ -680,4 +689,10 @@ class ItemStatisticViewModel @Inject constructor(
TestIdlingResource.decrement()
}
}
fun updateAccountDeletionState(newName: String) {
accountNameConfirmation = selectEndTextFieldValue(newName)
account.value?.name?.let { accountName ->
enableDeletionButton = newName == accountName
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalView
Expand Down Expand Up @@ -47,6 +50,7 @@ fun IvyNameTextField(
imeAction = ImeAction.Done,
capitalization = KeyboardCapitalization.Sentences
),
focusRequester: FocusRequester = remember { FocusRequester() },
keyboardActions: KeyboardActions? = null,
onValueChanged: (TextFieldValue) -> Unit
) {
Expand All @@ -72,7 +76,8 @@ fun IvyNameTextField(
val view = LocalView.current
BasicTextField(
modifier = Modifier
.testTag("base_input"),
.testTag("base_input")
.focusRequester(focusRequester),
value = value,
onValueChange = onValueChanged,
textStyle = UI.typo.b1.style(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,29 @@ import androidx.compose.foundation.layout.BoxWithConstraintsScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import com.ivy.design.l0_system.UI
import com.ivy.design.l0_system.style
import com.ivy.legacy.utils.hideKeyboard
import com.ivy.resources.R
import com.ivy.wallet.ui.theme.Red
import com.ivy.wallet.ui.theme.components.IvyNameTextField
import kotlinx.coroutines.delay
import java.util.UUID

@Deprecated("Old design system. Use `:ivy-design` and Material3")
Expand Down Expand Up @@ -66,3 +79,90 @@ fun BoxWithConstraintsScope.DeleteModal(
Spacer(Modifier.height(48.dp))
}
}

@Composable
fun BoxWithConstraintsScope.DeleteConfirmationModal(
id: UUID = UUID.randomUUID(),
title: String,
description: String,
accountName: TextFieldValue,
hint: String = stringResource(id = R.string.account_name),
visible: Boolean,
enableDeletionButton: Boolean,
buttonText: String = stringResource(R.string.delete),
iconStart: Int = R.drawable.ic_delete,
onAccountNameChange: (String) -> Unit,
dismiss: () -> Unit,
onDelete: () -> Unit,
) {
IvyModal(
id = id,
visible = visible,
dismiss = dismiss,
PrimaryAction = {
ModalNegativeButton(
text = buttonText,
iconStart = iconStart,
enabled = enableDeletionButton
) {
onDelete()
}
}
) {
Spacer(Modifier.height(32.dp))

Text(
modifier = Modifier.padding(horizontal = 32.dp),
text = title,
style = UI.typo.b1.style(
color = Red,
fontWeight = FontWeight.ExtraBold
)
)

Spacer(Modifier.height(24.dp))

Text(
modifier = Modifier.padding(horizontal = 32.dp),
text = description,
style = UI.typo.b2.style(
color = UI.colors.pureInverse,
fontWeight = FontWeight.Medium
)
)

Spacer(Modifier.height(12.dp))

val view = LocalView.current
val focusRequester = remember { FocusRequester() }

IvyNameTextField(
modifier = Modifier
.padding(start = 28.dp, end = 36.dp),
focusRequester = focusRequester,
underlineModifier = Modifier.padding(start = 24.dp, end = 32.dp),
value = accountName,
hint = hint,
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words,
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Text,
autoCorrect = true
),
keyboardActions = KeyboardActions(
onDone = {
hideKeyboard(view)
}
),
) { newValue ->
onAccountNameChange(newValue.text)
}

LaunchedEffect(key1 = true){
delay(50)
focusRequester.requestFocus()
}

Spacer(Modifier.height(48.dp))
}
}