mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Merge branch 'develop' into feature/DatabaseProvider
This commit is contained in:
@@ -674,7 +674,10 @@ class GroupActivity : LockingActivity(),
|
||||
|
||||
private fun updateEntryWithSearchInfo(database: Database, entry: Entry, searchInfo: SearchInfo) {
|
||||
val newEntry = Entry(entry)
|
||||
newEntry.setEntryInfo(database, newEntry.getEntryInfo(database, true).apply {
|
||||
newEntry.setEntryInfo(database, newEntry.getEntryInfo(database,
|
||||
raw = true,
|
||||
removeTemplateConfiguration = false
|
||||
).apply {
|
||||
saveSearchInfo(database, searchInfo)
|
||||
})
|
||||
updateEntry(entry, newEntry)
|
||||
|
||||
@@ -397,10 +397,16 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
||||
* Retrieve generated entry info.
|
||||
* If are not [raw] data, remove parameter fields and add auto generated elements in auto custom fields
|
||||
*/
|
||||
fun getEntryInfo(database: Database?, raw: Boolean = false): EntryInfo {
|
||||
fun getEntryInfo(database: Database?,
|
||||
raw: Boolean = false,
|
||||
removeTemplateConfiguration: Boolean = true): EntryInfo {
|
||||
val entryInfo = EntryInfo()
|
||||
// Remove unwanted template fields
|
||||
(database?.removeTemplateConfiguration(this) ?: this).apply {
|
||||
val baseInfo = if (removeTemplateConfiguration)
|
||||
database?.removeTemplateConfiguration(this) ?: this
|
||||
else
|
||||
this
|
||||
baseInfo.apply {
|
||||
if (raw)
|
||||
database?.stopManageEntry(this)
|
||||
else
|
||||
|
||||
@@ -170,24 +170,18 @@ class EntryInfo : NodeInfo {
|
||||
|
||||
if (database?.allowEntryCustomFields() == true) {
|
||||
val creditCard: CreditCard? = registerInfo.creditCard
|
||||
|
||||
creditCard?.let { cc ->
|
||||
cc.cardholder?.let {
|
||||
val v = ProtectedString(false, it)
|
||||
addUniqueField(Field(TemplateField.LABEL_HOLDER, v))
|
||||
}
|
||||
cc.expiration?.let {
|
||||
expires = true
|
||||
expiryTime = DateInstant(cc.expiration.millis)
|
||||
}
|
||||
cc.number?.let {
|
||||
val v = ProtectedString(false, it)
|
||||
addUniqueField(Field(TemplateField.LABEL_NUMBER, v))
|
||||
}
|
||||
cc.cvv?.let {
|
||||
val v = ProtectedString(true, it)
|
||||
addUniqueField(Field(TemplateField.LABEL_CVV, v))
|
||||
}
|
||||
creditCard?.cardholder?.let {
|
||||
addUniqueField(Field(TemplateField.LABEL_HOLDER, ProtectedString(false, it)))
|
||||
}
|
||||
creditCard?.expiration?.let {
|
||||
expires = true
|
||||
expiryTime = DateInstant(creditCard.expiration.millis)
|
||||
}
|
||||
creditCard?.number?.let {
|
||||
addUniqueField(Field(TemplateField.LABEL_NUMBER, ProtectedString(false, it)))
|
||||
}
|
||||
creditCard?.cvv?.let {
|
||||
addUniqueField(Field(TemplateField.LABEL_CVV, ProtectedString(true, it)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ class DateTimeEditFieldView @JvmOverloads constructor(context: Context,
|
||||
|
||||
private var mDateTime: DateInstant = DateInstant.IN_ONE_MONTH_DATE_TIME
|
||||
|
||||
private var mDefault: DateInstant = DateInstant.NEVER_EXPIRES
|
||||
|
||||
var setOnDateClickListener: ((DateInstant) -> Unit)? = null
|
||||
|
||||
init {
|
||||
@@ -68,7 +70,7 @@ class DateTimeEditFieldView @JvmOverloads constructor(context: Context,
|
||||
DateInstant.Type.TIME -> DateInstant.IN_ONE_HOUR_TIME
|
||||
}
|
||||
} else {
|
||||
DateInstant.NEVER_EXPIRES
|
||||
mDefault
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +107,7 @@ class DateTimeEditFieldView @JvmOverloads constructor(context: Context,
|
||||
return if (activation)
|
||||
mDateTime
|
||||
else
|
||||
DateInstant.NEVER_EXPIRES
|
||||
mDefault
|
||||
}
|
||||
set(value) {
|
||||
mDateTime = DateInstant(value.date, mDateTime.type)
|
||||
@@ -124,7 +126,17 @@ class DateTimeEditFieldView @JvmOverloads constructor(context: Context,
|
||||
mDateTime = try {
|
||||
DateInstant(value)
|
||||
} catch (e: Exception) {
|
||||
DateInstant.NEVER_EXPIRES
|
||||
mDefault
|
||||
}
|
||||
}
|
||||
|
||||
override var default: String
|
||||
get() = mDefault.toString()
|
||||
set(value) {
|
||||
mDefault = try {
|
||||
DateInstant(value)
|
||||
} catch (e: Exception) {
|
||||
mDefault
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
|
||||
private var mActivated: Boolean = false
|
||||
private var mDateTime: DateInstant = DateInstant.IN_ONE_MONTH_DATE_TIME
|
||||
|
||||
private var mDefault: DateInstant = DateInstant.NEVER_EXPIRES
|
||||
|
||||
var setOnDateClickListener: ((DateInstant) -> Unit)? = null
|
||||
|
||||
init {
|
||||
@@ -112,7 +114,7 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
|
||||
DateInstant.Type.TIME -> DateInstant.IN_ONE_HOUR_TIME
|
||||
}
|
||||
} else {
|
||||
DateInstant.NEVER_EXPIRES
|
||||
mDefault
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +126,7 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
|
||||
return if (activation)
|
||||
mDateTime
|
||||
else
|
||||
DateInstant.NEVER_EXPIRES
|
||||
mDefault
|
||||
}
|
||||
set(value) {
|
||||
mDateTime = DateInstant(value.date, mDateTime.type)
|
||||
@@ -139,7 +141,17 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
|
||||
mDateTime = try {
|
||||
DateInstant(value)
|
||||
} catch (e: Exception) {
|
||||
DateInstant.NEVER_EXPIRES
|
||||
mDefault
|
||||
}
|
||||
}
|
||||
|
||||
override var default: String
|
||||
get() = mDefault.toString()
|
||||
set(value) {
|
||||
mDefault = try {
|
||||
DateInstant(value)
|
||||
} catch (e: Exception) {
|
||||
mDefault
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,5 +3,6 @@ package com.kunzisoft.keepass.view
|
||||
interface GenericFieldView {
|
||||
var label: String
|
||||
var value: String
|
||||
var default: String
|
||||
var isFieldVisible: Boolean
|
||||
}
|
||||
@@ -141,7 +141,8 @@ abstract class TemplateAbstractView<
|
||||
templateAttribute,
|
||||
Field(
|
||||
templateAttribute.label,
|
||||
ProtectedString(templateAttribute.protected, "")
|
||||
ProtectedString(templateAttribute.protected,
|
||||
templateAttribute.default)
|
||||
),
|
||||
fieldTag
|
||||
)
|
||||
@@ -233,7 +234,14 @@ abstract class TemplateAbstractView<
|
||||
val indexOldItem = indexCustomFieldIdByName(field.name)
|
||||
if (indexOldItem >= 0)
|
||||
mCustomFieldIds.removeAt(indexOldItem)
|
||||
mCustomFieldIds.add(FieldId(field.name, itemView!!.id, field.protectedValue.isProtected))
|
||||
if (itemView?.id != null) {
|
||||
mCustomFieldIds.add(
|
||||
FieldId(
|
||||
itemView.id,
|
||||
field
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return itemView
|
||||
}
|
||||
@@ -451,32 +459,49 @@ abstract class TemplateAbstractView<
|
||||
* -------------
|
||||
*/
|
||||
|
||||
protected data class FieldId(var label: String, var viewId: Int, var protected: Boolean)
|
||||
protected data class FieldId(var viewId: Int, var field: Field)
|
||||
|
||||
private fun isStandardFieldName(name: String): Boolean {
|
||||
return TemplateField.isStandardFieldName(name)
|
||||
}
|
||||
|
||||
protected fun customFieldIdByName(name: String): FieldId? {
|
||||
return mCustomFieldIds.find { it.label.equals(name, true) }
|
||||
return mCustomFieldIds.find { it.field.name.equals(name, true) }
|
||||
}
|
||||
|
||||
protected fun indexCustomFieldIdByName(name: String): Int {
|
||||
return mCustomFieldIds.indexOfFirst { it.label.equals(name, true) }
|
||||
return mCustomFieldIds.indexOfFirst { it.field.name.equals(name, true) }
|
||||
}
|
||||
|
||||
private fun retrieveCustomFieldsFromView(templateFieldNotEmpty: Boolean = false) {
|
||||
mEntryInfo?.customFields = mCustomFieldIds.mapNotNull {
|
||||
getCustomField(it.label, templateFieldNotEmpty)
|
||||
getCustomField(it.field.name, templateFieldNotEmpty)
|
||||
}.toMutableList()
|
||||
}
|
||||
|
||||
protected fun getCustomField(fieldName: String): Field {
|
||||
return getCustomField(fieldName, false)
|
||||
?: Field(fieldName, ProtectedString(false, ""))
|
||||
?: Field(fieldName, ProtectedString(false))
|
||||
}
|
||||
|
||||
protected abstract fun getCustomField(fieldName: String, templateFieldNotEmpty: Boolean): Field?
|
||||
protected fun getCustomField(fieldName: String, templateFieldNotEmpty: Boolean): Field? {
|
||||
customFieldIdByName(fieldName)?.let { fieldId ->
|
||||
val editView: View? = templateContainerView.findViewById(fieldId.viewId)
|
||||
?: customFieldsContainerView.findViewById(fieldId.viewId)
|
||||
if (editView is GenericFieldView) {
|
||||
// Do not return field with a default value
|
||||
val defaultViewValue = if (editView.value == editView.default) "" else editView.value
|
||||
if (!templateFieldNotEmpty
|
||||
|| (editView.tag == FIELD_CUSTOM_TAG && defaultViewValue.isNotEmpty())) {
|
||||
return Field(
|
||||
fieldName,
|
||||
ProtectedString(fieldId.field.protectedValue.isProtected, defaultViewValue)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a custom field or create a new one if doesn't exists, the old value is lost
|
||||
@@ -493,16 +518,19 @@ abstract class TemplateAbstractView<
|
||||
replaceCustomField(customField, customField, focus)
|
||||
} else {
|
||||
val newCustomView = buildViewForCustomField(customField)
|
||||
customFieldsContainerView.addView(newCustomView)
|
||||
val fieldId = FieldId(customField.name,
|
||||
newCustomView!!.id,
|
||||
customField.protectedValue.isProtected)
|
||||
val indexOldItem = indexCustomFieldIdByName(fieldId.label)
|
||||
if (indexOldItem >= 0)
|
||||
mCustomFieldIds.removeAt(indexOldItem)
|
||||
mCustomFieldIds.add(indexOldItem, fieldId)
|
||||
if (focus)
|
||||
newCustomView.requestFocus()
|
||||
newCustomView?.let {
|
||||
customFieldsContainerView.addView(newCustomView)
|
||||
val fieldId = FieldId(
|
||||
newCustomView.id,
|
||||
customField
|
||||
)
|
||||
val indexOldItem = indexCustomFieldIdByName(fieldId.field.name)
|
||||
if (indexOldItem >= 0)
|
||||
mCustomFieldIds.removeAt(indexOldItem)
|
||||
mCustomFieldIds.add(indexOldItem, fieldId)
|
||||
if (focus)
|
||||
newCustomView.requestFocus()
|
||||
}
|
||||
true
|
||||
}
|
||||
} else {
|
||||
@@ -536,12 +564,18 @@ abstract class TemplateAbstractView<
|
||||
mCustomFieldIds.removeAt(oldPosition)
|
||||
|
||||
val newCustomView = buildViewForCustomField(newCustomFieldWithValue)
|
||||
parentGroup.addView(newCustomView, indexInParent)
|
||||
mCustomFieldIds.add(oldPosition, FieldId(newCustomFieldWithValue.name,
|
||||
newCustomView!!.id,
|
||||
newCustomFieldWithValue.protectedValue.isProtected))
|
||||
if (focus)
|
||||
newCustomView.requestFocus()
|
||||
newCustomView?.let {
|
||||
parentGroup.addView(newCustomView, indexInParent)
|
||||
mCustomFieldIds.add(
|
||||
oldPosition,
|
||||
FieldId(
|
||||
newCustomView.id,
|
||||
newCustomFieldWithValue
|
||||
)
|
||||
)
|
||||
if (focus)
|
||||
newCustomView.requestFocus()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
return context?.let {
|
||||
TextSelectFieldView(it).apply {
|
||||
setItems(templateAttribute.options.getListItems())
|
||||
default = field.protectedValue.stringValue
|
||||
setActionClick(templateAttribute, field, this)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO
|
||||
@@ -203,20 +204,6 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
}?.otpModel
|
||||
}
|
||||
|
||||
override fun getCustomField(fieldName: String, templateFieldNotEmpty: Boolean): Field? {
|
||||
customFieldIdByName(fieldName)?.let { fieldId ->
|
||||
val editView: View? = templateContainerView.findViewById(fieldId.viewId)
|
||||
?: customFieldsContainerView.findViewById(fieldId.viewId)
|
||||
if (editView is GenericFieldView) {
|
||||
if (!templateFieldNotEmpty ||
|
||||
(editView.tag == FIELD_CUSTOM_TAG
|
||||
&& editView.value.isNotEmpty()))
|
||||
return Field(fieldName, ProtectedString(fieldId.protected, editView.value))
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onRestoreEntryInstanceState(state: SavedState) {
|
||||
mTempDateTimeViewId = state.tempDateTimeViewId
|
||||
}
|
||||
|
||||
@@ -133,20 +133,6 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
return emptyCustomFields
|
||||
}
|
||||
|
||||
override fun getCustomField(fieldName: String, templateFieldNotEmpty: Boolean): Field? {
|
||||
customFieldIdByName(fieldName)?.let { fieldId ->
|
||||
val editView: View? = templateContainerView.findViewById(fieldId.viewId)
|
||||
?: customFieldsContainerView.findViewById(fieldId.viewId)
|
||||
if (editView is GenericFieldView) {
|
||||
if (!templateFieldNotEmpty ||
|
||||
(editView.tag == FIELD_CUSTOM_TAG
|
||||
&& editView.value.isNotEmpty()))
|
||||
return Field(fieldName, ProtectedString(fieldId.protected, editView.value))
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/*
|
||||
* OTP Runnable
|
||||
*/
|
||||
|
||||
@@ -122,6 +122,8 @@ class TextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
valueView.setText(value)
|
||||
}
|
||||
|
||||
override var default: String = ""
|
||||
|
||||
fun setMaxChars(numberChars: Int) {
|
||||
when {
|
||||
numberChars <= 0 -> {
|
||||
|
||||
@@ -88,6 +88,8 @@ class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
changeProtectedValueParameters()
|
||||
}
|
||||
|
||||
override var default: String = ""
|
||||
|
||||
fun setMaxChars(numberChars: Int) {
|
||||
when {
|
||||
numberChars <= 0 -> {
|
||||
|
||||
@@ -26,6 +26,7 @@ class TextSelectFieldView @JvmOverloads constructor(context: Context,
|
||||
private var valueViewId = ViewCompat.generateViewId()
|
||||
private var valueSpinnerAdapter = ValueSpinnerAdapter(context)
|
||||
private var actionImageButtonId = ViewCompat.generateViewId()
|
||||
private var mDefaultPosition = 0
|
||||
|
||||
private val labelView = AppCompatTextView(context).apply {
|
||||
setTextAppearance(context, R.style.KeepassDXStyle_TextAppearance_LabelTextStyle)
|
||||
@@ -142,12 +143,22 @@ class TextSelectFieldView @JvmOverloads constructor(context: Context,
|
||||
// To define default value and retrieve selected one
|
||||
override var value: String
|
||||
get() {
|
||||
return valueSpinnerView.selectedItem?.toString() ?: valueSpinnerAdapter.getItem(0)
|
||||
var selectedItemString = valueSpinnerView.selectedItem?.toString()
|
||||
if (selectedItemString.isNullOrEmpty()) {
|
||||
selectedItemString = valueSpinnerAdapter.getItem(0)
|
||||
}
|
||||
return selectedItemString
|
||||
}
|
||||
set(value) {
|
||||
valueSpinnerView.setSelection(valueSpinnerAdapter.getPosition(value))
|
||||
}
|
||||
|
||||
override var default: String
|
||||
get() = valueSpinnerAdapter.getItem(mDefaultPosition)
|
||||
set(value) {
|
||||
mDefaultPosition = valueSpinnerAdapter.getPosition(value)
|
||||
}
|
||||
|
||||
override fun setOnActionClickListener(onActionClickListener: OnClickListener?,
|
||||
@DrawableRes actionImageId: Int?) {
|
||||
actionImageId?.let {
|
||||
|
||||
Reference in New Issue
Block a user