mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Merge branch 'develop' into feature/Custom_Icons
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
KeePassDX(2.9.14)
|
KeePassDX(2.9.14)
|
||||||
* Dark Themes (WARNING: You must reselect your theme if upgrading from an old installation)
|
* Dark Themes (WARNING: You must reselect your theme if upgrading from an old installation) #532 #714
|
||||||
|
* Fix binary deduplication #715
|
||||||
|
* Fix IconId #901
|
||||||
|
|
||||||
KeePassDX(2.9.13)
|
KeePassDX(2.9.13)
|
||||||
* Binary image viewer #473 #749
|
* Binary image viewer #473 #749
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import org.junit.Test
|
|||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.lang.Exception
|
|
||||||
import java.security.MessageDigest
|
|
||||||
|
|
||||||
class BinaryAttachmentTest {
|
class BinaryAttachmentTest {
|
||||||
|
|
||||||
@@ -132,20 +130,6 @@ class BinaryAttachmentTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun BinaryAttachment.md5(): String {
|
|
||||||
val md = MessageDigest.getInstance("MD5")
|
|
||||||
return this.getInputDataStream(loadedKey).use { fis ->
|
|
||||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
|
||||||
generateSequence {
|
|
||||||
when (val bytesRead = fis.read(buffer)) {
|
|
||||||
-1 -> null
|
|
||||||
else -> bytesRead
|
|
||||||
}
|
|
||||||
}.forEach { bytesRead -> md.update(buffer, 0, bytesRead) }
|
|
||||||
md.digest().joinToString("") { "%02x".format(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TEST_FILE_CACHE_A = "testA"
|
private const val TEST_FILE_CACHE_A = "testA"
|
||||||
private const val TEST_FILE_CACHE_B = "testB"
|
private const val TEST_FILE_CACHE_B = "testB"
|
||||||
|
|||||||
@@ -172,10 +172,14 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
val parentIcon = mParent?.icon
|
val parentIcon = mParent?.icon
|
||||||
tempEntryInfo = mDatabase?.createEntry()?.getEntryInfo(mDatabase, true)
|
tempEntryInfo = mDatabase?.createEntry()?.getEntryInfo(mDatabase, true)
|
||||||
// Set default icon
|
// Set default icon
|
||||||
if (parentIcon != null
|
if (parentIcon != null) {
|
||||||
&& parentIcon.iconId != IconImage.UNKNOWN_ID
|
if (parentIcon.custom.isUnknown
|
||||||
&& parentIcon.iconId != IconImageStandard.FOLDER) {
|
&& parentIcon.standard.id != IconImageStandard.FOLDER_ID) {
|
||||||
tempEntryInfo?.icon = parentIcon
|
tempEntryInfo?.icon = IconImage(parentIcon.standard)
|
||||||
|
}
|
||||||
|
if (!parentIcon.custom.isUnknown) {
|
||||||
|
tempEntryInfo?.icon = IconImage(parentIcon.custom)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Set default username
|
// Set default username
|
||||||
tempEntryInfo?.username = mDatabase?.defaultUsername ?: ""
|
tempEntryInfo?.username = mDatabase?.defaultUsername ?: ""
|
||||||
@@ -711,7 +715,7 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iconPicked(icon: IconImageStandard) {
|
override fun iconPicked(icon: IconImage) {
|
||||||
entryEditFragment?.icon = icon
|
entryEditFragment?.icon = icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ import com.kunzisoft.keepass.adapters.SearchEntryCursorAdapter
|
|||||||
import com.kunzisoft.keepass.autofill.AutofillComponent
|
import com.kunzisoft.keepass.autofill.AutofillComponent
|
||||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||||
import com.kunzisoft.keepass.database.element.*
|
import com.kunzisoft.keepass.database.element.*
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||||
import com.kunzisoft.keepass.database.element.node.Node
|
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.Type
|
import com.kunzisoft.keepass.database.element.node.Type
|
||||||
@@ -1122,7 +1122,7 @@ class GroupActivity : LockingActivity(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For icon in create tree dialog
|
// For icon in create tree dialog
|
||||||
override fun iconPicked(icon: IconImageStandard) {
|
override fun iconPicked(icon: IconImage) {
|
||||||
(supportFragmentManager
|
(supportFragmentManager
|
||||||
.findFragmentByTag(GroupEditDialogFragment.TAG_CREATE_GROUP) as GroupEditDialogFragment)
|
.findFragmentByTag(GroupEditDialogFragment.TAG_CREATE_GROUP) as GroupEditDialogFragment)
|
||||||
.iconPicked(icon)
|
.iconPicked(icon)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGrou
|
|||||||
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE
|
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
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.icon.IconImageStandard
|
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||||
import com.kunzisoft.keepass.model.GroupInfo
|
import com.kunzisoft.keepass.model.GroupInfo
|
||||||
import com.kunzisoft.keepass.view.ExpirationView
|
import com.kunzisoft.keepass.view.ExpirationView
|
||||||
@@ -210,7 +210,7 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iconPicked(icon: IconImageStandard) {
|
override fun iconPicked(icon: IconImage) {
|
||||||
mGroupInfo.icon = icon
|
mGroupInfo.icon = icon
|
||||||
assignIconView()
|
assignIconView()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,11 @@ import androidx.fragment.app.*
|
|||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||||
|
|
||||||
|
|
||||||
class IconPickerDialogFragment : DialogFragment(), IconStandardFragment.IconStandardPickerListener {
|
class IconPickerDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
private lateinit var iconPickerPagerAdapter: IconPickerPagerAdapter
|
private lateinit var iconPickerPagerAdapter: IconPickerPagerAdapter
|
||||||
private lateinit var viewPager: ViewPager
|
private lateinit var viewPager: ViewPager
|
||||||
@@ -78,40 +79,46 @@ class IconPickerDialogFragment : DialogFragment(), IconStandardFragment.IconStan
|
|||||||
val root = layoutInflater.inflate(R.layout.fragment_icon_picker, container)
|
val root = layoutInflater.inflate(R.layout.fragment_icon_picker, container)
|
||||||
viewPager = root.findViewById(R.id.icon_picker_pager)
|
viewPager = root.findViewById(R.id.icon_picker_pager)
|
||||||
tabLayout = root.findViewById(R.id.icon_picker_tabs)
|
tabLayout = root.findViewById(R.id.icon_picker_tabs)
|
||||||
iconPickerPagerAdapter = IconPickerPagerAdapter(requireContext(), childFragmentManager)
|
iconPickerPagerAdapter = IconPickerPagerAdapter(childFragmentManager) { icon ->
|
||||||
|
iconPickerListener?.iconPicked(IconImage(icon))
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
viewPager.adapter = iconPickerPagerAdapter
|
viewPager.adapter = iconPickerPagerAdapter
|
||||||
tabLayout.setupWithViewPager(viewPager)
|
tabLayout.setupWithViewPager(viewPager)
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
||||||
class IconPickerPagerAdapter(private val context: Context, fragmentManager: FragmentManager)
|
class IconPickerPagerAdapter(fragmentManager: FragmentManager,
|
||||||
|
iconStandardSelected: (icon: IconImageStandard) -> Unit)
|
||||||
: FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_SET_USER_VISIBLE_HINT) {
|
: FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_SET_USER_VISIBLE_HINT) {
|
||||||
|
|
||||||
override fun getCount(): Int = 3
|
private val iconStandardFragment = IconStandardFragment()
|
||||||
|
private val iconCustomFragment = IconStandardFragment()
|
||||||
|
|
||||||
|
init {
|
||||||
|
iconStandardFragment.iconStandardPickerListener = iconStandardSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCount(): Int = 2
|
||||||
|
|
||||||
override fun getItem(i: Int): Fragment {
|
override fun getItem(i: Int): Fragment {
|
||||||
val fragment = IconStandardFragment()
|
return when (i) {
|
||||||
return fragment
|
1 -> iconCustomFragment
|
||||||
|
else -> iconStandardFragment
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPageTitle(position: Int): CharSequence {
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
return when (position) {
|
return when (position) {
|
||||||
0 -> "Standard" //context.getString(R.string.iconStandard)
|
1 -> "Custom" //context.getString(R.string.iconStandard)
|
||||||
1 -> "Service" //context.getString(R.string.iconStandard)
|
else -> "Standard" //context.getString(R.string.iconStandard)
|
||||||
else -> "Custom" //context.getString(R.string.iconStandard)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun iconStandardPicked(icon: IconImageStandard) {
|
|
||||||
iconPickerListener?.iconPicked(icon)
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IconPickerListener {
|
interface IconPickerListener {
|
||||||
fun iconPicked(icon: IconImageStandard)
|
fun iconPicked(icon: IconImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -25,18 +25,7 @@ class IconStandardFragment : Fragment() {
|
|||||||
|
|
||||||
private lateinit var currIconGridView: GridView
|
private lateinit var currIconGridView: GridView
|
||||||
private var iconPack: IconPack? = null
|
private var iconPack: IconPack? = null
|
||||||
private var iconStandardPickerListener: IconPickerDialogFragment.IconPickerListener? = null
|
var iconStandardPickerListener: ((icon: IconImageStandard) -> Unit)? = null
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
|
||||||
super.onAttach(context)
|
|
||||||
try {
|
|
||||||
iconStandardPickerListener = context as IconPickerDialogFragment.IconPickerListener
|
|
||||||
} catch (e: ClassCastException) {
|
|
||||||
// The activity doesn't implement the interface, throw exception
|
|
||||||
throw ClassCastException(context.toString()
|
|
||||||
+ " must implement " + IconStandardFragment::class.java.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetach() {
|
override fun onDetach() {
|
||||||
iconStandardPickerListener = null
|
iconStandardPickerListener = null
|
||||||
@@ -57,7 +46,7 @@ class IconStandardFragment : Fragment() {
|
|||||||
iconPack = IconPackChooser.getSelectedIconPack(requireContext())
|
iconPack = IconPackChooser.getSelectedIconPack(requireContext())
|
||||||
currIconGridView.adapter = IconStandardAdapter(requireActivity())
|
currIconGridView.adapter = IconStandardAdapter(requireActivity())
|
||||||
currIconGridView.setOnItemClickListener { _, _, position, _ ->
|
currIconGridView.setOnItemClickListener { _, _, position, _ ->
|
||||||
iconStandardPickerListener?.iconPicked(IconImageStandard(position))
|
iconStandardPickerListener?.invoke(IconImageStandard(position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,10 +110,10 @@ class SearchEntryCursorAdapter(private val context: Context,
|
|||||||
return database.createEntry()?.apply {
|
return database.createEntry()?.apply {
|
||||||
database.startManageEntry(this)
|
database.startManageEntry(this)
|
||||||
entryKDB?.let { entryKDB ->
|
entryKDB?.let { entryKDB ->
|
||||||
(cursor as EntryCursorKDB).populateEntry(entryKDB, database.iconFactory)
|
(cursor as EntryCursorKDB).populateEntry(entryKDB, database.iconPool)
|
||||||
}
|
}
|
||||||
entryKDBX?.let { entryKDBX ->
|
entryKDBX?.let { entryKDBX ->
|
||||||
(cursor as EntryCursorKDBX).populateEntry(entryKDBX, database.iconFactory)
|
(cursor as EntryCursorKDBX).populateEntry(entryKDBX, database.iconPool)
|
||||||
}
|
}
|
||||||
database.stopManageEntry(this)
|
database.stopManageEntry(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import android.database.MatrixCursor
|
|||||||
import android.provider.BaseColumns
|
import android.provider.BaseColumns
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryVersioned
|
import com.kunzisoft.keepass.database.element.entry.EntryVersioned
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageFactory
|
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||||
|
import com.kunzisoft.keepass.database.element.icon.IconPool
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -49,12 +50,14 @@ abstract class EntryCursor<EntryId, PwEntryV : EntryVersioned<*, EntryId, *, *>>
|
|||||||
|
|
||||||
abstract fun getPwNodeId(): NodeId<EntryId>
|
abstract fun getPwNodeId(): NodeId<EntryId>
|
||||||
|
|
||||||
open fun populateEntry(pwEntry: PwEntryV, iconFactory: IconImageFactory) {
|
open fun populateEntry(pwEntry: PwEntryV, iconPool: IconPool) {
|
||||||
pwEntry.nodeId = getPwNodeId()
|
pwEntry.nodeId = getPwNodeId()
|
||||||
pwEntry.title = getString(getColumnIndex(COLUMN_INDEX_TITLE))
|
pwEntry.title = getString(getColumnIndex(COLUMN_INDEX_TITLE))
|
||||||
|
|
||||||
val iconStandard = iconFactory.getIcon(getInt(getColumnIndex(COLUMN_INDEX_ICON_STANDARD)))
|
val iconStandard = iconPool.getIcon(getInt(getColumnIndex(COLUMN_INDEX_ICON_STANDARD)))
|
||||||
pwEntry.icon = iconStandard
|
val iconCustom = iconPool.getIcon(UUID(getLong(getColumnIndex(COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS)),
|
||||||
|
getLong(getColumnIndex(COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS))))
|
||||||
|
pwEntry.icon = IconImage(iconStandard, iconCustom)
|
||||||
|
|
||||||
pwEntry.username = getString(getColumnIndex(COLUMN_INDEX_USERNAME))
|
pwEntry.username = getString(getColumnIndex(COLUMN_INDEX_USERNAME))
|
||||||
pwEntry.password = getString(getColumnIndex(COLUMN_INDEX_PASSWORD))
|
pwEntry.password = getString(getColumnIndex(COLUMN_INDEX_PASSWORD))
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.cursor
|
package com.kunzisoft.keepass.database.cursor
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseVersioned
|
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
||||||
|
|
||||||
class EntryCursorKDB : EntryCursorUUID<EntryKDB>() {
|
class EntryCursorKDB : EntryCursorUUID<EntryKDB>() {
|
||||||
@@ -30,9 +29,9 @@ class EntryCursorKDB : EntryCursorUUID<EntryKDB>() {
|
|||||||
entry.id.mostSignificantBits,
|
entry.id.mostSignificantBits,
|
||||||
entry.id.leastSignificantBits,
|
entry.id.leastSignificantBits,
|
||||||
entry.title,
|
entry.title,
|
||||||
entry.icon.iconId,
|
entry.icon.standard.id,
|
||||||
DatabaseVersioned.UUID_ZERO.mostSignificantBits,
|
entry.icon.custom.uuid.mostSignificantBits,
|
||||||
DatabaseVersioned.UUID_ZERO.leastSignificantBits,
|
entry.icon.custom.uuid.leastSignificantBits,
|
||||||
entry.username,
|
entry.username,
|
||||||
entry.password,
|
entry.password,
|
||||||
entry.url,
|
entry.url,
|
||||||
|
|||||||
@@ -20,9 +20,7 @@
|
|||||||
package com.kunzisoft.keepass.database.cursor
|
package com.kunzisoft.keepass.database.cursor
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageFactory
|
import com.kunzisoft.keepass.database.element.icon.IconPool
|
||||||
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
class EntryCursorKDBX : EntryCursorUUID<EntryKDBX>() {
|
class EntryCursorKDBX : EntryCursorUUID<EntryKDBX>() {
|
||||||
|
|
||||||
@@ -34,9 +32,9 @@ class EntryCursorKDBX : EntryCursorUUID<EntryKDBX>() {
|
|||||||
entry.id.mostSignificantBits,
|
entry.id.mostSignificantBits,
|
||||||
entry.id.leastSignificantBits,
|
entry.id.leastSignificantBits,
|
||||||
entry.title,
|
entry.title,
|
||||||
entry.icon.iconId,
|
entry.icon.standard.id,
|
||||||
entry.iconCustom.uuid.mostSignificantBits,
|
entry.icon.custom.uuid.mostSignificantBits,
|
||||||
entry.iconCustom.uuid.leastSignificantBits,
|
entry.icon.custom.uuid.leastSignificantBits,
|
||||||
entry.username,
|
entry.username,
|
||||||
entry.password,
|
entry.password,
|
||||||
entry.url,
|
entry.url,
|
||||||
@@ -52,14 +50,8 @@ class EntryCursorKDBX : EntryCursorUUID<EntryKDBX>() {
|
|||||||
entryId++
|
entryId++
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun populateEntry(pwEntry: EntryKDBX, iconFactory: IconImageFactory) {
|
override fun populateEntry(pwEntry: EntryKDBX, iconPool: IconPool) {
|
||||||
super.populateEntry(pwEntry, iconFactory)
|
super.populateEntry(pwEntry, iconPool)
|
||||||
|
|
||||||
// Retrieve custom icon
|
|
||||||
val iconCustom = iconFactory.getIcon(
|
|
||||||
UUID(getLong(getColumnIndex(COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS)),
|
|
||||||
getLong(getColumnIndex(COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS))))
|
|
||||||
pwEntry.iconCustom = iconCustom
|
|
||||||
|
|
||||||
// Retrieve extra fields
|
// Retrieve extra fields
|
||||||
if (extraFieldCursor.moveToFirst()) {
|
if (extraFieldCursor.moveToFirst()) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.util.Log
|
|||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
||||||
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
||||||
import com.kunzisoft.keepass.database.element.database.*
|
import com.kunzisoft.keepass.database.element.database.*
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageFactory
|
import com.kunzisoft.keepass.database.element.icon.IconPool
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeIdInt
|
import com.kunzisoft.keepass.database.element.node.NodeIdInt
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||||
@@ -51,7 +51,6 @@ import java.security.Key
|
|||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.crypto.KeyGenerator
|
import javax.crypto.KeyGenerator
|
||||||
import javax.crypto.spec.IvParameterSpec
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
||||||
@@ -92,9 +91,9 @@ class Database {
|
|||||||
return mDatabaseKDB?.loadedCipherKey ?: mDatabaseKDBX?.loadedCipherKey
|
return mDatabaseKDB?.loadedCipherKey ?: mDatabaseKDBX?.loadedCipherKey
|
||||||
}
|
}
|
||||||
|
|
||||||
val iconFactory: IconImageFactory
|
val iconPool: IconPool
|
||||||
get() {
|
get() {
|
||||||
return mDatabaseKDB?.iconFactory ?: mDatabaseKDBX?.iconFactory ?: IconImageFactory()
|
return mDatabaseKDB?.iconPool ?: mDatabaseKDBX?.iconPool ?: IconPool()
|
||||||
}
|
}
|
||||||
|
|
||||||
val allowName: Boolean
|
val allowName: Boolean
|
||||||
@@ -625,6 +624,7 @@ class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun clear(filesDirectory: File? = null) {
|
fun clear(filesDirectory: File? = null) {
|
||||||
|
iconPool.clearCache()
|
||||||
drawFactory.clearCache()
|
drawFactory.clearCache()
|
||||||
// Delete the cache of the database if present
|
// Delete the cache of the database if present
|
||||||
mDatabaseKDB?.clearCache()
|
mDatabaseKDB?.clearCache()
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
|||||||
|
|
||||||
override var icon: IconImage
|
override var icon: IconImage
|
||||||
get() {
|
get() {
|
||||||
return entryKDB?.icon ?: entryKDBX?.icon ?: IconImageStandard()
|
return entryKDB?.icon ?: entryKDBX?.icon ?: IconImage()
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
entryKDB?.icon = value
|
entryKDB?.icon = value
|
||||||
@@ -257,31 +257,12 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
------------
|
|
||||||
KDB Methods
|
|
||||||
------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If it's a node with only meta information like Meta-info SYSTEM Database Color
|
|
||||||
* @return false by default, true if it's a meta stream
|
|
||||||
*/
|
|
||||||
val isMetaStream: Boolean
|
|
||||||
get() = entryKDB?.isMetaStream ?: false
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
------------
|
------------
|
||||||
KDBX Methods
|
KDBX Methods
|
||||||
------------
|
------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var iconCustom: IconImageCustom
|
|
||||||
get() = entryKDBX?.iconCustom ?: IconImageCustom.UNKNOWN_ICON
|
|
||||||
set(value) {
|
|
||||||
entryKDBX?.iconCustom = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve extra 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
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import com.kunzisoft.keepass.database.element.group.GroupKDB
|
|||||||
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupVersionedInterface
|
import com.kunzisoft.keepass.database.element.group.GroupVersionedInterface
|
||||||
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.database.element.node.*
|
import com.kunzisoft.keepass.database.element.node.*
|
||||||
import com.kunzisoft.keepass.model.EntryInfo
|
import com.kunzisoft.keepass.model.EntryInfo
|
||||||
import com.kunzisoft.keepass.model.GroupInfo
|
import com.kunzisoft.keepass.model.GroupInfo
|
||||||
@@ -124,7 +123,7 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override var icon: IconImage
|
override var icon: IconImage
|
||||||
get() = groupKDB?.icon ?: groupKDBX?.icon ?: IconImageStandard()
|
get() = groupKDB?.icon ?: groupKDBX?.icon ?: IconImage()
|
||||||
set(value) {
|
set(value) {
|
||||||
groupKDB?.icon = value
|
groupKDB?.icon = value
|
||||||
groupKDBX?.icon = value
|
groupKDBX?.icon = value
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.kunzisoft.keepass.database.element.Database
|
|||||||
import com.kunzisoft.keepass.stream.readAllBytes
|
import com.kunzisoft.keepass.stream.readAllBytes
|
||||||
import org.apache.commons.io.output.CountingOutputStream
|
import org.apache.commons.io.output.CountingOutputStream
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
import java.security.MessageDigest
|
||||||
import java.util.zip.GZIPInputStream
|
import java.util.zip.GZIPInputStream
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
@@ -176,6 +177,25 @@ class BinaryAttachment : Parcelable {
|
|||||||
throw IOException("Unable to delete temp file " + dataFile!!.absolutePath)
|
throw IOException("Unable to delete temp file " + dataFile!!.absolutePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MD5 of the raw encrypted file in temp folder, only to compare binary data
|
||||||
|
*/
|
||||||
|
fun md5(): String {
|
||||||
|
val md = MessageDigest.getInstance("MD5")
|
||||||
|
if (dataFile == null)
|
||||||
|
return ""
|
||||||
|
return FileInputStream(dataFile).use { fis ->
|
||||||
|
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||||
|
generateSequence {
|
||||||
|
when (val bytesRead = fis.read(buffer)) {
|
||||||
|
-1 -> null
|
||||||
|
else -> bytesRead
|
||||||
|
}
|
||||||
|
}.forEach { bytesRead -> md.update(buffer, 0, bytesRead) }
|
||||||
|
md.digest().joinToString("") { "%02x".format(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other)
|
if (this === other)
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -99,7 +99,13 @@ class BinaryPool {
|
|||||||
private fun orderedBinaries(): List<KeyBinary> {
|
private fun orderedBinaries(): List<KeyBinary> {
|
||||||
val keyBinaryList = ArrayList<KeyBinary>()
|
val keyBinaryList = ArrayList<KeyBinary>()
|
||||||
for ((key, binary) in pool) {
|
for ((key, binary) in pool) {
|
||||||
keyBinaryList.add(KeyBinary(key, binary))
|
// Don't deduplicate
|
||||||
|
val existentBinary = keyBinaryList.find { it.binary.md5() == binary.md5() }
|
||||||
|
if (existentBinary == null) {
|
||||||
|
keyBinaryList.add(KeyBinary(binary, key))
|
||||||
|
} else {
|
||||||
|
existentBinary.addKey(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return keyBinaryList
|
return keyBinaryList
|
||||||
}
|
}
|
||||||
@@ -108,7 +114,7 @@ class BinaryPool {
|
|||||||
* To register a binary with a ref corresponding to an ordered index
|
* To register a binary with a ref corresponding to an ordered index
|
||||||
*/
|
*/
|
||||||
fun getBinaryIndexFromKey(key: Int): Int? {
|
fun getBinaryIndexFromKey(key: Int): Int? {
|
||||||
val index = orderedBinaries().indexOfFirst { it.key == key }
|
val index = orderedBinaries().indexOfFirst { it.keys.contains(key) }
|
||||||
return if (index < 0)
|
return if (index < 0)
|
||||||
null
|
null
|
||||||
else
|
else
|
||||||
@@ -118,8 +124,10 @@ class BinaryPool {
|
|||||||
/**
|
/**
|
||||||
* Different from doForEach, provide an ordered index to each binary
|
* Different from doForEach, provide an ordered index to each binary
|
||||||
*/
|
*/
|
||||||
fun doForEachOrderedBinary(action: (index: Int, keyBinary: KeyBinary) -> Unit) {
|
fun doForEachOrderedBinary(action: (index: Int, binary: BinaryAttachment) -> Unit) {
|
||||||
orderedBinaries().forEachIndexed(action)
|
orderedBinaries().forEachIndexed { index, keyBinary ->
|
||||||
|
action.invoke(index, keyBinary.binary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,7 +157,16 @@ class BinaryPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility data class to order binaries
|
* Utility class to order binaries
|
||||||
*/
|
*/
|
||||||
data class KeyBinary(val key: Int, val binary: BinaryAttachment)
|
private class KeyBinary(val binary: BinaryAttachment, key: Int) {
|
||||||
|
val keys = HashSet<Int>()
|
||||||
|
init {
|
||||||
|
addKey(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addKey(key: Int) {
|
||||||
|
keys.add(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
|||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
||||||
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeIdInt
|
import com.kunzisoft.keepass.database.element.node.NodeIdInt
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeVersioned
|
import com.kunzisoft.keepass.database.element.node.NodeVersioned
|
||||||
@@ -175,6 +176,10 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getStandardIcon(iconId: Int): IconImageStandard {
|
||||||
|
return this.iconPool.getIcon(iconId)
|
||||||
|
}
|
||||||
|
|
||||||
override fun containsCustomData(): Boolean {
|
override fun containsCustomData(): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -223,7 +228,7 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
|||||||
// Create recycle bin
|
// Create recycle bin
|
||||||
val recycleBinGroup = createGroup().apply {
|
val recycleBinGroup = createGroup().apply {
|
||||||
title = BACKUP_FOLDER_TITLE
|
title = BACKUP_FOLDER_TITLE
|
||||||
icon = iconFactory.trashIcon
|
icon.standard = getStandardIcon(IconImageStandard.TRASH_ID)
|
||||||
}
|
}
|
||||||
addGroupTo(recycleBinGroup, rootGroup)
|
addGroupTo(recycleBinGroup, rootGroup)
|
||||||
backupGroupId = recycleBinGroup.id
|
backupGroupId = recycleBinGroup.id
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.kunzisoft.keepass.database.element.database.DatabaseKDB.Companion.BAC
|
|||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
||||||
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeVersioned
|
import com.kunzisoft.keepass.database.element.node.NodeVersioned
|
||||||
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
||||||
@@ -105,7 +106,6 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
var lastTopVisibleGroupUUID = UUID_ZERO
|
var lastTopVisibleGroupUUID = UUID_ZERO
|
||||||
var memoryProtection = MemoryProtectionConfig()
|
var memoryProtection = MemoryProtectionConfig()
|
||||||
val deletedObjects = ArrayList<DeletedObject>()
|
val deletedObjects = ArrayList<DeletedObject>()
|
||||||
val customIcons = ArrayList<IconImageCustom>()
|
|
||||||
val customData = HashMap<String, String>()
|
val customData = HashMap<String, String>()
|
||||||
|
|
||||||
var binaryPool = BinaryPool()
|
var binaryPool = BinaryPool()
|
||||||
@@ -129,7 +129,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
kdbxVersion = FILE_VERSION_32_3
|
kdbxVersion = FILE_VERSION_32_3
|
||||||
val group = createGroup().apply {
|
val group = createGroup().apply {
|
||||||
title = rootName
|
title = rootName
|
||||||
icon = iconFactory.folderIcon
|
icon.standard = getStandardIcon(IconImageStandard.FOLDER_ID)
|
||||||
}
|
}
|
||||||
rootGroup = group
|
rootGroup = group
|
||||||
addGroupIndex(group)
|
addGroupIndex(group)
|
||||||
@@ -307,16 +307,20 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
this.dataEngine = dataEngine
|
this.dataEngine = dataEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCustomIcons(): List<IconImageCustom> {
|
override fun getStandardIcon(iconId: Int): IconImageStandard {
|
||||||
return customIcons
|
return this.iconPool.getIcon(iconId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addCustomIcon(customIcon: IconImageCustom) {
|
fun getCustomIcon(iconUuid: UUID): IconImageCustom {
|
||||||
this.customIcons.add(customIcon)
|
return this.iconPool.getIcon(iconUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCustomData(): Map<String, String> {
|
fun putCustomIcon(customIcon: IconImageCustom) {
|
||||||
return customData
|
this.iconPool.putIcon(customIcon)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun containsCustomIcons(): Boolean {
|
||||||
|
return this.iconPool.containsCustomIcons()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putCustomData(label: String, value: String) {
|
fun putCustomData(label: String, value: String) {
|
||||||
@@ -324,7 +328,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun containsCustomData(): Boolean {
|
override fun containsCustomData(): Boolean {
|
||||||
return getCustomData().isNotEmpty()
|
return customData.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@@ -550,7 +554,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
// Create recycle bin
|
// Create recycle bin
|
||||||
val recycleBinGroup = createGroup().apply {
|
val recycleBinGroup = createGroup().apply {
|
||||||
title = resources.getString(R.string.recycle_bin)
|
title = resources.getString(R.string.recycle_bin)
|
||||||
icon = iconFactory.trashIcon
|
icon.standard = getStandardIcon(IconImageStandard.TRASH_ID)
|
||||||
enableAutoType = false
|
enableAutoType = false
|
||||||
enableSearching = false
|
enableSearching = false
|
||||||
isExpanded = false
|
isExpanded = false
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
|||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryVersioned
|
import com.kunzisoft.keepass.database.element.entry.EntryVersioned
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupVersioned
|
import com.kunzisoft.keepass.database.element.group.GroupVersioned
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageFactory
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||||
|
import com.kunzisoft.keepass.database.element.icon.IconPool
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||||
import com.kunzisoft.keepass.database.element.node.Type
|
import com.kunzisoft.keepass.database.element.node.Type
|
||||||
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
||||||
@@ -55,8 +56,7 @@ abstract class DatabaseVersioned<
|
|||||||
var finalKey: ByteArray? = null
|
var finalKey: ByteArray? = null
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
var iconFactory = IconImageFactory()
|
val iconPool = IconPool()
|
||||||
protected set
|
|
||||||
|
|
||||||
var changeDuplicateId = false
|
var changeDuplicateId = false
|
||||||
|
|
||||||
@@ -329,6 +329,8 @@ abstract class DatabaseVersioned<
|
|||||||
|
|
||||||
abstract fun rootCanContainsEntry(): Boolean
|
abstract fun rootCanContainsEntry(): Boolean
|
||||||
|
|
||||||
|
abstract fun getStandardIcon(iconId: Int): IconImageStandard
|
||||||
|
|
||||||
abstract fun containsCustomData(): Boolean
|
abstract fun containsCustomData(): Boolean
|
||||||
|
|
||||||
fun addGroupTo(newGroup: Group, parent: Group?) {
|
fun addGroupTo(newGroup: Group, parent: Group?) {
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ package com.kunzisoft.keepass.database.element.entry
|
|||||||
|
|
||||||
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.database.BinaryAttachment
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
||||||
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard.Companion.KEY_ID
|
||||||
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.NodeKDBInterface
|
import com.kunzisoft.keepass.database.element.node.NodeKDBInterface
|
||||||
import com.kunzisoft.keepass.database.element.node.Type
|
import com.kunzisoft.keepass.database.element.node.Type
|
||||||
import com.kunzisoft.keepass.database.element.database.BinaryAttachment
|
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure containing information about one entry.
|
* Structure containing information about one entry.
|
||||||
@@ -68,7 +68,8 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
if (username.isEmpty()) return false
|
if (username.isEmpty()) return false
|
||||||
if (username != PMS_ID_USER) return false
|
if (username != PMS_ID_USER) return false
|
||||||
if (url.isEmpty()) return false
|
if (url.isEmpty()) return false
|
||||||
return if (url != PMS_ID_URL) false else icon.isMetaStreamIcon
|
if (url != PMS_ID_URL) return false
|
||||||
|
return icon.standard.id == KEY_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initNodeId(): NodeId<UUID> {
|
override fun initNodeId(): NodeId<UUID> {
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ import com.kunzisoft.keepass.database.element.DateInstant
|
|||||||
import com.kunzisoft.keepass.database.element.database.BinaryPool
|
import com.kunzisoft.keepass.database.element.database.BinaryPool
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
|
||||||
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.NodeKDBXInterface
|
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
||||||
@@ -48,19 +45,6 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
@Transient
|
@Transient
|
||||||
private var mDecodeRef = false
|
private var mDecodeRef = false
|
||||||
|
|
||||||
override var icon: IconImage
|
|
||||||
get() {
|
|
||||||
return when {
|
|
||||||
iconCustom.isUnknown -> super.icon
|
|
||||||
else -> iconCustom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
if (value is IconImageStandard)
|
|
||||||
iconCustom = IconImageCustom.UNKNOWN_ICON
|
|
||||||
super.icon = value
|
|
||||||
}
|
|
||||||
var iconCustom = IconImageCustom.UNKNOWN_ICON
|
|
||||||
var customData = LinkedHashMap<String, String>()
|
var customData = LinkedHashMap<String, String>()
|
||||||
var fields = LinkedHashMap<String, ProtectedString>()
|
var fields = LinkedHashMap<String, ProtectedString>()
|
||||||
var binaries = LinkedHashMap<String, Int>() // Map<Label, PoolId>
|
var binaries = LinkedHashMap<String, Int>() // Map<Label, PoolId>
|
||||||
@@ -103,7 +87,6 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
constructor() : super()
|
constructor() : super()
|
||||||
|
|
||||||
constructor(parcel: Parcel) : super(parcel) {
|
constructor(parcel: Parcel) : super(parcel) {
|
||||||
iconCustom = parcel.readParcelable(IconImageCustom::class.java.classLoader) ?: iconCustom
|
|
||||||
usageCount = UnsignedLong(parcel.readLong())
|
usageCount = UnsignedLong(parcel.readLong())
|
||||||
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
||||||
customData = ParcelableUtil.readStringParcelableMap(parcel)
|
customData = ParcelableUtil.readStringParcelableMap(parcel)
|
||||||
@@ -121,7 +104,6 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
super.writeToParcel(dest, flags)
|
super.writeToParcel(dest, flags)
|
||||||
dest.writeParcelable(iconCustom, flags)
|
|
||||||
dest.writeLong(usageCount.toKotlinLong())
|
dest.writeLong(usageCount.toKotlinLong())
|
||||||
dest.writeParcelable(locationChanged, flags)
|
dest.writeParcelable(locationChanged, flags)
|
||||||
ParcelableUtil.writeStringParcelableMap(dest, customData)
|
ParcelableUtil.writeStringParcelableMap(dest, customData)
|
||||||
@@ -143,7 +125,6 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
*/
|
*/
|
||||||
fun updateWith(source: EntryKDBX, copyHistory: Boolean = true) {
|
fun updateWith(source: EntryKDBX, copyHistory: Boolean = true) {
|
||||||
super.updateWith(source)
|
super.updateWith(source)
|
||||||
iconCustom = IconImageCustom(source.iconCustom)
|
|
||||||
usageCount = source.usageCount
|
usageCount = source.usageCount
|
||||||
locationChanged = DateInstant(source.locationChanged)
|
locationChanged = DateInstant(source.locationChanged)
|
||||||
// Add all custom elements in map
|
// Add all custom elements in map
|
||||||
|
|||||||
@@ -21,37 +21,18 @@ package com.kunzisoft.keepass.database.element.group
|
|||||||
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseVersioned
|
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
|
import com.kunzisoft.keepass.database.element.database.DatabaseVersioned
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
|
||||||
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.NodeKDBXInterface
|
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
||||||
import com.kunzisoft.keepass.database.element.node.Type
|
import com.kunzisoft.keepass.database.element.node.Type
|
||||||
import com.kunzisoft.keepass.utils.UnsignedLong
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
|
import java.util.*
|
||||||
import java.util.HashMap
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInterface {
|
class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInterface {
|
||||||
|
|
||||||
// TODO Encapsulate
|
|
||||||
override var icon: IconImage
|
|
||||||
get() {
|
|
||||||
return if (iconCustom.isUnknown)
|
|
||||||
super.icon
|
|
||||||
else
|
|
||||||
iconCustom
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
if (value is IconImageStandard)
|
|
||||||
iconCustom = IconImageCustom.UNKNOWN_ICON
|
|
||||||
super.icon = value
|
|
||||||
}
|
|
||||||
var iconCustom = IconImageCustom.UNKNOWN_ICON
|
|
||||||
private val customData = HashMap<String, String>()
|
private val customData = HashMap<String, String>()
|
||||||
var notes = ""
|
var notes = ""
|
||||||
|
|
||||||
@@ -77,7 +58,6 @@ class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
constructor() : super()
|
constructor() : super()
|
||||||
|
|
||||||
constructor(parcel: Parcel) : super(parcel) {
|
constructor(parcel: Parcel) : super(parcel) {
|
||||||
iconCustom = parcel.readParcelable(IconImageCustom::class.java.classLoader) ?: iconCustom
|
|
||||||
usageCount = UnsignedLong(parcel.readLong())
|
usageCount = UnsignedLong(parcel.readLong())
|
||||||
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
||||||
// TODO customData = ParcelableUtil.readStringParcelableMap(parcel);
|
// TODO customData = ParcelableUtil.readStringParcelableMap(parcel);
|
||||||
@@ -101,7 +81,6 @@ class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
super.writeToParcel(dest, flags)
|
super.writeToParcel(dest, flags)
|
||||||
dest.writeParcelable(iconCustom, flags)
|
|
||||||
dest.writeLong(usageCount.toKotlinLong())
|
dest.writeLong(usageCount.toKotlinLong())
|
||||||
dest.writeParcelable(locationChanged, flags)
|
dest.writeParcelable(locationChanged, flags)
|
||||||
// TODO ParcelableUtil.writeStringParcelableMap(dest, customData);
|
// TODO ParcelableUtil.writeStringParcelableMap(dest, customData);
|
||||||
@@ -115,7 +94,6 @@ class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
|
|
||||||
fun updateWith(source: GroupKDBX) {
|
fun updateWith(source: GroupKDBX) {
|
||||||
super.updateWith(source)
|
super.updateWith(source)
|
||||||
iconCustom = IconImageCustom(source.iconCustom)
|
|
||||||
usageCount = source.usageCount
|
usageCount = source.usageCount
|
||||||
locationChanged = DateInstant(source.locationChanged)
|
locationChanged = DateInstant(source.locationChanged)
|
||||||
// Add all custom elements in map
|
// Add all custom elements in map
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
* Copyright 2021 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePassDX.
|
* This file is part of KeePassDX.
|
||||||
*
|
*
|
||||||
@@ -19,19 +19,49 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.element.icon
|
package com.kunzisoft.keepass.database.element.icon
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
|
||||||
abstract class IconImage protected constructor() : Parcelable {
|
class IconImage() : Parcelable {
|
||||||
|
|
||||||
abstract val iconId: Int
|
var standard: IconImageStandard = IconImageStandard()
|
||||||
abstract val isUnknown: Boolean
|
var custom: IconImageCustom = IconImageCustom()
|
||||||
abstract val isMetaStreamIcon: Boolean
|
|
||||||
|
constructor(iconImageStandard: IconImageStandard) : this() {
|
||||||
|
this.standard = iconImageStandard
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(iconImageCustom: IconImageCustom) : this() {
|
||||||
|
this.custom = iconImageCustom
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(iconImageStandard: IconImageStandard,
|
||||||
|
iconImageCustom: IconImageCustom) : this() {
|
||||||
|
this.standard = iconImageStandard
|
||||||
|
this.custom = iconImageCustom
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(parcel: Parcel) : this() {
|
||||||
|
standard = parcel.readParcelable(IconImageStandard::class.java.classLoader) ?: standard
|
||||||
|
custom = parcel.readParcelable(IconImageCustom::class.java.classLoader) ?: custom
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
|
parcel.writeParcelable(standard, flags)
|
||||||
|
parcel.writeParcelable(custom, flags)
|
||||||
|
}
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
override fun describeContents(): Int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object CREATOR : Parcelable.Creator<IconImage> {
|
||||||
const val UNKNOWN_ID = -1
|
override fun createFromParcel(parcel: Parcel): IconImage {
|
||||||
|
return IconImage(parcel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<IconImage?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
* Copyright 2021 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePassDX.
|
* This file is part of KeePassDX.
|
||||||
*
|
*
|
||||||
@@ -22,36 +22,34 @@ package com.kunzisoft.keepass.database.element.icon
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseVersioned
|
import com.kunzisoft.keepass.database.element.database.DatabaseVersioned
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
import java.util.UUID
|
class IconImageCustom() : Parcelable {
|
||||||
|
|
||||||
class IconImageCustom : IconImage {
|
var uuid: UUID = DatabaseVersioned.UUID_ZERO
|
||||||
|
|
||||||
val uuid: UUID
|
|
||||||
@Transient
|
@Transient
|
||||||
var imageData: ByteArray = ByteArray(0)
|
var imageData: ByteArray = ByteArray(0)
|
||||||
|
|
||||||
constructor(uuid: UUID, data: ByteArray) : super() {
|
constructor(uuid: UUID, data: ByteArray) : this() {
|
||||||
this.uuid = uuid
|
this.uuid = uuid
|
||||||
this.imageData = data
|
this.imageData = data
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(uuid: UUID) : super() {
|
constructor(uuid: UUID) : this() {
|
||||||
this.uuid = uuid
|
this.uuid = uuid
|
||||||
this.imageData = ByteArray(0)
|
this.imageData = ByteArray(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(icon: IconImageCustom) : super() {
|
constructor(parcel: Parcel) : this() {
|
||||||
uuid = icon.uuid
|
|
||||||
imageData = icon.imageData
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(parcel: Parcel) {
|
|
||||||
uuid = parcel.readSerializable() as UUID
|
uuid = parcel.readSerializable() as UUID
|
||||||
// TODO Take too much memories
|
// TODO Take too much memories
|
||||||
// parcel.readByteArray(imageData);
|
// parcel.readByteArray(imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
dest.writeSerializable(uuid)
|
dest.writeSerializable(uuid)
|
||||||
// Too big for a parcelable dest.writeByteArray(imageData);
|
// Too big for a parcelable dest.writeByteArray(imageData);
|
||||||
@@ -74,17 +72,10 @@ class IconImageCustom : IconImage {
|
|||||||
return uuid == other.uuid
|
return uuid == other.uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
override val iconId: Int
|
val isUnknown: Boolean
|
||||||
get() = UNKNOWN_ID
|
get() = uuid == DatabaseVersioned.UUID_ZERO
|
||||||
|
|
||||||
override val isUnknown: Boolean
|
|
||||||
get() = this == UNKNOWN_ICON
|
|
||||||
|
|
||||||
override val isMetaStreamIcon: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val UNKNOWN_ICON = IconImageCustom(DatabaseVersioned.UUID_ZERO, ByteArray(0))
|
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val CREATOR: Parcelable.Creator<IconImageCustom> = object : Parcelable.Creator<IconImageCustom> {
|
val CREATOR: Parcelable.Creator<IconImageCustom> = object : Parcelable.Creator<IconImageCustom> {
|
||||||
|
|||||||
@@ -22,32 +22,37 @@ package com.kunzisoft.keepass.database.element.icon
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
|
||||||
class IconImageStandard : IconImage {
|
class IconImageStandard : Parcelable {
|
||||||
|
|
||||||
|
val id: Int
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.iconId = KEY
|
this.id = KEY_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(iconId: Int) {
|
constructor(iconId: Int) {
|
||||||
this.iconId = iconId
|
if (iconId < MIN_ID || iconId > MAX_ID)
|
||||||
}
|
this.id = KEY_ID
|
||||||
|
else
|
||||||
constructor(icon: IconImageStandard) {
|
this.id = iconId
|
||||||
this.iconId = icon.iconId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(parcel: Parcel) {
|
constructor(parcel: Parcel) {
|
||||||
iconId = parcel.readInt()
|
id = parcel.readInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
dest.writeInt(iconId)
|
dest.writeInt(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
val prime = 31
|
val prime = 31
|
||||||
var result = 1
|
var result = 1
|
||||||
result = prime * result + iconId
|
result = prime * result + id
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,22 +64,16 @@ class IconImageStandard : IconImage {
|
|||||||
if (other !is IconImageStandard) {
|
if (other !is IconImageStandard) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return iconId == other.iconId
|
return id == other.id
|
||||||
}
|
}
|
||||||
|
|
||||||
override val iconId: Int
|
|
||||||
|
|
||||||
override val isUnknown: Boolean
|
|
||||||
get() = iconId == UNKNOWN_ID
|
|
||||||
|
|
||||||
override val isMetaStreamIcon: Boolean
|
|
||||||
get() = iconId == 0
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val KEY = 0
|
const val KEY_ID = 0
|
||||||
const val TRASH = 43
|
const val TRASH_ID = 43
|
||||||
const val FOLDER = 48
|
const val FOLDER_ID = 48
|
||||||
|
const val MIN_ID = 0
|
||||||
|
const val MAX_ID = 48
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val CREATOR: Parcelable.Creator<IconImageStandard> = object : Parcelable.Creator<IconImageStandard> {
|
val CREATOR: Parcelable.Creator<IconImageStandard> = object : Parcelable.Creator<IconImageStandard> {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
* Copyright 2021 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePassDX.
|
* This file is part of KeePassDX.
|
||||||
*
|
*
|
||||||
@@ -19,49 +19,26 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.element.icon
|
package com.kunzisoft.keepass.database.element.icon
|
||||||
|
|
||||||
import org.apache.commons.collections.map.AbstractReferenceMap
|
|
||||||
import org.apache.commons.collections.map.ReferenceMap
|
|
||||||
|
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class IconImageFactory {
|
class IconPool {
|
||||||
/** customIconMap
|
|
||||||
* Cache for icon drawable.
|
|
||||||
* Keys: Integer, Values: IconImageStandard
|
|
||||||
*/
|
|
||||||
private val cache = ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK)
|
|
||||||
|
|
||||||
/** standardIconMap
|
private val standardCache = HashMap<Int, IconImageStandard?>()
|
||||||
* Cache for icon drawable.
|
private val customCache = HashMap<UUID, IconImageCustom?>()
|
||||||
* Keys: UUID, Values: IconImageCustom
|
|
||||||
*/
|
|
||||||
private val customCache = ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK)
|
|
||||||
|
|
||||||
val unknownIcon: IconImageStandard
|
|
||||||
get() = getIcon(IconImage.UNKNOWN_ID)
|
|
||||||
|
|
||||||
val keyIcon: IconImageStandard
|
|
||||||
get() = getIcon(IconImageStandard.KEY)
|
|
||||||
|
|
||||||
val trashIcon: IconImageStandard
|
|
||||||
get() = getIcon(IconImageStandard.TRASH)
|
|
||||||
|
|
||||||
val folderIcon: IconImageStandard
|
|
||||||
get() = getIcon(IconImageStandard.FOLDER)
|
|
||||||
|
|
||||||
fun getIcon(iconId: Int): IconImageStandard {
|
fun getIcon(iconId: Int): IconImageStandard {
|
||||||
var icon: IconImageStandard? = cache[iconId] as IconImageStandard?
|
var icon: IconImageStandard? = standardCache[iconId]
|
||||||
|
|
||||||
if (icon == null) {
|
if (icon == null) {
|
||||||
icon = IconImageStandard(iconId)
|
icon = IconImageStandard(iconId)
|
||||||
cache[iconId] = icon
|
standardCache[iconId] = icon
|
||||||
}
|
}
|
||||||
|
|
||||||
return icon
|
return icon
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getIcon(iconUuid: UUID): IconImageCustom {
|
fun getIcon(iconUuid: UUID): IconImageCustom {
|
||||||
var icon: IconImageCustom? = customCache[iconUuid] as IconImageCustom?
|
var icon: IconImageCustom? = customCache[iconUuid]
|
||||||
|
|
||||||
if (icon == null) {
|
if (icon == null) {
|
||||||
icon = IconImageCustom(iconUuid)
|
icon = IconImageCustom(iconUuid)
|
||||||
@@ -71,7 +48,25 @@ class IconImageFactory {
|
|||||||
return icon
|
return icon
|
||||||
}
|
}
|
||||||
|
|
||||||
fun put(icon: IconImageCustom) {
|
fun putIcon(icon: IconImageCustom) {
|
||||||
customCache[icon.uuid] = icon
|
customCache[icon.uuid] = icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun containsCustomIcons(): Boolean {
|
||||||
|
return customCache.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doForEachCustomIcon(action: (customIcon: IconImageCustom) -> Unit) {
|
||||||
|
for ((_, customIcon) in customCache) {
|
||||||
|
action.invoke(customIcon!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the cache of icons
|
||||||
|
*/
|
||||||
|
fun clearCache() {
|
||||||
|
standardCache.clear()
|
||||||
|
customCache.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,11 +22,10 @@ package com.kunzisoft.keepass.database.element.node
|
|||||||
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.kunzisoft.keepass.database.element.*
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryVersionedInterface
|
import com.kunzisoft.keepass.database.element.entry.EntryVersionedInterface
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupVersionedInterface
|
import com.kunzisoft.keepass.database.element.group.GroupVersionedInterface
|
||||||
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 org.joda.time.LocalDateTime
|
import org.joda.time.LocalDateTime
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,7 +87,7 @@ abstract class NodeVersioned<IdType, Parent : GroupVersionedInterface<Parent, En
|
|||||||
|
|
||||||
final override var parent: Parent? = null
|
final override var parent: Parent? = null
|
||||||
|
|
||||||
override var icon: IconImage = IconImageStandard()
|
final override var icon: IconImage = IconImage()
|
||||||
|
|
||||||
final override var creationTime: DateInstant = DateInstant()
|
final override var creationTime: DateInstant = DateInstant()
|
||||||
|
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ class DatabaseInputKDB(cacheDirectory: File)
|
|||||||
if (iconId == -1) {
|
if (iconId == -1) {
|
||||||
iconId = 0
|
iconId = 0
|
||||||
}
|
}
|
||||||
entry.icon = mDatabase.iconFactory.getIcon(iconId)
|
entry.icon.standard = mDatabase.getStandardIcon(iconId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0x0004 -> {
|
0x0004 -> {
|
||||||
@@ -260,7 +260,7 @@ class DatabaseInputKDB(cacheDirectory: File)
|
|||||||
}
|
}
|
||||||
0x0007 -> {
|
0x0007 -> {
|
||||||
newGroup?.let { group ->
|
newGroup?.let { group ->
|
||||||
group.icon = mDatabase.iconFactory.getIcon(cipherInputStream.readBytes4ToUInt().toKotlinInt())
|
group.icon.standard = mDatabase.getStandardIcon(cipherInputStream.readBytes4ToUInt().toKotlinInt())
|
||||||
} ?:
|
} ?:
|
||||||
newEntry?.let { entry ->
|
newEntry?.let { entry ->
|
||||||
entry.password = cipherInputStream.readBytesToString(fieldSize,false)
|
entry.password = cipherInputStream.readBytesToString(fieldSize,false)
|
||||||
|
|||||||
@@ -507,9 +507,9 @@ class DatabaseInputKDBX(cacheDirectory: File)
|
|||||||
} else if (name.equals(DatabaseKDBXXML.ElemNotes, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemNotes, ignoreCase = true)) {
|
||||||
ctxGroup?.notes = readString(xpp)
|
ctxGroup?.notes = readString(xpp)
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
||||||
ctxGroup?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toKotlinInt())
|
ctxGroup?.icon?.standard = mDatabase.getStandardIcon(readUInt(xpp, UnsignedInt(0)).toKotlinInt())
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
||||||
ctxGroup?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
ctxGroup?.icon?.custom = mDatabase.getCustomIcon(readUuid(xpp))
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemTimes, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemTimes, ignoreCase = true)) {
|
||||||
return switchContext(ctx, KdbContext.GroupTimes, xpp)
|
return switchContext(ctx, KdbContext.GroupTimes, xpp)
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemIsExpanded, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemIsExpanded, ignoreCase = true)) {
|
||||||
@@ -561,9 +561,9 @@ class DatabaseInputKDBX(cacheDirectory: File)
|
|||||||
KdbContext.Entry -> if (name.equals(DatabaseKDBXXML.ElemUuid, ignoreCase = true)) {
|
KdbContext.Entry -> if (name.equals(DatabaseKDBXXML.ElemUuid, ignoreCase = true)) {
|
||||||
ctxEntry?.nodeId = NodeIdUUID(readUuid(xpp))
|
ctxEntry?.nodeId = NodeIdUUID(readUuid(xpp))
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
||||||
ctxEntry?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toKotlinInt())
|
ctxEntry?.icon?.standard = mDatabase.getStandardIcon(readUInt(xpp, UnsignedInt(0)).toKotlinInt())
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
||||||
ctxEntry?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
ctxEntry?.icon?.custom = mDatabase.getCustomIcon(readUuid(xpp))
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemFgColor, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemFgColor, ignoreCase = true)) {
|
||||||
ctxEntry?.foregroundColor = readString(xpp)
|
ctxEntry?.foregroundColor = readString(xpp)
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemBgColor, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemBgColor, ignoreCase = true)) {
|
||||||
@@ -706,8 +706,7 @@ class DatabaseInputKDBX(cacheDirectory: File)
|
|||||||
} else if (ctx == KdbContext.CustomIcon && name.equals(DatabaseKDBXXML.ElemCustomIconItem, ignoreCase = true)) {
|
} else if (ctx == KdbContext.CustomIcon && name.equals(DatabaseKDBXXML.ElemCustomIconItem, ignoreCase = true)) {
|
||||||
if (customIconID != DatabaseVersioned.UUID_ZERO && customIconData != null) {
|
if (customIconID != DatabaseVersioned.UUID_ZERO && customIconData != null) {
|
||||||
val icon = IconImageCustom(customIconID, customIconData!!)
|
val icon = IconImageCustom(customIconID, customIconData!!)
|
||||||
mDatabase.addCustomIcon(icon)
|
mDatabase.putCustomIcon(icon)
|
||||||
mDatabase.iconFactory.put(icon)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customIconID = DatabaseVersioned.UUID_ZERO
|
customIconID = DatabaseVersioned.UUID_ZERO
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import com.kunzisoft.keepass.database.element.database.DatabaseKDBX.Companion.BA
|
|||||||
import com.kunzisoft.keepass.database.element.entry.AutoType
|
import com.kunzisoft.keepass.database.element.entry.AutoType
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
||||||
import com.kunzisoft.keepass.database.element.security.MemoryProtectionConfig
|
import com.kunzisoft.keepass.database.element.security.MemoryProtectionConfig
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||||
@@ -137,24 +136,23 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
dataOutputStream.writeInt(streamKeySize)
|
dataOutputStream.writeInt(streamKeySize)
|
||||||
dataOutputStream.write(header.innerRandomStreamKey)
|
dataOutputStream.write(header.innerRandomStreamKey)
|
||||||
|
|
||||||
database.binaryPool.doForEachOrderedBinary { _, keyBinary ->
|
val binaryCipherKey = database.loadedCipherKey
|
||||||
val protectedBinary = keyBinary.binary
|
?: throw IOException("Unable to retrieve cipher key to write binaries")
|
||||||
val binaryCipherKey = database.loadedCipherKey
|
database.binaryPool.doForEachOrderedBinary { _, binary ->
|
||||||
?: throw IOException("Unable to retrieve cipher key to write binaries")
|
|
||||||
// Force decompression to add binary in header
|
// Force decompression to add binary in header
|
||||||
protectedBinary.decompress(binaryCipherKey)
|
binary.decompress(binaryCipherKey)
|
||||||
// Write type binary
|
// Write type binary
|
||||||
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary)
|
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary)
|
||||||
// Write size
|
// Write size
|
||||||
dataOutputStream.writeUInt(UnsignedInt.fromKotlinLong(protectedBinary.length + 1))
|
dataOutputStream.writeUInt(UnsignedInt.fromKotlinLong(binary.length + 1))
|
||||||
// Write protected flag
|
// Write protected flag
|
||||||
var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None
|
var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None
|
||||||
if (protectedBinary.isProtected) {
|
if (binary.isProtected) {
|
||||||
flag = flag or DatabaseHeaderKDBX.KdbxBinaryFlags.Protected
|
flag = flag or DatabaseHeaderKDBX.KdbxBinaryFlags.Protected
|
||||||
}
|
}
|
||||||
dataOutputStream.writeByte(flag)
|
dataOutputStream.writeByte(flag)
|
||||||
|
|
||||||
protectedBinary.getInputDataStream(binaryCipherKey).use { inputStream ->
|
binary.getInputDataStream(binaryCipherKey).use { inputStream ->
|
||||||
inputStream.readAllBytes { buffer ->
|
inputStream.readAllBytes { buffer ->
|
||||||
dataOutputStream.write(buffer)
|
dataOutputStream.write(buffer)
|
||||||
}
|
}
|
||||||
@@ -363,10 +361,10 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
writeUuid(DatabaseKDBXXML.ElemUuid, group.id)
|
writeUuid(DatabaseKDBXXML.ElemUuid, group.id)
|
||||||
writeObject(DatabaseKDBXXML.ElemName, group.title)
|
writeObject(DatabaseKDBXXML.ElemName, group.title)
|
||||||
writeObject(DatabaseKDBXXML.ElemNotes, group.notes)
|
writeObject(DatabaseKDBXXML.ElemNotes, group.notes)
|
||||||
writeObject(DatabaseKDBXXML.ElemIcon, group.icon.iconId.toLong())
|
writeObject(DatabaseKDBXXML.ElemIcon, group.icon.standard.id.toLong())
|
||||||
|
|
||||||
if (group.iconCustom != IconImageCustom.UNKNOWN_ICON) {
|
if (!group.icon.custom.isUnknown) {
|
||||||
writeUuid(DatabaseKDBXXML.ElemCustomIconID, group.iconCustom.uuid)
|
writeUuid(DatabaseKDBXXML.ElemCustomIconID, group.icon.custom.uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
writeTimes(group)
|
writeTimes(group)
|
||||||
@@ -388,10 +386,10 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
xml.startTag(null, DatabaseKDBXXML.ElemEntry)
|
xml.startTag(null, DatabaseKDBXXML.ElemEntry)
|
||||||
|
|
||||||
writeUuid(DatabaseKDBXXML.ElemUuid, entry.id)
|
writeUuid(DatabaseKDBXXML.ElemUuid, entry.id)
|
||||||
writeObject(DatabaseKDBXXML.ElemIcon, entry.icon.iconId.toLong())
|
writeObject(DatabaseKDBXXML.ElemIcon, entry.icon.standard.id.toLong())
|
||||||
|
|
||||||
if (entry.iconCustom != IconImageCustom.UNKNOWN_ICON) {
|
if (!entry.icon.custom.isUnknown) {
|
||||||
writeUuid(DatabaseKDBXXML.ElemCustomIconID, entry.iconCustom.uuid)
|
writeUuid(DatabaseKDBXXML.ElemCustomIconID, entry.icon.custom.uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
writeObject(DatabaseKDBXXML.ElemFgColor, entry.foregroundColor)
|
writeObject(DatabaseKDBXXML.ElemFgColor, entry.foregroundColor)
|
||||||
@@ -499,10 +497,9 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
xml.startTag(null, DatabaseKDBXXML.ElemBinaries)
|
xml.startTag(null, DatabaseKDBXXML.ElemBinaries)
|
||||||
|
|
||||||
// Use indexes because necessarily (binary header ref is the order)
|
// Use indexes because necessarily (binary header ref is the order)
|
||||||
mDatabaseKDBX.binaryPool.doForEachOrderedBinary { index, keyBinary ->
|
mDatabaseKDBX.binaryPool.doForEachOrderedBinary { index, binary ->
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString())
|
xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString())
|
||||||
val binary = keyBinary.binary
|
|
||||||
if (binary.length > 0) {
|
if (binary.length > 0) {
|
||||||
if (binary.isCompressed) {
|
if (binary.isCompressed) {
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
|
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
|
||||||
@@ -700,16 +697,15 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
|
|
||||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||||
private fun writeCustomIconList() {
|
private fun writeCustomIconList() {
|
||||||
val customIcons = mDatabaseKDBX.customIcons
|
if (!mDatabaseKDBX.containsCustomIcons()) return
|
||||||
if (customIcons.size == 0) return
|
|
||||||
|
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemCustomIcons)
|
xml.startTag(null, DatabaseKDBXXML.ElemCustomIcons)
|
||||||
|
|
||||||
for (icon in customIcons) {
|
mDatabaseKDBX.iconPool.doForEachCustomIcon { customIcon ->
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemCustomIconItem)
|
xml.startTag(null, DatabaseKDBXXML.ElemCustomIconItem)
|
||||||
|
|
||||||
writeUuid(DatabaseKDBXXML.ElemCustomIconItemID, icon.uuid)
|
writeUuid(DatabaseKDBXXML.ElemCustomIconItemID, customIcon.uuid)
|
||||||
writeObject(DatabaseKDBXXML.ElemCustomIconItemData, String(Base64.encode(icon.imageData, BASE_64_FLAG)))
|
writeObject(DatabaseKDBXXML.ElemCustomIconItemData, String(Base64.encode(customIcon.imageData, BASE_64_FLAG)))
|
||||||
|
|
||||||
xml.endTag(null, DatabaseKDBXXML.ElemCustomIconItem)
|
xml.endTag(null, DatabaseKDBXXML.ElemCustomIconItem)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class EntryOutputKDB(private val mEntry: EntryKDB,
|
|||||||
// Image ID
|
// Image ID
|
||||||
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
||||||
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
||||||
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mEntry.icon.iconId)))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mEntry.icon.standard.id)))
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
//byte[] title = mEntry.title.getBytes("UTF-8");
|
//byte[] title = mEntry.title.getBytes("UTF-8");
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class GroupOutputKDB(private val mGroup: GroupKDB,
|
|||||||
// Image ID
|
// Image ID
|
||||||
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
||||||
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
||||||
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mGroup.icon.iconId)))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mGroup.icon.standard.id)))
|
||||||
|
|
||||||
// Level
|
// Level
|
||||||
mOutputStream.write(LEVEL_FIELD_TYPE)
|
mOutputStream.write(LEVEL_FIELD_TYPE)
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import androidx.core.widget.ImageViewCompat
|
|||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
|
||||||
import org.apache.commons.collections.map.AbstractReferenceMap
|
import org.apache.commons.collections.map.AbstractReferenceMap
|
||||||
import org.apache.commons.collections.map.ReferenceMap
|
import org.apache.commons.collections.map.ReferenceMap
|
||||||
|
|
||||||
@@ -110,17 +109,12 @@ class IconDrawableFactory {
|
|||||||
* Get the [SuperDrawable] [icon] (from cache, or build it and add it to the cache if not exists yet), then [tint] it with [tintColor] if needed
|
* Get the [SuperDrawable] [icon] (from cache, or build it and add it to the cache if not exists yet), then [tint] it with [tintColor] if needed
|
||||||
*/
|
*/
|
||||||
fun getIconSuperDrawable(context: Context, icon: IconImage, width: Int, tint: Boolean = false, tintColor: Int = Color.WHITE): SuperDrawable {
|
fun getIconSuperDrawable(context: Context, icon: IconImage, width: Int, tint: Boolean = false, tintColor: Int = Color.WHITE): SuperDrawable {
|
||||||
return when (icon) {
|
return if (!icon.custom.isUnknown) {
|
||||||
is IconImageStandard -> {
|
SuperDrawable(getIconDrawable(context.resources, icon.custom))
|
||||||
val resId = IconPackChooser.getSelectedIconPack(context)?.iconToResId(icon.iconId) ?: R.drawable.ic_blank_32dp
|
} else IconPackChooser.getSelectedIconPack(context)?.iconToResId(icon.standard.id)?.let { resId ->
|
||||||
getIconSuperDrawable(context, resId, width, tint, tintColor)
|
getIconSuperDrawable(context, resId, width, tint, tintColor)
|
||||||
}
|
} ?: run {
|
||||||
is IconImageCustom -> {
|
SuperDrawable(PatternIcon(context.resources).blankDrawable)
|
||||||
SuperDrawable(getIconDrawable(context.resources, icon))
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
SuperDrawable(PatternIcon(context.resources).blankDrawable)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ 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.icon.IconImageStandard
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard.Companion.FOLDER
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard.Companion.FOLDER_ID
|
||||||
|
|
||||||
class GroupInfo : NodeInfo {
|
class GroupInfo : NodeInfo {
|
||||||
|
|
||||||
var notes: String? = null
|
var notes: String? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
icon = IconImageStandard(FOLDER)
|
icon.standard = IconImageStandard(FOLDER_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(): super()
|
constructor(): super()
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ import android.os.Parcel
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
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
|
|
||||||
|
|
||||||
open class NodeInfo() : Parcelable {
|
open class NodeInfo() : Parcelable {
|
||||||
|
|
||||||
var title: String = ""
|
var title: String = ""
|
||||||
var icon: IconImage = IconImageStandard()
|
var icon: IconImage = IconImage()
|
||||||
var creationTime: DateInstant = DateInstant()
|
var creationTime: DateInstant = DateInstant()
|
||||||
var lastModificationTime: DateInstant = DateInstant()
|
var lastModificationTime: DateInstant = DateInstant()
|
||||||
var expires: Boolean = false
|
var expires: Boolean = false
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
* Dark Themes (WARNING: You must reselect your theme if upgrading from an old installation)
|
* Dark Themes (WARNING: You must reselect your theme if upgrading from an old installation) #532 #714
|
||||||
|
* Fix binary deduplication #715
|
||||||
|
* Fix IconId #901
|
||||||
@@ -1 +1,3 @@
|
|||||||
* Thèmes sombres (ATTENTION: Vous devez reselectionner votre theme si mise à niveau d'une ancienne installation)
|
* Thèmes sombres (ATTENTION: Vous devez reselectionner votre theme si mise à niveau d'une ancienne installation) #532 #714
|
||||||
|
* Correction de la duplication des binaires #715
|
||||||
|
* Correction IconId #901
|
||||||
Reference in New Issue
Block a user