aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/injection/prefs/PasswordGeneratorPreferences.kt10
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/injection/prefs/PreferenceModule.kt5
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/dialogs/DicewarePasswordGeneratorDialogFragment.kt88
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt3
-rw-r--r--app/src/main/res/layout/fragment_pwgen_diceware.xml73
5 files changed, 179 insertions, 0 deletions
diff --git a/app/src/main/java/dev/msfjarvis/aps/injection/prefs/PasswordGeneratorPreferences.kt b/app/src/main/java/dev/msfjarvis/aps/injection/prefs/PasswordGeneratorPreferences.kt
new file mode 100644
index 00000000..14b3a6f2
--- /dev/null
+++ b/app/src/main/java/dev/msfjarvis/aps/injection/prefs/PasswordGeneratorPreferences.kt
@@ -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
diff --git a/app/src/main/java/dev/msfjarvis/aps/injection/prefs/PreferenceModule.kt b/app/src/main/java/dev/msfjarvis/aps/injection/prefs/PreferenceModule.kt
index 537ee1ad..e68a998f 100644
--- a/app/src/main/java/dev/msfjarvis/aps/injection/prefs/PreferenceModule.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/injection/prefs/PreferenceModule.kt
@@ -32,6 +32,11 @@ class PreferenceModule {
)
}
+ @[Provides PasswordGeneratorPreferences Reusable]
+ fun providePwgenPreferences(@ApplicationContext context: Context): SharedPreferences {
+ return provideBaseEncryptedPreferences(context, "pwgen_preferences")
+ }
+
@Provides
@SettingsPreferences
@Reusable
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/DicewarePasswordGeneratorDialogFragment.kt b/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/DicewarePasswordGeneratorDialogFragment.kt
new file mode 100644
index 00000000..cac60de3
--- /dev/null
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/dialogs/DicewarePasswordGeneratorDialogFragment.kt
@@ -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())
+ }
+ }
+}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt
index 7e3166d8..6168cfee 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt
@@ -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"
}
diff --git a/app/src/main/res/layout/fragment_pwgen_diceware.xml b/app/src/main/res/layout/fragment_pwgen_diceware.xml
new file mode 100644
index 00000000..ddb5ebd5
--- /dev/null
+++ b/app/src/main/res/layout/fragment_pwgen_diceware.xml
@@ -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>