diff --git a/api/src/main/java/com/getcode/manager/BottomBarManager.kt b/api/src/main/java/com/getcode/manager/BottomBarManager.kt index ab17e2f3a..098b1cf7b 100644 --- a/api/src/main/java/com/getcode/manager/BottomBarManager.kt +++ b/api/src/main/java/com/getcode/manager/BottomBarManager.kt @@ -11,7 +11,7 @@ import kotlin.concurrent.timerTask object BottomBarManager { data class BottomBarMessage( val title: String, - val subtitle: String, + val subtitle: String = "", val positiveText: String, val negativeText: String, val tertiaryText: String? = null, diff --git a/app/src/main/java/com/getcode/manager/AuthManager.kt b/app/src/main/java/com/getcode/manager/AuthManager.kt index 7a53ed651..68f75c413 100644 --- a/app/src/main/java/com/getcode/manager/AuthManager.kt +++ b/app/src/main/java/com/getcode/manager/AuthManager.kt @@ -132,6 +132,11 @@ class AuthManager @Inject constructor( .ignoreElement() } + fun deleteAndLogout(activity: Activity, onComplete: () -> Unit = {}) { + //todo: add account deletion + logout(activity, onComplete) + } + fun logout(activity: Activity, onComplete: () -> Unit = {}) { AccountUtils.removeAccounts(activity) .doOnSuccess { res: Boolean -> diff --git a/app/src/main/java/com/getcode/view/SheetNav.kt b/app/src/main/java/com/getcode/view/SheetNav.kt index 57bb47048..7b8b4bcd3 100644 --- a/app/src/main/java/com/getcode/view/SheetNav.kt +++ b/app/src/main/java/com/getcode/view/SheetNav.kt @@ -1,14 +1,36 @@ package com.getcode.view import androidx.annotation.StringRes +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.navigation.NamedNavArgument +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.navArgument import androidx.compose.animation.* import androidx.navigation.* import com.getcode.R import com.getcode.view.login.PhoneConfirm import com.getcode.view.login.PhoneVerify -import com.getcode.view.main.account.* -import com.getcode.view.main.account.AccountPage.* +import com.getcode.view.main.account.AccountAccessKey +import com.getcode.view.main.account.AccountDebugOptions +import com.getcode.view.main.account.AccountDeposit +import com.getcode.view.main.account.AccountDetails import com.getcode.view.main.account.AccountFaq +import com.getcode.view.main.account.AccountHome +import com.getcode.view.main.account.AccountPage +import com.getcode.view.main.account.AccountPage.ACCESS_KEY +import com.getcode.view.main.account.AccountPage.ACCOUNT_DEBUG_OPTIONS +import com.getcode.view.main.account.AccountPage.ACCOUNT_DETAILS +import com.getcode.view.main.account.AccountPage.DELETE_ACCOUNT +import com.getcode.view.main.account.AccountPage.DEPOSIT +import com.getcode.view.main.account.AccountPage.FAQ +import com.getcode.view.main.account.AccountPage.PHONE +import com.getcode.view.main.account.AccountPage.WITHDRAW +import com.getcode.view.main.account.AccountPage.BUY_AND_SELL_KIN +import com.getcode.view.main.account.AccountPhone +import com.getcode.view.main.account.ConfirmDeleteAccount +import com.getcode.view.main.account.DeleteCodeAccount import com.getcode.view.main.account.withdraw.AccountWithdrawAddress import com.getcode.view.main.account.withdraw.AccountWithdrawAmount import com.getcode.view.main.account.withdraw.AccountWithdrawSummary @@ -32,6 +54,7 @@ fun NavGraphBuilder.addSheetGraph( DEPOSIT -> navController.navigate(SheetSections.DEPOSIT.route) WITHDRAW -> navController.navigate(SheetSections.WITHDRAW_AMOUNT.route) ACCESS_KEY -> navController.navigate(SheetSections.ACCESS_KEY.route) + DELETE_ACCOUNT -> navController.navigate(SheetSections.DELETE_ACCOUNT.route) FAQ -> navController.navigate(SheetSections.FAQ.route) ACCOUNT_DETAILS -> navController.navigate(SheetSections.ACCOUNT_DETAILS.route) PHONE -> navController.navigate( @@ -85,6 +108,20 @@ fun NavGraphBuilder.addSheetGraph( onTitleChange(SheetSections.ACCESS_KEY.title) AccountAccessKey(navController) } + composableItem( + route = SheetSections.DELETE_ACCOUNT.route + ) { + onBackButtonVisibilityChange(true) + onTitleChange(SheetSections.DELETE_ACCOUNT.title) + DeleteCodeAccount(navController) + } + composableItem( + route = SheetSections.CONFIRM_DELETE_ACCOUNT.route + ) { + onBackButtonVisibilityChange(true) + onTitleChange(SheetSections.CONFIRM_DELETE_ACCOUNT.title) + ConfirmDeleteAccount(navController) + } composableItem( route = SheetSections.FAQ.route, ) { @@ -257,6 +294,14 @@ enum class SheetSections( title = R.string.title_myAccount, route = "sheet/accountDetails" ), + DELETE_ACCOUNT( + title = R.string.action_deleteAccount, + route = "sheet/deleteAccount" + ), + CONFIRM_DELETE_ACCOUNT( + title = R.string.action_deleteAccount, + route = "sheet/confirmDeleteAccount" + ), PHONE_VERIFY( title = R.string.title_enterPhoneNumber, route = "login/verifyPhone?" + diff --git a/app/src/main/java/com/getcode/view/components/TextSection.kt b/app/src/main/java/com/getcode/view/components/TextSection.kt new file mode 100644 index 000000000..618139900 --- /dev/null +++ b/app/src/main/java/com/getcode/view/components/TextSection.kt @@ -0,0 +1,25 @@ +package com.getcode.view.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp + +@Composable +fun TextSection(title: String, description: String) { + Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { + Text( + text = title, + style = MaterialTheme.typography.h6.copy( + fontWeight = FontWeight.Bold, + ) + ) + Text( + text = description, + style = MaterialTheme.typography.subtitle2 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/getcode/view/main/account/AccountDetails.kt b/app/src/main/java/com/getcode/view/main/account/AccountDetails.kt index e15313101..5c645ab4a 100644 --- a/app/src/main/java/com/getcode/view/main/account/AccountDetails.kt +++ b/app/src/main/java/com/getcode/view/main/account/AccountDetails.kt @@ -1,15 +1,20 @@ package com.getcode.view.main.account -import androidx.compose.foundation.* -import androidx.compose.foundation.layout.* -import androidx.compose.runtime.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import com.getcode.App import com.getcode.R import com.getcode.manager.BottomBarManager -import com.getcode.util.getActivity @Composable fun AccountDetails( @@ -54,6 +59,10 @@ fun AccountDetails( icon = R.drawable.ic_menu_phone, isPhoneLinked = dataState.isPhoneLinked, ) { onPage(AccountPage.PHONE) }, + AccountMainItem( + name = R.string.action_deleteAccount, + icon = R.drawable.ic_delete + ) { onPage(AccountPage.DELETE_ACCOUNT) }, ) for (action in actions) { diff --git a/app/src/main/java/com/getcode/view/main/account/AccountSheetViewModel.kt b/app/src/main/java/com/getcode/view/main/account/AccountSheetViewModel.kt index 4d48d5f35..8eddc938e 100644 --- a/app/src/main/java/com/getcode/view/main/account/AccountSheetViewModel.kt +++ b/app/src/main/java/com/getcode/view/main/account/AccountSheetViewModel.kt @@ -24,6 +24,7 @@ enum class AccountPage { DEPOSIT, WITHDRAW, PHONE, + DELETE_ACCOUNT, ACCESS_KEY, FAQ, ACCOUNT_DETAILS, diff --git a/app/src/main/java/com/getcode/view/main/account/ConfirmDeleteAccount.kt b/app/src/main/java/com/getcode/view/main/account/ConfirmDeleteAccount.kt new file mode 100644 index 000000000..9f99a9c57 --- /dev/null +++ b/app/src/main/java/com/getcode/view/main/account/ConfirmDeleteAccount.kt @@ -0,0 +1,98 @@ +package com.getcode.view.main.account + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import com.getcode.App +import com.getcode.R +import com.getcode.manager.BottomBarManager +import com.getcode.theme.inputColors +import com.getcode.util.getActivity +import com.getcode.view.components.ButtonState +import com.getcode.view.components.CodeButton + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun ConfirmDeleteAccount(navController: NavController) { + val viewModel = hiltViewModel() + val context = LocalContext.current + val keyboardController = LocalSoftwareKeyboardController.current + Column( + Modifier + .padding(20.dp) + .imePadding(), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + Text( + text = stringResource(id = R.string.subtitle_deleteAccountDescription), + style = MaterialTheme.typography.subtitle2 + ) + TextField( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + placeholder = { + Text( + stringResource(id = R.string.subtitle_typeDelete).format(viewModel.requiredPhrase), + style = MaterialTheme.typography.subtitle1.copy( + fontSize = 16.sp, + ) + ) + }, + value = viewModel.typedText.collectAsState().value, + onValueChange = { + viewModel.onTextUpdated(it) + }, + textStyle = MaterialTheme.typography.subtitle1.copy( + fontSize = 16.sp, + ), + singleLine = true, + colors = inputColors(), + shape = RoundedCornerShape(size = 5.dp) + ) + Spacer(modifier = Modifier.weight(1f)) + CodeButton( + onClick = { + keyboardController?.hide() + showConfirmDeletionBanner(onConfirm = { + context.getActivity()?.let { viewModel.onConfirmDelete(it) } + }) + }, + text = stringResource(R.string.action_deleteAccount), + buttonState = ButtonState.Filled, + enabled = viewModel.isDeletionAllowed() + ) + } +} + +fun showConfirmDeletionBanner(onConfirm: () -> Unit) { + BottomBarManager.showMessage( + BottomBarManager.BottomBarMessage( + title = App.getInstance() + .getString(R.string.prompt_title_deleteAccount), + positiveText = App.getInstance() + .getString(R.string.action_deleteAccount), + negativeText = App.getInstance().getString(R.string.action_cancel), + onPositive = onConfirm, + onNegative = { } + )) +} \ No newline at end of file diff --git a/app/src/main/java/com/getcode/view/main/account/DeleteAccount.kt b/app/src/main/java/com/getcode/view/main/account/DeleteAccount.kt new file mode 100644 index 000000000..b84fa910c --- /dev/null +++ b/app/src/main/java/com/getcode/view/main/account/DeleteAccount.kt @@ -0,0 +1,60 @@ +package com.getcode.view.main.account + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.getcode.R +import com.getcode.view.SheetSections +import com.getcode.view.components.ButtonState +import com.getcode.view.components.CodeButton +import com.getcode.view.components.TextSection + +@Composable +fun DeleteCodeAccount(navController: NavController) { + Column(Modifier.padding(20.dp)) { + LazyColumn( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(30.dp) + ) { + item { + Image( + painter = painterResource(id = R.drawable.ic_delete_bubble), + contentDescription = "Delete" + ) + } + item { + TextSection( + title = stringResource(id = R.string.deleteAccount_title_willDo), + description = stringResource(id = R.string.deleteAccount_description_willDo) + ) + } + item { + TextSection( + title = stringResource(id = R.string.deleteAccount_title_wontDo), + description = stringResource(id = R.string.deleteAccount_description_wontDo) + ) + } + item { + TextSection( + title = stringResource(id = R.string.deleteAccount_title_willHappen), + description = stringResource(id = R.string.deleteAccount_description_willHappen) + ) + } + } + CodeButton( + onClick = { + navController.navigate(SheetSections.CONFIRM_DELETE_ACCOUNT.route) + }, + text = stringResource(R.string.action_continue), + buttonState = ButtonState.Filled, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/getcode/view/main/account/DeleteAccountViewModel.kt b/app/src/main/java/com/getcode/view/main/account/DeleteAccountViewModel.kt new file mode 100644 index 000000000..bd9681b3b --- /dev/null +++ b/app/src/main/java/com/getcode/view/main/account/DeleteAccountViewModel.kt @@ -0,0 +1,27 @@ +package com.getcode.view.main.account + +import android.app.Activity +import com.getcode.manager.AuthManager +import com.getcode.view.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import javax.inject.Inject + + +@HiltViewModel +class DeleteAccountViewModel @Inject constructor( + private val authManager: AuthManager +) : BaseViewModel() { + val requiredPhrase = "Delete" + val typedText = MutableStateFlow("") + + fun onTextUpdated(text: String) { + typedText.value = text + } + + fun isDeletionAllowed() = typedText.value.equals(requiredPhrase, ignoreCase = true) + + fun onConfirmDelete(activity: Activity) { + authManager.deleteAndLogout(activity) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete_bubble.xml b/app/src/main/res/drawable/ic_delete_bubble.xml new file mode 100644 index 000000000..3af2bb3b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_bubble.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/app/src/main/res/values-en-rGB/strings.xml b/app/src/main/res/values-en-rGB/strings.xml index 549be4855..8f0e31983 100644 --- a/app/src/main/res/values-en-rGB/strings.xml +++ b/app/src/main/res/values-en-rGB/strings.xml @@ -13,7 +13,7 @@ Copy Address Create an Account Create a New Code Account - Delete Account + Delete Code Account Enable Face ID Enable Touch ID Exit diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 994d034f4..8aa27f9a0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,7 +13,7 @@ Copy Address Create an Account Create a New Code Account - Delete Account + Delete Code Account Enable Face ID Enable Touch ID Exit @@ -267,6 +267,7 @@ Withdrew Your Access Key My Account + Delete Code Account Buy & Sell Kin You Have %d Invite