mirror of
https://github.com/bitwarden/android.git
synced 2026-06-07 14:57:41 -05:00
BIT-543: Add Remember Me functionality to Landing Screen (#104)
Co-authored-by: Brian Yencho <brian@livefront.com>
This commit is contained in:
committed by
Álison Fernandes
parent
c7ab805f91
commit
5a2a2f93f3
@@ -0,0 +1,11 @@
|
||||
package com.x8bit.bitwarden.data.auth.datasource.disk
|
||||
|
||||
/**
|
||||
* Primary access point for disk information.
|
||||
*/
|
||||
interface AuthDiskSource {
|
||||
/**
|
||||
* The currently persisted saved email address (or `null` if not set).
|
||||
*/
|
||||
var rememberedEmailAddress: String?
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.x8bit.bitwarden.data.auth.datasource.disk
|
||||
|
||||
import android.content.SharedPreferences
|
||||
|
||||
private const val REMEMBERED_EMAIL_ADDRESS_KEY = "bwPreferencesStorage:rememberedEmail"
|
||||
|
||||
/**
|
||||
* Primary implementation of [AuthDiskSource].
|
||||
*/
|
||||
class AuthDiskSourceImpl(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
) : AuthDiskSource {
|
||||
override var rememberedEmailAddress: String?
|
||||
get() = sharedPreferences.getString(REMEMBERED_EMAIL_ADDRESS_KEY, null)
|
||||
set(value) {
|
||||
sharedPreferences
|
||||
.edit()
|
||||
.putString(REMEMBERED_EMAIL_ADDRESS_KEY, value)
|
||||
.apply()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.x8bit.bitwarden.data.auth.datasource.disk.di
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSourceImpl
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Provides persistence-related dependencies in the auth package.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DiskModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthDiskSource(
|
||||
sharedPreferences: SharedPreferences,
|
||||
): AuthDiskSource =
|
||||
AuthDiskSourceImpl(sharedPreferences = sharedPreferences)
|
||||
}
|
||||
@@ -21,6 +21,11 @@ interface AuthRepository {
|
||||
*/
|
||||
val captchaTokenResultFlow: Flow<CaptchaCallbackTokenResult>
|
||||
|
||||
/**
|
||||
* The currently persisted saved email address (or `null` if not set).
|
||||
*/
|
||||
var rememberedEmailAddress: String?
|
||||
|
||||
/**
|
||||
* Attempt to login with the given email and password. Updated access token will be reflected
|
||||
* in [authStateFlow].
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.auth.repository
|
||||
|
||||
import com.bitwarden.core.Kdf
|
||||
import com.bitwarden.sdk.Client
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.AuthState
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson.CaptchaRequired
|
||||
@@ -21,6 +22,8 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val REMEMBERED_EMAIL_ADDRESS_KEY = "bwPreferencesStorage:rememberedEmail"
|
||||
|
||||
/**
|
||||
* Default implementation of [AuthRepository].
|
||||
*/
|
||||
@@ -29,6 +32,7 @@ class AuthRepositoryImpl @Inject constructor(
|
||||
private val accountsService: AccountsService,
|
||||
private val identityService: IdentityService,
|
||||
private val bitwardenSdkClient: Client,
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
private val authTokenInterceptor: AuthTokenInterceptor,
|
||||
) : AuthRepository {
|
||||
|
||||
@@ -40,6 +44,12 @@ class AuthRepositoryImpl @Inject constructor(
|
||||
override val captchaTokenResultFlow: Flow<CaptchaCallbackTokenResult> =
|
||||
mutableCaptchaTokenFlow.asSharedFlow()
|
||||
|
||||
override var rememberedEmailAddress: String?
|
||||
get() = authDiskSource.rememberedEmailAddress
|
||||
set(value) {
|
||||
authDiskSource.rememberedEmailAddress = value
|
||||
}
|
||||
|
||||
override suspend fun login(
|
||||
email: String,
|
||||
password: String,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.x8bit.bitwarden.data.platform.datasource.di
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Provides dependencies related to encryption / decryption / secure generation.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object PreferenceModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDefaultSharedPreferences(
|
||||
application: Application,
|
||||
): SharedPreferences = application.getSharedPreferences(null, Context.MODE_PRIVATE)
|
||||
}
|
||||
@@ -32,10 +32,8 @@ import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
@@ -43,7 +41,6 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
/**
|
||||
* The top level composable for the Landing screen.
|
||||
@@ -234,15 +231,3 @@ private fun RegionSelector(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun LandingScreen_preview() {
|
||||
BitwardenTheme {
|
||||
LandingScreen(
|
||||
onNavigateToCreateAccount = {},
|
||||
onNavigateToLogin = { _, _ -> },
|
||||
viewModel = LandingViewModel(SavedStateHandle()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.landing
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -18,13 +19,14 @@ private const val KEY_STATE = "state"
|
||||
*/
|
||||
@HiltViewModel
|
||||
class LandingViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<LandingState, LandingEvent, LandingAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
?: LandingState(
|
||||
emailInput = "",
|
||||
isContinueButtonEnabled = false,
|
||||
isRememberMeEnabled = false,
|
||||
emailInput = authRepository.rememberedEmailAddress.orEmpty(),
|
||||
isContinueButtonEnabled = authRepository.rememberedEmailAddress != null,
|
||||
isRememberMeEnabled = authRepository.rememberedEmailAddress != null,
|
||||
selectedRegion = LandingState.RegionOption.BITWARDEN_US,
|
||||
),
|
||||
) {
|
||||
@@ -61,8 +63,14 @@ class LandingViewModel @Inject constructor(
|
||||
if (mutableStateFlow.value.emailInput.isBlank()) {
|
||||
return
|
||||
}
|
||||
|
||||
val email = mutableStateFlow.value.emailInput
|
||||
val isRememberMeEnabled = mutableStateFlow.value.isRememberMeEnabled
|
||||
val selectedRegionLabel = mutableStateFlow.value.selectedRegion.label
|
||||
|
||||
// Update the remembered email address
|
||||
authRepository.rememberedEmailAddress = email.takeUnless { !isRememberMeEnabled }
|
||||
|
||||
sendEvent(LandingEvent.NavigateToLogin(email, selectedRegionLabel))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user