Add keyfile selection view

This commit is contained in:
J-Jamet
2020-03-31 21:48:51 +02:00
parent 587f006259
commit 110cc402cc
6 changed files with 148 additions and 119 deletions

View File

@@ -65,6 +65,7 @@ import com.kunzisoft.keepass.utils.FileDatabaseInfo
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.view.AdvancedUnlockInfoView
import com.kunzisoft.keepass.view.KeyFileSelectionView
import com.kunzisoft.keepass.view.asError
import kotlinx.android.synthetic.main.activity_password.*
import java.io.FileNotFoundException
@@ -76,7 +77,7 @@ open class PasswordActivity : StylishActivity() {
private var containerView: View? = null
private var filenameView: TextView? = null
private var passwordView: EditText? = null
private var keyFileView: EditText? = null
private var keyFileSelectionView: KeyFileSelectionView? = null
private var confirmButtonView: Button? = null
private var checkboxPasswordView: CompoundButton? = null
private var checkboxKeyFileView: CompoundButton? = null
@@ -123,7 +124,7 @@ open class PasswordActivity : StylishActivity() {
confirmButtonView = findViewById(R.id.activity_password_open_button)
filenameView = findViewById(R.id.filename)
passwordView = findViewById(R.id.password)
keyFileView = findViewById(R.id.pass_keyfile)
keyFileSelectionView = findViewById(R.id.keyfile_selection)
checkboxPasswordView = findViewById(R.id.password_checkbox)
checkboxKeyFileView = findViewById(R.id.keyfile_checkox)
checkboxDefaultDatabaseView = findViewById(R.id.default_database)
@@ -134,7 +135,7 @@ open class PasswordActivity : StylishActivity() {
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrPreference(this, savedInstanceState)
mOpenFileHelper = OpenFileHelper(this@PasswordActivity)
findViewById<View>(R.id.open_keyfile_button)?.apply {
keyFileSelectionView?.apply {
mOpenFileHelper?.openFileOnClickViewListener?.let {
setOnClickListener(it)
setOnLongClickListener(it)
@@ -152,17 +153,6 @@ open class PasswordActivity : StylishActivity() {
checkboxPasswordView?.isChecked = true
}
})
keyFileView?.setOnEditorActionListener(onEditorActionListener)
keyFileView?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
if (editable.toString().isNotEmpty() && checkboxKeyFileView?.isChecked != true)
checkboxKeyFileView?.isChecked = true
}
})
enableButtonOnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { _, _ ->
enableOrNotTheConfirmationButton()
@@ -357,7 +347,7 @@ open class PasswordActivity : StylishActivity() {
// Define Key File text
if (mRememberKeyFile) {
populateKeyFileTextView(keyFileUri?.toString())
populateKeyFileTextView(keyFileUri)
}
// Define listeners for default database checkbox and validate button
@@ -471,13 +461,13 @@ open class PasswordActivity : StylishActivity() {
}
}
private fun populateKeyFileTextView(text: String?) {
if (text == null || text.isEmpty()) {
keyFileView?.setText("")
private fun populateKeyFileTextView(uri: Uri?) {
if (uri == null || uri.toString().isEmpty()) {
keyFileSelectionView?.uri = null
if (checkboxKeyFileView?.isChecked == true)
checkboxKeyFileView?.isChecked = false
} else {
keyFileView?.setText(text)
keyFileSelectionView?.uri = uri
if (checkboxKeyFileView?.isChecked != true)
checkboxKeyFileView?.isChecked = true
}
@@ -498,7 +488,7 @@ open class PasswordActivity : StylishActivity() {
private fun verifyCheckboxesAndLoadDatabase(cipherDatabaseEntity: CipherDatabaseEntity? = null) {
val password: String? = passwordView?.text?.toString()
val keyFile: Uri? = UriUtil.parse(keyFileView?.text?.toString())
val keyFile: Uri? = keyFileSelectionView?.uri
verifyCheckboxesAndLoadDatabase(password, keyFile, cipherDatabaseEntity)
}
@@ -511,7 +501,7 @@ open class PasswordActivity : StylishActivity() {
}
private fun verifyKeyFileCheckboxAndLoadDatabase(password: String?) {
val keyFile: Uri? = UriUtil.parse(keyFileView?.text?.toString())
val keyFile: Uri? = keyFileSelectionView?.uri
verifyKeyFileCheckbox(keyFile)
loadDatabase(mDatabaseFileUri, password, mDatabaseKeyFileUri)
}
@@ -721,7 +711,7 @@ open class PasswordActivity : StylishActivity() {
) { uri ->
if (uri != null) {
mDatabaseKeyFileUri = uri
populateKeyFileTextView(uri.toString())
populateKeyFileTextView(uri)
}
}
}

View File

@@ -35,7 +35,7 @@ import android.widget.CompoundButton
import android.widget.TextView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.OpenFileHelper
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.view.KeyFileSelectionView
class AssignMasterKeyDialogFragment : DialogFragment() {
@@ -51,9 +51,8 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
private var passwordRepeatTextInputLayout: TextInputLayout? = null
private var passwordRepeatView: TextView? = null
private var keyFileTextInputLayout: TextInputLayout? = null
private var keyFileCheckBox: CompoundButton? = null
private var keyFileView: TextView? = null
private var keyFileSelectionView: KeyFileSelectionView? = null
private var mListener: AssignPasswordDialogListener? = null
@@ -69,16 +68,6 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
}
}
private val keyFileTextWatcher = object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
keyFileCheckBox?.isChecked = true
}
}
interface AssignPasswordDialogListener {
fun onAssignKeyDialogPositiveClick(masterPasswordChecked: Boolean, masterPassword: String?,
keyFileChecked: Boolean, keyFile: Uri?)
@@ -121,12 +110,11 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
passwordRepeatTextInputLayout = rootView?.findViewById(R.id.password_repeat_input_layout)
passwordRepeatView = rootView?.findViewById(R.id.pass_conf_password)
keyFileTextInputLayout = rootView?.findViewById(R.id.keyfile_input_layout)
keyFileCheckBox = rootView?.findViewById(R.id.keyfile_checkox)
keyFileView = rootView?.findViewById(R.id.pass_keyfile)
keyFileSelectionView = rootView?.findViewById(R.id.keyfile_selection)
mOpenFileHelper = OpenFileHelper(this)
rootView?.findViewById<View>(R.id.open_keyfile_button)?.apply {
keyFileSelectionView?.apply {
setOnClickListener(mOpenFileHelper?.openFileOnClickViewListener)
setOnLongClickListener(mOpenFileHelper?.openFileOnClickViewListener)
}
@@ -178,14 +166,12 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
// To check checkboxes if a text is present
passwordView?.addTextChangedListener(passwordTextWatcher)
keyFileView?.addTextChangedListener(keyFileTextWatcher)
}
override fun onPause() {
super.onPause()
passwordView?.removeTextChangedListener(passwordTextWatcher)
keyFileView?.removeTextChangedListener(keyFileTextWatcher)
}
private fun verifyPassword(): Boolean {
@@ -218,11 +204,11 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
if (keyFileCheckBox != null
&& keyFileCheckBox!!.isChecked) {
UriUtil.parse(keyFileView?.text?.toString())?.let { uri ->
keyFileSelectionView?.uri?.let { uri ->
mKeyFile = uri
} ?: run {
error = true
keyFileTextInputLayout?.error = getString(R.string.error_nokeyfile)
keyFileSelectionView?.error = getString(R.string.error_nokeyfile)
}
}
return error
@@ -267,8 +253,7 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
) { uri ->
uri?.let { pathUri ->
keyFileCheckBox?.isChecked = true
keyFileView?.text = pathUri.toString()
keyFileSelectionView?.uri = pathUri
}
}
}

View File

@@ -0,0 +1,60 @@
package com.kunzisoft.keepass.view
import android.content.Context
import android.net.Uri
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.documentfile.provider.DocumentFile
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
class KeyFileSelectionView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
: ConstraintLayout(context, attrs, defStyle) {
private var mUri: Uri? = null
private val keyFileNameInputLayout: TextInputLayout
private val keyFileNameView: TextView
private val keyFileOpenView: ImageView
init {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
inflater?.inflate(R.layout.view_keyfile_selection, this)
keyFileNameInputLayout = findViewById(R.id.input_entry_keyfile)
keyFileNameView = findViewById(R.id.keyfile_name)
keyFileOpenView = findViewById(R.id.keyfile_open_button)
}
override fun setOnClickListener(l: OnClickListener?) {
super.setOnClickListener(l)
keyFileNameView.setOnClickListener(l)
}
override fun setOnLongClickListener(l: OnLongClickListener?) {
super.setOnLongClickListener(l)
keyFileNameView.setOnLongClickListener(l)
}
var error: CharSequence?
get() = keyFileNameInputLayout.error
set(value) {
keyFileNameInputLayout.error = value
}
var uri: Uri?
get() {
return mUri
}
set(value) {
mUri = value
keyFileNameView.text = value?.let {
DocumentFile.fromSingleUri(context, value)?.name ?: ""
} ?: ""
}
}

View File

@@ -162,58 +162,33 @@
</RelativeLayout>
<!-- File Input -->
<RelativeLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container_key_file"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/keyfile_checkox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:paddingBottom="20dp"
android:contentDescription="@string/content_description_keyfile_checkbox"
android:focusable="false"
android:layout_alignBottom="@+id/input_entry_keyfile"
android:gravity="center_vertical"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_entry_keyfile"
android:layout_width="wrap_content"
<com.kunzisoft.keepass.view.KeyFileSelectionView
android:id="@+id/keyfile_selection"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/keyfile_checkox"
app:layout_constraintEnd_toEndOf="parent"
android:importantForAccessibility="no"
android:importantForAutofill="no"
android:layout_toEndOf="@+id/keyfile_checkox"
android:layout_toRightOf="@+id/keyfile_checkox"
android:layout_toLeftOf="@+id/open_keyfile_button"
android:layout_toStartOf="@+id/open_keyfile_button">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:hint="@string/entry_keyfile"
android:inputType="textUri"
android:importantForAccessibility="no"
android:importantForAutofill="no"
android:imeOptions="actionDone"
android:maxLines="1"/>
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/open_keyfile_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:layout_alignBottom="@+id/input_entry_keyfile"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/content_description_open_file"
android:focusable="true"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccent"/>
</RelativeLayout>
android:importantForAutofill="no" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -109,44 +109,14 @@
android:layout_height="wrap_content"
android:text="@string/entry_keyfile"/>
<RelativeLayout
<com.kunzisoft.keepass.view.KeyFileSelectionView
android:id="@+id/keyfile_selection"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/open_keyfile_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/content_description_open_file"
android:layout_alignTop="@+id/keyfile_input_layout"
android:layout_alignBottom="@+id/keyfile_input_layout"
android:padding="12dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccent" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/keyfile_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/open_keyfile_button"
android:layout_toStartOf="@+id/open_keyfile_button"
android:importantForAccessibility="no"
android:importantForAutofill="no"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:importantForAutofill="no"
android:hint="@string/hint_keyfile"
android:maxLines="1"
android:singleLine="true"/>
</com.google.android.material.textfield.TextInputLayout>
</RelativeLayout>
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/keyfile_checkox"
app:layout_constraintEnd_toEndOf="parent" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container_key_file"
android:layout_marginBottom="@dimen/default_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:importantForAutofill="noExcludeDescendants"
tools:ignore="UnusedAttribute">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_entry_keyfile"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/keyfile_open_button">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/keyfile_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:hint="@string/entry_keyfile"
android:inputType="textPassword"
android:focusable="false"
android:cursorVisible="false"
android:focusableInTouchMode="false"
android:imeOptions="actionDone"
android:maxLines="1"/>
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/keyfile_open_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:padding="12dp"
android:contentDescription="@string/content_description_open_file"
android:focusable="true"
android:background="@drawable/background_item_selection"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccent"/>
</androidx.constraintlayout.widget.ConstraintLayout>