mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: upgrade to API34 #1894
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
KeePassDX(4.1.0)
|
||||
* Upgrade to API 34 (Android 14)
|
||||
* Hide template group #1894
|
||||
|
||||
KeePassDX(4.0.8)
|
||||
* Fix graphical bug that prevented databases from being opened on some versions of Android #1848 #1850
|
||||
|
||||
@@ -358,43 +358,6 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
|
||||
searchFiltersView?.closeAdvancedFilters()
|
||||
|
||||
mBreadcrumbAdapter = BreadcrumbAdapter(this).apply {
|
||||
// Open group on breadcrumb click
|
||||
onItemClickListener = { node, _ ->
|
||||
// If last item & not a virtual root group
|
||||
val currentGroup = mMainGroup
|
||||
if (currentGroup != null && node == currentGroup
|
||||
&& (currentGroup != mDatabase?.rootGroup
|
||||
|| mDatabase?.rootGroupIsVirtual == false)
|
||||
) {
|
||||
finishNodeAction()
|
||||
launchDialogToShowGroupInfo(currentGroup)
|
||||
} else {
|
||||
if (mGroupFragment?.nodeActionSelectionMode == true) {
|
||||
finishNodeAction()
|
||||
}
|
||||
mDatabase?.let { database ->
|
||||
onNodeClick(database, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
onLongItemClickListener = { node, position ->
|
||||
val currentGroup = mMainGroup
|
||||
if (currentGroup != null && node == currentGroup
|
||||
&& (currentGroup != mDatabase?.rootGroup
|
||||
|| mDatabase?.rootGroupIsVirtual == false)
|
||||
) {
|
||||
finishNodeAction()
|
||||
launchDialogForGroupUpdate(currentGroup)
|
||||
} else {
|
||||
onItemClickListener?.invoke(node, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
breadcrumbListView?.apply {
|
||||
adapter = mBreadcrumbAdapter
|
||||
}
|
||||
|
||||
// Retrieve group if defined at launch
|
||||
manageIntent(intent)
|
||||
|
||||
@@ -616,6 +579,43 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
|
||||
super.onDatabaseRetrieved(database)
|
||||
|
||||
mBreadcrumbAdapter = BreadcrumbAdapter(this, database).apply {
|
||||
// Open group on breadcrumb click
|
||||
onItemClickListener = { node, _ ->
|
||||
// If last item & not a virtual root group
|
||||
val currentGroup = mMainGroup
|
||||
if (currentGroup != null && node == currentGroup
|
||||
&& (currentGroup != mDatabase?.rootGroup
|
||||
|| mDatabase?.rootGroupIsVirtual == false)
|
||||
) {
|
||||
finishNodeAction()
|
||||
launchDialogToShowGroupInfo(currentGroup)
|
||||
} else {
|
||||
if (mGroupFragment?.nodeActionSelectionMode == true) {
|
||||
finishNodeAction()
|
||||
}
|
||||
mDatabase?.let { database ->
|
||||
onNodeClick(database, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
onLongItemClickListener = { node, position ->
|
||||
val currentGroup = mMainGroup
|
||||
if (currentGroup != null && node == currentGroup
|
||||
&& (currentGroup != mDatabase?.rootGroup
|
||||
|| mDatabase?.rootGroupIsVirtual == false)
|
||||
) {
|
||||
finishNodeAction()
|
||||
launchDialogForGroupUpdate(currentGroup)
|
||||
} else {
|
||||
onItemClickListener?.invoke(node, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
breadcrumbListView?.apply {
|
||||
adapter = mBreadcrumbAdapter
|
||||
}
|
||||
|
||||
mGroupEditViewModel.setGroupNamesNotAllowed(database?.groupNamesNotAllowed)
|
||||
|
||||
mRecyclingBinEnabled = !mDatabaseReadOnly
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.Group
|
||||
import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
@@ -17,7 +18,7 @@ import com.kunzisoft.keepass.icons.IconDrawableFactory
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.view.strikeOut
|
||||
|
||||
class BreadcrumbAdapter(val context: Context)
|
||||
class BreadcrumbAdapter(val context: Context, val database: Database?)
|
||||
: RecyclerView.Adapter<BreadcrumbAdapter.BreadcrumbGroupViewHolder>() {
|
||||
|
||||
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||
@@ -31,6 +32,8 @@ class BreadcrumbAdapter(val context: Context)
|
||||
var onItemClickListener: ((item: Node, position: Int)->Unit)? = null
|
||||
var onLongItemClickListener: ((item: Node, position: Int)->Unit)? = null
|
||||
|
||||
private var mNodeFilter: NodeFilter = NodeFilter(context, database)
|
||||
|
||||
private var mShowNumberEntries = false
|
||||
private var mShowUUID = false
|
||||
private var mIconColor: Int = 0
|
||||
@@ -112,12 +115,9 @@ class BreadcrumbAdapter(val context: Context)
|
||||
|
||||
holder.groupNumbersView?.apply {
|
||||
if (mShowNumberEntries) {
|
||||
group.refreshNumberOfChildEntries(
|
||||
Group.ChildFilter.getDefaults(
|
||||
PreferencesUtil.showExpiredEntries(context)
|
||||
)
|
||||
)
|
||||
text = group.recursiveNumberOfChildEntries.toString()
|
||||
text = group.getNumberOfChildEntries {
|
||||
mNodeFilter.getFilter(node)
|
||||
}.toString()
|
||||
visibility = View.VISIBLE
|
||||
} else {
|
||||
visibility = View.GONE
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.kunzisoft.keepass.adapters
|
||||
|
||||
import android.content.Context
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.Entry
|
||||
import com.kunzisoft.keepass.database.element.Group
|
||||
import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
|
||||
class NodeFilter(
|
||||
context: Context,
|
||||
var database: Database? = null
|
||||
) {
|
||||
private var showExpired = PreferencesUtil.showExpiredEntries(context)
|
||||
private var showTemplate = PreferencesUtil.showTemplates(context)
|
||||
|
||||
fun getFilter(node: Node): Boolean {
|
||||
return (when (node) {
|
||||
is Entry -> {
|
||||
node.entryKDB?.isMetaStream() != true
|
||||
&& (showTemplate || database?.templatesGroup?.let {
|
||||
template -> node.isContainedIn(template)
|
||||
} != true)
|
||||
}
|
||||
is Group -> {
|
||||
showTemplate || database?.templatesGroup != node
|
||||
}
|
||||
else -> true
|
||||
}) && (showExpired || !node.isCurrentlyExpires)
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,7 @@ class NodesAdapter (
|
||||
private val mNodeSortedListCallback: NodeSortedListCallback
|
||||
private val mNodeSortedList: SortedList<Node>
|
||||
private val mInflater: LayoutInflater = LayoutInflater.from(context)
|
||||
private val mNodeFilter: NodeFilter = NodeFilter(context, database)
|
||||
|
||||
private var mCalculateViewTypeTextSize = Array(2) { true } // number of view type
|
||||
private var mTextSizeUnit: Int = TypedValue.COMPLEX_UNIT_PX
|
||||
@@ -82,7 +83,7 @@ class NodesAdapter (
|
||||
private var mShowNumberEntries: Boolean = true
|
||||
private var mShowOTP: Boolean = false
|
||||
private var mShowUUID: Boolean = false
|
||||
private var mEntryFilters = arrayOf<Group.ChildFilter>()
|
||||
private var mNodeFilters: NodeFilter? = null
|
||||
private var mOldVirtualGroup = false
|
||||
private var mVirtualGroup = false
|
||||
|
||||
@@ -161,9 +162,7 @@ class NodesAdapter (
|
||||
this.mShowOTP = PreferencesUtil.showOTPToken(context)
|
||||
this.mShowUUID = PreferencesUtil.showUUID(context)
|
||||
|
||||
this.mEntryFilters = Group.ChildFilter.getDefaults(
|
||||
PreferencesUtil.showExpiredEntries(context)
|
||||
)
|
||||
this.mNodeFilters = NodeFilter(context, database)
|
||||
|
||||
// Reinit textSize for all view type
|
||||
mCalculateViewTypeTextSize.forEachIndexed { index, _ -> mCalculateViewTypeTextSize[index] = true }
|
||||
@@ -176,7 +175,9 @@ class NodesAdapter (
|
||||
mOldVirtualGroup = mVirtualGroup
|
||||
mVirtualGroup = group.isVirtual
|
||||
assignPreferences()
|
||||
mNodeSortedList.replaceAll(group.getFilteredChildren(mEntryFilters))
|
||||
mNodeSortedList.replaceAll(group.getChildren { node ->
|
||||
mNodeFilters?.getFilter(node) ?: true
|
||||
})
|
||||
}
|
||||
|
||||
private inner class NodeSortedListCallback: SortedListAdapterCallback<Node>(this) {
|
||||
@@ -473,7 +474,7 @@ class NodesAdapter (
|
||||
if (mShowNumberEntries) {
|
||||
holder.numberChildren?.apply {
|
||||
text = (subNode as Group)
|
||||
.recursiveNumberOfChildEntries
|
||||
.getNumberOfChildEntries { mNodeFilter.getFilter(subNode) }
|
||||
.toString()
|
||||
setTextSize(mTextSizeUnit, mNumberChildrenTextDefaultDimension, mPrefSizeMultiplier)
|
||||
visibility = View.VISIBLE
|
||||
|
||||
@@ -162,6 +162,12 @@ object PreferencesUtil {
|
||||
context.resources.getBoolean(R.bool.hide_expired_entries_default))
|
||||
}
|
||||
|
||||
fun showTemplates(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return ! prefs.getBoolean(context.getString(R.string.hide_templates_key),
|
||||
context.resources.getBoolean(R.bool.hide_templates_default))
|
||||
}
|
||||
|
||||
fun getStyle(context: Context): String {
|
||||
val defaultStyleString = Stylish.defaultStyle(context)
|
||||
val styleString = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@@ -203,6 +203,8 @@
|
||||
<bool name="monospace_font_fields_enable_default" translatable="false">true</bool>
|
||||
<string name="hide_expired_entries_key" translatable="false">hide_expired_entries_key</string>
|
||||
<bool name="hide_expired_entries_default" translatable="false">false</bool>
|
||||
<string name="hide_templates_key" translatable="false">hide_templates_key</string>
|
||||
<bool name="hide_templates_default" translatable="false">true</bool>
|
||||
<string name="enable_education_screens_key" translatable="false">enable_education_screens_key</string>
|
||||
<bool name="enable_education_screens_default" translatable="false">true</bool>
|
||||
<string name="reset_education_screens_key" translatable="false">relaunch_education_screens_key</string>
|
||||
|
||||
@@ -733,4 +733,6 @@
|
||||
<string name="show_entry_colors_summary">Displays foreground and background colors for an entry</string>
|
||||
<string name="hide_expired_entries_title">Hide expired entries</string>
|
||||
<string name="hide_expired_entries_summary">Expired entries are not shown</string>
|
||||
<string name="hide_templates_title">Hide templates</string>
|
||||
<string name="hide_templates_summary">Templates are not shown</string>
|
||||
</resources>
|
||||
@@ -111,6 +111,11 @@
|
||||
android:title="@string/hide_expired_entries_title"
|
||||
android:summary="@string/hide_expired_entries_summary"
|
||||
android:defaultValue="@bool/hide_expired_entries_default"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/hide_templates_key"
|
||||
android:title="@string/hide_templates_title"
|
||||
android:summary="@string/hide_templates_summary"
|
||||
android:defaultValue="@bool/hide_templates_default"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/enable_education_screens_key"
|
||||
android:title="@string/enable_education_screens_title"
|
||||
|
||||
@@ -26,14 +26,17 @@ import com.kunzisoft.keepass.database.element.group.GroupKDB
|
||||
import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
||||
import com.kunzisoft.keepass.database.element.group.GroupVersionedInterface
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
import com.kunzisoft.keepass.database.element.node.*
|
||||
import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.NodeIdInt
|
||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.GroupInfo
|
||||
import com.kunzisoft.keepass.utils.readBooleanCompat
|
||||
import com.kunzisoft.keepass.utils.readParcelableCompat
|
||||
import com.kunzisoft.keepass.utils.writeBooleanCompat
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import java.util.UUID
|
||||
|
||||
class Group : Node, GroupVersionedInterface<Group, Entry> {
|
||||
|
||||
@@ -45,8 +48,11 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
|
||||
// Virtual group is used to defined a detached database group
|
||||
var isVirtual = false
|
||||
|
||||
// To optimize number of children call
|
||||
var numberOfChildEntries: Int = 0
|
||||
private set
|
||||
var recursiveNumberOfChildEntries: Int = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* Use this constructor to copy a Group
|
||||
@@ -84,20 +90,6 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
|
||||
isVirtual = parcel.readBooleanCompat()
|
||||
}
|
||||
|
||||
enum class ChildFilter {
|
||||
META_STREAM, EXPIRED;
|
||||
|
||||
companion object {
|
||||
fun getDefaults(showExpiredEntries: Boolean): Array<ChildFilter> {
|
||||
return if (showExpiredEntries) {
|
||||
arrayOf(META_STREAM)
|
||||
} else {
|
||||
arrayOf(META_STREAM, EXPIRED)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<Group> {
|
||||
override fun createFromParcel(parcel: Parcel): Group {
|
||||
return Group(parcel)
|
||||
@@ -280,20 +272,6 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
|
||||
ArrayList()
|
||||
}
|
||||
|
||||
fun getFilteredChildGroups(filters: Array<ChildFilter>): List<Group> {
|
||||
return groupKDB?.getChildGroups()?.map {
|
||||
Group(it).apply {
|
||||
this.refreshNumberOfChildEntries(filters)
|
||||
}
|
||||
} ?:
|
||||
groupKDBX?.getChildGroups()?.map {
|
||||
Group(it).apply {
|
||||
this.refreshNumberOfChildEntries(filters)
|
||||
}
|
||||
} ?:
|
||||
ArrayList()
|
||||
}
|
||||
|
||||
override fun getChildEntries(): List<Entry> {
|
||||
return groupKDB?.getChildEntries()?.map {
|
||||
Entry(it)
|
||||
@@ -312,53 +290,32 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
|
||||
return entriesInfo
|
||||
}
|
||||
|
||||
fun getFilteredChildEntries(filters: Array<ChildFilter>): List<Entry> {
|
||||
val withoutMetaStream = filters.contains(ChildFilter.META_STREAM)
|
||||
val showExpiredEntries = !filters.contains(ChildFilter.EXPIRED)
|
||||
|
||||
// TODO Change KDB parser to remove meta entries
|
||||
return groupKDB?.getChildEntries()?.filter {
|
||||
(!withoutMetaStream || (withoutMetaStream && !it.isMetaStream()))
|
||||
&& (!it.isCurrentlyExpires or showExpiredEntries)
|
||||
}?.map {
|
||||
Entry(it)
|
||||
} ?:
|
||||
groupKDBX?.getChildEntries()?.filter {
|
||||
!it.isCurrentlyExpires or showExpiredEntries
|
||||
}?.map {
|
||||
Entry(it)
|
||||
} ?:
|
||||
ArrayList()
|
||||
}
|
||||
|
||||
fun refreshNumberOfChildEntries(filters: Array<ChildFilter> = emptyArray()) {
|
||||
this.numberOfChildEntries = getFilteredChildEntries(filters).size
|
||||
this.recursiveNumberOfChildEntries = getFilteredChildEntriesInGroups(filters)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the cumulative number of entries in the current group and its children
|
||||
*/
|
||||
private fun getFilteredChildEntriesInGroups(filters: Array<ChildFilter>): Int {
|
||||
private fun getNumberOfChildEntriesInGroups(filter: (Node) -> Boolean): Int {
|
||||
var counter = 0
|
||||
getChildGroups().forEach { childGroup ->
|
||||
counter += childGroup.getFilteredChildEntriesInGroups(filters)
|
||||
counter += childGroup.getNumberOfChildEntriesInGroups(filter)
|
||||
}
|
||||
return getFilteredChildEntries(filters).size + counter
|
||||
return getChildEntries().filter(filter).size + counter
|
||||
}
|
||||
|
||||
fun getNumberOfChildEntries(
|
||||
directChildren: Boolean = true,
|
||||
filter: (Node) -> Boolean = { true }
|
||||
): Int {
|
||||
numberOfChildEntries = getChildEntries().filter(filter).size
|
||||
recursiveNumberOfChildEntries = getNumberOfChildEntriesInGroups(filter)
|
||||
return if (directChildren) numberOfChildEntries else recursiveNumberOfChildEntries
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter entries and return children
|
||||
* @return List of direct children (one level below) as NodeVersioned
|
||||
*/
|
||||
fun getChildren(): List<Node> {
|
||||
return getChildGroups() + getChildEntries()
|
||||
}
|
||||
|
||||
fun getFilteredChildren(filters: Array<ChildFilter>): List<Node> {
|
||||
val nodes = getFilteredChildGroups(filters) + getFilteredChildEntries(filters)
|
||||
refreshNumberOfChildEntries(filters)
|
||||
return nodes
|
||||
fun getChildren(filter: ((Node) -> Boolean) = { true }): List<Node> {
|
||||
return getChildGroups().filter(filter) + getChildEntries().filter(filter)
|
||||
}
|
||||
|
||||
override fun addChildGroup(group: Group) {
|
||||
|
||||
@@ -78,7 +78,7 @@ class SearchHelper {
|
||||
)
|
||||
}
|
||||
|
||||
searchGroup?.refreshNumberOfChildEntries()
|
||||
searchGroup?.getNumberOfChildEntries()
|
||||
return searchGroup
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
* Upgrade to API 34 (Android 14)
|
||||
* Hide template group #1894
|
||||
Reference in New Issue
Block a user