mirror of
https://github.com/yogeshpaliyal/KeyPass.git
synced 2025-12-30 16:31:29 -06:00
Add password config in account detail (#861)
* feat: WIP password configs from AccountDetail * feat: spotless fixes
This commit is contained in:
committed by
GitHub
parent
59fc381a9d
commit
892f65fc10
@@ -5,7 +5,6 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.yogeshpaliyal.common.utils.getUserSettings
|
||||
import com.yogeshpaliyal.common.utils.setDefaultPasswordLength
|
||||
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.ChangeDefaultPasswordLengthState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -24,7 +23,7 @@ class ChangeDefaultPasswordLengthViewModel : ViewModel() {
|
||||
viewModelScope.launch {
|
||||
_viewState.update {
|
||||
val oldPasswordLength =
|
||||
context.getUserSettings().defaultPasswordLength ?: DEFAULT_PASSWORD_LENGTH
|
||||
context.getUserSettings().passwordConfig.length
|
||||
ChangeDefaultPasswordLengthState(length = oldPasswordLength)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -29,12 +30,13 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.yogeshpaliyal.common.constants.ScannerType
|
||||
import com.yogeshpaliyal.common.data.AccountModel
|
||||
import com.yogeshpaliyal.common.utils.TOTPHelper
|
||||
import com.yogeshpaliyal.keypass.ui.detail.components.BottomBar
|
||||
import com.yogeshpaliyal.keypass.ui.detail.components.Fields
|
||||
import com.yogeshpaliyal.keypass.ui.redux.actions.CopyToClipboard
|
||||
import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction
|
||||
import com.yogeshpaliyal.keypass.ui.redux.actions.NavigationAction
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.PasswordGeneratorState
|
||||
import org.reduxkotlin.compose.rememberDispatcher
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@@ -60,17 +62,11 @@ fun AccountDetailPage(
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
|
||||
// task value state
|
||||
val (accountModel, setAccountModel) = remember {
|
||||
mutableStateOf(
|
||||
AccountModel()
|
||||
)
|
||||
}
|
||||
val accountModel = viewModel.accountModel.collectAsState().value
|
||||
|
||||
// Set initial object
|
||||
LaunchedEffect(key1 = id) {
|
||||
viewModel.loadAccount(id) {
|
||||
setAccountModel(it.copy())
|
||||
}
|
||||
viewModel.loadAccount(id)
|
||||
}
|
||||
|
||||
val goBack: () -> Unit = {
|
||||
@@ -80,7 +76,7 @@ fun AccountDetailPage(
|
||||
val launcher = rememberLauncherForActivityResult(QRScanner()) {
|
||||
when (it.type) {
|
||||
ScannerType.Password -> {
|
||||
setAccountModel(accountModel.copy(password = it.scannedText))
|
||||
viewModel.setAccountModel(accountModel.copy(password = it.scannedText))
|
||||
}
|
||||
ScannerType.Secret -> {
|
||||
it.scannedText ?: return@rememberLauncherForActivityResult
|
||||
@@ -94,7 +90,7 @@ fun AccountDetailPage(
|
||||
if (newAccountModel.username.isNullOrEmpty()) {
|
||||
newAccountModel = newAccountModel.copy(username = totp.issuer)
|
||||
}
|
||||
setAccountModel(newAccountModel)
|
||||
viewModel.setAccountModel(newAccountModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,6 +107,9 @@ fun AccountDetailPage(
|
||||
|
||||
val qrCodeBitmap = viewModel.generateQrCode(accountModel)
|
||||
generatedQrCodeBitmap.value = qrCodeBitmap
|
||||
},
|
||||
openPasswordConfiguration = {
|
||||
dispatchAction(NavigationAction(PasswordGeneratorState()))
|
||||
}
|
||||
) {
|
||||
viewModel.insertOrUpdate(accountModel, goBack)
|
||||
@@ -121,7 +120,7 @@ fun AccountDetailPage(
|
||||
Fields(
|
||||
accountModel = accountModel,
|
||||
updateAccountModel = { newAccountModel ->
|
||||
setAccountModel(newAccountModel)
|
||||
viewModel.setAccountModel(newAccountModel)
|
||||
},
|
||||
copyToClipboardClicked = { value ->
|
||||
dispatchAction(CopyToClipboard(value))
|
||||
|
||||
@@ -3,8 +3,6 @@ package com.yogeshpaliyal.keypass.ui.detail
|
||||
import android.app.Application
|
||||
import android.graphics.Bitmap
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.gson.Gson
|
||||
import com.google.zxing.BarcodeFormat
|
||||
@@ -16,6 +14,8 @@ import com.yogeshpaliyal.common.data.AccountModel
|
||||
import com.yogeshpaliyal.common.worker.executeAutoBackup
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
@@ -33,15 +33,23 @@ class DetailViewModel @Inject constructor(
|
||||
val appDb: com.yogeshpaliyal.common.AppDatabase
|
||||
) : AndroidViewModel(app) {
|
||||
|
||||
private val _accountModel by lazy { MutableLiveData<AccountModel>() }
|
||||
val accountModel: LiveData<AccountModel> = _accountModel
|
||||
private val _accountModel by lazy { MutableStateFlow<AccountModel>(AccountModel()) }
|
||||
val accountModel: StateFlow<AccountModel> = _accountModel
|
||||
|
||||
fun loadAccount(id: Long?, getAccount: (AccountModel) -> Unit) {
|
||||
fun loadAccount(id: Long?) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
getAccount(appDb.getDao().getAccount(id) ?: AccountModel())
|
||||
if (id == null) {
|
||||
_accountModel.emit(AccountModel())
|
||||
} else {
|
||||
_accountModel.emit(appDb.getDao().getAccount(id) ?: AccountModel())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setAccountModel(accountModel: AccountModel) {
|
||||
_accountModel.value = accountModel
|
||||
}
|
||||
|
||||
fun deleteAccount(accountModel: AccountModel, onExecCompleted: () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
accountModel.let {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.yogeshpaliyal.keypass.ui.detail.components
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Password
|
||||
import androidx.compose.material.icons.filled.QrCode
|
||||
import androidx.compose.material.icons.rounded.ArrowBackIosNew
|
||||
import androidx.compose.material.icons.rounded.Delete
|
||||
@@ -24,6 +25,7 @@ fun BottomBar(
|
||||
backPressed: () -> Unit,
|
||||
onDeleteAccount: () -> Unit,
|
||||
generateQrCodeClicked: () -> Unit,
|
||||
openPasswordConfiguration: () -> Unit,
|
||||
onSaveClicked: () -> Unit
|
||||
) {
|
||||
val openDialog = remember { mutableStateOf(false) }
|
||||
@@ -38,6 +40,17 @@ fun BottomBar(
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier.testTag("action_configure_password"),
|
||||
onClick = { openPasswordConfiguration() }
|
||||
) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(image = Icons.Default.Password),
|
||||
contentDescription = "Open Password Configuration",
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
|
||||
if (accountModel.id != null) {
|
||||
IconButton(
|
||||
modifier = Modifier.testTag("action_delete"),
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.yogeshpaliyal.common.utils.PasswordGenerator
|
||||
import com.yogeshpaliyal.keypass.R
|
||||
import com.yogeshpaliyal.keypass.ui.commonComponents.KeyPassInputField
|
||||
import com.yogeshpaliyal.keypass.ui.commonComponents.PasswordTrailingIcon
|
||||
import com.yogeshpaliyal.keypass.ui.nav.LocalUserSettings
|
||||
|
||||
@Composable
|
||||
fun Fields(
|
||||
@@ -39,6 +40,8 @@ fun Fields(
|
||||
copyToClipboardClicked: (String) -> Unit,
|
||||
scanClicked: (scannerType: Int) -> Unit
|
||||
) {
|
||||
val passwordConfig = LocalUserSettings.current.passwordConfig
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
@@ -90,7 +93,7 @@ fun Fields(
|
||||
{
|
||||
IconButton(
|
||||
onClick = {
|
||||
updateAccountModel(accountModel.copy(password = PasswordGenerator().generatePassword()))
|
||||
updateAccountModel(accountModel.copy(password = PasswordGenerator(passwordConfig).generatePassword()))
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
|
||||
@@ -14,7 +14,6 @@ class GeneratePasswordActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
viewModel.retrieveSavedPasswordLength(baseContext)
|
||||
setContent {
|
||||
Mdc3Theme {
|
||||
GeneratePasswordScreen(viewModel)
|
||||
|
||||
@@ -3,10 +3,10 @@ package com.yogeshpaliyal.keypass.ui.generate
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.yogeshpaliyal.common.data.PasswordConfig
|
||||
import com.yogeshpaliyal.common.utils.PasswordGenerator
|
||||
import com.yogeshpaliyal.common.utils.getUserSettings
|
||||
import com.yogeshpaliyal.common.utils.setDefaultPasswordLength
|
||||
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
|
||||
import com.yogeshpaliyal.common.utils.setPasswordConfig
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
@@ -23,18 +23,18 @@ class GeneratePasswordViewModel @Inject constructor(
|
||||
@ApplicationContext context: Context
|
||||
) : ViewModel() {
|
||||
|
||||
private val _viewState = MutableStateFlow(GeneratePasswordViewState.Initial)
|
||||
private val _viewState = MutableStateFlow(PasswordConfig.Initial)
|
||||
val viewState = _viewState.asStateFlow()
|
||||
|
||||
init {
|
||||
observeState(context)
|
||||
}
|
||||
|
||||
fun retrieveSavedPasswordLength(context: Context) {
|
||||
fun retrieveSavedPasswordConfig(context: Context) {
|
||||
viewModelScope.launch {
|
||||
val savedPasswordLength = context.getUserSettings().defaultPasswordLength ?: DEFAULT_PASSWORD_LENGTH
|
||||
val passwordConfig = context.getUserSettings().passwordConfig
|
||||
_viewState.update {
|
||||
_viewState.value.copy(length = savedPasswordLength)
|
||||
passwordConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,12 +43,7 @@ class GeneratePasswordViewModel @Inject constructor(
|
||||
val currentViewState = _viewState.value
|
||||
|
||||
val passwordGenerator = PasswordGenerator(
|
||||
length = currentViewState.length.toInt(),
|
||||
includeUpperCaseLetters = currentViewState.includeUppercaseLetters,
|
||||
includeLowerCaseLetters = currentViewState.includeLowercaseLetters,
|
||||
includeSymbols = currentViewState.includeSymbols,
|
||||
includeNumbers = currentViewState.includeNumbers,
|
||||
includeBlankSpaces = currentViewState.includeBlankSpaces
|
||||
currentViewState
|
||||
)
|
||||
|
||||
_viewState.update {
|
||||
@@ -100,7 +95,7 @@ class GeneratePasswordViewModel @Inject constructor(
|
||||
_viewState
|
||||
.debounce(400)
|
||||
.collectLatest { state ->
|
||||
context.setDefaultPasswordLength(state.length)
|
||||
context.setPasswordConfig(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.yogeshpaliyal.keypass.ui.generate
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
|
||||
|
||||
@Keep
|
||||
data class GeneratePasswordViewState(
|
||||
val length: Float,
|
||||
val includeUppercaseLetters: Boolean,
|
||||
|
||||
@@ -23,13 +23,13 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.accompanist.themeadapter.material3.Mdc3Theme
|
||||
import com.yogeshpaliyal.keypass.ui.generate.GeneratePasswordViewState
|
||||
import com.yogeshpaliyal.common.data.PasswordConfig
|
||||
import com.yogeshpaliyal.keypass.ui.generate.ui.components.CheckboxWithLabel
|
||||
import com.yogeshpaliyal.keypass.ui.generate.ui.components.PasswordLengthInput
|
||||
|
||||
@Composable
|
||||
fun GeneratePasswordContent(
|
||||
viewState: GeneratePasswordViewState,
|
||||
viewState: PasswordConfig,
|
||||
onCopyPasswordClick: () -> Unit,
|
||||
onGeneratePasswordClick: () -> Unit,
|
||||
onPasswordLengthChange: (Float) -> Unit,
|
||||
@@ -77,7 +77,7 @@ private fun GeneratePasswordFab(onGeneratePasswordClick: () -> Unit) {
|
||||
|
||||
@Composable
|
||||
private fun FormInputCard(
|
||||
viewState: GeneratePasswordViewState,
|
||||
viewState: PasswordConfig,
|
||||
onCopyPasswordClick: () -> Unit,
|
||||
onPasswordLengthChange: (Float) -> Unit,
|
||||
onUppercaseCheckedChange: (Boolean) -> Unit,
|
||||
@@ -211,7 +211,7 @@ private fun BlankSpaceInput(
|
||||
@Composable
|
||||
@Suppress("UnusedPrivateMember", "MagicNumber")
|
||||
private fun GeneratePasswordContentPreview() {
|
||||
val viewState = GeneratePasswordViewState.Initial
|
||||
val viewState = PasswordConfig.Initial
|
||||
|
||||
Mdc3Theme {
|
||||
GeneratePasswordContent(
|
||||
|
||||
@@ -4,22 +4,22 @@ import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.yogeshpaliyal.keypass.R
|
||||
import com.yogeshpaliyal.keypass.ui.generate.GeneratePasswordViewModel
|
||||
import com.yogeshpaliyal.keypass.ui.generate.ui.utils.copyTextToClipboard
|
||||
|
||||
@Composable
|
||||
fun GeneratePasswordScreen(viewModel: GeneratePasswordViewModel) {
|
||||
fun GeneratePasswordScreen(viewModel: GeneratePasswordViewModel = hiltViewModel()) {
|
||||
val context = LocalContext.current
|
||||
|
||||
// replace collectAsState() with collectAsStateWithLifecycle() when compose version and kotlin version are bumped up.
|
||||
val viewState by viewModel.viewState.collectAsState()
|
||||
val viewState by viewModel.viewState.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
viewModel.generatePassword()
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.retrieveSavedPasswordConfig(context)
|
||||
}
|
||||
|
||||
GeneratePasswordContent(
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.yogeshpaliyal.keypass.ui.backupsImport.BackupImporter
|
||||
import com.yogeshpaliyal.keypass.ui.changeDefaultPasswordLength.ChangeDefaultPasswordLengthScreen
|
||||
import com.yogeshpaliyal.keypass.ui.changePassword.ChangePassword
|
||||
import com.yogeshpaliyal.keypass.ui.detail.AccountDetailPage
|
||||
import com.yogeshpaliyal.keypass.ui.generate.ui.GeneratePasswordScreen
|
||||
import com.yogeshpaliyal.keypass.ui.home.Homepage
|
||||
import com.yogeshpaliyal.keypass.ui.nav.components.DashboardBottomSheet
|
||||
import com.yogeshpaliyal.keypass.ui.nav.components.KeyPassBottomBar
|
||||
@@ -46,6 +47,7 @@ import com.yogeshpaliyal.keypass.ui.redux.states.ChangeAppPasswordState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.ChangeDefaultPasswordLengthState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.HomeState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.KeyPassState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.PasswordGeneratorState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.ScreenState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.states.SettingsState
|
||||
import com.yogeshpaliyal.keypass.ui.settings.MySettingCompose
|
||||
@@ -169,6 +171,7 @@ fun CurrentPage() {
|
||||
|
||||
is BackupImporterState -> BackupImporter(state = it)
|
||||
is AboutState -> AboutScreen()
|
||||
is PasswordGeneratorState -> GeneratePasswordScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.yogeshpaliyal.keypass.ui.redux.states
|
||||
|
||||
class PasswordGeneratorState : ScreenState(false)
|
||||
@@ -64,7 +64,7 @@ fun MySettingCompose() {
|
||||
// Retrieving saved password length
|
||||
var savedPasswordLength by remember { mutableStateOf(DEFAULT_PASSWORD_LENGTH) }
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
userSettings.defaultPasswordLength.let { value -> savedPasswordLength = value }
|
||||
userSettings.passwordConfig.length.let { value -> savedPasswordLength = value }
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.fillMaxSize(1f).verticalScroll(rememberScrollState())) {
|
||||
|
||||
@@ -28,7 +28,7 @@ class SharedPreferenceUtilsTest {
|
||||
|
||||
@Test
|
||||
fun getKeyPassPasswordLength_test() = runBlocking {
|
||||
val result = context.getUserSettings().defaultPasswordLength
|
||||
val result = context.getUserSettings().passwordConfig.length
|
||||
assertEquals(DEFAULT_PASSWORD_LENGTH, result)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class SharedPreferenceUtilsTest {
|
||||
fun setKeyPassPasswordLength_test() = runBlocking {
|
||||
val expectedLength = 8f
|
||||
context.setDefaultPasswordLength(expectedLength)
|
||||
val result = context.getUserSettings().defaultPasswordLength
|
||||
val result = context.getUserSettings().passwordConfig.length
|
||||
assertEquals(expectedLength, result)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.yogeshpaliyal.common.data
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Keep
|
||||
@Serializable
|
||||
data class PasswordConfig(
|
||||
val length: Float,
|
||||
val includeUppercaseLetters: Boolean,
|
||||
val includeLowercaseLetters: Boolean,
|
||||
val includeSymbols: Boolean,
|
||||
val includeNumbers: Boolean,
|
||||
val includeBlankSpaces: Boolean,
|
||||
val password: String
|
||||
) {
|
||||
companion object {
|
||||
val Initial = PasswordConfig(
|
||||
length = DEFAULT_PASSWORD_LENGTH,
|
||||
includeUppercaseLetters = true,
|
||||
includeLowercaseLetters = true,
|
||||
includeSymbols = true,
|
||||
includeNumbers = true,
|
||||
includeBlankSpaces = true,
|
||||
password = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ const val DEFAULT_PASSWORD_LENGTH = 10f
|
||||
data class UserSettings(
|
||||
val keyPassPassword: String? = null,
|
||||
val dbPassword: String? = null,
|
||||
@Deprecated("Use passwordConfig instead")
|
||||
val defaultPasswordLength: Float = DEFAULT_PASSWORD_LENGTH,
|
||||
val backupKey: String? = null,
|
||||
val isBiometricEnable: Boolean = false,
|
||||
@@ -18,7 +19,8 @@ data class UserSettings(
|
||||
val autoBackupEnable: Boolean = false,
|
||||
val overrideAutoBackup: Boolean = false,
|
||||
val lastAppVersion: Int? = null,
|
||||
val currentAppVersion: Int? = null
|
||||
val currentAppVersion: Int? = null,
|
||||
val passwordConfig: PasswordConfig = PasswordConfig.Initial
|
||||
) {
|
||||
fun isKeyPresent() = backupKey != null
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package com.yogeshpaliyal.common.utils
|
||||
|
||||
class PasswordGenerator(
|
||||
private var length: Int,
|
||||
private var includeUpperCaseLetters: Boolean,
|
||||
private var includeLowerCaseLetters: Boolean,
|
||||
private var includeSymbols: Boolean,
|
||||
private var includeNumbers: Boolean,
|
||||
private var includeBlankSpaces: Boolean
|
||||
) {
|
||||
import com.yogeshpaliyal.common.data.PasswordConfig
|
||||
|
||||
constructor() : this(10, true, true, true, true, true) private val UPPER_CASE = 0
|
||||
class PasswordGenerator(
|
||||
val passwordConfig: PasswordConfig
|
||||
) {
|
||||
private val UPPER_CASE = 0
|
||||
private val LOWER_CASE = 1
|
||||
private val NUMBERS = 2
|
||||
private val SYMBOLS = 3
|
||||
@@ -18,24 +14,24 @@ class PasswordGenerator(
|
||||
fun generatePassword(): String {
|
||||
var password = ""
|
||||
val list = ArrayList<Int>()
|
||||
if (includeUpperCaseLetters) {
|
||||
if (passwordConfig.includeUppercaseLetters) {
|
||||
list.add(UPPER_CASE)
|
||||
}
|
||||
if (includeLowerCaseLetters) {
|
||||
if (passwordConfig.includeLowercaseLetters) {
|
||||
list.add(LOWER_CASE)
|
||||
}
|
||||
if (includeNumbers) {
|
||||
if (passwordConfig.includeNumbers) {
|
||||
list.add(NUMBERS)
|
||||
}
|
||||
if (includeSymbols) {
|
||||
if (passwordConfig.includeSymbols) {
|
||||
list.add(SYMBOLS)
|
||||
}
|
||||
|
||||
if (includeBlankSpaces) {
|
||||
if (passwordConfig.includeBlankSpaces) {
|
||||
list.add(BLANKSPACES)
|
||||
}
|
||||
|
||||
for (i in 1..length) {
|
||||
for (i in 1..passwordConfig.length.toInt()) {
|
||||
if (list.isNotEmpty()) {
|
||||
when (list.random()) {
|
||||
UPPER_CASE -> password += ('A'..'Z').random().toString()
|
||||
|
||||
@@ -9,6 +9,7 @@ import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.yogeshpaliyal.common.data.DEFAULT_PASSWORD_LENGTH
|
||||
import com.yogeshpaliyal.common.data.PasswordConfig
|
||||
import com.yogeshpaliyal.common.data.UserSettings
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
@@ -32,6 +33,12 @@ private fun Context.getUserSettingsDataStore(): DataStore<UserSettings> {
|
||||
return res
|
||||
}
|
||||
|
||||
suspend fun Context.setPasswordConfig(passwordConfig: PasswordConfig) {
|
||||
getUserSettingsDataStore().updateData {
|
||||
it.copy(passwordConfig = passwordConfig)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun Context.getUserSettings(): UserSettings {
|
||||
return getUserSettingsDataStore().data.firstOrNull() ?: UserSettings()
|
||||
}
|
||||
@@ -52,7 +59,7 @@ suspend fun Context.setKeyPassPassword(password: String?) {
|
||||
|
||||
suspend fun Context.setDefaultPasswordLength(password: Float) {
|
||||
getUserSettingsDataStore().updateData {
|
||||
it.copy(defaultPasswordLength = password)
|
||||
it.copy(passwordConfig = it.passwordConfig.copy(length = password))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +166,10 @@ suspend fun Context.migrateOldDataToNewerDataStore() {
|
||||
userSettings = userSettings.copy(defaultPasswordLength = olderData[KEYPASS_PASSWORD_LENGTH] ?: DEFAULT_PASSWORD_LENGTH)
|
||||
}
|
||||
|
||||
if (userSettings.defaultPasswordLength != DEFAULT_PASSWORD_LENGTH) {
|
||||
userSettings = userSettings.copy(passwordConfig = userSettings.passwordConfig.copy(length = userSettings.defaultPasswordLength))
|
||||
}
|
||||
|
||||
if (olderData.contains(BACKUP_DIRECTORY)) {
|
||||
userSettings = userSettings.copy(backupDirectory = olderData[BACKUP_DIRECTORY])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user