Merge branch 'develop' of github.com:Kunzisoft/KeePassDX into develop

This commit is contained in:
J-Jamet
2019-08-20 21:41:44 +02:00
88 changed files with 842 additions and 567 deletions

View File

@@ -1,3 +1,21 @@
KeepassDX (2.5.0.0beta22)
* Rebuild code for actions
* Add UUID as entry view
* Fix bug with natural order
* Fix number of entries in databaseV1
* New entry views
KeepassDX (2.5.0.0beta21)
* Fix nested groups no longer visible in V1 databases
* Improved data import algorithm for V1 databases
* Add natural database sort
* Add username database sort
* Fix button disabled with only KeyFile
* Show the number of entries in a group
KeepassDX (2.5.0.0beta20)
* Fix a major bug that displays an entry history
KeepassDX (2.5.0.0beta19)
* Add lock button always visible
* New connection workflow

View File

@@ -11,8 +11,8 @@ android {
applicationId "com.kunzisoft.keepass"
minSdkVersion 14
targetSdkVersion 27
versionCode = 19
versionName = "2.5.0.0beta19"
versionCode = 22
versionName = "2.5.0.0beta22"
multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests"

View File

@@ -152,7 +152,7 @@ class EntryActivity : LockingHideActivity() {
titleIconView?.assignDatabaseIcon(database.drawFactory, entry.icon, iconColor)
// Assign title text
val entryTitle = entry.getVisualTitle()
val entryTitle = entry.title
collapsingToolbarLayout?.title = entryTitle
toolbar?.title = entryTitle
@@ -236,6 +236,9 @@ class EntryActivity : LockingHideActivity() {
entryContentsView?.assignExpiresDate(getString(R.string.never))
}
// Assign special data
entryContentsView?.assignUUID(entry.nodeId.id)
database.stopManageEntry(entry)
}

View File

@@ -54,6 +54,7 @@ import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.database.SortNodeEnum
import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
import com.kunzisoft.keepass.database.action.node.*
import com.kunzisoft.keepass.database.action.node.ActionNodeDatabaseRunnable.Companion.NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.education.GroupActivityEducation
import com.kunzisoft.keepass.icons.assignDatabaseIcon
@@ -61,7 +62,6 @@ import com.kunzisoft.keepass.magikeyboard.KeyboardHelper
import com.kunzisoft.keepass.magikeyboard.MagikIME
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.LOCK_ACTION
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.view.AddNodeButtonView
import net.cachapa.expandablelayout.ExpandableLayout
@@ -523,10 +523,10 @@ class GroupActivity : LockingActivity(),
MoveGroupRunnable(
this,
Database.getInstance(),
groupToMove,
newParent,
AfterAddNodeRunnable(),
!readOnly)
groupToMove,
newParent,
AfterAddNodeRunnable(),
!readOnly)
}.start()
}
@@ -812,20 +812,30 @@ class GroupActivity : LockingActivity(),
override fun onActionNodeFinish(actionNodeValues: ActionNodeValues) {
runOnUiThread {
if (actionNodeValues.result.isSuccess) {
actionNodeValues.oldNode?.let { oldNode ->
mListNodesFragment?.removeNode(oldNode)
// If the action register the position, use it to remove the entry view
val positionNode = actionNodeValues.result.data?.getInt(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY)
if (PreferencesUtil.getListSort(this@GroupActivity) == SortNodeEnum.DB
&& positionNode != null) {
mListNodesFragment?.removeNodeAt(positionNode)
} else {
// else use the old Node that was the entry unchanged with the old parent
actionNodeValues.oldNode?.let { oldNode ->
mListNodesFragment?.removeNode(oldNode)
}
}
// TODO Move trash view
// Add trash in views list if it doesn't exists
val database = Database.getInstance()
if (database.isRecycleBinEnabled) {
val recycleBin = database.recycleBin
if (mCurrentGroup != null && recycleBin != null
// Add trash in views list if it doesn't exists
val database = Database.getInstance()
if (database.isRecycleBinEnabled) {
val recycleBin = database.recycleBin
if (mCurrentGroup != null && recycleBin != null
&& mCurrentGroup!!.parent == null
&& mCurrentGroup != recycleBin) {
mListNodesFragment?.addNode(recycleBin)
}
if (mListNodesFragment?.contains(recycleBin) == true)
mListNodesFragment?.updateNode(recycleBin)
else
mListNodesFragment?.addNode(recycleBin)
}
}
}

View File

@@ -25,6 +25,7 @@ import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.activities.stylish.StylishFragment
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.database.element.Database
class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionListener {
@@ -205,24 +206,20 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
R.id.menu_sort -> {
context?.let { context ->
val sortDialogFragment: SortDialogFragment
/*
// TODO Recycle bin bottom
if (database.isRecycleBinAvailable() && database.isRecycleBinEnabled()) {
sortDialogFragment =
val sortDialogFragment: SortDialogFragment =
if (Database.getInstance().isRecycleBinAvailable
&& Database.getInstance().isRecycleBinEnabled) {
SortDialogFragment.getInstance(
PrefsUtil.getListSort(this),
PrefsUtil.getAscendingSort(this),
PrefsUtil.getGroupsBeforeSort(this),
PrefsUtil.getRecycleBinBottomSort(this));
} else {
*/
sortDialogFragment = SortDialogFragment.getInstance(
PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context))
//}
PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context),
PreferencesUtil.getRecycleBinBottomSort(context))
} else {
SortDialogFragment.getInstance(
PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context))
}
sortDialogFragment.show(childFragmentManager, "sortDialog")
}
@@ -255,18 +252,26 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
}
}
fun contains(node: NodeVersioned): Boolean {
return mAdapter?.contains(node) ?: false
}
fun addNode(newNode: NodeVersioned) {
mAdapter?.addNode(newNode)
}
fun updateNode(oldNode: NodeVersioned, newNode: NodeVersioned) {
mAdapter?.updateNode(oldNode, newNode)
fun updateNode(oldNode: NodeVersioned, newNode: NodeVersioned? = null) {
mAdapter?.updateNode(oldNode, newNode ?: oldNode)
}
fun removeNode(pwNode: NodeVersioned) {
mAdapter?.removeNode(pwNode)
}
fun removeNodeAt(position: Int) {
mAdapter?.removeNodeAt(position)
}
interface OnScrollListener {
/**

View File

@@ -48,7 +48,6 @@ import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment
import com.kunzisoft.keepass.activities.helpers.*
import com.kunzisoft.keepass.activities.lock.LockingActivity
import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.app.App
import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.database.action.LoadDatabaseRunnable
import com.kunzisoft.keepass.database.action.ProgressDialogThread
@@ -148,10 +147,8 @@ class PasswordActivity : StylishActivity(),
}
})
enableButtonOnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
if (!PreferencesUtil.emptyPasswordAllowed(this@PasswordActivity)) {
confirmButtonView?.isEnabled = isChecked
}
enableButtonOnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { _, _ ->
enableOrNotTheConfirmationButton()
}
}
@@ -175,15 +172,6 @@ class PasswordActivity : StylishActivity(),
// For check shutdown
super.onResume()
// Enable or not the open button
if (!PreferencesUtil.emptyPasswordAllowed(this@PasswordActivity)) {
checkboxPasswordView?.let {
confirmButtonView?.isEnabled = it.isChecked
}
} else {
confirmButtonView?.isEnabled = true
}
UriIntentInitTask(WeakReference(this), this, mRememberKeyFile)
.execute(intent)
}
@@ -288,6 +276,21 @@ class PasswordActivity : StylishActivity(),
if (!fingerPrintInit) {
checkboxPasswordView?.setOnCheckedChangeListener(enableButtonOnCheckedChangeListener)
}
checkboxKeyFileView?.setOnCheckedChangeListener(enableButtonOnCheckedChangeListener)
}
enableOrNotTheConfirmationButton()
}
private fun enableOrNotTheConfirmationButton() {
// Enable or not the open button if setting is checked
if (!PreferencesUtil.emptyPasswordAllowed(this@PasswordActivity)) {
checkboxPasswordView?.let {
confirmButtonView?.isEnabled = (checkboxPasswordView?.isChecked == true
|| checkboxKeyFileView?.isChecked == true)
}
} else {
confirmButtonView?.isEnabled = true
}
}

View File

@@ -35,12 +35,14 @@ class SortDialogFragment : DialogFragment() {
private var mListener: SortSelectionListener? = null
private var mSortNodeEnum: SortNodeEnum? = null
private var mSortNodeEnum: SortNodeEnum = SortNodeEnum.DB
@IdRes
private var mCheckedId: Int = 0
private var mGroupsBefore: Boolean = false
private var mAscending: Boolean = false
private var mRecycleBinBottom: Boolean = false
private var mGroupsBefore: Boolean = true
private var mAscending: Boolean = true
private var mRecycleBinBottom: Boolean = true
private var recycleBinBottomView: CompoundButton? = null
override fun onAttach(context: Context?) {
super.onAttach(context)
@@ -50,18 +52,13 @@ class SortDialogFragment : DialogFragment() {
throw ClassCastException(context!!.toString()
+ " must implement " + SortSelectionListener::class.java.name)
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
val builder = AlertDialog.Builder(activity)
mSortNodeEnum = SortNodeEnum.TITLE
mAscending = true
mGroupsBefore = true
var recycleBinAllowed = false
mRecycleBinBottom = true
arguments?.apply {
if (containsKey(SORT_NODE_ENUM_BUNDLE_KEY))
@@ -78,14 +75,14 @@ class SortDialogFragment : DialogFragment() {
}
}
mCheckedId = retrieveViewFromEnum(mSortNodeEnum!!)
mCheckedId = retrieveViewFromEnum(mSortNodeEnum)
val rootView = activity.layoutInflater.inflate(R.layout.fragment_sort_selection, null)
builder.setTitle(R.string.sort_menu)
builder.setView(rootView)
// Add action buttons
.setPositiveButton(android.R.string.ok
) { _, _ -> mListener?.onSortSelected(mSortNodeEnum!!, mAscending, mGroupsBefore, mRecycleBinBottom) }
) { _, _ -> mListener?.onSortSelected(mSortNodeEnum, mAscending, mGroupsBefore, mRecycleBinBottom) }
.setNegativeButton(R.string.cancel) { _, _ -> }
val ascendingView = rootView.findViewById<CompoundButton>(R.id.sort_selection_ascending)
@@ -98,25 +95,35 @@ class SortDialogFragment : DialogFragment() {
groupsBeforeView.isChecked = mGroupsBefore
groupsBeforeView.setOnCheckedChangeListener { _, isChecked -> mGroupsBefore = isChecked }
val recycleBinBottomView = rootView.findViewById<CompoundButton>(R.id.sort_selection_recycle_bin_bottom)
recycleBinBottomView = rootView.findViewById(R.id.sort_selection_recycle_bin_bottom)
if (!recycleBinAllowed) {
recycleBinBottomView.visibility = View.GONE
recycleBinBottomView?.visibility = View.GONE
} else {
// Check if recycle bin at the bottom
recycleBinBottomView.isChecked = mRecycleBinBottom
recycleBinBottomView.setOnCheckedChangeListener { _, isChecked -> mRecycleBinBottom = isChecked }
recycleBinBottomView?.isChecked = mRecycleBinBottom
recycleBinBottomView?.setOnCheckedChangeListener { _, isChecked -> mRecycleBinBottom = isChecked }
disableRecycleBinBottomOptionIfNaturalOrder()
}
val sortSelectionRadioGroupView = rootView.findViewById<RadioGroup>(R.id.sort_selection_radio_group)
// Check value by default
sortSelectionRadioGroupView.check(mCheckedId)
sortSelectionRadioGroupView.setOnCheckedChangeListener { _, checkedId -> mSortNodeEnum = retrieveSortEnumFromViewId(checkedId) }
sortSelectionRadioGroupView.setOnCheckedChangeListener { _, checkedId ->
mSortNodeEnum = retrieveSortEnumFromViewId(checkedId)
disableRecycleBinBottomOptionIfNaturalOrder()
}
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
private fun disableRecycleBinBottomOptionIfNaturalOrder() {
// Disable recycle bin if natural order
recycleBinBottomView?.isEnabled = mSortNodeEnum != SortNodeEnum.DB
}
@IdRes
private fun retrieveViewFromEnum(sortNodeEnum: SortNodeEnum): Int {
return when (sortNodeEnum) {

View File

@@ -30,7 +30,6 @@ import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.app.App
import com.kunzisoft.keepass.database.SortNodeEnum
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.icons.assignDatabaseIcon
@@ -48,11 +47,14 @@ class NodeAdapter
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var textSize: Float = 0.toFloat()
private var subtextSize: Float = 0.toFloat()
private var infoTextSize: Float = 0.toFloat()
private var iconSize: Float = 0.toFloat()
private var listSort: SortNodeEnum? = null
private var groupsBeforeSort: Boolean = false
private var ascendingSort: Boolean = false
private var showUserNames: Boolean = false
private var listSort: SortNodeEnum = SortNodeEnum.DB
private var ascendingSort: Boolean = true
private var groupsBeforeSort: Boolean = true
private var recycleBinBottomSort: Boolean = true
private var showUserNames: Boolean = true
private var showNumberEntries: Boolean = true
private var nodeClickCallback: NodeClickCallback? = null
private var nodeMenuListener: NodeMenuListener? = null
@@ -80,11 +82,13 @@ class NodeAdapter
this.nodeSortedList = SortedList(NodeVersioned::class.java, object : SortedListAdapterCallback<NodeVersioned>(this) {
override fun compare(item1: NodeVersioned, item2: NodeVersioned): Int {
return listSort?.getNodeComparator(ascendingSort, groupsBeforeSort)?.compare(item1, item2) ?: 0
return listSort.getNodeComparator(ascendingSort, groupsBeforeSort, recycleBinBottomSort).compare(item1, item2)
}
override fun areContentsTheSame(oldItem: NodeVersioned, newItem: NodeVersioned): Boolean {
return oldItem.title == newItem.title && oldItem.icon == newItem.icon
return oldItem.type == newItem.type
&& oldItem.title == newItem.title
&& oldItem.icon == newItem.icon
}
override fun areItemsTheSame(item1: NodeVersioned, item2: NodeVersioned): Boolean {
@@ -121,13 +125,16 @@ class NodeAdapter
val textSizeDefault = java.lang.Float.parseFloat(context.getString(R.string.list_size_default))
this.textSize = PreferencesUtil.getListTextSize(context)
this.subtextSize = context.resources.getInteger(R.integer.list_small_size_default) * textSize / textSizeDefault
this.infoTextSize = context.resources.getInteger(R.integer.list_tiny_size_default) * textSize / textSizeDefault
// Retrieve the icon size
val iconDefaultSize = context.resources.getDimension(R.dimen.list_icon_size_default)
this.iconSize = iconDefaultSize * textSize / textSizeDefault
this.listSort = PreferencesUtil.getListSort(context)
this.groupsBeforeSort = PreferencesUtil.getGroupsBeforeSort(context)
this.ascendingSort = PreferencesUtil.getAscendingSort(context)
this.groupsBeforeSort = PreferencesUtil.getGroupsBeforeSort(context)
this.recycleBinBottomSort = PreferencesUtil.getRecycleBinBottomSort(context)
this.showUserNames = PreferencesUtil.showUsernamesListEntries(context)
this.showNumberEntries = PreferencesUtil.showNumberEntries(context)
}
/**
@@ -136,14 +143,16 @@ class NodeAdapter
fun rebuildList(group: GroupVersioned) {
this.nodeSortedList.clear()
assignPreferences()
// TODO verify sort
try {
this.nodeSortedList.addAll(group.getChildrenWithoutMetaStream())
this.nodeSortedList.addAll(group.getChildren())
} catch (e: Exception) {
Log.e(TAG, "Can't add node elements to the list", e)
Toast.makeText(context, "Can't add node elements to the list : " + e.message, Toast.LENGTH_LONG).show()
}
}
fun contains(node: NodeVersioned): Boolean {
return nodeSortedList.indexOf(node) != SortedList.INVALID_POSITION
}
/**
@@ -162,6 +171,13 @@ class NodeAdapter
nodeSortedList.remove(node)
}
/**
* Remove a node at [position] in the list
*/
fun removeNodeAt(position: Int) {
nodeSortedList.removeItemAt(position)
}
/**
* Update a node in the list
* @param oldNode Node before the update
@@ -239,6 +255,17 @@ class NodeAdapter
holder.icon.layoutParams?.width = iconSize.toInt()
holder.text.textSize = textSize
holder.subText.textSize = subtextSize
if (subNode.type == Type.GROUP) {
if (showNumberEntries) {
holder.numberChildren?.apply {
text = (subNode as GroupVersioned).getChildEntries(true).size.toString()
textSize = infoTextSize
visibility = View.VISIBLE
}
} else {
holder.numberChildren?.visibility = View.GONE
}
}
}
override fun getItemCount(): Int {
@@ -356,6 +383,7 @@ class NodeAdapter
var icon: ImageView = itemView.findViewById(R.id.node_icon)
var text: TextView = itemView.findViewById(R.id.node_text)
var subText: TextView = itemView.findViewById(R.id.node_subtext)
var numberChildren: TextView? = itemView.findViewById(R.id.node_child_numbers)
}
companion object {

View File

@@ -20,41 +20,54 @@
package com.kunzisoft.keepass.database
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.EntryVersioned
import com.kunzisoft.keepass.database.element.GroupVersioned
import com.kunzisoft.keepass.database.element.NodeVersioned
import java.util.Comparator
import com.kunzisoft.keepass.database.element.Type
import java.util.*
enum class SortNodeEnum {
DB, TITLE, USERNAME, CREATION_TIME, LAST_MODIFY_TIME, LAST_ACCESS_TIME;
fun getNodeComparator(ascending: Boolean, groupsBefore: Boolean): Comparator<NodeVersioned> {
fun getNodeComparator(ascending: Boolean, groupsBefore: Boolean, recycleBinBottom: Boolean): Comparator<NodeVersioned> {
return when (this) {
DB -> NodeCreationComparator(ascending, groupsBefore) // TODO Sort
TITLE -> NodeTitleComparator(ascending, groupsBefore)
USERNAME -> NodeCreationComparator(ascending, groupsBefore) // TODO Sort
CREATION_TIME -> NodeCreationComparator(ascending, groupsBefore)
LAST_MODIFY_TIME -> NodeLastModificationComparator(ascending, groupsBefore)
LAST_ACCESS_TIME -> NodeLastAccessComparator(ascending, groupsBefore)
DB -> NodeNaturalComparator(ascending, groupsBefore, false) // Force false because natural order contains recycle bin
TITLE -> NodeTitleComparator(ascending, groupsBefore, recycleBinBottom)
USERNAME -> NodeUsernameComparator(ascending, groupsBefore, recycleBinBottom)
CREATION_TIME -> NodeCreationComparator(ascending, groupsBefore, recycleBinBottom)
LAST_MODIFY_TIME -> NodeLastModificationComparator(ascending, groupsBefore, recycleBinBottom)
LAST_ACCESS_TIME -> NodeLastAccessComparator(ascending, groupsBefore, recycleBinBottom)
}
}
abstract class NodeComparator internal constructor(internal var ascending: Boolean, private var groupsBefore: Boolean) : Comparator<NodeVersioned> {
abstract class NodeComparator(var ascending: Boolean, var groupsBefore: Boolean, var recycleBinBottom: Boolean) : Comparator<NodeVersioned> {
internal fun compareWith(comparatorGroup: Comparator<GroupVersioned>,
comparatorEntry: Comparator<EntryVersioned>,
object1: NodeVersioned,
object2: NodeVersioned,
resultOfNodeMethodCompare: Int): Int {
abstract fun compareBySpecificOrder(object1: NodeVersioned, object2: NodeVersioned): Int
private fun specificOrderOrHashIfEquals(object1: NodeVersioned, object2: NodeVersioned): Int {
val specificOrderComp = compareBySpecificOrder(object1, object2)
return if (specificOrderComp == 0) {
object1.hashCode() - object2.hashCode()
} else if (!ascending) -specificOrderComp else specificOrderComp // If descending, revert
}
override fun compare(object1: NodeVersioned,object2: NodeVersioned): Int {
if (object1 == object2)
return 0
if (object1 is GroupVersioned) {
return if (object2 is GroupVersioned) {
comparatorGroup
.compare(object1, object2)
} else if (object2 is EntryVersioned) {
if (object1.type == Type.GROUP) {
return if (object2.type == Type.GROUP) {
// RecycleBin at end of groups
if (recycleBinBottom) {
if (Database.getInstance().recycleBin == object1)
return 1
if (Database.getInstance().recycleBin == object2)
return -1
}
specificOrderOrHashIfEquals(object1, object2)
} else if (object2.type == Type.ENTRY) {
if (groupsBefore)
-1
else
@@ -62,11 +75,10 @@ enum class SortNodeEnum {
} else {
-1
}
} else if (object1 is EntryVersioned) {
return if (object2 is EntryVersioned) {
comparatorEntry
.compare(object1, object2)
} else if (object2 is GroupVersioned) {
} else if (object1.type == Type.ENTRY) {
return if (object2.type == Type.ENTRY) {
specificOrderOrHashIfEquals(object1, object2)
} else if (object2.type == Type.GROUP) {
if (groupsBefore)
1
else
@@ -76,235 +88,83 @@ enum class SortNodeEnum {
}
}
// If same name, can be different
return if (resultOfNodeMethodCompare == 0) object1.hashCode() - object2.hashCode() else resultOfNodeMethodCompare
// Type not known
return -1
}
}
/**
* Comparator of Node by Title, Groups first, Entries second
* Comparator of node by natural database placement
*/
class NodeTitleComparator internal constructor(ascending: Boolean, groupsBefore: Boolean) : NodeComparator(ascending, groupsBefore) {
class NodeNaturalComparator(ascending: Boolean, groupsBefore: Boolean, recycleBinBottom: Boolean)
: NodeComparator(ascending, groupsBefore, recycleBinBottom) {
override fun compare(object1: NodeVersioned, object2: NodeVersioned): Int {
return compareWith(
GroupNameComparator(ascending),
EntryNameComparator(ascending),
object1,
object2,
object1.title
.compareTo(object2.title, ignoreCase = true))
override fun compareBySpecificOrder(object1: NodeVersioned, object2: NodeVersioned): Int {
return object1.nodePositionInParent.compareTo(object2.nodePositionInParent)
}
}
/**
* Comparator of node by creation, Groups first, Entries second
* Comparator of Node by Title
*/
class NodeCreationComparator internal constructor(ascending: Boolean, groupsBefore: Boolean) : NodeComparator(ascending, groupsBefore) {
class NodeTitleComparator(ascending: Boolean, groupsBefore: Boolean, recycleBinBottom: Boolean)
: NodeComparator(ascending, groupsBefore, recycleBinBottom) {
override fun compare(object1: NodeVersioned, object2: NodeVersioned): Int {
return compareWith(
GroupCreationComparator(ascending),
EntryCreationComparator(ascending),
object1,
object2,
object1.creationTime.date
?.compareTo(object2.creationTime.date) ?: 0)
override fun compareBySpecificOrder(object1: NodeVersioned, object2: NodeVersioned): Int {
return object1.title.compareTo(object2.title, ignoreCase = true)
}
}
/**
* Comparator of node by last modification, Groups first, Entries second
* Comparator of Node by Username, Groups by title
*/
class NodeLastModificationComparator internal constructor(ascending: Boolean, groupsBefore: Boolean) : NodeComparator(ascending, groupsBefore) {
class NodeUsernameComparator(ascending: Boolean, groupsBefore: Boolean, recycleBinBottom: Boolean)
: NodeComparator(ascending, groupsBefore, recycleBinBottom) {
override fun compare(object1: NodeVersioned, object2: NodeVersioned): Int {
return compareWith(
GroupLastModificationComparator(ascending),
EntryLastModificationComparator(ascending),
object1,
object2,
object1.lastModificationTime.date
?.compareTo(object2.lastModificationTime.date) ?: 0)
override fun compareBySpecificOrder(object1: NodeVersioned, object2: NodeVersioned): Int {
if (object1.type == Type.ENTRY && object2.type == Type.ENTRY) {
// To get username if it's a ref
return (object1 as EntryVersioned).getEntryInfo(Database.getInstance()).username
.compareTo((object2 as EntryVersioned).getEntryInfo(Database.getInstance()).username,
ignoreCase = true)
}
return NodeTitleComparator(ascending, groupsBefore, recycleBinBottom).compare(object1, object2)
}
}
/**
* Comparator of node by last access, Groups first, Entries second
* Comparator of node by creation
*/
class NodeLastAccessComparator internal constructor(ascending: Boolean, groupsBefore: Boolean) : NodeComparator(ascending, groupsBefore) {
class NodeCreationComparator(ascending: Boolean, groupsBefore: Boolean, recycleBinBottom: Boolean)
: NodeComparator(ascending, groupsBefore, recycleBinBottom) {
override fun compare(object1: NodeVersioned, object2: NodeVersioned): Int {
return compareWith(
GroupLastAccessComparator(ascending),
EntryLastAccessComparator(ascending),
object1,
object2,
object1.lastAccessTime.date
?.compareTo(object2.lastAccessTime.date) ?: 0)
}
}
abstract class AscendingComparator<Node> internal constructor(private val ascending: Boolean) : Comparator<Node> {
internal fun compareWithAscending(basicCompareResult: Int): Int {
// If descending, revert
return if (!ascending) -basicCompareResult else basicCompareResult
}
}
/**
* Group comparator by name
*/
class GroupNameComparator internal constructor(ascending: Boolean) : AscendingComparator<GroupVersioned>(ascending) {
override fun compare(object1: GroupVersioned, object2: GroupVersioned): Int {
if (object1 == object2)
return 0
val groupNameComp = object1.title.compareTo(object2.title, ignoreCase = true)
// If same name, can be different
return if (groupNameComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(groupNameComp)
}
}
/**
* Group comparator by name
*/
class GroupCreationComparator internal constructor(ascending: Boolean) : AscendingComparator<GroupVersioned>(ascending) {
override fun compare(object1: GroupVersioned, object2: GroupVersioned): Int {
if (object1 == object2)
return 0
val groupCreationComp = object1.creationTime.date
override fun compareBySpecificOrder(object1: NodeVersioned, object2: NodeVersioned): Int {
return object1.creationTime.date
?.compareTo(object2.creationTime.date) ?: 0
// If same creation, can be different
return if (groupCreationComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(groupCreationComp)
}
}
/**
* Group comparator by last modification
* Comparator of node by last modification
*/
class GroupLastModificationComparator internal constructor(ascending: Boolean) : AscendingComparator<GroupVersioned>(ascending) {
class NodeLastModificationComparator(ascending: Boolean, groupsBefore: Boolean, recycleBinBottom: Boolean)
: NodeComparator(ascending, groupsBefore, recycleBinBottom) {
override fun compare(object1: GroupVersioned, object2: GroupVersioned): Int {
if (object1 == object2)
return 0
val groupLastModificationComp = object1.lastModificationTime.date
override fun compareBySpecificOrder(object1: NodeVersioned, object2: NodeVersioned): Int {
return object1.lastModificationTime.date
?.compareTo(object2.lastModificationTime.date) ?: 0
// If same creation, can be different
return if (groupLastModificationComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(groupLastModificationComp)
}
}
/**
* Group comparator by last access
* Comparator of node by last access
*/
class GroupLastAccessComparator internal constructor(ascending: Boolean) : AscendingComparator<GroupVersioned>(ascending) {
class NodeLastAccessComparator(ascending: Boolean, groupsBefore: Boolean, recycleBinBottom: Boolean)
: NodeComparator(ascending, groupsBefore, recycleBinBottom) {
override fun compare(object1: GroupVersioned, object2: GroupVersioned): Int {
if (object1 == object2)
return 0
val groupLastAccessComp = object1.lastAccessTime.date
override fun compareBySpecificOrder(object1: NodeVersioned, object2: NodeVersioned): Int {
return object1.lastAccessTime.date
?.compareTo(object2.lastAccessTime.date) ?: 0
// If same creation, can be different
return if (groupLastAccessComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(groupLastAccessComp)
}
}
/**
* Comparator of Entry by Name
*/
class EntryNameComparator internal constructor(ascending: Boolean) : AscendingComparator<EntryVersioned>(ascending) {
override fun compare(object1: EntryVersioned, object2: EntryVersioned): Int {
if (object1 == object2)
return 0
val entryTitleComp = object1.title.compareTo(object2.title, ignoreCase = true)
// If same title, can be different
return if (entryTitleComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(entryTitleComp)
}
}
/**
* Comparator of Entry by Creation
*/
class EntryCreationComparator internal constructor(ascending: Boolean) : AscendingComparator<EntryVersioned>(ascending) {
override fun compare(object1: EntryVersioned, object2: EntryVersioned): Int {
if (object1 == object2)
return 0
val entryCreationComp = object1.creationTime.date
?.compareTo(object2.creationTime.date) ?: 0
// If same creation, can be different
return if (entryCreationComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(entryCreationComp)
}
}
/**
* Comparator of Entry by Last Modification
*/
class EntryLastModificationComparator internal constructor(ascending: Boolean) : AscendingComparator<EntryVersioned>(ascending) {
override fun compare(object1: EntryVersioned, object2: EntryVersioned): Int {
if (object1 == object2)
return 0
val entryLastModificationComp = object1.lastModificationTime.date
?.compareTo(object2.lastModificationTime.date) ?: 0
// If same creation, can be different
return if (entryLastModificationComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(entryLastModificationComp)
}
}
/**
* Comparator of Entry by Last Access
*/
class EntryLastAccessComparator internal constructor(ascending: Boolean) : AscendingComparator<EntryVersioned>(ascending) {
override fun compare(object1: EntryVersioned, object2: EntryVersioned): Int {
if (object1 == object2)
return 0
val entryLastAccessComp = object1.lastAccessTime.date
?.compareTo(object2.lastAccessTime.date) ?: 0
// If same creation, can be different
return if (entryLastAccessComp == 0) {
object1.hashCode() - object2.hashCode()
} else compareWithAscending(entryLastAccessComp)
}
}
}

View File

@@ -1,6 +1,7 @@
package com.kunzisoft.keepass.database.action.node
import android.support.v4.app.FragmentActivity
import android.util.Log
import com.kunzisoft.keepass.database.action.SaveDatabaseRunnable
import com.kunzisoft.keepass.database.element.Database
@@ -23,6 +24,7 @@ abstract class ActionNodeDatabaseRunnable(
super.run()
finishRun(true)
} catch (e: Exception) {
Log.e("ActionNodeDBRunnable", e.message)
finishRun(false, e.message)
}
}
@@ -43,4 +45,8 @@ abstract class ActionNodeDatabaseRunnable(
super.onFinishRun(result)
}
companion object {
const val NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY = "NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY"
}
}

View File

@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.database.action.node
import android.support.v4.app.FragmentActivity
import android.util.Log
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.EntryVersioned
import com.kunzisoft.keepass.database.element.GroupVersioned
@@ -37,9 +38,18 @@ class CopyEntryRunnable constructor(
private var mEntryCopied: EntryVersioned? = null
override fun nodeAction() {
// Update entry with new values
mNewParent.touch(modified = false, touchParents = true)
mEntryCopied = database.copyEntryTo(mEntryToCopy, mNewParent)
// Condition
var conditionAccepted = true
if(mNewParent == database.rootGroup && !database.rootCanContainsEntry())
conditionAccepted = false
if (conditionAccepted) {
// Update entry with new values
mNewParent.touch(modified = false, touchParents = true)
mEntryCopied = database.copyEntryTo(mEntryToCopy, mNewParent)
} else {
// Only finish thread
throw Exception(context.getString(R.string.error_copy_entry_here))
}
mEntryCopied?.apply {
touch(modified = true, touchParents = true)
@@ -56,7 +66,6 @@ class CopyEntryRunnable constructor(
} catch (e: Exception) {
Log.i(TAG, "Unable to delete the copied entry")
}
}
return ActionNodeValues(result, mEntryToCopy, mEntryCopied)
}

View File

@@ -19,6 +19,7 @@
*/
package com.kunzisoft.keepass.database.action.node
import android.os.Bundle
import android.support.v4.app.FragmentActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.EntryVersioned
@@ -35,11 +36,19 @@ class DeleteEntryRunnable constructor(
private var mParent: GroupVersioned? = null
private var mCanRecycle: Boolean = false
private var mEntryToDeleteBackup: EntryVersioned? = null
private var mNodePosition: Int? = null
override fun nodeAction() {
mParent = mEntryToDelete.parent
mParent?.touch(modified = false, touchParents = true)
// Get the node position
mNodePosition = mEntryToDelete.nodePositionInParent
// Create a copy to keep the old ref and remove it visually
mEntryToDeleteBackup = EntryVersioned(mEntryToDelete)
// Remove Entry from parent
mCanRecycle = database.canRecycle(mEntryToDelete)
if (mCanRecycle) {
@@ -59,6 +68,16 @@ class DeleteEntryRunnable constructor(
}
}
}
return ActionNodeValues(result, mEntryToDelete, null)
// Add position in bundle to delete the node in view
mNodePosition?.let { position ->
result.data = Bundle().apply {
putInt(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY, position )
}
}
// Return a copy of unchanged entry as old param
// and entry deleted or moved in recycle bin as new param
return ActionNodeValues(result, mEntryToDeleteBackup, mEntryToDelete)
}
}

View File

@@ -19,6 +19,7 @@
*/
package com.kunzisoft.keepass.database.action.node
import android.os.Bundle
import android.support.v4.app.FragmentActivity
import com.kunzisoft.keepass.database.element.Database
@@ -32,10 +33,19 @@ class DeleteGroupRunnable(context: FragmentActivity,
private var mParent: GroupVersioned? = null
private var mRecycle: Boolean = false
private var mGroupToDeleteBackup: GroupVersioned? = null
private var mNodePosition: Int? = null
override fun nodeAction() {
mParent = mGroupToDelete.parent
mParent?.touch(modified = false, touchParents = true)
// Get the node position
mNodePosition = mGroupToDelete.nodePositionInParent
// Create a copy to keep the old ref and remove it visually
mGroupToDeleteBackup = GroupVersioned(mGroupToDelete)
// Remove Group from parent
mRecycle = database.canRecycle(mGroupToDelete)
if (mRecycle) {
@@ -56,6 +66,16 @@ class DeleteGroupRunnable(context: FragmentActivity,
// TODO database.undoDeleteGroupFrom(mGroup, mParent);
}
}
return ActionNodeValues(result, mGroupToDelete, null)
// Add position in bundle to delete the node in view
mNodePosition?.let { position ->
result.data = Bundle().apply {
putInt(NODE_POSITION_FOR_ACTION_NATURAL_ORDER_KEY, position )
}
}
// Return a copy of unchanged group as old param
// and group deleted or moved in recycle bin as new param
return ActionNodeValues(result, mGroupToDeleteBackup, mGroupToDelete)
}
}

View File

@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.database.action.node
import android.support.v4.app.FragmentActivity
import android.util.Log
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.EntryVersioned
import com.kunzisoft.keepass.database.element.GroupVersioned
@@ -40,7 +41,18 @@ class MoveEntryRunnable constructor(
// Move entry in new parent
mEntryToMove?.let {
mOldParent = it.parent
database.moveEntryTo(it, mNewParent)
// Condition
var conditionAccepted = true
if(mNewParent == database.rootGroup && !database.rootCanContainsEntry())
conditionAccepted = false
// Move only if the parent change
if (mOldParent != mNewParent && conditionAccepted) {
database.moveEntryTo(it, mNewParent)
} else {
// Only finish thread
throw Exception(context.getString(R.string.error_move_entry_here))
}
it.touch(modified = true, touchParents = true)
} ?: Log.e(TAG, "Unable to create a copy of the entry")
}

View File

@@ -46,9 +46,7 @@ class MoveGroupRunnable constructor(
finishRun(true)
} else {
// Only finish thread
val message = context.getString(R.string.error_move_folder_in_itself)
Log.e(TAG, message)
finishRun(false, message)
throw Exception(context.getString(R.string.error_move_folder_in_itself))
}
} ?: Log.e(TAG, "Unable to create a copy of the group")
}

View File

@@ -304,14 +304,12 @@ class Database {
val searchResult = search(query, SearchDbHelper.MAX_SEARCH_ENTRY)
if (searchResult != null) {
for (entry in searchResult.getChildEntries()) {
if (!entry.isMetaStream) { // TODO metastream
entry.pwEntryV3?.let {
cursorV3?.addEntry(it)
}
entry.pwEntryV4?.let {
cursorV4?.addEntry(it)
}
for (entry in searchResult.getChildEntries(true)) {
entry.pwEntryV3?.let {
cursorV3?.addEntry(it)
}
entry.pwEntryV4?.let {
cursorV4?.addEntry(it)
}
}
}
@@ -484,6 +482,10 @@ class Database {
pwDatabaseV4?.retrieveMasterKey(key, keyInputStream)
}
fun rootCanContainsEntry(): Boolean {
return pwDatabaseV3?.rootCanContainsEntry() ?: pwDatabaseV4?.rootCanContainsEntry() ?: false
}
fun createEntry(): EntryVersioned? {
pwDatabaseV3?.let { database ->
return EntryVersioned(database.createEntry()).apply {

View File

@@ -338,11 +338,24 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
return entryInfo
}
/*
------------
Class methods
------------
*/
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as EntryVersioned
if (pwEntryV3 != other.pwEntryV3) return false
if (pwEntryV4 != other.pwEntryV4) return false
return true
}
override fun hashCode(): Int {
var result = pwEntryV3?.hashCode() ?: 0
result = 31 * result + (pwEntryV4?.hashCode() ?: 0)
return result
}
companion object CREATOR : Parcelable.Creator<EntryVersioned> {
override fun createFromParcel(parcel: Parcel): EntryVersioned {

View File

@@ -179,10 +179,16 @@ class GroupVersioned : NodeVersioned, PwGroupInterface<GroupVersioned, EntryVers
}
override fun getChildEntries(): MutableList<EntryVersioned> {
return getChildEntries(false)
}
fun getChildEntries(withoutMetaStream: Boolean): MutableList<EntryVersioned> {
val children = ArrayList<EntryVersioned>()
pwGroupV3?.getChildEntries()?.forEach {
children.add(EntryVersioned(it))
val entryToAddAsChild = EntryVersioned(it)
if (!withoutMetaStream || (withoutMetaStream && !entryToAddAsChild.isMetaStream))
children.add(entryToAddAsChild)
}
pwGroupV4?.getChildEntries()?.forEach {
children.add(EntryVersioned(it))
@@ -195,16 +201,16 @@ class GroupVersioned : NodeVersioned, PwGroupInterface<GroupVersioned, EntryVers
* Filter MetaStream entries and return children
* @return List of direct children (one level below) as PwNode
*/
fun getChildrenWithoutMetaStream(): List<NodeVersioned> {
fun getChildren(withoutMetaStream: Boolean = true): List<NodeVersioned> {
val children = ArrayList<NodeVersioned>()
children.addAll(getChildGroups())
pwGroupV3?.let {
children.addAll(getChildEntries().filter { !it.isMetaStream })
children.addAll(getChildEntries(withoutMetaStream))
}
pwGroupV4?.let {
// No MetasStream in V4
children.addAll(getChildEntries())
children.addAll(getChildEntries(withoutMetaStream))
}
return children

View File

@@ -1,6 +1,18 @@
package com.kunzisoft.keepass.database.element
interface NodeVersioned: PwNodeInterface<GroupVersioned>
interface NodeVersioned: PwNodeInterface<GroupVersioned> {
val nodePositionInParent: Int
get() {
parent?.getChildren(true)?.let { children ->
for ((i, child) in children.withIndex()) {
if (child == this)
return i
}
}
return -1
}
}
/**
* Type of available Nodes

View File

@@ -19,6 +19,7 @@
*/
package com.kunzisoft.keepass.database.element
import android.util.Log
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
import com.kunzisoft.keepass.database.exception.KeyFileEmptyException
import com.kunzisoft.keepass.utils.MemUtil
@@ -233,7 +234,12 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
}
fun addGroupIndex(group: Group) {
this.groupIndexes[group.nodeId] = group
val groupId = group.nodeId
if (groupIndexes.containsKey(groupId)) {
Log.e(TAG, "Error, a group with the same UUID $groupId already exists")
} else {
this.groupIndexes[groupId] = group
}
}
fun removeGroupIndex(group: Group) {
@@ -263,7 +269,12 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
}
fun addEntryIndex(entry: Entry) {
this.entryIndexes[entry.nodeId] = entry
val entryId = entry.nodeId
if (entryIndexes.containsKey(entryId)) {
Log.e(TAG, "Error, a group with the same UUID $entryId already exists, change the UUID")
} else {
this.entryIndexes[entryId] = entry
}
}
fun removeEntryIndex(entry: Entry) {
@@ -285,6 +296,8 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
* -------------------------------------
*/
abstract fun rootCanContainsEntry(): Boolean
fun addGroupTo(newGroup: Group, parent: Group?) {
// Add tree to parent tree
parent?.addChildGroup(newGroup)
@@ -306,7 +319,7 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
}
open fun removeEntryFrom(entryToRemove: Entry, parent: Group?) {
// Remove entry for parent
// Remove entry from parent
parent?.removeChildEntry(entryToRemove)
removeEntryIndex(entryToRemove)
}
@@ -332,6 +345,8 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
companion object {
private const val TAG = "PwDatabase"
val UUID_ZERO = UUID(0, 0)
fun hexStringToByteArray(s: String): ByteArray {

View File

@@ -27,7 +27,6 @@ import java.io.InputStream
import java.security.DigestOutputStream
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.*
/**
* @author Naomaru Itoi <nao></nao>@phoneid.org>
@@ -76,53 +75,6 @@ class PwDatabaseV3 : PwDatabase<PwGroupV3, PwEntryV3>() {
numKeyEncRounds = DEFAULT_ENCRYPTION_ROUNDS
}
private fun assignGroupsChildren(parent: PwGroupV3) {
val levelToCheck = parent.level + 1
var startFromParentPosition = false
for (groupToCheck in getGroupIndexes()) {
rootGroup?.let { root ->
if (root.nodeId == parent.nodeId || groupToCheck.nodeId == parent.nodeId) {
startFromParentPosition = true
}
}
if (startFromParentPosition) {
if (groupToCheck.level < levelToCheck)
break
else if (groupToCheck.level == levelToCheck)
parent.addChildGroup(groupToCheck)
}
}
}
private fun assignEntriesChildren(parent: PwGroupV3) {
for (entry in getEntryIndexes()) {
if (entry.parent!!.nodeId == parent.nodeId)
parent.addChildEntry(entry)
}
}
private fun constructTreeFromIndex(currentGroup: PwGroupV3) {
assignGroupsChildren(currentGroup)
assignEntriesChildren(currentGroup)
// set parent in child entries (normally useless but to be sure or to update parent metadata)
for (childEntry in currentGroup.getChildEntries()) {
childEntry.parent = currentGroup
}
// recursively construct child groups
for (childGroup in currentGroup.getChildGroups()) {
childGroup.parent = currentGroup
constructTreeFromIndex(childGroup)
}
}
fun constructTreeFromIndex() {
rootGroup?.let {
constructTreeFromIndex(it)
}
}
/**
* Generates an unused random tree id
*
@@ -198,6 +150,10 @@ class PwDatabaseV3 : PwDatabase<PwGroupV3, PwEntryV3>() {
return PwEntryV3()
}
override fun rootCanContainsEntry(): Boolean {
return false
}
override fun isBackup(group: PwGroupV3): Boolean {
var currentGroup: PwGroupV3? = group
while (currentGroup != null) {

View File

@@ -317,6 +317,10 @@ class PwDatabaseV4 : PwDatabase<PwGroupV4, PwEntryV4> {
return PwEntryV4()
}
override fun rootCanContainsEntry(): Boolean {
return true
}
override fun isBackup(group: PwGroupV4): Boolean {
if (recycleBin == null)
return false

View File

@@ -268,10 +268,6 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
binaries[key] = value
}
fun addToHistory(entry: PwEntryV4) {
history.add(entry)
}
fun sizeOfHistory(): Int {
return history.size
}

View File

@@ -1,7 +1,6 @@
package com.kunzisoft.keepass.database.element
import android.os.Parcel
import java.util.*
abstract class PwGroup
<
@@ -31,6 +30,8 @@ abstract class PwGroup
protected fun updateWith(source: PwGroup<Id, Group, Entry>) {
super.updateWith(source)
titleGroup = source.titleGroup
childGroups.addAll(source.childGroups)
childEntries.addAll(source.childEntries)
}
override var title: String
@@ -46,10 +47,14 @@ abstract class PwGroup
}
override fun addChildGroup(group: Group) {
if (childGroups.contains(group))
removeChildGroup(group)
this.childGroups.add(group)
}
override fun addChildEntry(entry: Entry) {
if (childEntries.contains(entry))
removeChildEntry(entry)
this.childEntries.add(entry)
}

View File

@@ -68,9 +68,6 @@ import java.util.Arrays
/**
* Load a v3 database file.
*
* @author Naomaru Itoi <nao></nao>@phoneid.org>
* @author Bill Zwicky <wrzwicky></wrzwicky>@pobox.com>
*/
class ImporterV3 : Importer<PwDatabaseV3>() {
@@ -223,11 +220,52 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
pos += 2 + 4 + fieldSize
}
mDatabaseToOpen.constructTreeFromIndex()
constructTreeFromIndex()
return mDatabaseToOpen
}
private fun buildTreeGroups(previousGroup: PwGroupV3, currentGroup: PwGroupV3, groupIterator: Iterator<PwGroupV3>) {
if (currentGroup.parent == null && (previousGroup.level + 1) == currentGroup.level) {
// Current group has an increment level compare to the previous, current group is a child
previousGroup.addChildGroup(currentGroup)
currentGroup.parent = previousGroup
} else if (previousGroup.parent != null && previousGroup.level == currentGroup.level) {
// In the same level, previous parent is the same as previous group
previousGroup.parent!!.addChildGroup(currentGroup)
currentGroup.parent = previousGroup.parent
} else if (previousGroup.parent != null) {
// Previous group has a higher level than the current group, check it's parent
buildTreeGroups(previousGroup.parent!!, currentGroup, groupIterator)
}
// Next current group
if (groupIterator.hasNext()){
buildTreeGroups(currentGroup, groupIterator.next(), groupIterator)
}
}
private fun constructTreeFromIndex() {
mDatabaseToOpen.rootGroup?.let {
// add each group
val groupIterator = mDatabaseToOpen.getGroupIndexes().iterator()
if (groupIterator.hasNext())
buildTreeGroups(it, groupIterator.next(), groupIterator)
// add each child
for (currentEntry in mDatabaseToOpen.getEntryIndexes()) {
if (currentEntry.parent != null) {
// Only the parent id is known so complete the info
val parentGroupRetrieve = mDatabaseToOpen.getGroupById(currentEntry.parent!!.nodeId)
parentGroupRetrieve?.addChildEntry(currentEntry)
currentEntry.parent = parentGroupRetrieve
}
}
}
}
/**
* Parse and save one record from binary file.
* @param buf

View File

@@ -533,7 +533,6 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
KdbContext.Entry -> if (name.equals(PwDatabaseV4XML.ElemUuid, ignoreCase = true)) {
ctxEntry?.nodeId = PwNodeIdUUID(readUuid(xpp))
ctxEntry?.let { mDatabase.addEntryIndex(it) }
} else if (name.equals(PwDatabaseV4XML.ElemIcon, ignoreCase = true)) {
ctxEntry?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, 0).toInt())
} else if (name.equals(PwDatabaseV4XML.ElemCustomIconID, ignoreCase = true)) {
@@ -633,7 +632,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
KdbContext.EntryHistory -> if (name.equals(PwDatabaseV4XML.ElemEntry, ignoreCase = true)) {
ctxEntry = PwEntryV4()
ctxEntry?.let { ctxHistoryBase?.addToHistory(it) }
ctxEntry?.let { ctxHistoryBase?.addEntryToHistory(it) }
entryInHistory = true
return switchContext(ctx, KdbContext.Entry, xpp)
@@ -731,15 +730,18 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
return KdbContext.GroupCustomData
} else if (ctx == KdbContext.Entry && name.equals(PwDatabaseV4XML.ElemEntry, ignoreCase = true)) {
if (ctxEntry != null && ctxEntry?.id == PwDatabase.UUID_ZERO) {
if (ctxEntry?.id == PwDatabase.UUID_ZERO)
ctxEntry?.nodeId = mDatabase.newEntryId()
mDatabase.addEntryIndex(ctxEntry!!)
}
if (entryInHistory) {
ctxEntry = ctxHistoryBase
return KdbContext.EntryHistory
}
else if (ctxEntry != null) {
// Add entry to the index only when close the XML element
mDatabase.addEntryIndex(ctxEntry!!)
}
return KdbContext.Group
} else if (ctx == KdbContext.EntryTimes && name.equals(PwDatabaseV4XML.ElemTimes, ignoreCase = true)) {

View File

@@ -40,6 +40,12 @@ object PreferencesUtil {
context.resources.getBoolean(R.bool.list_entries_show_username_default))
}
fun showNumberEntries(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.list_groups_show_number_entries_key),
context.resources.getBoolean(R.bool.list_groups_show_number_entries_default))
}
/**
* Retrieve the text size in SP, verify the integrity of the size stored in preference
*/
@@ -130,7 +136,7 @@ object PreferencesUtil {
fun getListSort(context: Context): SortNodeEnum {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.getString(context.getString(R.string.sort_node_key),
SortNodeEnum.TITLE.name)?.let {
SortNodeEnum.DB.name)?.let {
return SortNodeEnum.valueOf(it)
}
return SortNodeEnum.DB

View File

@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.tasks
import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.widget.Toast
@@ -88,5 +89,5 @@ abstract class ActionRunnable(private var nestedActionRunnable: ActionRunnable?
/**
* Class to manage result from ActionRunnable
*/
data class Result(var isSuccess: Boolean = true, var message: String? = null)
data class Result(var isSuccess: Boolean = true, var message: String? = null, var data: Bundle? = null)
}

View File

@@ -65,6 +65,8 @@ class EntryContentsView @JvmOverloads constructor(context: Context, attrs: Attri
private val lastAccessDateView: TextView
private val expiresDateView: TextView
private val uuidView: TextView
val isUserNamePresent: Boolean
get() = userNameContainerView.visibility == View.VISIBLE
@@ -97,6 +99,8 @@ class EntryContentsView @JvmOverloads constructor(context: Context, attrs: Attri
lastAccessDateView = findViewById(R.id.entry_accessed)
expiresDateView = findViewById(R.id.entry_expires)
uuidView = findViewById(R.id.entry_UUID)
val attrColorAccent = intArrayOf(R.attr.colorAccent)
val taColorAccent = context.theme.obtainStyledAttributes(attrColorAccent)
colorAccent = taColorAccent.getColor(0, Color.BLACK)
@@ -238,6 +242,10 @@ class EntryContentsView @JvmOverloads constructor(context: Context, attrs: Attri
expiresDateView.text = constString
}
fun assignUUID(uuid: UUID) {
uuidView.text = uuid.toString()
}
override fun generateDefaultLayoutParams(): LayoutParams {
return LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="@color/white"
tools:targetApi="lollipop">
<item>
<shape
android:shape="oval">
<padding
android:left="12dp"
android:right="12dp"
android:top="12dp"
android:bottom="12dp"/>
<solid android:color="?attr/colorAccent"/>
</shape>
</item>
</ripple>

View File

@@ -6,7 +6,7 @@
<item>
<shape
android:shape="oval">
<stroke android:color="?attr/colorAccent" android:width="2dp"/>
<stroke android:color="?attr/colorAccent" android:width="1dp"/>
<padding
android:left="12dp"
android:right="12dp"

View File

@@ -6,11 +6,6 @@
<item>
<shape>
<stroke android:color="?attr/colorAccent" android:width="1dp"/>
<padding
android:left="12dp"
android:right="12dp"
android:top="12dp"
android:bottom="12dp"/>
<solid android:color="@color/transparent"/>
</shape>
</item>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="oval">
<padding
android:left="12dp"
android:right="12dp"
android:top="12dp"
android:bottom="12dp"/>
<solid android:color="@color/orange"/>
</shape>
</item>
</selector>

View File

@@ -3,7 +3,7 @@
<item android:state_pressed="true">
<shape
android:shape="oval">
<stroke android:color="@color/orange_light" android:width="2dp"/>
<stroke android:color="@color/orange_light" android:width="1dp"/>
<padding
android:left="12dp"
android:right="12dp"
@@ -15,7 +15,7 @@
<item>
<shape
android:shape="oval">
<stroke android:color="@color/orange" android:width="2dp"/>
<stroke android:color="@color/orange" android:width="1dp"/>
<padding
android:left="12dp"
android:right="12dp"

View File

@@ -3,11 +3,6 @@
<item>
<shape>
<stroke android:color="@color/orange" android:width="1dp"/>
<padding
android:left="12dp"
android:right="12dp"
android:top="12dp"
android:bottom="12dp"/>
<solid android:color="@color/transparent"/>
</shape>
</item>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<corners android:radius="25dp" />
<padding
android:left="4dp"
android:right="4dp"
android:top="1dp"
android:bottom="1dp"/>
<solid android:color="@color/orange"/>
</shape>
</item>
</layer-list>

View File

@@ -52,12 +52,13 @@
android:gravity="center"
android:paddingBottom="12dp"
style="@style/KeepassDXStyle.TextAppearance.Default">
<android.support.v7.widget.AppCompatImageButton
<android.support.v7.widget.AppCompatImageView
android:id="@+id/entry_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:src="@drawable/ic_blank_32dp"
style="@style/KeepassDXStyle.Icon"
android:layout_gravity="center"/>
</FrameLayout>
<android.support.v7.widget.Toolbar

View File

@@ -65,6 +65,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="@drawable/ic_save_white_24dp"
android:contentDescription="@string/content_description_entry_save"
app:useCompatPadding="true"
style="@style/KeepassDXStyle.Fab"/>
</android.support.constraint.ConstraintLayout>

View File

@@ -197,21 +197,17 @@
<android.support.v7.widget.AppCompatImageView
android:id="@+id/file_select_expandable_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="48dp"
android:layout_height="48dp"
android:elevation="8dp"
app:layout_constraintTop_toTopOf="@+id/browse_button"
app:layout_constraintBottom_toBottomOf="@+id/browse_button"
app:layout_constraintStart_toStartOf="parent"
android:focusable="true"
android:paddingStart="12dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingEnd="12dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:padding="12dp"
android:tint="?attr/textColorInverse"
android:src="@drawable/ic_link_white_24dp"/>
android:src="@drawable/ic_link_white_24dp"
android:contentDescription="@string/content_description_show_file_link"/>
<net.cachapa.expandablelayout.ExpandableLayout
android:id="@+id/file_select_expandable"
@@ -226,39 +222,36 @@
android:id="@+id/file_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorPrimaryDark"
android:paddingLeft="@dimen/default_margin"
android:paddingStart="@dimen/default_margin"
android:paddingRight="@dimen/default_margin"
android:paddingEnd="@dimen/default_margin">
android:background="?attr/colorPrimaryDark">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/file_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:inputType="textUri"
android:textColor="?attr/textColorInverse"
android:textColorHint="?attr/android:textColorHintInverse"
android:layout_toLeftOf="@+id/open_database"
android:layout_toStartOf="@+id/open_database"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:layout_marginStart="2dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginEnd="2dp"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:maxLines="1"/>
<android.support.v7.widget.AppCompatImageView
android:id="@+id/open_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:layout_alignTop="@+id/file_filename"
android:layout_alignBottom="@+id/file_filename"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:focusable="true"
android:src="@drawable/ic_send_white_24dp"
android:contentDescription="@string/content_description_open_file_link"
android:tint="?attr/textColorInverse"/>
</RelativeLayout>

View File

@@ -53,6 +53,7 @@
android:id="@+id/default_database"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:layout_gravity="end"
style="@style/KeepassDXStyle.TextAppearance.Small"
android:textColor="?android:attr/textColorHintInverse"
@@ -61,7 +62,6 @@
android:layout_marginStart="24dp"
android:layout_marginRight="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="6dp"
android:text="@string/default_checkbox" />
<com.kunzisoft.keepass.view.FingerPrintInfoView
android:id="@+id/fingerprint_info"
@@ -128,6 +128,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:contentDescription="@string/content_description_password_checkbox"
android:focusable="false"
android:layout_alignBottom="@+id/password_input_layout"
android:gravity="center_vertical" />
@@ -138,6 +139,8 @@
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/password_checkbox"
android:layout_toEndOf="@+id/password_checkbox"
android:importantForAccessibility="no"
android:importantForAutofill="no"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?attr/colorAccent">
@@ -145,6 +148,7 @@
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:hint="@string/password"
android:inputType="textPassword"
android:importantForAccessibility="no"
@@ -165,6 +169,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:contentDescription="@string/content_description_keyfile_checkbox"
android:focusable="false"
android:layout_alignBottom="@+id/input_entry_keyfile"
android:gravity="center_vertical" />
@@ -173,6 +178,8 @@
android:id="@+id/input_entry_keyfile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:importantForAutofill="no"
android:layout_toEndOf="@+id/keyfile_checkox"
android:layout_toRightOf="@+id/keyfile_checkox"
android:layout_toLeftOf="@+id/browse_button"
@@ -182,6 +189,7 @@
android:id="@+id/pass_keyfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:hint="@string/entry_keyfile"
android:inputType="textUri"
android:importantForAccessibility="no"
@@ -192,12 +200,13 @@
<android.support.v7.widget.AppCompatImageView
android:id="@+id/browse_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:layout_alignBottom="@+id/input_entry_keyfile"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:padding="8dp"
android:contentDescription="@string/content_description_open_file"
android:focusable="true"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccent" />

View File

@@ -17,6 +17,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dp"
android:contentDescription="@string/content_description_open_file"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/folder_path_input_layout"

View File

@@ -33,7 +33,8 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText android:id="@+id/password"
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
@@ -41,14 +42,17 @@
android:hint="@string/hint_generated_password"
tools:ignore="TextFields" />
<Button android:id="@+id/generate_password_button"
<Button
android:id="@+id/generate_password_button"
android:layout_margin="@dimen/button_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="@string/generate_password" />
</LinearLayout>
<ScrollView android:id="@+id/ScrollView"
<ScrollView
android:id="@+id/ScrollView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
@@ -61,12 +65,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/length_label"
<TextView
android:id="@+id/length_label"
android:text="@string/length"
android:layout_height="match_parent"
android:layout_width="match_parent" />
<EditText android:id="@+id/length"
<EditText
android:id="@+id/length"
android:layout_width="50dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
@@ -78,7 +84,8 @@
android:text="@string/default_password_length"
android:hint="@string/hint_length"/>
<android.support.v7.widget.AppCompatSeekBar android:id="@+id/seekbar_length"
<android.support.v7.widget.AppCompatSeekBar
android:id="@+id/seekbar_length"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/length"
@@ -87,13 +94,15 @@
android:layout_alignTop="@+id/length"
android:layout_toEndOf="@+id/length"
android:layout_toRightOf="@+id/length"
android:contentDescription="@string/content_description_password_length"
app:min="@string/min_password_length"
android:progress="@string/default_password_length"
android:max="@string/max_password_length"/>
</RelativeLayout>
<LinearLayout android:id="@+id/RelativeLayout"
<LinearLayout
android:id="@+id/RelativeLayout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
@@ -103,7 +112,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_uppercase"
<CheckBox
android:id="@+id/cb_uppercase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/uppercase"
@@ -123,7 +133,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_lowercase"
<CheckBox
android:id="@+id/cb_lowercase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lowercase"
@@ -143,7 +154,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_digits"
<CheckBox
android:id="@+id/cb_digits"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/digits"
@@ -163,7 +175,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_minus"
<CheckBox
android:id="@+id/cb_minus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/minus" />
@@ -182,7 +195,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_underline"
<CheckBox
android:id="@+id/cb_underline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/underline" />
@@ -201,7 +215,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_space"
<CheckBox
android:id="@+id/cb_space"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/space" />
@@ -220,7 +235,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_specials"
<CheckBox
android:id="@+id/cb_specials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/special" />
@@ -239,7 +255,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_brackets"
<CheckBox
android:id="@+id/cb_brackets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/brackets"
@@ -260,7 +277,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox android:id="@+id/cb_extended"
<CheckBox
android:id="@+id/cb_extended"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/extended_ASCII"

View File

@@ -25,6 +25,7 @@
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/nodes_list"
android:contentDescription="@string/content_description_node_children"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground" />

View File

@@ -115,6 +115,7 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/content_description_open_file"
android:padding="12dp"
android:src="@drawable/ic_folder_white_24dp"
android:tint="?attr/colorAccent" />

View File

@@ -15,8 +15,7 @@
<RadioButton android:id="@+id/sort_selection_db"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sort_db"
android:visibility="gone"/>
android:text="@string/sort_db"/>
<RadioButton android:id="@+id/sort_selection_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -24,8 +23,7 @@
<RadioButton android:id="@+id/sort_selection_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sort_username"
android:visibility="gone"/>
android:text="@string/sort_username"/>
<RadioButton android:id="@+id/sort_selection_creation_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@@ -22,8 +22,8 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:paddingEnd="12dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
@@ -45,10 +45,12 @@
android:paddingStart="12dp" />
<android.support.v7.widget.AppCompatImageView
android:id="@+id/file_information"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:layout_centerVertical="true"
android:src="@drawable/ic_info_white_24dp"
android:contentDescription="@string/content_description_file_information"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:tint="?android:attr/textColorHintInverse"/>

View File

@@ -20,6 +20,7 @@
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/node_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -61,6 +62,7 @@
android:id="@+id/node_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
tools:text="Node Title"
android:lines="1"
android:singleLine="true"
style="@style/KeepassDXStyle.TextAppearance.Default" /> <!-- style override -->
@@ -69,6 +71,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="-4dp"
tools:text="Node SubTitle"
android:lines="1"
android:singleLine="true"
style="@style/KeepassDXStyle.TextAppearance.Secondary" /> <!-- style override -->

View File

@@ -20,6 +20,7 @@
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/node_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -57,6 +58,17 @@
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/group_arrow"
android:layout_toEndOf="@+id/group_arrow" />
<TextView
android:id="@+id/node_child_numbers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="3"
android:layout_marginEnd="-18dp"
android:layout_marginRight="-18dp"
style="@style/KeepassDXStyle.TextAppearance.Info"
android:layout_toLeftOf="@+id/node_icon"
android:layout_toStartOf="@+id/node_icon"
android:layout_alignTop="@+id/node_icon" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -73,6 +85,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
tools:text="Node Title"
android:lines="1"
android:singleLine="true"
style="@style/KeepassDXStyle.TextAppearance.Title" /> <!-- style override -->
@@ -81,6 +94,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
tools:text="Node SubTitle"
android:layout_marginTop="-4dp"
android:lines="1"
android:singleLine="true"

View File

@@ -10,6 +10,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_add_white_24dp"
android:contentDescription="@string/content_description_add_node"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
@@ -43,6 +44,7 @@
android:layout_marginRight="@dimen/image_button_margin"
android:layout_marginEnd="@dimen/image_button_margin"
android:src="@drawable/ic_key_white_24dp"
android:contentDescription="@string/add_entry"
android:theme="@style/KeepassDXStyle.Fab.White"
app:fabSize="mini"
app:useCompatPadding="true" />
@@ -73,6 +75,7 @@
android:layout_marginRight="@dimen/image_button_margin"
android:layout_marginEnd="@dimen/image_button_margin"
android:src="@drawable/ic_folder_white_24dp"
android:contentDescription="@string/add_group"
android:theme="@style/KeepassDXStyle.Fab.White"
app:fabSize="mini"
app:useCompatPadding="true" />

View File

@@ -182,45 +182,53 @@
android:orientation="vertical">
<!-- Created -->
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_created_label"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_created_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_created"
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_created"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_created"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TextEntryItem" />
<!-- Modified -->
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_modified_label"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_modified_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_modified"
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_modified"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_modified"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TextEntryItem" />
<!-- Accessed -->
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_accessed_label"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_accessed_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_accessed"
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_accessed"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_accessed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TextEntryItem" />
<!-- Expires -->
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_expires_label"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_expires_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_expires"
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
<android.support.v7.widget.AppCompatTextView android:id="@+id/entry_expires"
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_expires"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TextEntryItem" />
@@ -228,4 +236,36 @@
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_marginBottom="@dimen/default_margin">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_margin="@dimen/default_margin"
android:orientation="vertical">
<!-- Expires -->
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_UUID_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/entry_UUID"
style="@style/KeepassDXStyle.TextAppearance.LabelTextStyle" />
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatTextView
android:id="@+id/entry_UUID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.TextAppearance.TextEntryItem" />
</HorizontalScrollView>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

View File

@@ -38,6 +38,7 @@
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:src="@drawable/ic_blank_32dp"
android:contentDescription="@string/content_description_entry_icon"
android:layout_gravity="center"/>
<!-- Title -->
@@ -108,6 +109,7 @@
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
app:passwordToggleEnabled="true"
android:contentDescription="@string/content_description_repeat_toggle_password_visibility"
android:layout_toLeftOf="@+id/entry_edit_generate_button"
android:layout_toStartOf="@+id/entry_edit_generate_button"
android:layout_below="@+id/entry_edit_container_password">
@@ -125,13 +127,15 @@
<android.support.v7.widget.AppCompatImageView
android:id="@+id/entry_edit_generate_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_margin="8dp"
android:src="@drawable/ic_key_white_24dp"
android:contentDescription="@string/content_description_password_generator"
android:tint="?attr/colorAccent"/>
</RelativeLayout>
@@ -176,15 +180,14 @@
android:orientation="vertical">
</LinearLayout>
<ImageView
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/entry_edit_add_new_field"
android:layout_width="30sp"
android:layout_height="30sp"
android:contentDescription="@string/add_string"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_add_white_24dp"
android:contentDescription="@string/content_description_add_field"
android:tint="?attr/colorAccent"
android:scaleType="centerCrop"
android:visibility="gone"/>
android:scaleType="centerCrop"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>

View File

@@ -22,8 +22,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:layout_marginBottom="@dimen/default_margin"
android:importantForAutofill="noExcludeDescendants"
android:background="@drawable/background_new_field"
@@ -33,8 +31,11 @@
android:id="@+id/title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/entry_new_field_delete"
android:layout_toStartOf="@+id/entry_new_field_delete">
android:paddingTop="12dp"
android:paddingLeft="12dp"
android:paddingStart="12dp"
android:paddingRight="12dp"
android:paddingEnd="12dp">
<EditText
android:id="@+id/entry_new_field_label"
@@ -49,13 +50,13 @@
<android.support.v7.widget.AppCompatImageView
android:id="@+id/entry_new_field_delete"
android:layout_margin="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:scaleType="centerCrop"
android:src="@drawable/ic_close_white_24dp"
android:contentDescription="@string/content_description_remove_field"
android:tint="?attr/colorAccent" />
<android.support.v7.widget.SwitchCompat
@@ -63,6 +64,7 @@
style="@style/KeepassDXStyle.TextAppearance.Default"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:layout_below="@+id/value_container"
android:layout_centerHorizontal="true"
android:text="@string/protection" />
@@ -71,6 +73,10 @@
android:id="@+id/value_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="12dp"
android:paddingStart="12dp"
android:paddingRight="12dp"
android:paddingEnd="12dp"
android:layout_below="@+id/title_container">
<EditText

View File

@@ -20,7 +20,6 @@
<string name="about_homepage">الصفحة الرئيسية :</string>
<string name="accept">قبول</string>
<string name="add_group">إضافة مجموعة</string>
<string name="add_string">إضافة سلسلة</string>
<string name="encryption">التعمية</string>
<string name="encryption_algorithm">خوارزمية التعمية</string>
<string name="application">التطبيق</string>

View File

@@ -179,7 +179,6 @@
<item>Velký</item>
</string-array>
<string name="edit_entry">Upravit záznam</string>
<string name="add_string">Přidat řetězec</string>
<string name="encryption">Šifrování</string>
<string name="key_derivation_function">Funkce pro tvorbu klíče</string>
<string name="extended_ASCII">Rozšířené ASCII</string>

View File

@@ -125,7 +125,7 @@
<string name="no_url_handler">Installer en web-browser til at åbne URL.</string>
<string name="open_recent">Seneste databaser</string>
<string name="omitbackup_title">Gennemsøg ikke backup poster</string>
<string name="omitbackup_summary">Udelad \"Backup\" - gruppe fra søgeresultaterne (gælder kun for .kdb filer)</string>
<string name="omitbackup_summary">Udelader \"Backup\" og \"Papirkurv\" - grupper fra søgeresultater</string>
<string name="progress_create">Opretter ny database…</string>
<string name="progress_title">Arbejder…</string>
<string name="protection">Beskyttelse</string>
@@ -175,7 +175,6 @@
<item>Stor</item>
</string-array>
<string name="edit_entry">Rediger post</string>
<string name="add_string">Tilføj streng</string>
<string name="encryption">Kryptering</string>
<string name="key_derivation_function">Nøgleafledningsfunktion</string>
<string name="extended_ASCII">Udvidet ASCII</string>
@@ -188,7 +187,7 @@
<string name="file_not_found_content">Kunne ikke finde filen. Prøv at åbne den fra filhåndtering.</string>
<string name="list_entries_show_username_title">Vis brugernavne</string>
<string name="list_entries_show_username_summary">Vis brugernavne i postlister</string>
<string name="copy_field">Kopieret %1$s</string>
<string name="copy_field">Kopi af %1$s</string>
<string name="menu_form_filling_settings">Formularudfyldning</string>
<string name="menu_copy">Kopier</string>
<string name="menu_move">Flyt</string>
@@ -216,7 +215,7 @@
<string name="use_saf_summary">Brug Android Storage Access (SAF) som filhåndtering (KitKat og senere)</string>
<string name="use_saf_title">Storage Access Framework</string>
<string name="warning">Advarsel</string>
<string name="warning_password_encoding">Undgå adgangskodetegn undenfor Latin-1 tegnsæt i .kdb filer, da de alle konverteres til det samme bogstav.</string>
<string name="warning_password_encoding">Undgå adgangskodetegn uden for tekstkodningsformatet i databasefilen (ukendte tegn konverteres til samme bogstav).</string>
<string name="warning_empty_password">Bekræft brug af ingen adgangskode til beskyttelse mod oplåsning\?</string>
<string name="warning_no_encryption_key">Bekræft ingen brug af en krypteringsnøgle?</string>
<string name="configure_fingerprint">Fingeraftryksscanning understøttes, men er ikke sat op.</string>
@@ -241,7 +240,7 @@
<string name="list_password_generator_options_summary">Angiv tilladte tegn for adgangskodegenerator</string>
<string name="clipboard">Udklipsholder</string>
<string name="clipboard_notifications_title">Udklipsholdermeddelelser</string>
<string name="clipboard_notifications_summary">Aktivere meddelelser fra udklipsholder for at kopiere indtastningsfelter</string>
<string name="clipboard_notifications_summary">Aktivér udklipsholder for at kopiere felter når en post vises</string>
<string name="clipboard_warning">Hvis automatisk sletning af udklipsholder mislykkes, slet historikken manuelt.</string>
<string name="lock">Lås</string>
<string name="lock_database_screen_off_title">Skærmlås</string>
@@ -379,13 +378,13 @@
<string name="keyboard_setting_label">Magikeyboard indstillinger</string>
<string name="keyboard_entry_category">Post</string>
<string name="keyboard_entry_timeout_title">Timeout</string>
<string name="keyboard_notification_entry_title">Meddelsesinformation</string>
<string name="keyboard_notification_entry_title">Meddelelsesinfo</string>
<string name="keyboard_notification_entry_summary">Vis en meddelelse, når en post er til rådighed</string>
<string name="keyboard_notification_entry_content_title_text">Post</string>
<string name="keyboard_notification_entry_content_title">%1$s til rådighed på Magikeyboard</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="keyboard_notification_entry_clear_close_title">Ryd ved lukning</string>
<string name="keyboard_notification_entry_clear_close_summary">Ryd tastatur post, når meddelse lukkes</string>
<string name="keyboard_notification_entry_clear_close_summary">Luk databasen, når meddelse lukkes</string>
<string name="keyboard_appearance_category">Udseende</string>
<string name="keyboard_theme_title">Tastaturtema</string>
<string name="keyboard_keys_category">Taster</string>
@@ -393,4 +392,16 @@
<string name="keyboard_key_sound_title">Lyd ved tastetryk</string>
<string name="build_label">Build %1$s</string>
<string name="keyboard_entry_timeout_summary">Timeout for at rydde indtastning</string>
<string name="entry_notes">Noter</string>
<string name="selection_mode">Valgstilstand</string>
<string name="do_not_kill_app">Luk ikke programmet…</string>
<string name="lock_database_back_root_title">Lås ved retur</string>
<string name="lock_database_back_root_summary">Lås databasen, når brugeren klikker på tilbage-knappen fra startskærmen</string>
<string name="clear_clipboard_notification_title">Ryd ved lukning</string>
<string name="clear_clipboard_notification_summary">Luk databasen ved lukning af underretning</string>
<string name="recycle_bin">Papirkurv</string>
<string name="keyboard_selection_entry_title">Valg af indtastning</string>
<string name="keyboard_selection_entry_summary">Vis indtastningsfelter i Magikeyboard, når der vises en post</string>
<string name="delete_entered_password_title">Slet adgangskode</string>
<string name="delete_entered_password_summary">Sletter adgangskoden som er indtastet efter et forbindelsesforsøg</string>
</resources>

View File

@@ -27,12 +27,11 @@
<string name="accept">Akzeptieren</string>
<string name="add_entry">Eintrag hinzufügen</string>
<string name="add_group">Gruppe hinzufügen</string>
<string name="add_string">Text hinzufügen</string>
<string name="encryption_algorithm">Verschlüsselungsalgorithmus</string>
<string name="app_timeout">App-Sperre</string>
<string name="app_timeout_summary">Dauer der Inaktivität bis die App gesperrt wird</string>
<string name="application">App</string>
<string name="menu_app_settings">Einstellungen</string>
<string name="menu_app_settings">App Einstellungen</string>
<string name="beta_dontask">Nicht mehr anzeigen</string>
<string name="brackets">Klammern</string>
<string name="browser_intall_text">Durchsuchen Sie Ihre Dateien, indem Sie den OpenIntents File Manager installieren</string>

View File

@@ -157,7 +157,6 @@ Spanish translation by José I. Paños. Updated by David García-Abad (23-09-201
<item>Mediano</item>
<item>Grande</item>
</string-array>
<string name="add_string">Añadir cadena</string>
<string name="encryption">Cifrado</string>
<string name="key_derivation_function">Función de derivación de clave</string>
<string name="beta_dontask">No mostrar nuevamente</string>

View File

@@ -23,7 +23,6 @@
<string name="accept">Accepter</string>
<string name="add_entry">Ajouter une entrée</string>
<string name="add_group">Ajouter un groupe</string>
<string name="add_string">Ajouter une chaîne</string>
<string name="encryption">Chiffrement</string>
<string name="encryption_algorithm">Algorithme de chiffrement</string>
<string name="key_derivation_function">Fonction de dérivation de clé</string>
@@ -135,7 +134,7 @@
<string name="select_database_file">Ouvrir une base de données existante</string>
<string name="open_recent">Bases de données récentes</string>
<string name="omitbackup_title">Ne pas rechercher dans les entrées de sauvegarde</string>
<string name="omitbackup_summary">Omet le groupe «Sauvegarde» des résultats de recherche (ne sapplique quaux fichiers .kdb)</string>
<string name="omitbackup_summary">Omet les groupes «Sauvegarde» et \"Corbeille\" des résultats de recherche</string>
<string name="progress_create">Création dune nouvelle base de données…</string>
<string name="progress_title">Traitement en cours …</string>
<string name="protection">Protection</string>
@@ -154,7 +153,7 @@
<string name="rounds_explanation">Des tours de chiffrement supplémentaires fournissent une protection plus élevée contre les attaques par force brute, mais cela peut considérablement ralentir les opérations de chargement et denregistrement.</string>
<string name="rounds_hint">tours de transformation</string>
<string name="memory_usage">Utilisation de la mémoire</string>
<string name="memory_usage_explanation">Quantité de mémoire (en multiplets binaires) à utiliser par la fonction de dérivation de clé.</string>
<string name="memory_usage_explanation">Quantité de mémoire (en octets) à utiliser par la fonction de dérivation de clé.</string>
<string name="parallelism">Parallélisme</string>
<string name="parallelism_explanation">Degré de parallélisme (nombre de fils dexécution) utilisé par la fonction de dérivation de clé.</string>
<string name="saving_database">Enregistrement de la base de données…</string>
@@ -207,7 +206,7 @@
<string name="list_password_generator_options_summary">Définir les caractères autorisés du générateur de mot de passe</string>
<string name="clipboard">Presse-papier</string>
<string name="clipboard_notifications_title">Notifications du presse-papier</string>
<string name="clipboard_notifications_summary">Activer les notifications du presse-papier pour copier les champs des entrées</string>
<string name="clipboard_notifications_summary">Activer les notifications du presse-papier pour copier les champs lors de l\'affichage d\'une entrée</string>
<string name="clipboard_warning">Si la suppression automatique du presse-papier échoue, supprimer son historique manuellement.</string>
<string name="lock">Verrouiller</string>
<string name="lock_database_screen_off_title">Verrouillage décran</string>
@@ -232,7 +231,7 @@
<string name="path">Chemin</string>
<string name="assign_master_key">Assigner une clé maîtresse</string>
<string name="create_keepass_file">Créer une nouvelle base de données</string>
<string name="bytes">Multiplets</string>
<string name="bytes">Octets</string>
<string name="full_file_path_enable_title">Chemin de fichier</string>
<string name="full_file_path_enable_summary">Afficher le chemin complet du fichier</string>
<string name="recycle_bin_title">Utiliser la corbeille</string>
@@ -393,10 +392,21 @@
<string name="keyboard_notification_entry_content_title">1$s disponible sur Magikeyboard</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="keyboard_notification_entry_clear_close_title">Effacer à la fermeture</string>
<string name="keyboard_notification_entry_clear_close_summary">Effacer lentrée au clavier lors de la fermeture de la notification</string>
<string name="keyboard_notification_entry_clear_close_summary">Fermer la base de données lors de la fermeture de la notification</string>
<string name="keyboard_appearance_category">Apparence</string>
<string name="keyboard_theme_title">Thème du clavier</string>
<string name="keyboard_keys_category">Touches</string>
<string name="keyboard_key_vibrate_title">Vibrer au toucher</string>
<string name="keyboard_key_sound_title">Son au toucher</string>
<string name="selection_mode">Mode sélection</string>
<string name="do_not_kill_app">Ne pas tuer l\'application…</string>
<string name="lock_database_back_root_title">Déverouillage de retour</string>
<string name="lock_database_back_root_summary">Verrouille la base de données lorsque l\'utilisateur clique sur le bouton Précédent de l\'écran racine</string>
<string name="clear_clipboard_notification_title">Suppression à la fermeture</string>
<string name="clear_clipboard_notification_summary">Ferme la base de données lors de la fermeture de notification</string>
<string name="recycle_bin">Corbeille</string>
<string name="keyboard_selection_entry_title">Sélection d\'entrée</string>
<string name="keyboard_selection_entry_summary">Afficher les champs de saisie dans Magikeyboard lors de l\'affichage d\'une entrée</string>
<string name="delete_entered_password_title">Supprimer le mot de passe</string>
<string name="delete_entered_password_summary">Supprime le mot de passe entré après une tentative de connexion</string>
</resources>

View File

@@ -5,7 +5,6 @@
<string name="accept">Aceptar</string>
<string name="add_entry">Engadir entrada</string>
<string name="add_group">Engadir grupo</string>
<string name="add_string">Engadir texto</string>
<string name="encryption">Cifrado</string>
<string name="encryption_algorithm">Algoritmo de cifrado</string>
<string name="key_derivation_function">Función de derivación de chave</string>

View File

@@ -184,7 +184,6 @@
<item>Nagy</item>
</string-array>
<string name="edit_entry">Bejegyzés szerkesztése</string>
<string name="add_string">Karakterlánc hozzáadása</string>
<string name="encryption">Titkosítás</string>
<string name="key_derivation_function">Kulcsváltozási függvény</string>
<string name="extended_ASCII">Bővített ASCII</string>

View File

@@ -26,7 +26,6 @@
<string name="accept">Accetto</string>
<string name="add_entry">Aggiungi voce</string>
<string name="add_group">Aggiungi gruppo</string>
<string name="add_string">Aggiungi stringa</string>
<string name="encryption_algorithm">Algoritmo di cifratura</string>
<string name="app_timeout">Scadenza app</string>
<string name="app_timeout_summary">Inattività prima del blocco dell\'app</string>

View File

@@ -165,7 +165,6 @@
<item>גדול</item>
</string-array>
<string name="edit_entry">ערוך רשומה</string>
<string name="add_string">הוסף מחרוזת</string>
<string name="encryption">הצפנה</string>
<string name="allow">אפשר</string>
<string name="clipboard_swipe_clean">החלק לניקוי לוח העתקה עכשיו</string>

View File

@@ -154,7 +154,6 @@
<item></item>
</string-array>
<string name="edit_entry">エントリーを編集</string>
<string name="add_string">文字列を追加</string>
<string name="encryption">暗号化</string>
<string name="key_derivation_function">鍵導出関数</string>
<string name="beta_dontask">今後、表示しない</string>

View File

@@ -7,7 +7,6 @@
<string name="add_entry">항목 추가</string>
<string name="edit_entry">항목 수정</string>
<string name="add_group">그룹 추가</string>
<string name="add_string">단어 추가</string>
<string name="encryption">암호화</string>
<string name="encryption_algorithm">안호화 방식</string>
<string name="key_derivation_function">키 파생 기능</string>

View File

@@ -9,7 +9,6 @@
<string name="accept">Priimti</string>
<string name="add_entry">Pridėti įrašą</string>
<string name="add_group">Pridėti grupę</string>
<string name="add_string">Pridėti eilutę</string>
<string name="encryption_algorithm">Algortimas</string>
<string name="app_timeout_summary">Laikas, per kurį yra užrakinama duomenų bazė po neveiklumo programėlėje.</string>
<string name="application">Programėlė</string>

View File

@@ -7,7 +7,6 @@
<string name="add_entry">Legg til oppføring</string>
<string name="edit_entry">Rediger oppføring</string>
<string name="add_group">Legg til gruppe</string>
<string name="add_string">Legg til streng</string>
<string name="encryption">Kryptering</string>
<string name="encryption_algorithm">Krypteringsalgoritme</string>
<string name="key_derivation_function">Nøkkelutledningsfunksjon</string>
@@ -356,4 +355,15 @@
<string name="keyboard_keys_category">Taster</string>
<string name="keyboard_key_vibrate_title">Vibrer ved tastetrykk</string>
<string name="keyboard_key_sound_title">Lyd ved tastetrykk</string>
<string name="selection_mode">Valgmodus</string>
<string name="do_not_kill_app">Ikke drep programmet…</string>
<string name="lock_database_back_root_title">Tilbakelås</string>
<string name="lock_database_back_root_summary">Lås databasen når brukeren klikker tilbakeknappen på root-skjermen</string>
<string name="clear_clipboard_notification_title">Tøm ved lukking</string>
<string name="clear_clipboard_notification_summary">Lukk databasen ved lukking av merknaden</string>
<string name="recycle_bin">Papirkurv</string>
<string name="keyboard_selection_entry_title">Oppføringsvalg</string>
<string name="keyboard_selection_entry_summary">Vis inndatafelter i Magikeyboard når en oppføring vises</string>
<string name="delete_entered_password_title">Slett passord</string>
<string name="delete_entered_password_summary">Sletter passord innskrevet etter et tilkoblingsforsøk</string>
</resources>

View File

@@ -161,7 +161,6 @@
<item>Groot</item>
</string-array>
<string name="edit_entry">Item bewerken</string>
<string name="add_string">Zin toevoegen</string>
<string name="encryption">Versleuteling</string>
<string name="key_derivation_function">Sleutelafleidingsfunctie</string>
<string name="beta_dontask">Niet meer tonen</string>

View File

@@ -158,7 +158,6 @@ along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
<item>Duża</item>
</string-array>
<string name="edit_entry">Edytuj wpis</string>
<string name="add_string">Dodaj ciąg</string>
<string name="encryption">Szyfrowanie</string>
<string name="key_derivation_function">Funkcja generująca klucz</string>
<string name="beta_dontask">Nie pokazuj więcej</string>

View File

@@ -116,7 +116,7 @@
<string name="no_url_handler">Instale um navegador para abrir esta URL.</string>
<string name="open_recent">Bancos de dados recentes</string>
<string name="omitbackup_title">Não procurar por entradas no backup ou na lixeira</string>
<string name="omitbackup_summary">Omite o grupo \"Backup\" dos resultados da busca (apenas se aplica a arquivos .kdb)</string>
<string name="omitbackup_summary">Omite os grupos \"Backup\" e \"Lixeira\" dos resultados da busca</string>
<string name="progress_create">Criando novo banco de dados…</string>
<string name="progress_title">Trabalhando…</string>
<string name="remember_keyfile_summary">Lembra o local dos arquivos-chave dos bancos de dados</string>
@@ -158,7 +158,6 @@
<item>Médio</item>
<item>Grande</item>
</string-array>
<string name="add_string">Adicionar texto</string>
<string name="encryption">Encriptação</string>
<string name="key_derivation_function">Função de derivação de chave</string>
<string name="beta_dontask">Não mostre novamente</string>
@@ -178,7 +177,7 @@
<string name="invalid_algorithm">Algoritmo errado.</string>
<string name="keyfile_does_not_exist">Não existem arquivos-chave.</string>
<string name="keyfile_is_empty">O arquivo-chave está vazio.</string>
<string name="copy_field">Copiado %1$s</string>
<string name="copy_field">Cópia de %1$s</string>
<string name="menu_form_filling_settings">Preenchimento de formulário</string>
<string name="menu_copy">Cópia</string>
<string name="menu_move">Mover</string>
@@ -212,7 +211,7 @@
<string name="use_saf_summary">Use o framework de acesso de armazenamento (SAF) do Android para navegação de arquivos (KitKat e posterior)</string>
<string name="use_saf_title">Framework de acesso de armazenamento</string>
<string name="warning">Aviso</string>
<string name="warning_password_encoding">Evite caracteres fora da tabela Latin-1 em arquivos .kdb, pois todos estes são convertidos para a mesma letra.</string>
<string name="warning_password_encoding">Evite caracteres fora do formato de codificação do arquivo do banco (todos os caracteres não reconhecidos são convertidos para a mesma letra).</string>
<string name="warning_empty_password">Você realmente não quer proteção por senha\?</string>
<string name="warning_no_encryption_key">Você tem certeza de que não quer usar uma chave de encriptação\?</string>
<string name="configure_fingerprint">Impressão digital é suportada, mas não está configurada.</string>
@@ -236,7 +235,7 @@
<string name="list_password_generator_options_title">Caracteres da senha</string>
<string name="list_password_generator_options_summary">Definir os caracteres padrão do gerador de senha</string>
<string name="clipboard_notifications_title">Notificações da área de transferência</string>
<string name="clipboard_notifications_summary">Habilite notificações da área de transferência para copiar campos de entrada</string>
<string name="clipboard_notifications_summary">Habilite notificações da área de transferência para campos copiáveis quando estiver visualizando uma entrada</string>
<string name="clipboard_warning">Se a limpeza da área de transferência falhar, limpe seu histórico manualmente.</string>
<string name="lock">Bloquear</string>
<string name="lock_database_screen_off_title">Bloqueio de tela</string>
@@ -325,7 +324,7 @@
<string name="education_entry_edit_title">Modifique a entrada</string>
<string name="education_entry_edit_summary">Edite a sua entrada com campos personalizados. Os conjuntos de dados podem ser referenciados entre campos de entradas diferentes.</string>
<string name="education_generate_password_title">Crie uma senha forte para sua entrada.</string>
<string name="education_generate_password_summary">Gere uma senha forte para associar a sua entrada, defina-a facilmente de acordo com os critérios do formulário e não se esqueça de tornar a senha segura.</string>
<string name="education_generate_password_summary">Gere uma senha forte para associar a sua entrada, defina-a facilmente de acordo com os critérios do formulário e não se esqueça de torná-la segura.</string>
<string name="education_entry_new_field_title">Adicione campos customizados</string>
<string name="education_entry_new_field_summary">Registre facilmente um campo básico não fornecido que você também pode proteger.</string>
<string name="education_unlock_title">Desbloqueie seu banco de dados</string>
@@ -354,7 +353,7 @@
<string name="html_text_dev_feature">Esse recurso está <strong>em desenvolvimento</strong> e exige que sua <strong>contribuição</strong> para que esteja disponível em breve.</string>
<string name="html_text_dev_feature_buy_pro">Ao comprar a versão <strong>pro</strong>,</string>
<string name="html_text_dev_feature_contibute">
<strong>contribuindo </strong>,</string>
<strong>Contribuindo </strong>,</string>
<string name="html_text_dev_feature_encourage">Você está incentivando os desenvolvedores a criar <strong>novos recursos</strong> e a <strong>corrigir erros </strong> de acordo com suas observações.</string>
<string name="html_text_dev_feature_thanks">Obrigado por sua contribuição.</string>
<string name="html_text_dev_feature_work_hard">Estamos trabalhando duro para lançar esse recurso o mais rápido possível.</string>
@@ -388,10 +387,21 @@
<string name="keyboard_notification_entry_content_title">%1$s disponível no Magikeyboard</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="keyboard_notification_entry_clear_close_title">Limpar ao fechar</string>
<string name="keyboard_notification_entry_clear_close_summary">Limpar a entrada do teclado ao fechar a notificação</string>
<string name="keyboard_notification_entry_clear_close_summary">Fecha a base de dados ao dispensar a notificação</string>
<string name="keyboard_appearance_category">Aparência</string>
<string name="keyboard_theme_title">Tema do teclado</string>
<string name="keyboard_keys_category">Teclas</string>
<string name="keyboard_key_vibrate_title">Vibrar ao clicar</string>
<string name="keyboard_key_sound_title">Som ao clicar</string>
<string name="selection_mode">Modo de seleção</string>
<string name="do_not_kill_app">Não feche o aplicativo…</string>
<string name="lock_database_back_root_title">Trancar ao voltar</string>
<string name="lock_database_back_root_summary">Tranca a base de dados quando o usuário pressiona o botão Voltar na tela inicial</string>
<string name="clear_clipboard_notification_title">Limpar a Área de Transferência ao fechar</string>
<string name="clear_clipboard_notification_summary">Fecha a base de dados ao dispensar a notificação</string>
<string name="recycle_bin">Lixeira</string>
<string name="keyboard_selection_entry_title">Seleção de entrada</string>
<string name="keyboard_selection_entry_summary">Mostrar campos de entrada no Magikeyboard quando estiver visualizando uma Entrada</string>
<string name="delete_entered_password_title">Deletar senha</string>
<string name="delete_entered_password_summary">Deleta a senha inserida após uma tentativa de conexão</string>
</resources>

View File

@@ -23,7 +23,6 @@
<string name="accept">Aceitar</string>
<string name="add_entry">Adicionar entrada</string>
<string name="add_group">Adicionar grupo</string>
<string name="add_string">Adicionar linha</string>
<string name="encryption_algorithm">Algoritmo de encriptação</string>
<string name="app_timeout">Tempo de espera da app</string>
<string name="app_timeout_summary">Inatividade antes da app ser bloqueada</string>

View File

@@ -23,7 +23,6 @@
<string name="accept">Принять</string>
<string name="add_entry">Новая запись</string>
<string name="add_group">Новая группа</string>
<string name="add_string">Новая строка</string>
<string name="encryption_algorithm">Алгоритм шифрования</string>
<string name="app_timeout">Задержка</string>
<string name="app_timeout_summary">Задержка блокировки при бездействии</string>

View File

@@ -154,7 +154,6 @@
<item>Veľké</item>
</string-array>
<string name="edit_entry">Upraviť záznam</string>
<string name="add_string">Pridať reťazec</string>
<string name="encryption">Šifrovanie</string>
<string name="key_derivation_function">Funkcia pre tvorbu kľúča</string>
<string name="beta_dontask">Nezobrazovať znovu</string>

View File

@@ -6,7 +6,6 @@
<string name="add_entry">"ఎంట్రీని జత చెయ్యండి "</string>
<string name="edit_entry">ఎంట్రీని మార్పు చెయ్యండి</string>
<string name="add_group">"గ్రూపుని జత చెయ్యండి "</string>
<string name="add_string">"స్ట్రింగ్ ని జత చెయ్యండి "</string>
<string name="encryption">ఎన్క్రిప్షన్</string>
<string name="encryption_algorithm">ఎన్క్రిప్షన్ అల్గోరిథం</string>
<string name="key_derivation_function">కీ వ్యుత్పత్తి ఫంక్షన్</string>

View File

@@ -7,7 +7,6 @@
<string name="add_entry">"Girdi Ekle "</string>
<string name="edit_entry">"Girdi Düzenle "</string>
<string name="add_group">"Grup Ekle "</string>
<string name="add_string">Dizi ekle</string>
<string name="encryption">Şifreleme</string>
<string name="encryption_algorithm">Şifreleme algoritması</string>
<string name="key_derivation_function">Anahtar üretme fonksiyonu</string>
@@ -102,7 +101,7 @@
<string name="maskpass_summary">Parola maskesi. Varsayılan (***)</string>
<string name="menu_about">Hakkında</string>
<string name="menu_change_key">Ana anahtarı değitir</string>
<string name="copy_field">1$s kopyalandı</string>
<string name="copy_field">%1$s kopyalandı</string>
<string name="settings">Ayarlar</string>
<string name="menu_app_settings">Uygulama ayarları</string>
<string name="menu_form_filling_settings">Form doldurma</string>

View File

@@ -152,7 +152,6 @@
<item></item>
<item></item>
</string-array>
<string name="add_string">添加字符串</string>
<string name="encryption">加密</string>
<string name="beta_dontask">不再显示</string>
<string name="extended_ASCII">ASCⅡ 拓展区字符</string>

View File

@@ -175,7 +175,6 @@
<string name="read_only">唯讀</string>
<string name="read_only_warning">KeePass DX 無法存取資料庫所在位置,將以唯讀模式開啟資料庫。</string>
<string name="read_only_kitkat_warning">Adnroid 4.4 開始,許多裝置不允許應用程式對 SD 卡進行寫入。</string>
<string name="add_string">添加字串</string>
<string name="encryption">加密</string>
<string name="key_derivation_function">金鑰派生函數</string>
<string name="edit_entry">編輯入口</string>

View File

@@ -62,7 +62,7 @@
<color name="colorTextPrimaryInverse">#cccccc</color>
<color name="colorText">#616161</color>
<color name="colorTextDisable">#c7c7c7</color>
<color name="colorTextInverse">#eeeeee</color>
<color name="colorTextInverse">#FFFFFF</color>
<color name="colorTextInverseDisable">#565656</color>
<color name="colorTextSecondary">#7c7c7c</color>
<color name="colorTextSecondaryDisable">#c7c7c7</color>

View File

@@ -132,6 +132,8 @@
<string name="setting_icon_pack_choose_key" translatable="false">setting_icon_pack_choose_key</string>
<string name="list_entries_show_username_key" translatable="false">list_entries_show_username_key</string>
<bool name="list_entries_show_username_default" translatable="false">true</bool>
<string name="list_groups_show_number_entries_key" translatable="false">list_groups_show_number_entries_key</string>
<bool name="list_groups_show_number_entries_default" translatable="false">true</bool>
<string name="list_size_key" translatable="false">list_size</string>
<string name="monospace_font_fields_enable_key" translatable="false">monospace_font_extra_fields_enable_key</string>
<bool name="monospace_font_fields_enable_default" translatable="false">true</bool>
@@ -227,6 +229,7 @@
<!-- Text Size -->
<dimen name="list_icon_size_default" translatable="false">32dp</dimen>
<integer name="list_tiny_size_default" translatable="false">9</integer>
<integer name="list_small_size_default" translatable="false">13</integer>
<string name="list_size_default" translatable="false">16</string>
<string-array name="list_size_values">

View File

@@ -1,4 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 Jeremy Jamet / Kunzisoft.
@@ -25,7 +25,6 @@
<string name="add_entry">Add entry</string>
<string name="edit_entry">Edit entry</string>
<string name="add_group">Add group</string>
<string name="add_string">Add string</string>
<string name="encryption">Encryption</string>
<string name="encryption_algorithm">Encryption algorithm</string>
<string name="key_derivation_function">Key derivation function</string>
@@ -45,7 +44,26 @@
<string name="clipboard_timeout">Clipboard timeout</string>
<string name="clipboard_timeout_summary">Duration of storage in the clipboard</string>
<string name="clipboard_swipe_clean">Swipe to clear clipboard now</string>
<!--%1$s is either \"Username\" or \"Password\".-->
<string name="content_description_open_file">Open file</string>
<string name="content_description_show_file_link">Show file link</string>
<string name="content_description_open_file_link">Open file link</string>
<string name="content_description_node_children">Node children</string>
<string name="content_description_add_node">Add node</string>
<string name="content_description_add_entry">Add entry</string>
<string name="content_description_add_group">Add group</string>
<string name="content_description_file_information">File information</string>
<string name="content_description_password_checkbox">Password checkbox</string>
<string name="content_description_keyfile_checkbox">Keyfile checkbox</string>
<string name="content_description_repeat_toggle_password_visibility">Repeat toggle password visibility</string>
<string name="content_description_entry_icon">Entry icon</string>
<string name="content_description_entry_save">Entry save</string>
<string name="content_description_password_generator">Password generator</string>
<string name="content_description_password_length">Password length</string>
<string name="content_description_add_field">Add field</string>
<string name="content_description_remove_field">Remove field</string>
<!--%1$s is either \"Username\" or \"Password\".-->
<string name="select_to_copy">Select to copy %1$s to clipboard</string>
<string name="retrieving_db_key">Retrieving database key…</string>
<string name="database">Database</string>
@@ -59,6 +77,7 @@
<string name="entry_confpassword">Confirm password</string>
<string name="entry_created">Created</string>
<string name="entry_expires">Expires</string>
<string name="entry_UUID">UUID</string>
<string name="entry_keyfile">Keyfile</string>
<string name="entry_modified">Modified</string>
<string name="entry_not_found">Could not find entry data.</string>
@@ -90,6 +109,8 @@
<string name="error_wrong_length">Enter a positive whole number in the \"Length\" field.</string>
<string name="error_autofill_enable_service">Could not enable autofill service.</string>
<string name="error_move_folder_in_itself">You can not move a group into itself.</string>
<string name="error_move_entry_here">You can not move an entry here.</string>
<string name="error_copy_entry_here">You can not copy an entry here.</string>
<string name="field_name">Field name</string>
<string name="field_value">Field value</string>
<string name="file_not_found">Could not find file.</string>
@@ -113,6 +134,8 @@
<string name="length">Length</string>
<string name="list_entries_show_username_title">Show usernames</string>
<string name="list_entries_show_username_summary">Show usernames in entry lists</string>
<string name="list_groups_show_number_entries_title">Show number of entries</string>
<string name="list_groups_show_number_entries_summary">Show the number of entries in a group</string>
<string name="list_size_title">Size of list items</string>
<string name="list_size_summary">Text size in the element list</string>
<string name="loading_database">Loading database…</string>
@@ -181,7 +204,7 @@
<string name="sort_ascending">Lowest first ↓</string>
<string name="sort_groups_before">Groups before</string>
<string name="sort_recycle_bin_bottom">Recycle bin at the bottom</string>
<string name="sort_db">Natural Database</string>
<string name="sort_db">Natural order</string>
<string name="sort_title">Title</string>
<string name="sort_username">Username</string>
<string name="sort_creation_time">Creation</string>
@@ -232,7 +255,7 @@
<string name="lock">Lock</string>
<string name="lock_database_screen_off_title">Screen lock</string>
<string name="lock_database_screen_off_summary">Lock the database when the screen is off</string>
<string name="lock_database_back_root_title">Back lock</string>
<string name="lock_database_back_root_title">Press Back on root to lock</string>
<string name="lock_database_back_root_summary">Lock the database when the user clicks the back button on the root screen</string>
<string name="fingerprint_quick_unlock_title">How to set up fingerprint scanning for quick unlocking?</string>
<string name="fingerprint_setting_text">Save your scanned fingerprint for your device in </string>
@@ -297,45 +320,33 @@
<string name="keyboard_fill_field_text">Fill in your fields using the entry elements.</string>
<string name="keyboard_lock_database_text">Lock the database.</string>
<string name="keyboard_back_main_keyboard_text">Use default keyboard again.</string>
<string name="keyboard_name">Magikeyboard</string>
<string name="keyboard_label">Magikeyboard (KeePass DX)</string>
<string name="keyboard_setting_label">Magikeyboard settings</string>
<string name="keyboard_entry_category">Entry</string>
<string name="keyboard_selection_entry_title">Entry selection</string>
<string name="keyboard_selection_entry_summary">Show input fields in Magikeyboard when viewing an entry</string>
<string name="keyboard_notification_entry_title">Notification information</string>
<string name="keyboard_notification_entry_title">Notification info</string>
<string name="keyboard_notification_entry_summary">Show a notification when an entry is available</string>
<string name="keyboard_notification_entry_clear_close_title">Clear at closing</string>
<string name="keyboard_notification_entry_clear_close_summary">Close the database when closing the notification</string>
<string name="keyboard_entry_timeout_title">Timeout</string>
<string name="keyboard_entry_timeout_summary">Timeout to clear the keyboard entry</string>
<string name="keyboard_notification_entry_content_title_text">Entry</string>
<string name="keyboard_notification_entry_content_title">%1$s available on Magikeyboard</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="keyboard_appearance_category">Appearance</string>
<string name="keyboard_theme_title">Keyboard theme</string>
<string name="keyboard_keys_category">Keys</string>
<string name="keyboard_key_vibrate_title">Vibrate on keypress</string>
<string name="keyboard_key_sound_title">Sound on keypress</string>
<string name="allow_no_password_title">Allow no password</string>
<string name="allow_no_password_summary">Enable the \"Open\" button if no password identification is selected</string>
<string name="allow_no_password_title">Allow no master key</string>
<string name="allow_no_password_summary">Enable the \"Open\" button if no credentials are selected</string>
<string name="enable_read_only_title">Write-protected</string>
<string name="enable_read_only_summary">Open your database read-only by default</string>
<string name="delete_entered_password_title">Delete password</string>
<string name="delete_entered_password_summary">Deletes the password entered after a connection attempt</string>
<string name="enable_education_screens_title">Educational screens</string>
<string name="enable_education_screens_summary">Highlight the elements to learn how the app works</string>
<string name="reset_education_screens_title">Reset educational screens</string>
@@ -372,12 +383,10 @@
<string name="education_sort_summary">Choose how entries and groups are sorted.</string>
<string name="education_donation_title">Participate</string>
<string name="education_donation_summary">Help increase the stability, security and in adding more features.</string>
<string name="html_text_ad_free">Unlike many password management apps, this one is &lt;strong&gt;ad-free&lt;/strong&gt;, &lt;strong&gt;copylefted libre software&lt;/strong&gt; and does not collect personal data on its servers, no matter what version you use.</string>
<string name="html_text_buy_pro">By buying the pro version, you will have access to this &lt;strong&gt;visual feature&lt;/strong&gt; and you will especially help &lt;strong&gt;the realization of community projects.&lt;/strong&gt;</string>
<string name="html_text_feature_generosity">This &lt;strong&gt;visual feature&lt;/strong&gt; is available thanks to your generosity.</string>
<string name="html_text_donation">In order to keep our freedom and to always be active, we count on your &lt;strong&gt;contribution.&lt;/strong&gt;</string>
<string name="html_text_dev_feature">This feature is &lt;strong&gt;under development&lt;/strong&gt; and requires your &lt;strong&gt;contribution&lt;/strong&gt; to be available soon.</string>
<string name="html_text_dev_feature_buy_pro">By buying the &lt;strong&gt;pro&lt;/strong&gt; version,</string>
<string name="html_text_dev_feature_contibute">By &lt;strong&gt;contributing&lt;/strong&gt;,</string>
@@ -385,36 +394,31 @@
<string name="html_text_dev_feature_thanks">Thanks a lot for your contribution.</string>
<string name="html_text_dev_feature_work_hard">We are working hard to release this feature quickly.</string>
<string name="html_text_dev_feature_upgrade">Do not forget to keep your app up to date by installing new versions.</string>
<string name="download">Download</string>
<string name="contribute">Contribute</string>
<!-- Algorithms -->
<string name="encryption_rijndael">Rijndael (AES)</string>
<string name="encryption_twofish">Twofish</string>
<string name="encryption_chacha20">ChaCha20</string>
<!-- Key Derivation Functions -->
<string name="kdf_AES">AES KDF</string>
<string name="kdf_Argon2">Argon2</string>
<string-array name="timeout_options">
<item>5 seconds</item>
<item>10 seconds</item>
<item>20 seconds</item>
<item>30 seconds</item>
<item>1 minute</item>
<item>5 minutes</item>
<item>15 minutes</item>
<item>30 minutes</item>
<item>Never</item>
<item>5 seconds</item>
<item>10 seconds</item>
<item>20 seconds</item>
<item>30 seconds</item>
<item>1 minute</item>
<item>5 minutes</item>
<item>15 minutes</item>
<item>30 minutes</item>
<item>Never</item>
</string-array>
<string-array name="list_size_options">
<item>Small</item>
<item>Medium</item>
<item>Large</item>
<item>Small</item>
<item>Medium</item>
<item>Large</item>
</string-array>
<string name="style_choose_title">App theme</string>
<string name="style_choose_summary">Theme used in the app</string>
<string-array name="list_style_names">
@@ -427,5 +431,4 @@
</string-array>
<string name="icon_pack_choose_title">Icon pack</string>
<string name="icon_pack_choose_summary">Icon pack used in the app</string>
</resources>
</resources>

View File

@@ -270,6 +270,12 @@
<item name="android:textColor">?attr/colorAccent</item>
</style>
<style name="KeepassDXStyle.TextAppearance.Info" parent="KeepassDXStyle.TextAppearance">
<item name="android:textColor">@color/colorTextInverse</item>
<item name="android:background">@drawable/background_text_info</item>
<item name="backgroundTint">?attr/colorAccent</item>
</style>
<!-- Button Style -->
<style name="KeepassDXStyle.v21.Button" parent="Base.TextAppearance.AppCompat.Button">
<item name="android:gravity">center</item>
@@ -290,6 +296,12 @@
<item name="backgroundTint">@color/background_button_color_accent</item>
</style>
<!-- Icon Style -->
<style name="KeepassDXStyle.Icon" parent="KeepassDXStyle.v21.Button">
<item name="android:background">@drawable/background_icon</item>
<item name="backgroundTint">?attr/colorAccent</item>
</style>
<!-- FAB -->
<style name="KeepassDXStyle.v21.Fab" parent="KeepassDXStyle.Light.v21" />
<style name="KeepassDXStyle.Fab" parent="KeepassDXStyle.v21.Fab">

View File

@@ -44,6 +44,11 @@
android:title="@string/list_entries_show_username_title"
android:summary="@string/list_entries_show_username_summary"
android:defaultValue="@bool/list_entries_show_username_default"/>
<SwitchPreference
android:key="@string/list_groups_show_number_entries_key"
android:title="@string/list_groups_show_number_entries_title"
android:summary="@string/list_groups_show_number_entries_summary"
android:defaultValue="@bool/list_groups_show_number_entries_default"/>
<ListPreference
android:key="@string/list_size_key"
android:title="@string/list_size_title"

View File

@@ -49,8 +49,8 @@ platform :android do
lane :deploy_beta_free do
upload_to_play_store(
track: "beta",
skip_upload_metadata: "true",
skip_upload_images: "false",
skip_upload_metadata: "false",
skip_upload_images: "true",
skip_upload_screenshots: "true",
apk: "./app/build/outputs/apk/free/release/app-free-release.apk",
validate_only: "false",
@@ -62,11 +62,11 @@ platform :android do
sh("cp", "-a", "./pro/.", "./")
upload_to_play_store(
track: "beta",
skip_upload_metadata: "true",
skip_upload_images: "false",
skip_upload_metadata: "false",
skip_upload_images: "true",
skip_upload_screenshots: "true",
apk: "./app/build/outputs/apk/pro/release/app-pro-release.apk",
validate_only: "true",
validate_only: "false",
)
gradle(
task: 'clean'

View File

@@ -0,0 +1,9 @@
* Add lock button always visible
* New connection workflow
* Code refactored in Kotlin
* Better notification implementation
* Better views for large screen
* Magikeyboard enhancement
* Fix Recycle Bin
* Fix memory when load database
* Fix a bug that displays an entry history in 2.5.0.0beta19

View File

@@ -0,0 +1,6 @@
* Fix nested groups no longer visible in V1 databases
* Improved data import algorithm for V1 databases
* Add natural database sort
* Add username database sort
* Fix button disabled with only KeyFile
* Show the number of entries in a group

View File

@@ -0,0 +1,5 @@
* Rebuild code for actions
* Add UUID as entry view
* Fix bug with natural order
* Fix number of entries in databaseV1
* New entry views

View File

@@ -0,0 +1,9 @@
* Ajout du bouton de lock toujours visible
* Nouveau workflow de connexion
* Code refactorisé en Kotlin
* Meilleure implementation des notifications
* Meilleures vues pour les écrans larges
* Amélioration du Magikeyboard
* Correction de la Corbeille
* Correction de la mémoire lors du chargement de base de données
* Correction d'un bug qui affiche un historique d'entrée (2.5.0.0beta19)

View File

@@ -0,0 +1,6 @@
* Correction des groupes imbriqués plus visible dans les bases V1
* Amélioration de l'algortihme d'import des données pour les bases V1
* Ajout du tri par ordre naturel de la base
* Ajout du tri par nom d'utilisateur
* Correction du bouton désactivé avec seulement un fichier de clé
* Affiche le nombre d'entrées dans un groupe

View File

@@ -0,0 +1,5 @@
* Recréation du code pour les actions
* Ajout de l'UUID comme vue d'entrée
* Correction d'un bug avec l'ordre naturel
* Correction du nombre d'entrée dans les bases de données V1 number of entries in databaseV1
* Nouvelles vues d'entrée