Refactor fragment edit entry, using EntryInfo

This commit is contained in:
J-Jamet
2020-09-15 19:04:20 +02:00
parent 1d57309db9
commit 7247de6908
8 changed files with 208 additions and 176 deletions

View File

@@ -311,7 +311,9 @@ class EntryActivity : LockingActivity() {
// Assign custom fields // Assign custom fields
if (mDatabase?.allowEntryCustomFields() == true) { if (mDatabase?.allowEntryCustomFields() == true) {
entryContentsView?.clearExtraFields() entryContentsView?.clearExtraFields()
for ((label, value) in entry.customFields) { entry.getExtraFields().forEach { field ->
val label = field.name
val value = field.protectedValue
val allowCopyProtectedField = !value.isProtected || allowCopyPasswordAndProtectedFields val allowCopyProtectedField = !value.isProtected || allowCopyPasswordAndProtectedFields
if (allowCopyProtectedField) { if (allowCopyProtectedField) {
entryContentsView?.addExtraField(label, value, allowCopyProtectedField) { entryContentsView?.addExtraField(label, value, allowCopyProtectedField) {

View File

@@ -132,7 +132,7 @@ class EntryEditActivity : LockingActivity(),
// Likely the app has been killed exit the activity // Likely the app has been killed exit the activity
mDatabase = Database.getInstance() mDatabase = Database.getInstance()
var tempEntry: Entry? = null var tempEntryInfo: EntryInfo? = null
// Entry is retrieve, it's an entry to update // Entry is retrieve, it's an entry to update
intent.getParcelableExtra<NodeId<UUID>>(KEY_ENTRY)?.let { intent.getParcelableExtra<NodeId<UUID>>(KEY_ENTRY)?.let {
@@ -149,14 +149,7 @@ class EntryEditActivity : LockingActivity(),
entry.parent = mParent entry.parent = mParent
} }
} }
tempEntryInfo = mEntry?.getEntryInfo(mDatabase, true)
mEntry?.let { entry ->
// Create a copy to modify
tempEntry = Entry(entry).also { newEntry ->
// WARNING Remove the parent to keep memory with parcelable
newEntry.removeParent()
}
}
} }
// Parent is retrieve, it's a new entry to create // Parent is retrieve, it's a new entry to create
@@ -165,12 +158,15 @@ class EntryEditActivity : LockingActivity(),
mParent = mDatabase?.getGroupById(it) mParent = mDatabase?.getGroupById(it)
// Add the default icon from parent if not a folder // Add the default icon from parent if not a folder
val parentIcon = mParent?.icon val parentIcon = mParent?.icon
tempEntryInfo = mDatabase?.createEntry()?.getEntryInfo(mDatabase, true)
// Set default icon
if (parentIcon != null if (parentIcon != null
&& parentIcon.iconId != IconImage.UNKNOWN_ID && parentIcon.iconId != IconImage.UNKNOWN_ID
&& parentIcon.iconId != IconImageStandard.FOLDER) { && parentIcon.iconId != IconImageStandard.FOLDER) {
tempEntry?.icon = parentIcon tempEntryInfo?.icon = parentIcon
} }
tempEntry = mDatabase?.createEntry() // Set default username
tempEntryInfo?.username = mDatabase?.defaultUsername ?: ""
} }
// Build fragment to manage entry modification // Build fragment to manage entry modification
@@ -181,16 +177,14 @@ class EntryEditActivity : LockingActivity(),
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.replace(R.id.entry_edit_contents, entryEditFragment!!, ENTRY_EDIT_FRAGMENT_TAG) .replace(R.id.entry_edit_contents, entryEditFragment!!, ENTRY_EDIT_FRAGMENT_TAG)
.commit() .commit()
mDatabase?.let { database -> entryEditFragment?.drawFactory = mDatabase?.drawFactory
entryEditFragment?.setDatabase(database) tempEntryInfo?.let {
} entryEditFragment?.setEntryInfo(it)
tempEntry?.let {
entryEditFragment?.setEntry(it, mIsNew)
} }
entryEditFragment?.apply { entryEditFragment?.apply {
applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this@EntryEditActivity)) applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this@EntryEditActivity))
setOnDateClickListener = View.OnClickListener { setOnDateClickListener = View.OnClickListener {
expiresDate.date.let { expiresDate -> expiryTime.date.let { expiresDate ->
val dateTime = DateTime(expiresDate) val dateTime = DateTime(expiresDate)
val defaultYear = dateTime.year val defaultYear = dateTime.year
val defaultMonth = dateTime.monthOfYear-1 val defaultMonth = dateTime.monthOfYear-1
@@ -208,6 +202,7 @@ class EntryEditActivity : LockingActivity(),
} }
setOnRemoveAttachment = { attachment -> setOnRemoveAttachment = { attachment ->
mAttachmentFileBinderManager?.removeBinaryAttachment(attachment) mAttachmentFileBinderManager?.removeBinaryAttachment(attachment)
removeAttachment(EntryAttachmentState(attachment, StreamDirection.DOWNLOAD))
} }
setOnEditCustomField = { field -> setOnEditCustomField = { field ->
editCustomField(field) editCustomField(field)
@@ -475,39 +470,47 @@ class EntryEditActivity : LockingActivity(),
*/ */
private fun saveEntry() { private fun saveEntry() {
// Get the temp entry // Get the temp entry
entryEditFragment?.getEntry()?.let { newEntry -> entryEditFragment?.getEntryInfo()?.let { newEntryInfo ->
// WARNING Add the parent previously deleted if (mIsNew) {
newEntry.parent = mEntry?.parent // Create new one
// Build info mDatabase?.createEntry()
newEntry.lastAccessTime = DateInstant() } else {
newEntry.lastModificationTime = DateInstant() // Create a clone
Entry(mEntry!!)
}?.let { newEntry ->
// Delete temp attachment if not used newEntry.setEntryInfo(mDatabase, newEntryInfo)
mTempAttachments.forEach { // Build info
mDatabase?.binaryPool?.let { binaryPool -> newEntry.lastAccessTime = DateInstant()
if (!newEntry.getAttachments(binaryPool).contains(it)) { newEntry.lastModificationTime = DateInstant()
mDatabase?.removeAttachmentIfNotUsed(it)
// Delete temp attachment if not used
mTempAttachments.forEach {
mDatabase?.binaryPool?.let { binaryPool ->
if (!newEntry.getAttachments(binaryPool).contains(it)) {
mDatabase?.removeAttachmentIfNotUsed(it)
}
} }
} }
}
// Open a progress dialog and save entry // Open a progress dialog and save entry
if (mIsNew) { if (mIsNew) {
mParent?.let { parent -> mParent?.let { parent ->
mProgressDatabaseTaskProvider?.startDatabaseCreateEntry( mProgressDatabaseTaskProvider?.startDatabaseCreateEntry(
newEntry, newEntry,
parent, parent,
!mReadOnly && mAutoSaveEnable !mReadOnly && mAutoSaveEnable
) )
} }
} else { } else {
mEntry?.let { oldEntry -> mEntry?.let { oldEntry ->
mProgressDatabaseTaskProvider?.startDatabaseUpdateEntry( mProgressDatabaseTaskProvider?.startDatabaseUpdateEntry(
oldEntry, oldEntry,
newEntry, newEntry,
!mReadOnly && mAutoSaveEnable !mReadOnly && mAutoSaveEnable
) )
}
} }
} }
} }
@@ -603,7 +606,7 @@ class EntryEditActivity : LockingActivity(),
// Update the otp field with otpauth:// url // Update the otp field with otpauth:// url
val otpField = OtpEntryFields.buildOtpField(otpElement, val otpField = OtpEntryFields.buildOtpField(otpElement,
mEntry?.title, mEntry?.username) mEntry?.title, mEntry?.username)
mEntry?.putExtraField(otpField.name, otpField.protectedValue) mEntry?.putExtraField(Field(otpField.name, otpField.protectedValue))
entryEditFragment?.apply { entryEditFragment?.apply {
putExtraField(otpField) putExtraField(otpField)
getExtraFieldViewPosition(otpField) { position -> getExtraFieldViewPosition(otpField) { position ->
@@ -622,9 +625,9 @@ class EntryEditActivity : LockingActivity(),
// To fix android 4.4 issue // To fix android 4.4 issue
// https://stackoverflow.com/questions/12436073/datepicker-ondatechangedlistener-called-twice // https://stackoverflow.com/questions/12436073/datepicker-ondatechangedlistener-called-twice
if (datePicker?.isShown == true) { if (datePicker?.isShown == true) {
entryEditFragment?.expiresDate?.date?.let { expiresDate -> entryEditFragment?.expiryTime?.date?.let { expiresDate ->
// Save the date // Save the date
entryEditFragment?.expiresDate = entryEditFragment?.expiryTime =
DateInstant(DateTime(expiresDate) DateInstant(DateTime(expiresDate)
.withYear(year) .withYear(year)
.withMonthOfYear(month + 1) .withMonthOfYear(month + 1)
@@ -641,9 +644,9 @@ class EntryEditActivity : LockingActivity(),
} }
override fun onTimeSet(timePicker: TimePicker?, hours: Int, minutes: Int) { override fun onTimeSet(timePicker: TimePicker?, hours: Int, minutes: Int) {
entryEditFragment?.expiresDate?.date?.let { expiresDate -> entryEditFragment?.expiryTime?.date?.let { expiresDate ->
// Save the date // Save the date
entryEditFragment?.expiresDate = entryEditFragment?.expiryTime =
DateInstant(DateTime(expiresDate) DateInstant(DateTime(expiresDate)
.withHourOfDay(hours) .withHourOfDay(hours)
.withMinuteOfHour(minutes) .withMinuteOfHour(minutes)

View File

@@ -39,13 +39,12 @@ import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.StylishFragment import com.kunzisoft.keepass.activities.stylish.StylishFragment
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
import com.kunzisoft.keepass.database.element.Attachment import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.DateInstant import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.icon.IconImage import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageStandard import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.icons.assignDatabaseIcon import com.kunzisoft.keepass.icons.assignDatabaseIcon
import com.kunzisoft.keepass.model.EntryAttachmentState import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.Field import com.kunzisoft.keepass.model.Field
import com.kunzisoft.keepass.model.StreamDirection import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.view.applyFontVisibility import com.kunzisoft.keepass.view.applyFontVisibility
@@ -86,9 +85,7 @@ class EntryEditFragment: StylishFragment() {
var setOnRemoveAttachment: ((Attachment) -> Unit)? = null var setOnRemoveAttachment: ((Attachment) -> Unit)? = null
// Elements to modify the current entry // Elements to modify the current entry
private var mDatabase: Database? = null private var mEntryInfo = EntryInfo()
private var mEntry: Entry? = null
private var mIsNewEntry = true
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
@@ -149,94 +146,58 @@ class EntryEditFragment: StylishFragment() {
taIconColor?.recycle() taIconColor?.recycle()
// Retrieve the new entry after an orientation change // Retrieve the new entry after an orientation change
if (savedInstanceState?.containsKey(KEY_TEMP_ENTRY) == true) { if (savedInstanceState?.containsKey(KEY_TEMP_ENTRY_INFO) == true) {
mEntry = savedInstanceState.getParcelable(KEY_TEMP_ENTRY) mEntryInfo = savedInstanceState.getParcelable(KEY_TEMP_ENTRY_INFO) ?: mEntryInfo
} }
mDatabase?.let { database -> populateViewsWithEntry()
mEntry?.let { entry ->
populateViewsWithEntry(database, entry, mIsNewEntry)
}
}
return rootView return rootView
} }
fun setDatabase(database: Database) { fun getEntryInfo(): EntryInfo? {
mDatabase = database populateEntryWithViews()
return mEntryInfo
} }
fun getEntry(): Entry? { fun setEntryInfo(entryInfo: EntryInfo) {
mDatabase?.let { database -> populateViewsWithEntry()
mEntry?.let { entry -> mEntryInfo = entryInfo
populateEntryWithViews(database, entry) }
private fun populateViewsWithEntry() {
try {
// Set info in view
icon = mEntryInfo.icon
title = mEntryInfo.title
username = mEntryInfo.username
url = mEntryInfo.url
password = mEntryInfo.password
expires = mEntryInfo.expires
expiryTime = mEntryInfo.expiryTime
notes = mEntryInfo.notes
assignExtraFields(mEntryInfo.customFields) { fields ->
setOnEditCustomField?.invoke(fields)
} }
} assignAttachments(mEntryInfo.attachments, StreamDirection.UPLOAD) { attachment ->
return mEntry setOnRemoveAttachment?.invoke(attachment)
}
fun setEntry(entry: Entry, isNewEntry: Boolean) {
mEntry = entry
mIsNewEntry = isNewEntry
}
private fun populateViewsWithEntry(database: Database, entry: Entry, isNewEntry: Boolean) {
// Don't start the field reference manager, we want to see the raw ref
database.stopManageEntry(entry)
// Set info in view
icon = entry.icon
title = entry.title
username = if (isNewEntry && entry.username.isEmpty())
database.defaultUsername
else
entry.username
url = entry.url
password = entry.password
expires = entry.expires
if (expires)
expiresDate = entry.expiryTime
notes = entry.notes
assignExtraFields(entry.customFields.mapTo(ArrayList()) {
Field(it.key, it.value)
}) {
setOnEditCustomField?.invoke(it)
}
assignAttachments(entry.getAttachments(database.binaryPool).toSet(), StreamDirection.UPLOAD) { attachment ->
// Remove entry by clicking trash button
entry.removeAttachment(attachment)
}
}
private fun populateEntryWithViews(database: Database, newEntry: Entry) {
database.startManageEntry(newEntry)
newEntry.apply {
// Build info from view
this@EntryEditFragment.let { entryView ->
removeAllFields()
title = entryView.title
username = entryView.username
url = entryView.url
password = entryView.password
expires = entryView.expires
if (entryView.expires) {
expiryTime = entryView.expiresDate
}
notes = entryView.notes
entryView.getExtraFields().forEach { customField ->
putExtraField(customField.name, customField.protectedValue)
}
database.binaryPool.let { binaryPool ->
entryView.getAttachments().forEach {
putAttachment(it, binaryPool)
}
}
} }
} } catch (e: Exception) {}
}
database.stopManageEntry(newEntry) private fun populateEntryWithViews() {
try {
// Icon already populate
mEntryInfo.title = title
mEntryInfo.username = username
mEntryInfo.url = url
mEntryInfo.password = password
mEntryInfo.expires = expires
mEntryInfo.expiryTime = expiryTime
mEntryInfo.notes = notes
mEntryInfo.customFields = getExtraFields()
mEntryInfo.attachments = getAttachments()
} catch (e: Exception) {}
} }
fun applyFontVisibilityToFields(fontInVisibility: Boolean) { fun applyFontVisibilityToFields(fontInVisibility: Boolean) {
@@ -253,13 +214,15 @@ class EntryEditFragment: StylishFragment() {
entryTitleView.applyFontVisibility() entryTitleView.applyFontVisibility()
} }
var drawFactory: IconDrawableFactory? = null
var icon: IconImage var icon: IconImage
get() { get() {
return mEntry?.icon ?: IconImageStandard() return mEntryInfo.icon
} }
set(value) { set(value) {
mEntry?.icon = value mEntryInfo.icon = value
mDatabase?.drawFactory?.let { drawFactory -> drawFactory?.let { drawFactory ->
entryIconView.assignDatabaseIcon(drawFactory, value, iconColor) entryIconView.assignDatabaseIcon(drawFactory, value, iconColor)
} }
} }
@@ -316,7 +279,7 @@ class EntryEditFragment: StylishFragment() {
assignExpiresDateText() assignExpiresDateText()
} }
var expiresDate: DateInstant var expiryTime: DateInstant
get() { get() {
return expiresInstant return expiresInstant
} }
@@ -471,7 +434,7 @@ class EntryEditFragment: StylishFragment() {
return attachmentsAdapter.itemsList.map { it.attachment } return attachmentsAdapter.itemsList.map { it.attachment }
} }
fun assignAttachments(attachments: Set<Attachment>, fun assignAttachments(attachments: List<Attachment>,
streamDirection: StreamDirection, streamDirection: StreamDirection,
onDeleteItem: (attachment: Attachment)->Unit) { onDeleteItem: (attachment: Attachment)->Unit) {
attachmentsContainerView.visibility = if (attachments.isEmpty()) View.GONE else View.VISIBLE attachmentsContainerView.visibility = if (attachments.isEmpty()) View.GONE else View.VISIBLE
@@ -513,18 +476,14 @@ class EntryEditFragment: StylishFragment() {
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
mEntry?.let { entry -> populateEntryWithViews()
mDatabase?.let { database -> outState.putParcelable(KEY_TEMP_ENTRY_INFO, mEntryInfo)
populateEntryWithViews(database, entry)
}
outState.putParcelable(KEY_TEMP_ENTRY, entry)
}
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
} }
companion object { companion object {
const val KEY_TEMP_ENTRY = "KEY_TEMP_ENTRY" const val KEY_TEMP_ENTRY_INFO = "KEY_TEMP_ENTRY_INFO"
} }
} }

View File

@@ -33,7 +33,6 @@ import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.NodeIdUUID import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.model.EntryInfo import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.Field import com.kunzisoft.keepass.model.Field
import com.kunzisoft.keepass.otp.OtpElement import com.kunzisoft.keepass.otp.OtpElement
@@ -284,29 +283,43 @@ class Entry : Node, EntryVersionedInterface<Group> {
} }
/** /**
* Retrieve custom fields to show, key is the label, value is the value of field (protected or not) * Retrieve extra fields to show, key is the label, value is the value of field (protected or not)
* @return Map of label/value * @return Map of label/value
*/ */
val customFields: HashMap<String, ProtectedString> fun getExtraFields(): List<Field> {
get() = entryKDBX?.customFields ?: HashMap() val extraFields = ArrayList<Field>()
entryKDBX?.let {
fun removeAllFields() { for (field in it.customFields) {
entryKDBX?.removeAllFields() extraFields.add(Field(field.key, field.value))
}
}
return extraFields
} }
/** /**
* Update or add an extra field to the list (standard or custom) * Update or add an extra field to the list (standard or custom)
* @param label Label of field, must be unique
* @param value Value of field
*/ */
fun putExtraField(label: String, value: ProtectedString) { fun putExtraField(field: Field) {
entryKDBX?.putExtraField(label, value) entryKDBX?.putExtraField(field.name, field.protectedValue)
}
private fun addExtraFields(fields: List<Field>) {
fields.forEach {
putExtraField(it)
}
}
private fun removeAllFields() {
entryKDBX?.removeAllFields()
} }
fun getOtpElement(): OtpElement? { fun getOtpElement(): OtpElement? {
return OtpEntryFields.parseFields { key -> entryKDBX?.let {
customFields[key]?.toString() return OtpEntryFields.parseFields { key ->
it.customFields[key]?.toString()
}
} }
return null
} }
fun startToManageFieldReferences(database: DatabaseKDBX) { fun startToManageFieldReferences(database: DatabaseKDBX) {
@@ -333,16 +346,27 @@ class Entry : Node, EntryVersionedInterface<Group> {
|| entryKDBX?.containsAttachment() == true || entryKDBX?.containsAttachment() == true
} }
fun putAttachment(attachment: Attachment, binaryPool: BinaryPool) { private fun addAttachments(binaryPool: BinaryPool, attachments: List<Attachment>) {
entryKDB?.putAttachment(attachment) attachments.forEach {
entryKDBX?.putAttachment(attachment, binaryPool) putAttachment(it, binaryPool)
}
} }
fun removeAttachment(attachment: Attachment) { private fun removeAttachment(attachment: Attachment) {
entryKDB?.removeAttachment(attachment) entryKDB?.removeAttachment(attachment)
entryKDBX?.removeAttachment(attachment) entryKDBX?.removeAttachment(attachment)
} }
private fun removeAllAttachments() {
entryKDB?.removeAttachment()
entryKDBX?.removeAttachments()
}
private fun putAttachment(attachment: Attachment, binaryPool: BinaryPool) {
entryKDB?.putAttachment(attachment)
entryKDBX?.putAttachment(attachment, binaryPool)
}
fun getHistory(): ArrayList<Entry> { fun getHistory(): ArrayList<Entry> {
val history = ArrayList<Entry>() val history = ArrayList<Entry>()
val entryKDBXHistory = entryKDBX?.history ?: ArrayList() val entryKDBXHistory = entryKDBX?.history ?: ArrayList()
@@ -396,6 +420,7 @@ class Entry : Node, EntryVersionedInterface<Group> {
database?.stopManageEntry(this) database?.stopManageEntry(this)
else else
database?.startManageEntry(this) database?.startManageEntry(this)
entryInfo.id = nodeId.toString() entryInfo.id = nodeId.toString()
entryInfo.title = title entryInfo.title = title
entryInfo.icon = icon entryInfo.icon = icon
@@ -403,19 +428,44 @@ class Entry : Node, EntryVersionedInterface<Group> {
entryInfo.password = password entryInfo.password = password
entryInfo.url = url entryInfo.url = url
entryInfo.notes = notes entryInfo.notes = notes
for (entry in customFields.entries) { entryInfo.customFields = getExtraFields()
entryInfo.customFields.add(
Field(entry.key, entry.value))
}
// Add otpElement to generate token // Add otpElement to generate token
entryInfo.otpModel = getOtpElement()?.otpModel entryInfo.otpModel = getOtpElement()?.otpModel
// Replace parameter fields by generated OTP fields if (!raw) {
entryInfo.customFields = OtpEntryFields.generateAutoFields(entryInfo.customFields) // Replace parameter fields by generated OTP fields
entryInfo.customFields = OtpEntryFields.generateAutoFields(entryInfo.customFields)
}
database?.binaryPool?.let { binaryPool ->
entryInfo.attachments = getAttachments(binaryPool)
}
if (!raw) if (!raw)
database?.stopManageEntry(this) database?.stopManageEntry(this)
return entryInfo return entryInfo
} }
fun setEntryInfo(database: Database?, newEntryInfo: EntryInfo) {
database?.startManageEntry(this)
removeAllFields()
removeAllAttachments()
// NodeId stay as is
title = newEntryInfo.title
icon = newEntryInfo.icon
username = newEntryInfo.username
password = newEntryInfo.password
expires = newEntryInfo.expires
expiryTime = newEntryInfo.expiryTime
url = newEntryInfo.url
notes = newEntryInfo.notes
addExtraFields(newEntryInfo.customFields)
database?.binaryPool?.let { binaryPool ->
addAttachments(binaryPool, newEntryInfo.attachments)
}
database?.stopManageEntry(this)
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false

View File

@@ -153,8 +153,8 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
this.binaryData = attachment.binaryAttachment this.binaryData = attachment.binaryAttachment
} }
fun removeAttachment(attachment: Attachment) { fun removeAttachment(attachment: Attachment? = null) {
if (this.binaryDescription == attachment.name) { if (attachment == null || this.binaryDescription == attachment.name) {
this.binaryDescription = "" this.binaryDescription = ""
this.binaryData = null this.binaryData = null
} }

View File

@@ -309,6 +309,12 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
binaries.remove(attachment.name) binaries.remove(attachment.name)
} }
fun removeAttachments() {
binaries.keys.forEach {
binaries.remove(it)
}
}
private fun getAttachmentsSize(binaryPool: BinaryPool): Long { private fun getAttachmentsSize(binaryPool: BinaryPool): Long {
var size = 0L var size = 0L
for ((label, poolId) in binaries) { for ((label, poolId) in binaries) {

View File

@@ -21,7 +21,10 @@ package com.kunzisoft.keepass.model
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.icon.IconImage import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
import com.kunzisoft.keepass.otp.OtpElement import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
import java.util.* import java.util.*
@@ -30,12 +33,15 @@ class EntryInfo : Parcelable {
var id: String = "" var id: String = ""
var title: String = "" var title: String = ""
var icon: IconImage? = null var icon: IconImage = IconImageStandard()
var username: String = "" var username: String = ""
var password: String = "" var password: String = ""
var expires: Boolean = false
var expiryTime: DateInstant = DateInstant.NEVER_EXPIRE
var url: String = "" var url: String = ""
var notes: String = "" var notes: String = ""
var customFields: MutableList<Field> = ArrayList() var customFields: List<Field> = ArrayList()
var attachments: List<Attachment> = ArrayList()
var otpModel: OtpModel? = null var otpModel: OtpModel? = null
constructor() constructor()
@@ -43,12 +49,15 @@ class EntryInfo : Parcelable {
private constructor(parcel: Parcel) { private constructor(parcel: Parcel) {
id = parcel.readString() ?: id id = parcel.readString() ?: id
title = parcel.readString() ?: title title = parcel.readString() ?: title
icon = parcel.readParcelable(IconImage::class.java.classLoader) icon = parcel.readParcelable(IconImage::class.java.classLoader) ?: icon
username = parcel.readString() ?: username username = parcel.readString() ?: username
password = parcel.readString() ?: password password = parcel.readString() ?: password
expires = parcel.readInt() != 0
expiryTime = parcel.readParcelable(DateInstant::class.java.classLoader) ?: expiryTime
url = parcel.readString() ?: url url = parcel.readString() ?: url
notes = parcel.readString() ?: notes notes = parcel.readString() ?: notes
parcel.readList(customFields as List<Field>, Field::class.java.classLoader) parcel.readList(customFields, Field::class.java.classLoader)
parcel.readList(attachments, Attachment::class.java.classLoader)
otpModel = parcel.readParcelable(OtpModel::class.java.classLoader) ?: otpModel otpModel = parcel.readParcelable(OtpModel::class.java.classLoader) ?: otpModel
} }
@@ -62,9 +71,12 @@ class EntryInfo : Parcelable {
parcel.writeParcelable(icon, flags) parcel.writeParcelable(icon, flags)
parcel.writeString(username) parcel.writeString(username)
parcel.writeString(password) parcel.writeString(password)
parcel.writeInt(if (expires) 1 else 0)
parcel.writeParcelable(expiryTime, flags)
parcel.writeString(url) parcel.writeString(url)
parcel.writeString(notes) parcel.writeString(notes)
parcel.writeArray(customFields.toTypedArray()) parcel.writeArray(customFields.toTypedArray())
parcel.writeArray(attachments.toTypedArray())
parcel.writeParcelable(otpModel, flags) parcel.writeParcelable(otpModel, flags)
} }

View File

@@ -347,7 +347,7 @@ object OtpEntryFields {
* Build new generated fields in a new list from [fieldsToParse] in parameter, * Build new generated fields in a new list from [fieldsToParse] in parameter,
* Remove parameters fields use to generate auto fields * Remove parameters fields use to generate auto fields
*/ */
fun generateAutoFields(fieldsToParse: MutableList<Field>): MutableList<Field> { fun generateAutoFields(fieldsToParse: List<Field>): MutableList<Field> {
val newCustomFields: MutableList<Field> = ArrayList(fieldsToParse) val newCustomFields: MutableList<Field> = ArrayList(fieldsToParse)
// Remove parameter fields // Remove parameter fields
val otpField = Field(OTP_FIELD) val otpField = Field(OTP_FIELD)