Fix OTP runnable

This commit is contained in:
J-Jamet
2021-06-17 20:35:42 +02:00
parent 0d376bd5b7
commit 531e345dd9
4 changed files with 80 additions and 55 deletions

View File

@@ -182,7 +182,9 @@ class EntryActivity : LockingActivity() {
} }
mEntryViewModel.onOtpElementUpdated.observe(this) { otpElement -> mEntryViewModel.onOtpElementUpdated.observe(this) { otpElement ->
when (otpElement.type) { if (otpElement == null)
entryProgress?.visibility = View.GONE
when (otpElement?.type) {
// Only add token if HOTP // Only add token if HOTP
OtpType.HOTP -> { OtpType.HOTP -> {
entryProgress?.visibility = View.GONE entryProgress?.visibility = View.GONE

View File

@@ -46,7 +46,6 @@ class EntryFragment: DatabaseFragment() {
private lateinit var uuidView: TextView private lateinit var uuidView: TextView
private lateinit var uuidReferenceView: TextView private lateinit var uuidReferenceView: TextView
private var mOtpRunnable: Runnable? = null
private var mClipboardHelper: ClipboardHelper? = null private var mClipboardHelper: ClipboardHelper? = null
private val mEntryViewModel: EntryViewModel by activityViewModels() private val mEntryViewModel: EntryViewModel by activityViewModels()
@@ -143,8 +142,10 @@ class EntryFragment: DatabaseFragment() {
// Populate entry views // Populate entry views
templateView.setEntryInfo(entryInfo) templateView.setEntryInfo(entryInfo)
//Assign OTP field // OTP timer updated
assignOtp(entryInfo) templateView.setOnOtpElementUpdated { otpElementUpdated ->
mEntryViewModel.onOtpElementUpdated(otpElementUpdated)
}
// Manage attachments // Manage attachments
assignAttachments(entryInfo?.attachments ?: listOf()) assignAttachments(entryInfo?.attachments ?: listOf())
@@ -185,39 +186,6 @@ class EntryFragment: DatabaseFragment() {
templateView.reload() templateView.reload()
} }
private fun assignOtp(entryInfo: EntryInfo?) {
entryInfo?.otpModel?.let { otpModel ->
val otpElement = OtpElement(otpModel)
templateView.getOtpTokenView()?.let { otpFieldView ->
otpFieldView.removeCallbacks(mOtpRunnable)
if (otpElement.token.isEmpty()) {
otpFieldView.setLabel(R.string.entry_otp)
otpFieldView.setValue(R.string.error_invalid_OTP)
otpFieldView.setCopyButtonState(EntryFieldView.ButtonState.GONE)
} else {
otpFieldView.label = otpElement.type.name
otpFieldView.value = otpElement.token
otpFieldView.setCopyButtonState(EntryFieldView.ButtonState.ACTIVATE)
otpFieldView.setCopyButtonClickListener {
mClipboardHelper?.timeoutCopyToClipboard(
otpElement.token,
getString(R.string.copy_field, getString(R.string.entry_otp))
)
}
mOtpRunnable = Runnable {
if (otpElement.shouldRefreshToken()) {
otpFieldView.value = otpElement.token
}
mEntryViewModel.onOtpElementUpdated(otpElement)
otpFieldView.postDelayed(mOtpRunnable, 1000)
}
mEntryViewModel.onOtpElementUpdated(otpElement)
otpFieldView.post(mOtpRunnable)
}
}
}
}
private fun assignCreationDate(date: DateInstant?) { private fun assignCreationDate(date: DateInstant?) {
creationDateView.text = date?.getDateTimeString(resources) creationDateView.text = date?.getDateTimeString(resources)
} }

View File

@@ -5,6 +5,7 @@ import android.util.AttributeSet
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.DateInstant import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.Field import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.database.element.security.ProtectedString import com.kunzisoft.keepass.database.element.security.ProtectedString
@@ -12,7 +13,8 @@ import com.kunzisoft.keepass.database.element.template.TemplateAttribute
import com.kunzisoft.keepass.database.element.template.TemplateAttributeType import com.kunzisoft.keepass.database.element.template.TemplateAttributeType
import com.kunzisoft.keepass.database.element.template.TemplateField import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.model.EntryInfo import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.otp.OtpEntryFields import com.kunzisoft.keepass.model.OtpModel
import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
@@ -205,6 +207,12 @@ class TemplateView @JvmOverloads constructor(context: Context,
templateContainerView.findViewById<View>(customFieldId.viewId) templateContainerView.findViewById<View>(customFieldId.viewId)
.isVisible = false .isVisible = false
} }
// Assign specific OTP dynamic view
removeOtpRunnable()
entryInfo.otpModel?.let {
assignOtp(it)
}
} }
} }
@@ -248,20 +256,6 @@ class TemplateView @JvmOverloads constructor(context: Context,
} }
retrieveCustomFieldsFromView(templateFieldNotEmpty) retrieveCustomFieldsFromView(templateFieldNotEmpty)
mEntryInfo?.otpModel = OtpEntryFields.parseFields { key ->
getCustomField(key).protectedValue.toString()
}?.otpModel
}
fun getOtpTokenView(): EntryFieldView? {
val indexFieldViewId = indexCustomFieldIdByName(OTP_TOKEN_FIELD)
if (indexFieldViewId >= 0) {
// Template contains the custom view
val customFieldId = mCustomFieldIds[indexFieldViewId]
return findViewById(customFieldId.viewId)
}
return null
} }
override fun getCustomField(fieldName: String, templateFieldNotEmpty: Boolean): Field? { override fun getCustomField(fieldName: String, templateFieldNotEmpty: Boolean): Field? {
@@ -285,6 +279,67 @@ class TemplateView @JvmOverloads constructor(context: Context,
return null return null
} }
/*
* OTP Runnable
*/
private var mOtpRunnable: Runnable? = null
private var mLastOtpTokenView: View? = null
fun setOnOtpElementUpdated(listener: ((OtpElement?) -> Unit)?) {
this.mOnOtpElementUpdated = listener
}
private var mOnOtpElementUpdated: ((OtpElement?) -> Unit)? = null
private fun getOtpTokenView(): EntryFieldView? {
val indexFieldViewId = indexCustomFieldIdByName(OTP_TOKEN_FIELD)
if (indexFieldViewId >= 0) {
// Template contains the custom view
val customFieldId = mCustomFieldIds[indexFieldViewId]
return findViewById(customFieldId.viewId)
}
return null
}
private fun assignOtp(otpModel: OtpModel) {
getOtpTokenView()?.apply {
val otpElement = OtpElement(otpModel)
if (otpElement.token.isEmpty()) {
setLabel(R.string.entry_otp)
setValue(R.string.error_invalid_OTP)
setCopyButtonState(EntryFieldView.ButtonState.GONE)
} else {
label = otpElement.type.name
value = otpElement.token
setCopyButtonState(EntryFieldView.ButtonState.ACTIVATE)
setCopyButtonClickListener {
mOnCopyActionClickListener?.invoke(Field(
otpElement.type.name,
ProtectedString(false, otpElement.token)))
}
mLastOtpTokenView = this
mOtpRunnable = Runnable {
if (otpElement.shouldRefreshToken()) {
value = otpElement.token
}
if (mLastOtpTokenView == null) {
mOnOtpElementUpdated?.invoke(null)
} else {
mOnOtpElementUpdated?.invoke(otpElement)
postDelayed(mOtpRunnable, 1000)
}
}
mOnOtpElementUpdated?.invoke(otpElement)
post(mOtpRunnable)
}
}
}
private fun removeOtpRunnable() {
mLastOtpTokenView?.removeCallbacks(mOtpRunnable)
mLastOtpTokenView = null
}
companion object { companion object {
private val TAG = TemplateEditView::class.java.name private val TAG = TemplateEditView::class.java.name
} }

View File

@@ -37,8 +37,8 @@ class EntryViewModel: ViewModel() {
val entryHistory : LiveData<List<EntryInfo>> get() = _entryHistory val entryHistory : LiveData<List<EntryInfo>> get() = _entryHistory
private val _entryHistory = MutableLiveData<List<EntryInfo>>() private val _entryHistory = MutableLiveData<List<EntryInfo>>()
val onOtpElementUpdated : LiveData<OtpElement> get() = _onOtpElementUpdated val onOtpElementUpdated : LiveData<OtpElement?> get() = _onOtpElementUpdated
private val _onOtpElementUpdated = SingleLiveEvent<OtpElement>() private val _onOtpElementUpdated = SingleLiveEvent<OtpElement?>()
val attachmentSelected : LiveData<Attachment> get() = _attachmentSelected val attachmentSelected : LiveData<Attachment> get() = _attachmentSelected
private val _attachmentSelected = SingleLiveEvent<Attachment>() private val _attachmentSelected = SingleLiveEvent<Attachment>()
@@ -122,7 +122,7 @@ class EntryViewModel: ViewModel() {
return entryIsHistory.value ?: false return entryIsHistory.value ?: false
} }
fun onOtpElementUpdated(optElement: OtpElement) { fun onOtpElementUpdated(optElement: OtpElement?) {
_onOtpElementUpdated.value = optElement _onOtpElementUpdated.value = optElement
} }