From b3d454483e8e7211cf09545e0a6ec0e9d059b6f5 Mon Sep 17 00:00:00 2001 From: Flavia Handrea Date: Fri, 13 Dec 2024 17:46:28 +0200 Subject: [PATCH] 2FA Verification - Disabled Status. Login & Security Menu Text update. --- .../permanent/network/ITwoFAListener.kt | 8 ++ .../permanent/network/NetworkClient.kt | 3 +- .../permanent/network/StelaAccountService.kt | 6 +- .../permanent/network/models/ResponseVO.kt | 2 +- .../permanent/network/models/TwoFAVO.kt | 7 ++ .../repositories/StelaAccountRepository.kt | 3 +- .../StelaAccountRepositoryImpl.kt | 86 ++++++++-------- .../permanent/ui/PreferencesHelper.kt | 12 +++ .../permanent/ui/activities/MainActivity.kt | 2 +- .../settings/TwoStepVerificationFragment.kt | 42 ++++++++ .../settings/compose/LoginAndSecurityMenu.kt | 4 +- .../ui/settings/compose/SettingsMenuScreen.kt | 4 +- .../compose/TwoStepVerificationScreen.kt | 98 +++++++++++++++++++ .../viewmodels/ArchiveOnboardingViewModel.kt | 3 +- .../viewmodels/AuthenticationViewModel.kt | 20 +--- .../viewmodels/LoginAndSecurityViewModel.kt | 3 + .../viewmodels/SettingsMenuViewModel.kt | 4 + .../permanent/viewmodels/SplashViewModel.kt | 22 ++++- .../main/res/drawable/ic_lock_open_red.xml | 9 ++ .../res/navigation/main_navigation_graph.xml | 10 +- app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 4 +- 22 files changed, 279 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/org/permanent/permanent/network/ITwoFAListener.kt create mode 100644 app/src/main/java/org/permanent/permanent/network/models/TwoFAVO.kt create mode 100644 app/src/main/java/org/permanent/permanent/ui/settings/TwoStepVerificationFragment.kt create mode 100644 app/src/main/java/org/permanent/permanent/ui/settings/compose/TwoStepVerificationScreen.kt create mode 100644 app/src/main/res/drawable/ic_lock_open_red.xml diff --git a/app/src/main/java/org/permanent/permanent/network/ITwoFAListener.kt b/app/src/main/java/org/permanent/permanent/network/ITwoFAListener.kt new file mode 100644 index 00000000..dd1a1e9c --- /dev/null +++ b/app/src/main/java/org/permanent/permanent/network/ITwoFAListener.kt @@ -0,0 +1,8 @@ +package org.permanent.permanent.network + +import org.permanent.permanent.network.models.TwoFAVO + +interface ITwoFAListener { + fun onSuccess(twoFAVO: TwoFAVO?) + fun onFailed(error: String?) +} \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/network/NetworkClient.kt b/app/src/main/java/org/permanent/permanent/network/NetworkClient.kt index 56a2f706..0185a423 100644 --- a/app/src/main/java/org/permanent/permanent/network/NetworkClient.kt +++ b/app/src/main/java/org/permanent/permanent/network/NetworkClient.kt @@ -42,6 +42,7 @@ import org.permanent.permanent.network.models.ResponseVO import org.permanent.permanent.network.models.Shareby_urlVO import org.permanent.permanent.network.models.SimpleRequestContainer import org.permanent.permanent.network.models.StorageGift +import org.permanent.permanent.network.models.TwoFAVO import org.permanent.permanent.network.models.UploadDestination import org.permanent.permanent.ui.PREFS_NAME import org.permanent.permanent.ui.PreferencesHelper @@ -764,7 +765,7 @@ class NetworkClient(private var okHttpClient: OkHttpClient?, context: Context) { fun addRemoveTags(tags: Tags): Call = stelaAccountService.addRemoveTags(tags) -// fun getTwoFAMethod(): Call = stelaAccountService.getTwoFAMethod() + fun getTwoFAMethod(): Call> = stelaAccountService.getTwoFAMethod() fun getPaymentIntent( accountId: Int, diff --git a/app/src/main/java/org/permanent/permanent/network/StelaAccountService.kt b/app/src/main/java/org/permanent/permanent/network/StelaAccountService.kt index 60c61de2..b077cadc 100644 --- a/app/src/main/java/org/permanent/permanent/network/StelaAccountService.kt +++ b/app/src/main/java/org/permanent/permanent/network/StelaAccountService.kt @@ -2,8 +2,10 @@ package org.permanent.permanent.network import org.permanent.permanent.models.Tags import org.permanent.permanent.network.models.ResponseVO +import org.permanent.permanent.network.models.TwoFAVO import retrofit2.Call import retrofit2.http.Body +import retrofit2.http.GET import retrofit2.http.PUT interface StelaAccountService { @@ -11,6 +13,6 @@ interface StelaAccountService { @PUT("api/v2/account/tags") fun addRemoveTags(@Body tags: Tags): Call -// @GET("api/v2/idpuser") -// fun getTwoFAMethod(): Call + @GET("api/v2/idpuser") + fun getTwoFAMethod(): Call> } \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/network/models/ResponseVO.kt b/app/src/main/java/org/permanent/permanent/network/models/ResponseVO.kt index 01fafc6c..514bb54c 100644 --- a/app/src/main/java/org/permanent/permanent/network/models/ResponseVO.kt +++ b/app/src/main/java/org/permanent/permanent/network/models/ResponseVO.kt @@ -77,6 +77,7 @@ class ResponseVO { fun getLocationVO(): LocnVO? = getData()?.get(0)?.LocnVO fun getTagVO(): TagVO? = getData()?.get(0)?.TagVO + fun getProfileItemVO(): Profile_itemVO? { return getData()?.get(0)?.Profile_itemVO } @@ -84,5 +85,4 @@ class ResponseVO { fun getPromoVO(): PromoVO? { return getData()?.get(0)?.PromoVO } - } diff --git a/app/src/main/java/org/permanent/permanent/network/models/TwoFAVO.kt b/app/src/main/java/org/permanent/permanent/network/models/TwoFAVO.kt new file mode 100644 index 00000000..e0131dcd --- /dev/null +++ b/app/src/main/java/org/permanent/permanent/network/models/TwoFAVO.kt @@ -0,0 +1,7 @@ +package org.permanent.permanent.network.models + +class TwoFAVO { + var methodId: String? = null + var method: String? = null + var value: String? = null // email or phone nr +} \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepository.kt b/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepository.kt index 21077f68..e9bebf10 100644 --- a/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepository.kt +++ b/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepository.kt @@ -2,10 +2,11 @@ package org.permanent.permanent.repositories import org.permanent.permanent.models.Tags import org.permanent.permanent.network.IResponseListener +import org.permanent.permanent.network.ITwoFAListener interface StelaAccountRepository { fun addRemoveTags(tags: Tags, listener: IResponseListener) -// fun getTwoFAMethod(listener: IResponseListener) + fun getTwoFAMethod(listener: ITwoFAListener) } \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepositoryImpl.kt b/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepositoryImpl.kt index 992ef738..a5193ba4 100644 --- a/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepositoryImpl.kt +++ b/app/src/main/java/org/permanent/permanent/repositories/StelaAccountRepositoryImpl.kt @@ -4,8 +4,10 @@ import android.content.Context import org.permanent.permanent.R import org.permanent.permanent.models.Tags import org.permanent.permanent.network.IResponseListener +import org.permanent.permanent.network.ITwoFAListener import org.permanent.permanent.network.NetworkClient import org.permanent.permanent.network.models.ResponseVO +import org.permanent.permanent.network.models.TwoFAVO import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -17,52 +19,52 @@ class StelaAccountRepositoryImpl(context: Context) : StelaAccountRepository { NetworkClient.instance().addRemoveTags(tags).enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - val newLegacyContact = response.body() - if (newLegacyContact != null) { - listener.onSuccess("") - } else { - listener.onFailed(appContext.getString(R.string.generic_error)) - } + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + val newLegacyContact = response.body() + if (newLegacyContact != null) { + listener.onSuccess("") } else { - try { - listener.onFailed(response.errorBody().toString()) - } catch (e: Exception) { - listener.onFailed(e.message) - } + listener.onFailed(appContext.getString(R.string.generic_error)) + } + } else { + try { + listener.onFailed(response.errorBody().toString()) + } catch (e: Exception) { + listener.onFailed(e.message) } } + } - override fun onFailure(call: Call, t: Throwable) { - listener.onFailed(t.message) - } - }) + override fun onFailure(call: Call, t: Throwable) { + listener.onFailed(t.message) + } + }) } -// override fun getTwoFAMethod(listener: IResponseListener) { -// NetworkClient.instance().getTwoFAMethod().enqueue(object : Callback { -// -// override fun onResponse(call: Call, response: Response) { -// if (response.isSuccessful) { -// val responseBody = response.body() -// if (responseBody != null) { -// listener.onSuccess("") -// } else { -// listener.onFailed(appContext.getString(R.string.generic_error)) -// } -// } else { -// try { -// listener.onFailed(response.errorBody().toString()) -// } catch (e: Exception) { -// listener.onFailed(e.message) -// } -// } -// } -// -// override fun onFailure(call: Call, t: Throwable) { -// listener.onFailed(t.message) -// } -// }) -// } + override fun getTwoFAMethod(listener: ITwoFAListener) { + NetworkClient.instance().getTwoFAMethod().enqueue(object : Callback> { + + override fun onResponse(call: Call>, response: Response>) { + if (response.isSuccessful) { + val twoFAVOList = response.body() + if (twoFAVOList != null) { + listener.onSuccess(if (twoFAVOList.isEmpty()) null else twoFAVOList[0]) + } else { + listener.onFailed(appContext.getString(R.string.generic_error)) + } + } else { + try { + listener.onFailed(response.errorBody().toString()) + } catch (e: Exception) { + listener.onFailed(e.message) + } + } + } + + override fun onFailure(call: Call>, t: Throwable) { + listener.onFailed(t.message) + } + }) + } } \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/ui/PreferencesHelper.kt b/app/src/main/java/org/permanent/permanent/ui/PreferencesHelper.kt index 9958a54a..047bc908 100644 --- a/app/src/main/java/org/permanent/permanent/ui/PreferencesHelper.kt +++ b/app/src/main/java/org/permanent/permanent/ui/PreferencesHelper.kt @@ -11,6 +11,7 @@ const val PREFS_NAME = "permanent_preferences" const val IS_USER_LOGGED_IN = "is_user_logged_in" const val IS_BIOMETRICS_LOG_IN = "is_biometrics_log_in" const val IS_LIST_VIEW_MODE = "is_list_view_mode" +const val IS_TWO_FA_ENABLED = "is_two_fa_enabled" const val SHOW_ARCHIVES_SCREEN = "should_show_archives_screen" const val SHOW_REDEEM_CODE_SCREEN = "should_redeem_code_screen" const val PROMO_CODE = "promo_code" @@ -409,4 +410,15 @@ class PreferencesHelper(private val sharedPreferences: SharedPreferences) { val windowWidthSizeString = sharedPreferences.getString(WINDOW_WIDTH_SIZE_CLASS, "") return !windowWidthSizeString.equals(WindowWidthSizeClass.COMPACT.toString()) } + + fun setIsTwoFAEnabled(isEnabled: Boolean) { + with(sharedPreferences.edit()) { + putBoolean(IS_TWO_FA_ENABLED, isEnabled) + apply() + } + } + + fun isTwoFAEnabled(): Boolean { + return sharedPreferences.getBoolean(IS_TWO_FA_ENABLED, false) + } } \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/ui/activities/MainActivity.kt b/app/src/main/java/org/permanent/permanent/ui/activities/MainActivity.kt index 7a00ebef..3e52e9a2 100644 --- a/app/src/main/java/org/permanent/permanent/ui/activities/MainActivity.kt +++ b/app/src/main/java/org/permanent/permanent/ui/activities/MainActivity.kt @@ -100,7 +100,7 @@ class MainActivity : PermanentBaseActivity(), Toolbar.OnMenuItemClickListener { binding.toolbar.menu?.findItem(R.id.moreItem)?.isVisible = true } - R.id.legacyLoadingFragment, R.id.storageMenuFragment, R.id.addStorageFragment, R.id.giftStorageFragment, R.id.redeemCodeFragment, R.id.loginAndSecurityFragment, R.id.changePasswordFragment -> { + R.id.legacyLoadingFragment, R.id.storageMenuFragment, R.id.addStorageFragment, R.id.giftStorageFragment, R.id.redeemCodeFragment, R.id.loginAndSecurityFragment, R.id.changePasswordFragment, R.id.twoStepVerificationFragment -> { binding.toolbar.menu?.findItem(R.id.settingsItem)?.isVisible = false } diff --git a/app/src/main/java/org/permanent/permanent/ui/settings/TwoStepVerificationFragment.kt b/app/src/main/java/org/permanent/permanent/ui/settings/TwoStepVerificationFragment.kt new file mode 100644 index 00000000..9b593c11 --- /dev/null +++ b/app/src/main/java/org/permanent/permanent/ui/settings/TwoStepVerificationFragment.kt @@ -0,0 +1,42 @@ +package org.permanent.permanent.ui.settings + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.material3.MaterialTheme +import androidx.compose.ui.platform.ComposeView +import org.permanent.permanent.ui.PermanentBaseFragment +import org.permanent.permanent.ui.settings.compose.TwoStepVerificationScreen + +class TwoStepVerificationFragment : PermanentBaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + return ComposeView(requireContext()).apply { + setContent { + MaterialTheme { + TwoStepVerificationScreen { //TODO: onAddTwoStepBtn + } + } + } + } + } + + override fun connectViewModelEvents() { + } + + override fun disconnectViewModelEvents() { + } + + override fun onResume() { + super.onResume() + connectViewModelEvents() + } + + override fun onPause() { + super.onPause() + disconnectViewModelEvents() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/ui/settings/compose/LoginAndSecurityMenu.kt b/app/src/main/java/org/permanent/permanent/ui/settings/compose/LoginAndSecurityMenu.kt index ba169b82..75cd395e 100644 --- a/app/src/main/java/org/permanent/permanent/ui/settings/compose/LoginAndSecurityMenu.kt +++ b/app/src/main/java/org/permanent/permanent/ui/settings/compose/LoginAndSecurityMenu.kt @@ -25,6 +25,7 @@ fun LoginAndSecurityMenu( onTwoStepVerificationClick: () -> Unit ) { val isFingerprintEnabled by viewModel.isBiometricsEnabled.collectAsState() + val isTwoFAEnabled by viewModel.isTwoFAEnabled.collectAsState() Box( modifier = Modifier @@ -48,7 +49,8 @@ fun LoginAndSecurityMenu( iconResource = painterResource(id = R.drawable.ic_lock_primary), title = stringResource(R.string.two_step_verification), subtitle = stringResource(R.string.two_step_verification_description), - showOffLabel = true, + showOffLabel = !isTwoFAEnabled, + showOnLabel = isTwoFAEnabled, showArrow = true, ) { onTwoStepVerificationClick() } diff --git a/app/src/main/java/org/permanent/permanent/ui/settings/compose/SettingsMenuScreen.kt b/app/src/main/java/org/permanent/permanent/ui/settings/compose/SettingsMenuScreen.kt index 1a9dffb4..445ec9db 100644 --- a/app/src/main/java/org/permanent/permanent/ui/settings/compose/SettingsMenuScreen.kt +++ b/app/src/main/java/org/permanent/permanent/ui/settings/compose/SettingsMenuScreen.kt @@ -69,6 +69,8 @@ fun SettingsMenuScreen( val spaceUsedBytes by viewModel.getSpaceUsed().observeAsState(initial = 0L) val spaceUsedPercentage by viewModel.getSpaceUsedPercentage().observeAsState(initial = 0) + val isTwoFAEnabled by viewModel.isTwoFAEnabled().observeAsState(initial = false) + Column( modifier = Modifier .fillMaxSize() @@ -127,7 +129,7 @@ fun SettingsMenuScreen( SettingsMenuItem( painterResource(id = R.drawable.ic_security_primary), stringResource(R.string.login_and_security), - showWarning = true, + showWarning = !isTwoFAEnabled, ) { onLoginAndSecurityClick() } SettingsMenuItem( diff --git a/app/src/main/java/org/permanent/permanent/ui/settings/compose/TwoStepVerificationScreen.kt b/app/src/main/java/org/permanent/permanent/ui/settings/compose/TwoStepVerificationScreen.kt new file mode 100644 index 00000000..8734c74d --- /dev/null +++ b/app/src/main/java/org/permanent/permanent/ui/settings/compose/TwoStepVerificationScreen.kt @@ -0,0 +1,98 @@ +package org.permanent.permanent.ui.settings.compose + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import org.permanent.permanent.R + +@Composable +fun TwoStepVerificationScreen( + onAddTwoStepVerificationClick: () -> Unit +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(colorResource(id = R.color.superLightBlue)) + ) { + // Top Snackbar-style banner + Row( + modifier = Modifier + .fillMaxWidth() + .background(colorResource(id = R.color.errorLight)) + .padding(24.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.ic_lock_open_red), + contentDescription = "Next", + modifier = Modifier.size(20.dp) + ) + + Spacer(modifier = Modifier.width(16.dp)) + + Text( + text = stringResource(id = R.string.two_step_verification_disabled), + fontSize = 14.sp, + lineHeight = 24.sp, + color = colorResource(id = R.color.darkRed), + fontFamily = FontFamily(Font(R.font.usual_regular)) + ) + } + + Spacer(modifier = Modifier.height(24.dp)) + + // Description Text + Text( + text = stringResource(id = R.string.two_step_verification_description), + color = colorResource(id = R.color.colorPrimary), + fontSize = 16.sp, + lineHeight = 24.sp, + fontFamily = FontFamily(Font(R.font.usual_medium)), + modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp) + ) + + Spacer(modifier = Modifier.height(24.dp)) + + // Action Button + Button( + onClick = onAddTwoStepVerificationClick, + colors = ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.colorPrimary)), + modifier = Modifier + .fillMaxWidth() + .height(56.dp) + .padding(horizontal = 24.dp), + shape = RoundedCornerShape(12.dp) + ) { + Text( + text = stringResource(id = R.string.add_two_step_verification), + color = Color.White, + fontSize = 14.sp, + lineHeight = 24.sp, + fontFamily = FontFamily(Font(R.font.usual_medium)) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/permanent/permanent/viewmodels/ArchiveOnboardingViewModel.kt b/app/src/main/java/org/permanent/permanent/viewmodels/ArchiveOnboardingViewModel.kt index 53c2068b..ca1ff9cd 100644 --- a/app/src/main/java/org/permanent/permanent/viewmodels/ArchiveOnboardingViewModel.kt +++ b/app/src/main/java/org/permanent/permanent/viewmodels/ArchiveOnboardingViewModel.kt @@ -240,6 +240,7 @@ class ArchiveOnboardingViewModel(application: Application) : override fun onSuccess() { _isBusyState.value = false prefsHelper.saveUserLoggedIn(true) + prefsHelper.setIsTwoFAEnabled(false) if (_isArchiveCreationFlow.value) sendGoalsAndPriorities() } @@ -251,7 +252,7 @@ class ArchiveOnboardingViewModel(application: Application) : null -> _showError.value = appContext.getString(R.string.generic_error) - else -> _showError.value = error!! + else -> _showError.value = error } } }) diff --git a/app/src/main/java/org/permanent/permanent/viewmodels/AuthenticationViewModel.kt b/app/src/main/java/org/permanent/permanent/viewmodels/AuthenticationViewModel.kt index f1008747..9ed6b96c 100644 --- a/app/src/main/java/org/permanent/permanent/viewmodels/AuthenticationViewModel.kt +++ b/app/src/main/java/org/permanent/permanent/viewmodels/AuthenticationViewModel.kt @@ -71,8 +71,6 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM AuthenticationRepositoryImpl(application) private val archiveRepository: IArchiveRepository = ArchiveRepositoryImpl(application) private var accountRepository: IAccountRepository = AccountRepositoryImpl(application) -// private var stelaAccountRepository: StelaAccountRepository = -// StelaAccountRepositoryImpl(application) enum class SnackbarType { SUCCESS, ERROR, NONE @@ -102,6 +100,7 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM authRepository.login(email, password, object : IAuthenticationRepository.IOnLoginListener { override fun onSuccess() { _isBusyState.value = false + prefsHelper.setIsTwoFAEnabled(false) val defaultArchiveId = prefsHelper.getDefaultArchiveId() if (defaultArchiveId == 0) { @@ -123,8 +122,8 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM ) Constants.ERROR_MFA_TOKEN -> { + prefsHelper.setIsTwoFAEnabled(true) prefsHelper.saveAccountEmail(email) // Save email for verification -// getTwoFAMethod() if (withNavigation) _navigateToPage.value = AuthPage.CODE_VERIFICATION else showSuccessMessage(appContext.getString(R.string.code_resent)) } @@ -169,21 +168,6 @@ class AuthenticationViewModel(application: Application) : ObservableAndroidViewM }) } -// fun getTwoFAMethod() { -// stelaAccountRepository.getTwoFAMethod(object : IResponseListener { -// -// override fun onSuccess(message: String?) { -// _isBusyState.value = false -// _navigateToPage.value = AuthPage.CODE_VERIFICATION -// } -// -// override fun onFailed(error: String?) { -// _isBusyState.value = false -// error?.let { showErrorMessage(it) } -// } -// }) -// } - fun resendCode() { val email = savedEmail val password = savedPassword diff --git a/app/src/main/java/org/permanent/permanent/viewmodels/LoginAndSecurityViewModel.kt b/app/src/main/java/org/permanent/permanent/viewmodels/LoginAndSecurityViewModel.kt index 1e808544..a6a89b55 100644 --- a/app/src/main/java/org/permanent/permanent/viewmodels/LoginAndSecurityViewModel.kt +++ b/app/src/main/java/org/permanent/permanent/viewmodels/LoginAndSecurityViewModel.kt @@ -15,6 +15,9 @@ class LoginAndSecurityViewModel(application: Application) : ObservableAndroidVie private val _isBiometricsEnabled = MutableStateFlow(prefsHelper.isBiometricsLogIn()) val isBiometricsEnabled: StateFlow = _isBiometricsEnabled + private val _isTwoFAEnabled = MutableStateFlow(prefsHelper.isTwoFAEnabled()) + val isTwoFAEnabled: StateFlow = _isTwoFAEnabled + fun updateBiometricsEnabled(enabled: Boolean) { _isBiometricsEnabled.value = enabled prefsHelper.setBiometricsLogIn(enabled) diff --git a/app/src/main/java/org/permanent/permanent/viewmodels/SettingsMenuViewModel.kt b/app/src/main/java/org/permanent/permanent/viewmodels/SettingsMenuViewModel.kt index 614614aa..b7477c43 100644 --- a/app/src/main/java/org/permanent/permanent/viewmodels/SettingsMenuViewModel.kt +++ b/app/src/main/java/org/permanent/permanent/viewmodels/SettingsMenuViewModel.kt @@ -33,6 +33,7 @@ class SettingsMenuViewModel(application: Application) : ObservableAndroidViewMod private var archiveThumb = MutableLiveData("") private var accountName = MutableLiveData("") private var accountEmail = MutableLiveData("") + private var isTwoFAEnabled = MutableLiveData(false) private val errorMessage = MutableLiveData() private val onLoggedOut = SingleLiveEvent() private var accountRepository: IAccountRepository = AccountRepositoryImpl(application) @@ -43,6 +44,7 @@ class SettingsMenuViewModel(application: Application) : ObservableAndroidViewMod archiveThumb.value = prefsHelper.getCurrentArchiveThumbURL() accountName.value = prefsHelper.getAccountName() accountEmail.value = prefsHelper.getAccountEmail() + isTwoFAEnabled.value = prefsHelper.isTwoFAEnabled() } fun updateUsedStorage() { @@ -133,6 +135,8 @@ class SettingsMenuViewModel(application: Application) : ObservableAndroidViewMod fun getAccountEmail() = accountEmail + fun isTwoFAEnabled() = isTwoFAEnabled + fun getErrorMessage(): LiveData = errorMessage fun getOnLoggedOut(): LiveData = onLoggedOut diff --git a/app/src/main/java/org/permanent/permanent/viewmodels/SplashViewModel.kt b/app/src/main/java/org/permanent/permanent/viewmodels/SplashViewModel.kt index 34ab2db3..3e5d4366 100644 --- a/app/src/main/java/org/permanent/permanent/viewmodels/SplashViewModel.kt +++ b/app/src/main/java/org/permanent/permanent/viewmodels/SplashViewModel.kt @@ -5,9 +5,13 @@ import android.content.Context import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import org.permanent.permanent.network.IDataListener +import org.permanent.permanent.network.ITwoFAListener import org.permanent.permanent.network.models.Datum +import org.permanent.permanent.network.models.TwoFAVO import org.permanent.permanent.repositories.ArchiveRepositoryImpl import org.permanent.permanent.repositories.IArchiveRepository +import org.permanent.permanent.repositories.StelaAccountRepository +import org.permanent.permanent.repositories.StelaAccountRepositoryImpl import org.permanent.permanent.ui.PREFS_NAME import org.permanent.permanent.ui.PreferencesHelper @@ -19,12 +23,14 @@ class SplashViewModel(application: Application) : ObservableAndroidViewModel(app private val onArchiveSwitchedToCurrent = SingleLiveEvent() private val showError = MutableLiveData() private val archiveRepository: IArchiveRepository = ArchiveRepositoryImpl(application) + private var stelaAccountRepository: StelaAccountRepository = + StelaAccountRepositoryImpl(application) fun switchArchiveToCurrent() { prefsHelper.getCurrentArchiveNr()?.let { currentArchiveNr -> archiveRepository.switchToArchive(currentArchiveNr, object : IDataListener { override fun onSuccess(dataList: List?) { - onArchiveSwitchedToCurrent.call() + getTwoFAMethod() } override fun onFailed(error: String?) { @@ -34,6 +40,20 @@ class SplashViewModel(application: Application) : ObservableAndroidViewModel(app } } + fun getTwoFAMethod() { + stelaAccountRepository.getTwoFAMethod(object : ITwoFAListener { + + override fun onSuccess(twoFAVO: TwoFAVO?) { + prefsHelper.setIsTwoFAEnabled(twoFAVO != null) + onArchiveSwitchedToCurrent.call() + } + + override fun onFailed(error: String?) { + error?.let { showError.value = it } + } + }) + } + fun getOnArchiveSwitchedToCurrent(): MutableLiveData = onArchiveSwitchedToCurrent fun getShowError(): LiveData = showError } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_lock_open_red.xml b/app/src/main/res/drawable/ic_lock_open_red.xml new file mode 100644 index 00000000..24d9f71c --- /dev/null +++ b/app/src/main/res/drawable/ic_lock_open_red.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/navigation/main_navigation_graph.xml b/app/src/main/res/navigation/main_navigation_graph.xml index 13e16b93..eafb2312 100644 --- a/app/src/main/res/navigation/main_navigation_graph.xml +++ b/app/src/main/res/navigation/main_navigation_graph.xml @@ -195,15 +195,19 @@ + app:destination="@id/twoStepVerificationFragment" /> - + tools:layout="@layout/fragment_change_password" /> + + #FECDCA #F04438 #FF3D3D + #B42318 #A10000 #800080 #B843A6 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e417b0e..26aabcde 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -54,7 +54,7 @@ I agree with Terms and Conditions Sign in with fingerprint - This option lets you securely sign in with just a glance. + This option lets you securely sign in with your biometric credentials. Unlock with fingerprint Unlock with Sign in credentials @@ -129,6 +129,8 @@ Sign out Two-step verification Enhance account security by requiring a login verification code. + Two-step verification is disabled. + Add two-step verification method Archives My Files