Add Password Generator with Specific Special Characters #862 (#865)

* Precise choice about what special characters I need to use #862

* List Of Symbols Bug

* Changed

* Code Formatted

* SpotlessApply Checked
This commit is contained in:
Kapil Baser
2024-06-05 22:53:14 +05:30
committed by GitHub
parent 88515323bb
commit 993ab75b40
12 changed files with 118 additions and 40 deletions

View File

@@ -41,12 +41,11 @@ android {
applicationIdSuffix = ".staging"
signingConfig = signingConfigs.getByName("debug")
}
}
productFlavors {
create("free") {
isDefault=true
isDefault = true
}
create("pro") {
applicationIdSuffix = ".pro"
@@ -61,7 +60,7 @@ android {
jvmTarget = "17"
freeCompilerArgs = listOf(
"-Xopt-in=androidx.compose.material3.ExperimentalMaterial3Api"
"-Xopt-in=androidx.compose.material3.ExperimentalMaterial3Api",
)
}
buildFeatures {
@@ -71,8 +70,6 @@ android {
flavorDimensions("default")
packagingOptions {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
@@ -89,11 +86,10 @@ android {
}
}
lint{
lint {
disable += "MissingTranslation"
abortOnError = true
}
}
ruler {
@@ -103,10 +99,9 @@ ruler {
sdkVersion.set(27)
}
dependencies {
//api(project(":shared"))
// api(project(":shared"))
api(project(":common"))
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
@@ -151,12 +146,10 @@ dependencies {
kapt("androidx.hilt:hilt-compiler:1.2.0")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
// zxing library
// implementation "com.googl.ezxing:android-core:3.4.1"
implementation("com.journeyapps:zxing-android-embedded:4.3.0")
// For instrumented tests.
androidTestImplementation("com.google.dagger:hilt-android-testing:2.51.1")
// ...with Kotlin.
@@ -171,6 +164,4 @@ dependencies {
implementation("me.saket.cascade:cascade-compose:2.2.0")
implementation("androidx.biometric:biometric:1.1.0")
}

View File

@@ -26,7 +26,7 @@ fun KeyPassInputField(
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
visualTransformation: VisualTransformation = VisualTransformation.None,
copyToClipboardClicked: ((String) -> Unit) ? = null
copyToClipboardClicked: ((String) -> Unit)? = null
) {
OutlinedTextField(
modifier = modifier.fillMaxWidth(),

View File

@@ -89,20 +89,22 @@ fun Fields(
},
leadingIcon = if (accountModel.id != null) {
null
} else (
{
IconButton(
onClick = {
updateAccountModel(accountModel.copy(password = PasswordGenerator(passwordConfig).generatePassword()))
} else {
(
{
IconButton(
onClick = {
updateAccountModel(accountModel.copy(password = PasswordGenerator(passwordConfig).generatePassword()))
}
) {
Icon(
painter = rememberVectorPainter(image = Icons.Rounded.Refresh),
contentDescription = ""
)
}
) {
Icon(
painter = rememberVectorPainter(image = Icons.Rounded.Refresh),
contentDescription = ""
)
}
}
),
)
},
visualTransformation = visualTransformation,
copyToClipboardClicked = copyToClipboardClicked
)

View File

@@ -52,6 +52,38 @@ class GeneratePasswordViewModel @Inject constructor(
}
}
fun selectSymbolForPassword(symbol: Char) {
val tempList = _viewState.value.listOfSymbols.toMutableList()
if (tempList.size == PasswordGenerator.totalSymbol.size && tempList.contains(symbol)) {
tempList.clear()
}
if (symbol == 's') {
_viewState.update {
it.copy(
listOfSymbols = PasswordGenerator.totalSymbol
)
}
return
}
if (tempList.contains(symbol)) {
tempList.remove(symbol)
if (tempList.isEmpty()) {
selectSymbolForPassword('s')
return
}
} else {
tempList.add(symbol)
}
_viewState.update {
it.copy(
listOfSymbols = tempList.toList()
)
}
}
fun onPasswordLengthSliderChange(value: Float) {
_viewState.update {
it.copy(length = value)

View File

@@ -3,6 +3,8 @@ package com.yogeshpaliyal.keypass.ui.generate.ui
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -14,16 +16,19 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.accompanist.themeadapter.material3.Mdc3Theme
import com.yogeshpaliyal.common.data.PasswordConfig
import com.yogeshpaliyal.common.utils.PasswordGenerator
import com.yogeshpaliyal.keypass.ui.generate.ui.components.CheckboxWithLabel
import com.yogeshpaliyal.keypass.ui.generate.ui.components.PasswordLengthInput
@@ -37,6 +42,7 @@ fun GeneratePasswordContent(
onLowercaseCheckedChange: (Boolean) -> Unit,
onNumbersCheckedChange: (Boolean) -> Unit,
onSymbolsCheckedChange: (Boolean) -> Unit,
selectSymbolForPassword: (Char) -> Unit = {},
onBlankSpacesCheckedChange: (Boolean) -> Unit
) {
Scaffold(
@@ -56,6 +62,7 @@ fun GeneratePasswordContent(
onLowercaseCheckedChange = onLowercaseCheckedChange,
onNumbersCheckedChange = onNumbersCheckedChange,
onSymbolsCheckedChange = onSymbolsCheckedChange,
selectSymbolForPassword = selectSymbolForPassword,
onBlankSpacesCheckedChange = onBlankSpacesCheckedChange
)
}
@@ -84,6 +91,7 @@ private fun FormInputCard(
onLowercaseCheckedChange: (Boolean) -> Unit,
onNumbersCheckedChange: (Boolean) -> Unit,
onSymbolsCheckedChange: (Boolean) -> Unit,
selectSymbolForPassword: (Char) -> Unit = {},
onBlankSpacesCheckedChange: (Boolean) -> Unit
) {
OutlinedCard(
@@ -107,7 +115,7 @@ private fun FormInputCard(
NumberInput(viewState.includeNumbers, onNumbersCheckedChange)
SymbolInput(viewState.includeSymbols, onSymbolsCheckedChange)
SymbolInput(viewState.includeSymbols, onSymbolsCheckedChange, selectSymbolForPassword, viewState.listOfSymbols)
BlankSpaceInput(viewState.includeBlankSpaces, onBlankSpacesCheckedChange)
}
@@ -176,16 +184,55 @@ private fun NumberInput(
)
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun SymbolInput(
includeSymbols: Boolean,
onSymbolsCheckedChange: (Boolean) -> Unit
onSymbolsCheckedChange: (Boolean) -> Unit,
selectSymbolForPassword: (Char) -> Unit = {},
selectedSymbols: List<Char>
) {
CheckboxWithLabel(
label = "Symbols",
checked = includeSymbols,
onCheckedChange = onSymbolsCheckedChange
)
Column {
CheckboxWithLabel(
label = "Symbols",
checked = includeSymbols,
onCheckedChange = onSymbolsCheckedChange
)
if (includeSymbols) {
FlowRow(modifier = Modifier.fillMaxWidth()) {
OutlinedCard(
onClick = {
selectSymbolForPassword('s')
},
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.outlinedCardColors(
containerColor = if (selectedSymbols.size == PasswordGenerator.totalSymbol.size) MaterialTheme.colorScheme.primary else Color.Unspecified
)
) {
Text(
text = "All",
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
}
PasswordGenerator.totalSymbol.forEach { symbol ->
OutlinedCard(
onClick = {
selectSymbolForPassword(symbol)
},
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.outlinedCardColors(
if (symbol in selectedSymbols && selectedSymbols.size != PasswordGenerator.totalSymbol.size) MaterialTheme.colorScheme.primary else Color.Unspecified
)
) {
Text(
text = "$symbol",
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
}
}
}
}
}
}
@Composable

View File

@@ -31,6 +31,7 @@ fun GeneratePasswordScreen(viewModel: GeneratePasswordViewModel = hiltViewModel(
onLowercaseCheckedChange = viewModel::onLowercaseCheckedChange,
onNumbersCheckedChange = viewModel::onNumbersCheckedChange,
onSymbolsCheckedChange = viewModel::onSymbolsCheckedChange,
selectSymbolForPassword = viewModel::selectSymbolForPassword,
onBlankSpacesCheckedChange = viewModel::onBlankSpacesCheckedChange
)
}

View File

@@ -41,7 +41,7 @@ dependencies {
// apache common codec
implementation("commons-codec:commons-codec:1.17.0")
//Androidx Security
// Androidx Security
implementation("androidx.security:security-crypto:1.1.0-alpha06")
api("androidx.documentfile:documentfile:1.0.1")
@@ -76,6 +76,4 @@ dependencies {
implementation("androidx.sqlite:sqlite:2.3.1")
api("com.opencsv:opencsv:5.8")
}

View File

@@ -3,6 +3,7 @@ package com.yogeshpaliyal.common.constants
annotation class AccountType {
companion object {
const val DEFAULT = 1 // used to store password and user information
@Deprecated("TOTP type removed, added TOTP support in Default")
const val TOTP = 2 // used to store Time base - One time Password
/* const val HOTP = 3

View File

@@ -1,6 +1,7 @@
package com.yogeshpaliyal.common.data
import androidx.annotation.Keep
import com.yogeshpaliyal.common.utils.PasswordGenerator
import kotlinx.serialization.Serializable
@Keep
@@ -10,6 +11,7 @@ data class PasswordConfig(
val includeUppercaseLetters: Boolean,
val includeLowercaseLetters: Boolean,
val includeSymbols: Boolean,
val listOfSymbols: List<Char>,
val includeNumbers: Boolean,
val includeBlankSpaces: Boolean,
val password: String
@@ -20,6 +22,7 @@ data class PasswordConfig(
includeUppercaseLetters = true,
includeLowercaseLetters = true,
includeSymbols = true,
listOfSymbols = PasswordGenerator.totalSymbol,
includeNumbers = true,
includeBlankSpaces = true,
password = ""

View File

@@ -11,6 +11,10 @@ class PasswordGenerator(
private val SYMBOLS = 3
private val BLANKSPACES = 4
companion object {
val totalSymbol = listOf('!', '@', '#', '$', '%', '&', '*', '+', '=', '-', '~', '?', '/', '_')
}
fun generatePassword(): String {
var password = ""
val list = ArrayList<Int>()
@@ -37,7 +41,7 @@ class PasswordGenerator(
UPPER_CASE -> password += ('A'..'Z').random().toString()
LOWER_CASE -> password += ('a'..'z').random().toString()
NUMBERS -> password += ('0'..'9').random().toString()
SYMBOLS -> password += listOf('!', '@', '#', '$', '%', '&', '*', '+', '=', '-', '~', '?', '/', '_').random().toString()
SYMBOLS -> password += passwordConfig.listOfSymbols.random().toString()
BLANKSPACES -> password += (' ').toString()
}
}

View File

@@ -4,5 +4,5 @@
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Tue May 09 21:09:59 IST 2023
sdk.dir=/Users/yogesh.choudhary3/Library/Android/sdk
#Tue Jun 04 13:10:19 IST 2024
sdk.dir=C\:\\Users\\win10\\AppData\\Local\\Android\\Sdk

View File

@@ -39,7 +39,6 @@ kotlin {
}
val desktopMain by getting {
dependencies {
}
}
val desktopTest by getting