diff options
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> |