app: add diceware generator dialog

This commit is contained in:
Harsh Shandilya 2021-12-21 01:13:17 +05:30
parent 0e8f899434
commit fd46f1f0ba
No known key found for this signature in database
GPG Key ID: 366D7BBAD1031E80
5 changed files with 179 additions and 0 deletions

View File

@ -0,0 +1,10 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.injection.prefs
import javax.inject.Qualifier
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class PasswordGeneratorPreferences

View File

@ -32,6 +32,11 @@ class PreferenceModule {
)
}
@[Provides PasswordGeneratorPreferences Reusable]
fun providePwgenPreferences(@ApplicationContext context: Context): SharedPreferences {
return provideBaseEncryptedPreferences(context, "pwgen_preferences")
}
@Provides
@SettingsPreferences
@Reusable

View File

@ -0,0 +1,88 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.dialogs
import android.app.AlertDialog
import android.app.Dialog
import android.content.SharedPreferences
import android.graphics.Typeface
import android.os.Bundle
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.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.databinding.FragmentPwgenDicewareBinding
import dev.msfjarvis.aps.injection.prefs.PasswordGeneratorPreferences
import dev.msfjarvis.aps.passgen.diceware.DicewarePassphraseGenerator
import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivity
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.settings.PreferenceKeys.DICEWARE_LENGTH
import dev.msfjarvis.aps.util.settings.PreferenceKeys.DICEWARE_SEPARATOR
import javax.inject.Inject
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.afterTextChanges
@AndroidEntryPoint
class DicewarePasswordGeneratorDialogFragment : DialogFragment() {
@Inject lateinit var dicewareGenerator: DicewarePassphraseGenerator
@Inject @PasswordGeneratorPreferences lateinit var prefs: SharedPreferences
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
val binding = FragmentPwgenDicewareBinding.inflate(layoutInflater)
val monoTypeface = Typeface.createFromAsset(requireContext().assets, "fonts/sourcecodepro.ttf")
binding.passwordSeparatorText.setText(prefs.getString(DICEWARE_SEPARATOR) ?: "-")
binding.passwordLengthText.setText(prefs.getInt(DICEWARE_LENGTH, 5).toString())
binding.passwordText.typeface = monoTypeface
builder.setView(binding.root)
merge(
binding.passwordLengthText.afterTextChanges(),
binding.passwordSeparatorText.afterTextChanges(),
)
.onEach { generatePassword(binding) }
.launchIn(lifecycleScope)
return builder
.run {
setTitle(R.string.pwgen_title)
setPositiveButton(R.string.dialog_ok) { _, _ ->
setFragmentResult(
PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY,
bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}")
)
}
setNeutralButton(R.string.dialog_cancel) { _, _ -> }
setNegativeButton(R.string.pwgen_generate, null)
create()
}
.apply {
setOnShowListener {
generatePassword(binding)
getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener { generatePassword(binding) }
}
}
}
private fun generatePassword(binding: FragmentPwgenDicewareBinding) {
val length = binding.passwordLengthText.text?.toString()?.toIntOrNull() ?: 5
val separator = binding.passwordSeparatorText.text?.toString()?.getOrNull(0) ?: '-'
setPreferences(length, separator)
binding.passwordText.text = dicewareGenerator.generatePassphrase(length, separator)
}
private fun setPreferences(length: Int, separator: Char) {
prefs.edit {
putInt(DICEWARE_LENGTH, length)
putString(DICEWARE_SEPARATOR, separator.toString())
}
}
}

View File

@ -82,4 +82,7 @@ object PreferenceKeys {
const val PROXY_PASSWORD = "proxy_password"
const val REBASE_ON_PULL = "rebase_on_pull"
const val DICEWARE_SEPARATOR = "diceware_separator"
const val DICEWARE_LENGTH = "diceware_length"
}

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
~ SPDX-License-Identifier: GPL-3.0-only
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="24dp"
android:paddingTop="20dp"
android:paddingRight="24dp"
android:paddingBottom="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/password_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_length"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="4dp"
android:hint="@string/pwgen_length"
android:labelFor="@id/password_length_text"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:layout_constraintEnd_toStartOf="@id/password_separator"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/password_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_length_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="2" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_separator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="8dp"
android:hint="@string/pwgen_separator"
android:labelFor="@id/password_separator_text"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintStart_toEndOf="@id/password_length"
app:layout_constraintTop_toBottomOf="@id/password_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_separator_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:importantForAutofill="no"
android:inputType="text"
android:maxLength="1" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>