Make password generator parameter changes reactive (#1480)

* Make XkPassword generator reactive

* Handle empty strings

* Make password generator reactive

* Sync changelog for 1.13.5 release

* Add to changelog
This commit is contained in:
Harsh Shandilya 2021-08-08 13:06:26 +05:30 committed by GitHub
parent 1b54e679b7
commit 1738364d2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 9 deletions

View file

@ -30,11 +30,17 @@ All notable changes to this project will be documented in this file.
- Using the `git://` protocol in the server URL now presents an explicit discouragement rather than a generic error
- Encrypted data is no longer ASCII armored, bringing it in line with `pass`
- Removed Bromite from supported Autofill browsers, since they [disable Android autofill](https://github.com/bromite/bromite/blob/master/FAQ.md#does-bromite-support-the-android-autofill-framework).
- Changing password generator parameters now automatically updates the password without needing to press the 'Generate' button again
## [1.13.4] - 2021-03-20
## [1.13.5] - 2021-07-28
### Fixed
- When prompted to select a GPG key during onboarding, the app would crash if the user did not make a selection in OpenKeychain
- Certain apps had incorrect Autofill hints which would crash the app
## [1.13.4] - 2021-03-20
- Fix support for ECDSA SSH keys and support AES-GCM
- Fix a couple issues with Autofill
@ -448,7 +454,9 @@ All notable changes to this project will be documented in this file.
- Fix elements overlapping.
[Unreleased]: https://github.com/android-password-store/Android-Password-Store/compare/v1.13.4...HEAD
[Unreleased]: https://github.com/android-password-store/Android-Password-Store/compare/v1.13.5...release-1.13
[1.13.5]: https://github.com/android-password-store/Android-Password-Store/compare/v1.13.4...v1.13.5
[1.13.4]: https://github.com/android-password-store/Android-Password-Store/compare/v1.13.3...v1.13.4

View file

@ -102,6 +102,7 @@ dependencies {
implementation(libs.thirdparty.bouncycastle)
implementation(libs.thirdparty.eddsa)
implementation(libs.thirdparty.fastscroll)
implementation(libs.thirdparty.flowbinding.android)
implementation(libs.thirdparty.jgit) {
exclude(group = "org.apache.httpcomponents", module = "httpclient")
}

View file

@ -17,6 +17,7 @@ import androidx.appcompat.widget.AppCompatTextView
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.lifecycleScope
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -28,7 +29,14 @@ import dev.msfjarvis.aps.util.pwgen.PasswordGenerator.generate
import dev.msfjarvis.aps.util.pwgen.PasswordGenerator.setPrefs
import dev.msfjarvis.aps.util.pwgen.PasswordOption
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.afterTextChanges
import reactivecircus.flowbinding.android.widget.checkedChanges
@OptIn(ExperimentalCoroutinesApi::class)
class PasswordGeneratorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
@ -49,9 +57,21 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
binding.lowercase.isChecked = !prefs.getBoolean(PasswordOption.NoLowercaseLetters.key, false)
binding.ambiguous.isChecked = !prefs.getBoolean(PasswordOption.NoAmbiguousCharacters.key, false)
binding.pronounceable.isChecked = !prefs.getBoolean(PasswordOption.FullyRandom.key, true)
binding.lengthNumber.setText(prefs.getInt(PreferenceKeys.LENGTH, 20).toString())
binding.passwordText.typeface = monoTypeface
merge(
binding.numerals.checkedChanges().skipInitialValue(),
binding.symbols.checkedChanges().skipInitialValue(),
binding.uppercase.checkedChanges().skipInitialValue(),
binding.lowercase.checkedChanges().skipInitialValue(),
binding.ambiguous.checkedChanges().skipInitialValue(),
binding.pronounceable.checkedChanges().skipInitialValue(),
binding.lengthNumber.afterTextChanges().skipInitialValue(),
)
.onEach { generate(binding.passwordText) }
.launchIn(lifecycleScope)
return builder
.run {
setTitle(R.string.pwgen_title)

View file

@ -15,6 +15,7 @@ import androidx.core.content.edit
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.Timber.tag
import com.github.michaelbull.result.fold
import com.github.michaelbull.result.getOr
@ -26,8 +27,14 @@ import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivity
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.pwgenxkpwd.CapsType
import dev.msfjarvis.aps.util.pwgenxkpwd.PasswordBuilder
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.afterTextChanges
import reactivecircus.flowbinding.android.widget.selectionEvents
/** A placeholder fragment containing a simple view. */
@OptIn(ExperimentalCoroutinesApi::class)
class XkPasswordGeneratorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
@ -69,21 +76,34 @@ class XkPasswordGeneratorDialogFragment : DialogFragment() {
val dialog = builder.setTitle(this.resources.getString(R.string.xkpwgen_title)).create()
// make parameter changes reactive and automatically update passwords
merge(
binding.xkSeparator.afterTextChanges().skipInitialValue(),
binding.xkCapType.selectionEvents().skipInitialValue(),
binding.xkNumWords.afterTextChanges().skipInitialValue(),
binding.xkNumberSymbolMask.afterTextChanges().skipInitialValue(),
)
.onEach { updatePassword(binding, prefs) }
.launchIn(lifecycleScope)
dialog.setOnShowListener {
setPreferences(binding, prefs)
makeAndSetPassword(binding)
updatePassword(binding, prefs)
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener {
setPreferences(binding, prefs)
makeAndSetPassword(binding)
updatePassword(binding, prefs)
}
}
return dialog
}
private fun updatePassword(binding: FragmentXkpwgenBinding, prefs: SharedPreferences) {
setPreferences(binding, prefs)
makeAndSetPassword(binding)
}
private fun makeAndSetPassword(binding: FragmentXkpwgenBinding) {
PasswordBuilder(requireContext())
.setNumberOfWords(Integer.valueOf(binding.xkNumWords.text.toString()))
.setNumberOfWords(binding.xkNumWords.text.toString().ifBlank { "0" }.toInt())
.setMinimumWordLength(DEFAULT_MIN_WORD_LENGTH)
.setMaximumWordLength(DEFAULT_MAX_WORD_LENGTH)
.setSeparator(binding.xkSeparator.text.toString())

View file

@ -5,6 +5,7 @@ androidx_test = "1.4.0"
compose = "1.1.0-alpha01"
composeSnapshot = "-"
coroutines = "1.5.1"
flowbinding = "1.2.0"
hilt = "2.38.1"
kotlin = "1.5.21"
lifecycle = "2.4.0-alpha03"
@ -69,6 +70,7 @@ thirdparty-bouncycastle = "org.bouncycastle:bcprov-jdk15on:1.69"
thirdparty-commons_codec = "commons-codec:commons-codec:1.14"
thirdparty-eddsa = "net.i2p.crypto:eddsa:0.3.0"
thirdparty-fastscroll = "me.zhanghai.android.fastscroll:library:1.1.7"
thirdparty-flowbinding-android = { module = "io.github.reactivecircus.flowbinding:flowbinding-android", version.ref = "flowbinding" }
thirdparty-jgit = "org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r"
thirdparty-kotlinResult = "com.michael-bull.kotlin-result:kotlin-result:1.1.12"
thirdparty-leakcanary = "com.squareup.leakcanary:leakcanary-android:2.7"