From 1738364d2fdb3c4069d55516ea623d49dcebfd48 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Sun, 8 Aug 2021 13:06:26 +0530 Subject: 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 --- CHANGELOG.md | 12 ++++++-- app/build.gradle.kts | 1 + .../ui/dialogs/PasswordGeneratorDialogFragment.kt | 22 +++++++++++++- .../dialogs/XkPasswordGeneratorDialogFragment.kt | 34 +++++++++++++++++----- gradle/libs.versions.toml | 2 ++ 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66a756f1..bedec617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4ae3136e..0ca522f7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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") } diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/PasswordGeneratorDialogFragment.kt b/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/PasswordGeneratorDialogFragment.kt index 4820521f..ab51cc4e 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/PasswordGeneratorDialogFragment.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/PasswordGeneratorDialogFragment.kt @@ -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) diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/XkPasswordGeneratorDialogFragment.kt b/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/XkPasswordGeneratorDialogFragment.kt index ad252975..645ab9ba 100644 --- a/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/XkPasswordGeneratorDialogFragment.kt +++ b/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/XkPasswordGeneratorDialogFragment.kt @@ -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 - -/** A placeholder fragment containing a simple view. */ +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 + +@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()) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 223ea9a2..32837d4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" -- cgit v1.2.3