Manually change templates group and recyclebin group

This commit is contained in:
J-Jamet
2021-07-23 18:02:41 +02:00
parent 706d117d80
commit 422984ac41
12 changed files with 293 additions and 33 deletions

View File

@@ -71,6 +71,8 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_MEMORY_USAGE_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_NAME_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_PARALLELISM_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_TEMPLATES_GROUP_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.getBundleFromListNodes
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment
@@ -521,6 +523,28 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
, ACTION_DATABASE_REMOVE_UNLINKED_DATA_TASK)
}
fun startDatabaseSaveRecycleBin(oldRecycleBin: Group?,
newRecycleBin: Group?,
save: Boolean) {
start(Bundle().apply {
putParcelable(DatabaseTaskNotificationService.OLD_ELEMENT_KEY, oldRecycleBin)
putParcelable(DatabaseTaskNotificationService.NEW_ELEMENT_KEY, newRecycleBin)
putBoolean(DatabaseTaskNotificationService.SAVE_DATABASE_KEY, save)
}
, ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK)
}
fun startDatabaseSaveTemplatesGroup(oldTemplatesGroup: Group?,
newTemplatesGroup: Group?,
save: Boolean) {
start(Bundle().apply {
putParcelable(DatabaseTaskNotificationService.OLD_ELEMENT_KEY, oldTemplatesGroup)
putParcelable(DatabaseTaskNotificationService.NEW_ELEMENT_KEY, newTemplatesGroup)
putBoolean(DatabaseTaskNotificationService.SAVE_DATABASE_KEY, save)
}
, ACTION_DATABASE_UPDATE_TEMPLATES_GROUP_TASK)
}
fun startDatabaseSaveMaxHistoryItems(oldMaxHistoryItems: Int,
newMaxHistoryItems: Int,
save: Boolean) {

View File

@@ -369,6 +369,15 @@ class Database {
return null
}
/**
* Do not modify groups here, used for read only
*/
fun getAllGroupsWithoutRoot(): List<Group> {
return mDatabaseKDB?.getGroupIndexes()?.filter { it != mDatabaseKDB?.rootGroup }?.map { Group(it) }
?: mDatabaseKDBX?.getGroupIndexes()?.filter { it != mDatabaseKDBX?.rootGroup }?.map { Group(it) }
?: listOf()
}
val manageHistory: Boolean
get() = mDatabaseKDBX != null
@@ -404,7 +413,7 @@ class Database {
if (enable) {
ensureRecycleBinExists(resources)
} else {
removeRecycleBin()
mDatabaseKDBX?.removeRecycleBin()
}
}
@@ -419,6 +428,15 @@ class Database {
return null
}
fun setRecycleBin(group: Group?) {
// Only the kdbx recycle bin can be changed
if (group != null) {
mDatabaseKDBX?.recycleBinUUID = group.nodeIdKDBX.id
} else {
mDatabaseKDBX?.removeTemplatesGroup()
}
}
/**
* Determine if a configurable templates group is available or not for this version of database
* @return true if a configurable templates group available
@@ -442,6 +460,15 @@ class Database {
return null
}
fun setTemplatesGroup(group: Group?) {
// Only the kdbx templates group can be changed
if (group != null) {
mDatabaseKDBX?.entryTemplatesGroup = group.nodeIdKDBX.id
} else {
mDatabaseKDBX?.entryTemplatesGroup
}
}
val groupNamesNotAllowed: List<String>
get() {
return mDatabaseKDB?.groupNamesNotAllowed ?: ArrayList()
@@ -977,11 +1004,6 @@ class Database {
mDatabaseKDBX?.ensureRecycleBinExists(resources)
}
fun removeRecycleBin() {
// Don't allow remove backup in KDB
mDatabaseKDBX?.removeRecycleBin()
}
fun canRecycle(entry: Entry): Boolean {
var canRecycle: Boolean? = null
entry.entryKDB?.let {

View File

@@ -455,4 +455,10 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
result = 31 * result + (groupKDBX?.hashCode() ?: 0)
return result
}
override fun toString(): String {
return groupKDB?.toString() ?: groupKDBX?.toString() ?: "Undefined"
}
}

View File

@@ -364,11 +364,16 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
entryTemplatesGroup = uuidTemplatesGroup.id
entryTemplatesGroupChanged = uuidTemplatesGroup.lastModificationTime
} else {
entryTemplatesGroup = UUID_ZERO
mTemplateEngine.clearCache()
removeTemplatesGroup()
}
}
fun removeTemplatesGroup() {
entryTemplatesGroup = UUID_ZERO
entryTemplatesGroupChanged = DateInstant()
mTemplateEngine.clearCache()
}
fun getTemplatesGroup(): GroupKDBX? {
if (isTemplatesGroupEnabled()) {
return getGroupById(entryTemplatesGroup)

View File

@@ -117,8 +117,4 @@ abstract class GroupVersioned
else
nodeIndexInParentForNaturalOrder
}
override fun toString(): String {
return titleGroup
}
}

View File

@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.database.element.node
import android.os.Parcel
import android.os.ParcelUuid
import android.os.Parcelable
import com.kunzisoft.keepass.utils.UuidUtil
import java.util.*
class NodeIdUUID : NodeId<UUID> {
@@ -60,7 +61,7 @@ class NodeIdUUID : NodeId<UUID> {
}
override fun toString(): String {
return id.toString()
return UuidUtil.toHexString(id) ?: id.toString()
}
companion object {

View File

@@ -26,7 +26,6 @@ import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.entry.EntryVersionedInterface
import com.kunzisoft.keepass.database.element.group.GroupVersionedInterface
import com.kunzisoft.keepass.database.element.icon.IconImage
import org.joda.time.LocalDateTime
/**
* Abstract class who manage Groups and Entries
@@ -149,4 +148,8 @@ abstract class NodeVersioned<IdType, Parent : GroupVersionedInterface<Parent, En
override fun hashCode(): Int {
return nodeId.hashCode()
}
override fun toString(): String {
return "$title ($nodeId)"
}
}

View File

@@ -214,6 +214,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
ACTION_DATABASE_UPDATE_DESCRIPTION_TASK,
ACTION_DATABASE_UPDATE_DEFAULT_USERNAME_TASK,
ACTION_DATABASE_UPDATE_COLOR_TASK,
ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK,
ACTION_DATABASE_UPDATE_TEMPLATES_GROUP_TASK,
ACTION_DATABASE_UPDATE_MAX_HISTORY_ITEMS_TASK,
ACTION_DATABASE_UPDATE_MAX_HISTORY_SIZE_TASK,
ACTION_DATABASE_UPDATE_ENCRYPTION_TASK,
@@ -856,6 +858,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
const val ACTION_DATABASE_UPDATE_COLOR_TASK = "ACTION_DATABASE_UPDATE_COLOR_TASK"
const val ACTION_DATABASE_UPDATE_COMPRESSION_TASK = "ACTION_DATABASE_UPDATE_COMPRESSION_TASK"
const val ACTION_DATABASE_REMOVE_UNLINKED_DATA_TASK = "ACTION_DATABASE_REMOVE_UNLINKED_DATA_TASK"
const val ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK = "ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK"
const val ACTION_DATABASE_UPDATE_TEMPLATES_GROUP_TASK = "ACTION_DATABASE_UPDATE_TEMPLATES_GROUP_TASK"
const val ACTION_DATABASE_UPDATE_MAX_HISTORY_ITEMS_TASK = "ACTION_DATABASE_UPDATE_MAX_HISTORY_ITEMS_TASK"
const val ACTION_DATABASE_UPDATE_MAX_HISTORY_SIZE_TASK = "ACTION_DATABASE_UPDATE_MAX_HISTORY_SIZE_TASK"
const val ACTION_DATABASE_UPDATE_ENCRYPTION_TASK = "ACTION_DATABASE_UPDATE_ENCRYPTION_TASK"

View File

@@ -33,7 +33,6 @@ import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
@@ -41,7 +40,6 @@ import com.kunzisoft.keepass.settings.preference.*
import com.kunzisoft.keepass.settings.preferencedialogfragment.*
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.utils.UuidUtil
class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
@@ -53,8 +51,8 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
private var dbDefaultUsername: InputTextPreference? = null
private var dbCustomColorPref: DialogColorPreference? = null
private var dbDataCompressionPref: Preference? = null
private var recycleBinGroupPref: Preference? = null
private var templatesGroupPref: Preference? = null
private var recycleBinGroupPref: DialogListExplanationPreference? = null
private var templatesGroupPref: DialogListExplanationPreference? = null
private var dbMaxHistoryItemsPref: InputNumberPreference? = null
private var dbMaxHistorySizePref: InputNumberPreference? = null
private var mEncryptionAlgorithmPref: DialogListExplanationPreference? = null
@@ -172,9 +170,15 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
false
}
}
// Change the recycle bin group
recycleBinGroupPref?.setOnPreferenceClickListener {
true
}
// Recycle Bin group
refreshRecycleBinGroup()
} else {
recycleBinGroupPref?.onPreferenceClickListener = null
dbRecycleBinPrefCategory?.isVisible = false
}
@@ -226,21 +230,10 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
}
}
private fun groupSummary(group: Group?): String? {
val groupTitle = group?.title
val groupUUID = group?.nodeIdKDBX?.let {
UuidUtil.toHexString(it.id)
}
if (groupTitle == null
|| groupUUID == null)
return null
return "$groupTitle ($groupUUID)"
}
private fun refreshRecycleBinGroup() {
recycleBinGroupPref?.apply {
if (mDatabase?.isRecycleBinEnabled == true) {
summary = groupSummary(mDatabase!!.recycleBin)
summary = mDatabase?.recycleBin?.toString()
isEnabled = true
} else {
summary = null
@@ -252,7 +245,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
private fun refreshTemplatesGroup() {
templatesGroupPref?.apply {
if (mDatabase?.isTemplatesEnabled == true) {
summary = groupSummary(mDatabase!!.templatesGroup)
summary = mDatabase?.templatesGroup?.toString()
isEnabled = true
} else {
summary = null
@@ -412,6 +405,30 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
}
dbDataCompressionPref?.summary = algorithmToShow.getName(resources)
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK -> {
val oldRecycleBin = data.getParcelable<Group?>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newRecycleBin = data.getParcelable<Group?>(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val recycleBinToShow =
if (result.isSuccess) {
newRecycleBin
} else {
oldRecycleBin
}
mDatabase?.setRecycleBin(recycleBinToShow)
refreshRecycleBinGroup()
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_TEMPLATES_GROUP_TASK -> {
val oldTemplatesGroup = data.getParcelable<Group?>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newTemplatesGroup = data.getParcelable<Group?>(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val templatesGroupToShow =
if (result.isSuccess) {
newTemplatesGroup
} else {
oldTemplatesGroup
}
mDatabase?.setTemplatesGroup(templatesGroupToShow)
refreshTemplatesGroup()
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_MAX_HISTORY_ITEMS_TASK -> {
val oldMaxHistoryItems = data.getInt(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newMaxHistoryItems = data.getInt(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
@@ -539,6 +556,12 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
getString(R.string.database_data_remove_unlinked_attachments_key) -> {
dialogFragment = DatabaseRemoveUnlinkedDataPreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.recycle_bin_group_key) -> {
dialogFragment = DatabaseRecycleBinGroupPreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.templates_group_uuid_key) -> {
dialogFragment = DatabaseTemplatesGroupPreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.max_history_items_key) -> {
dialogFragment = MaxHistoryItemsPreferenceDialogFragmentCompat.newInstance(preference.key)
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2021 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListRadioItemAdapter
class DatabaseRecycleBinGroupPreferenceDialogFragmentCompat
: DatabaseSavePreferenceDialogFragmentCompat(),
ListRadioItemAdapter.RadioItemSelectedCallback<Group> {
private var mGroupRecycleBin: Group? = null
override fun onBindDialogView(view: View) {
super.onBindDialogView(view)
val recyclerView = view.findViewById<RecyclerView>(R.id.pref_dialog_list)
recyclerView.layoutManager = LinearLayoutManager(context)
activity?.let { activity ->
val groupsAdapter = ListRadioItemAdapter<Group>(activity)
groupsAdapter.setRadioItemSelectedCallback(this)
recyclerView.adapter = groupsAdapter
mDatabase?.let { database ->
mGroupRecycleBin = database.recycleBin?.apply {
groupsAdapter.setItems(database.getAllGroupsWithoutRoot(), this)
}
}
}
}
override fun onItemSelected(item: Group) {
mGroupRecycleBin = item
}
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
mDatabase?.let { database ->
if (database.allowConfigurableRecycleBin) {
val oldGroup = database.recycleBin
val newGroup = mGroupRecycleBin
database.setRecycleBin(newGroup)
mProgressDatabaseTaskProvider?.startDatabaseSaveRecycleBin(
oldGroup,
newGroup,
mDatabaseAutoSaveEnable
)
}
}
}
}
companion object {
fun newInstance(
key: String): DatabaseRecycleBinGroupPreferenceDialogFragmentCompat {
val fragment = DatabaseRecycleBinGroupPreferenceDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2021 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListRadioItemAdapter
class DatabaseTemplatesGroupPreferenceDialogFragmentCompat
: DatabaseSavePreferenceDialogFragmentCompat(),
ListRadioItemAdapter.RadioItemSelectedCallback<Group> {
private var mGroupTemplates: Group? = null
override fun onBindDialogView(view: View) {
super.onBindDialogView(view)
val recyclerView = view.findViewById<RecyclerView>(R.id.pref_dialog_list)
recyclerView.layoutManager = LinearLayoutManager(context)
activity?.let { activity ->
val groupsAdapter = ListRadioItemAdapter<Group>(activity)
groupsAdapter.setRadioItemSelectedCallback(this)
recyclerView.adapter = groupsAdapter
mDatabase?.let { database ->
mGroupTemplates = database.templatesGroup?.apply {
groupsAdapter.setItems(database.getAllGroupsWithoutRoot(), this)
}
}
}
}
override fun onItemSelected(item: Group) {
mGroupTemplates = item
}
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
mDatabase?.let { database ->
if (database.allowConfigurableTemplatesGroup) {
val oldGroup = database.templatesGroup
val newGroup = mGroupTemplates
database.setTemplatesGroup(newGroup)
mProgressDatabaseTaskProvider?.startDatabaseSaveTemplatesGroup(
oldGroup,
newGroup,
mDatabaseAutoSaveEnable
)
}
}
}
}
companion object {
fun newInstance(
key: String): DatabaseTemplatesGroupPreferenceDialogFragmentCompat {
val fragment = DatabaseTemplatesGroupPreferenceDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@@ -84,7 +84,7 @@
android:title="@string/recycle_bin_title"
android:summary="@string/recycle_bin_summary"
android:checked="false"/>
<Preference
<com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference
android:key="@string/recycle_bin_group_key"
android:persistent="false"
android:title="@string/recycle_bin_group_title"/>
@@ -101,7 +101,7 @@
android:title="@string/templates_group_enable_title"
android:summary="@string/templates_group_enable_summary"
android:checked="false"/>
<Preference
<com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference
android:key="@string/templates_group_uuid_key"
android:persistent="false"
android:title="@string/templates_group_uuid_title"/>