mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Merge branch 'feature/RecyclerBin' into develop
This commit is contained in:
@@ -42,10 +42,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.ReadOnlyDialog
|
||||
import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.*
|
||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||
@@ -77,6 +74,7 @@ class GroupActivity : LockingActivity(),
|
||||
IconPickerDialogFragment.IconPickerListener,
|
||||
ListNodesFragment.NodeClickListener,
|
||||
ListNodesFragment.NodesActionMenuListener,
|
||||
DeleteNodesDialogFragment.DeleteNodeListener,
|
||||
ListNodesFragment.OnScrollListener,
|
||||
SortDialogFragment.SortSelectionListener {
|
||||
|
||||
@@ -234,29 +232,28 @@ class GroupActivity : LockingActivity(),
|
||||
ACTION_DATABASE_DELETE_NODES_TASK -> {
|
||||
if (result.isSuccess) {
|
||||
|
||||
// Rebuild all the list the avoid bug when delete node from db sort
|
||||
if (PreferencesUtil.getListSort(this@GroupActivity) == SortNodeEnum.DB) {
|
||||
// Rebuild all the list the avoid bug when delete node from sort
|
||||
mListNodesFragment?.rebuildList()
|
||||
} else {
|
||||
// Use the old Nodes / entries unchanged with the old parent
|
||||
mListNodesFragment?.removeNodes(oldNodes)
|
||||
}
|
||||
|
||||
// Add trash in views list if it doesn't exists
|
||||
if (database.isRecycleBinEnabled) {
|
||||
val recycleBin = database.recycleBin
|
||||
if (mCurrentGroup != null && recycleBin != null
|
||||
&& mCurrentGroup!!.parent == null
|
||||
&& mCurrentGroup != recycleBin) {
|
||||
if (mListNodesFragment?.contains(recycleBin) == true)
|
||||
val currentGroup = mCurrentGroup
|
||||
if (currentGroup != null && recycleBin != null
|
||||
&& currentGroup != recycleBin) {
|
||||
// Recycle bin already here, simply update it
|
||||
if (mListNodesFragment?.contains(recycleBin) == true) {
|
||||
mListNodesFragment?.updateNode(recycleBin)
|
||||
else
|
||||
}
|
||||
// Recycle bin not here, verify if parents are similar to add it
|
||||
else if (currentGroup.parent == recycleBin.parent) {
|
||||
mListNodesFragment?.addNode(recycleBin)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.isSuccess) {
|
||||
result.exception?.errorId?.let { errorId ->
|
||||
@@ -596,14 +593,31 @@ class GroupActivity : LockingActivity(),
|
||||
}
|
||||
|
||||
override fun onDeleteMenuClick(nodes: List<NodeVersioned>): Boolean {
|
||||
val database = mDatabase
|
||||
if (database != null
|
||||
&& database.isRecycleBinEnabled
|
||||
&& database.recycleBin != mCurrentGroup) {
|
||||
// If recycle bin enabled and not in recycle bin, move in recycle bin
|
||||
progressDialogThread?.startDatabaseDeleteNodes(
|
||||
nodes,
|
||||
!mReadOnly
|
||||
)
|
||||
} else {
|
||||
// open the dialog to confirm deletion
|
||||
DeleteNodesDialogFragment.getInstance(nodes)
|
||||
.show(supportFragmentManager, "deleteNodesDialogFragment")
|
||||
}
|
||||
finishNodeAction()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun permanentlyDeleteNodes(nodes: List<NodeVersioned>) {
|
||||
progressDialogThread?.startDatabaseDeleteNodes(
|
||||
nodes,
|
||||
!mReadOnly
|
||||
)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// Refresh the elements
|
||||
@@ -632,6 +646,12 @@ class GroupActivity : LockingActivity(),
|
||||
MenuUtil.contributionMenuInflater(inflater, menu)
|
||||
}
|
||||
|
||||
// Menu for recycle bin
|
||||
if (mDatabase?.isRecycleBinEnabled == true
|
||||
&& mDatabase?.recycleBin == mCurrentGroup) {
|
||||
inflater.inflate(R.menu.recycle_bin, menu)
|
||||
}
|
||||
|
||||
// Get the SearchView and set the searchable configuration
|
||||
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
|
||||
|
||||
@@ -740,6 +760,13 @@ class GroupActivity : LockingActivity(),
|
||||
lockAndExit()
|
||||
return true
|
||||
}
|
||||
R.id.menu_empty_recycle_bin -> {
|
||||
mCurrentGroup?.getChildren()?.let { listChildren ->
|
||||
// Automatically delete all elements
|
||||
onDeleteMenuClick(listChildren)
|
||||
}
|
||||
return true
|
||||
}
|
||||
else -> {
|
||||
// Check the time lock before launching settings
|
||||
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, mReadOnly, true)
|
||||
|
||||
@@ -228,8 +228,7 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
||||
R.id.menu_sort -> {
|
||||
context?.let { context ->
|
||||
val sortDialogFragment: SortDialogFragment =
|
||||
if (Database.getInstance().allowRecycleBin
|
||||
&& Database.getInstance().isRecycleBinEnabled) {
|
||||
if (Database.getInstance().isRecycleBinEnabled) {
|
||||
SortDialogFragment.getInstance(
|
||||
PreferencesUtil.getListSort(context),
|
||||
PreferencesUtil.getAscendingSort(context),
|
||||
@@ -276,7 +275,8 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
||||
// Open and Edit for a single item
|
||||
if (nodes.size == 1) {
|
||||
// Edition
|
||||
if (readOnly || nodes[0] == database.recycleBin) {
|
||||
if (readOnly
|
||||
|| (database.isRecycleBinEnabled && nodes[0] == database.recycleBin)) {
|
||||
menu?.removeItem(R.id.menu_edit)
|
||||
}
|
||||
} else {
|
||||
@@ -287,7 +287,6 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
||||
// Copy and Move (not for groups)
|
||||
if (readOnly
|
||||
|| isASearchResult
|
||||
|| nodes.any { it == database.recycleBin }
|
||||
|| nodes.any { it.type == Type.GROUP }) {
|
||||
// TODO COPY For Group
|
||||
menu?.removeItem(R.id.menu_copy)
|
||||
@@ -295,7 +294,8 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
||||
}
|
||||
|
||||
// Deletion
|
||||
if (readOnly || nodes.any { it == database.recycleBin }) {
|
||||
if (readOnly
|
||||
|| (database.isRecycleBinEnabled && nodes.any { it == database.recycleBin })) {
|
||||
menu?.removeItem(R.id.menu_delete)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.getBundleFromListNodes
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.getListNodesFromBundle
|
||||
|
||||
class DeleteNodesDialogFragment : DialogFragment() {
|
||||
|
||||
private var mNodesToDelete: List<NodeVersioned> = ArrayList()
|
||||
private var mListener: DeleteNodeListener? = null
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
mListener = context as DeleteNodeListener
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException(context.toString()
|
||||
+ " must implement " + DeleteNodeListener::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
||||
arguments?.apply {
|
||||
if (containsKey(DatabaseTaskNotificationService.GROUPS_ID_KEY)
|
||||
&& containsKey(DatabaseTaskNotificationService.ENTRIES_ID_KEY)) {
|
||||
mNodesToDelete = getListNodesFromBundle(Database.getInstance(), this)
|
||||
}
|
||||
} ?: savedInstanceState?.apply {
|
||||
if (containsKey(DatabaseTaskNotificationService.GROUPS_ID_KEY)
|
||||
&& containsKey(DatabaseTaskNotificationService.ENTRIES_ID_KEY)) {
|
||||
mNodesToDelete = getListNodesFromBundle(Database.getInstance(), savedInstanceState)
|
||||
}
|
||||
}
|
||||
activity?.let { activity ->
|
||||
// Use the Builder class for convenient dialog construction
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
|
||||
builder.setMessage(getString(R.string.warning_permanently_delete_nodes))
|
||||
builder.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
mListener?.permanentlyDeleteNodes(mNodesToDelete)
|
||||
}
|
||||
builder.setNegativeButton(android.R.string.no) { _, _ -> dismiss() }
|
||||
// Create the AlertDialog object and return it
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putAll(getBundleFromListNodes(mNodesToDelete))
|
||||
}
|
||||
|
||||
interface DeleteNodeListener {
|
||||
fun permanentlyDeleteNodes(nodes: List<NodeVersioned>)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getInstance(nodesToDelete: List<NodeVersioned>): DeleteNodesDialogFragment {
|
||||
return DeleteNodesDialogFragment().apply {
|
||||
arguments = getBundleFromListNodes(nodesToDelete)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,13 +59,13 @@ enum class SortNodeEnum {
|
||||
if (object1.type == Type.GROUP) {
|
||||
return if (object2.type == Type.GROUP) {
|
||||
// RecycleBin at end of groups
|
||||
if (recycleBinBottom) {
|
||||
if (Database.getInstance().recycleBin == object1)
|
||||
val database = Database.getInstance()
|
||||
if (database.isRecycleBinEnabled && recycleBinBottom) {
|
||||
if (database.recycleBin == object1)
|
||||
return 1
|
||||
if (Database.getInstance().recycleBin == object2)
|
||||
if (database.recycleBin == object2)
|
||||
return -1
|
||||
}
|
||||
|
||||
specificOrderOrHashIfEquals(object1, object2)
|
||||
} else if (object2.type == Type.ENTRY) {
|
||||
if (groupsBefore)
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Compa
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_MOVE_NODES_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_SAVE
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_SAVE_COLOR_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_SAVE_COMPRESSION_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_SAVE_DEFAULT_USERNAME_TASK
|
||||
@@ -461,4 +462,14 @@ class ProgressDialogThread(private val activity: FragmentActivity,
|
||||
}
|
||||
, ACTION_DATABASE_SAVE_PARALLELISM_TASK)
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Database without parameter
|
||||
*/
|
||||
fun startDatabaseSave(save: Boolean) {
|
||||
start(Bundle().apply {
|
||||
putBoolean(DatabaseTaskNotificationService.SAVE_DATABASE_KEY, save)
|
||||
}
|
||||
, ACTION_DATABASE_SAVE)
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.webkit.URLUtil
|
||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
||||
import com.kunzisoft.keepass.database.NodeHandler
|
||||
import com.kunzisoft.keepass.database.cursor.EntryCursorV3
|
||||
@@ -253,8 +252,11 @@ class Database {
|
||||
val allowRecycleBin: Boolean
|
||||
get() = pwDatabaseV4 != null
|
||||
|
||||
val isRecycleBinEnabled: Boolean
|
||||
var isRecycleBinEnabled: Boolean
|
||||
get() = pwDatabaseV4?.isRecycleBinEnabled ?: false
|
||||
set(value) {
|
||||
pwDatabaseV4?.isRecycleBinEnabled = value
|
||||
}
|
||||
|
||||
val recycleBin: GroupVersioned?
|
||||
get() {
|
||||
@@ -264,6 +266,14 @@ class Database {
|
||||
return null
|
||||
}
|
||||
|
||||
fun ensureRecycleBinExists(resources: Resources) {
|
||||
pwDatabaseV4?.ensureRecycleBinExists(resources)
|
||||
}
|
||||
|
||||
fun removeRecycleBin() {
|
||||
pwDatabaseV4?.removeRecycleBin()
|
||||
}
|
||||
|
||||
private fun setDatabaseV3(pwDatabaseV3: PwDatabaseV3) {
|
||||
this.pwDatabaseV3 = pwDatabaseV3
|
||||
this.pwDatabaseV4 = null
|
||||
|
||||
@@ -209,7 +209,7 @@ class PwDatabaseV4 : PwDatabase<UUID, UUID, PwGroupV4, PwEntryV4> {
|
||||
|
||||
// Retrieve recycle bin in index
|
||||
val recycleBin: PwGroupV4?
|
||||
get() = getGroupByUUID(recycleBinUUID)
|
||||
get() = if (recycleBinUUID == UUID_ZERO) null else getGroupByUUID(recycleBinUUID)
|
||||
|
||||
val lastSelectedGroup: PwGroupV4?
|
||||
get() = getGroupByUUID(lastSelectedGroupUUID)
|
||||
@@ -397,7 +397,7 @@ class PwDatabaseV4 : PwDatabase<UUID, UUID, PwGroupV4, PwEntryV4> {
|
||||
* Ensure that the recycle bin tree exists, if enabled and create it
|
||||
* if it doesn't exist
|
||||
*/
|
||||
private fun ensureRecycleBin(resources: Resources) {
|
||||
fun ensureRecycleBinExists(resources: Resources) {
|
||||
if (recycleBin == null) {
|
||||
// Create recycle bin
|
||||
val recycleBinGroup = createGroup().apply {
|
||||
@@ -413,6 +413,13 @@ class PwDatabaseV4 : PwDatabase<UUID, UUID, PwGroupV4, PwEntryV4> {
|
||||
}
|
||||
}
|
||||
|
||||
fun removeRecycleBin() {
|
||||
if (recycleBin != null) {
|
||||
recycleBinUUID = UUID_ZERO
|
||||
recycleBinChanged = PwDate().date
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define if a Node must be delete or recycle when remove action is called
|
||||
* @param node Node to remove
|
||||
@@ -422,21 +429,21 @@ class PwDatabaseV4 : PwDatabase<UUID, UUID, PwGroupV4, PwEntryV4> {
|
||||
if (!isRecycleBinEnabled)
|
||||
return false
|
||||
if (recycleBin == null)
|
||||
return true
|
||||
return false
|
||||
if (!node.isContainedIn(recycleBin!!))
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
fun recycle(group: PwGroupV4, resources: Resources) {
|
||||
ensureRecycleBin(resources)
|
||||
ensureRecycleBinExists(resources)
|
||||
removeGroupFrom(group, group.parent)
|
||||
addGroupTo(group, recycleBin)
|
||||
group.afterAssignNewParent()
|
||||
}
|
||||
|
||||
fun recycle(entry: PwEntryV4, resources: Resources) {
|
||||
ensureRecycleBin(resources)
|
||||
ensureRecycleBinExists(resources)
|
||||
removeEntryFrom(entry, entry.parent)
|
||||
addEntryTo(entry, recycleBin)
|
||||
entry.afterAssignNewParent()
|
||||
|
||||
@@ -108,7 +108,7 @@ class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdat
|
||||
ACTION_DATABASE_SAVE_MEMORY_USAGE_TASK,
|
||||
ACTION_DATABASE_SAVE_PARALLELISM_TASK,
|
||||
ACTION_DATABASE_SAVE_ITERATIONS_TASK -> buildDatabaseSaveElementActionTask(intent)
|
||||
else -> null
|
||||
else -> buildDatabaseSave(intent)
|
||||
}
|
||||
|
||||
actionRunnable?.let { actionRunnableNotNull ->
|
||||
@@ -412,6 +412,19 @@ class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdat
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save database without parameter
|
||||
*/
|
||||
private fun buildDatabaseSave(intent: Intent): ActionRunnable? {
|
||||
return if (intent.hasExtra(SAVE_DATABASE_KEY)) {
|
||||
SaveDatabaseRunnable(this,
|
||||
Database.getInstance(),
|
||||
intent.getBooleanExtra(SAVE_DATABASE_KEY, false))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionRunnableAsyncTask(private val progressTaskUpdater: ProgressTaskUpdater,
|
||||
private val onPreExecute: () -> Unit,
|
||||
private val onPostExecute: (result: ActionRunnable.Result) -> Unit)
|
||||
@@ -471,6 +484,7 @@ class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdat
|
||||
const val ACTION_DATABASE_SAVE_MEMORY_USAGE_TASK = "ACTION_DATABASE_SAVE_MEMORY_USAGE_TASK"
|
||||
const val ACTION_DATABASE_SAVE_PARALLELISM_TASK = "ACTION_DATABASE_SAVE_PARALLELISM_TASK"
|
||||
const val ACTION_DATABASE_SAVE_ITERATIONS_TASK = "ACTION_DATABASE_SAVE_ITERATIONS_TASK"
|
||||
const val ACTION_DATABASE_SAVE = "ACTION_DATABASE_SAVE"
|
||||
|
||||
const val DATABASE_URI_KEY = "DATABASE_URI_KEY"
|
||||
const val MASTER_PASSWORD_CHECKED_KEY = "MASTER_PASSWORD_CHECKED_KEY"
|
||||
@@ -509,23 +523,23 @@ class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdat
|
||||
}
|
||||
|
||||
fun getBundleFromListNodes(nodes: List<NodeVersioned>): Bundle {
|
||||
val groupsIdToCopy = ArrayList<PwNodeId<*>>()
|
||||
val entriesIdToCopy = ArrayList<PwNodeId<UUID>>()
|
||||
val groupsId = ArrayList<PwNodeId<*>>()
|
||||
val entriesId = ArrayList<PwNodeId<UUID>>()
|
||||
nodes.forEach { nodeVersioned ->
|
||||
when (nodeVersioned.type) {
|
||||
Type.GROUP -> {
|
||||
(nodeVersioned as GroupVersioned).nodeId?.let { groupId ->
|
||||
groupsIdToCopy.add(groupId)
|
||||
groupsId.add(groupId)
|
||||
}
|
||||
}
|
||||
Type.ENTRY -> {
|
||||
entriesIdToCopy.add((nodeVersioned as EntryVersioned).nodeId)
|
||||
entriesId.add((nodeVersioned as EntryVersioned).nodeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Bundle().apply {
|
||||
putParcelableArrayList(GROUPS_ID_KEY, groupsIdToCopy)
|
||||
putParcelableArrayList(ENTRIES_ID_KEY, entriesIdToCopy)
|
||||
putParcelableArrayList(GROUPS_ID_KEY, groupsId)
|
||||
putParcelableArrayList(ENTRIES_ID_KEY, entriesId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ class NestedSettingsFragment : PreferenceFragmentCompat() {
|
||||
private var dbDefaultUsername: InputTextPreference? = null
|
||||
private var dbCustomColorPref: DialogColorPreference? = null
|
||||
private var dbDataCompressionPref: Preference? = null
|
||||
private var recycleBinGroupPref: Preference? = null
|
||||
private var dbMaxHistoryItemsPref: InputNumberPreference? = null
|
||||
private var dbMaxHistorySizePref: InputNumberPreference? = null
|
||||
private var mEncryptionAlgorithmPref: DialogListExplanationPreference? = null
|
||||
@@ -452,17 +453,35 @@ class NestedSettingsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
|
||||
val dbRecycleBinPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_recycle_bin_key))
|
||||
recycleBinGroupPref = findPreference(getString(R.string.recycle_bin_group_key))
|
||||
|
||||
// Recycle bin
|
||||
val recycleBinPref: SwitchPreference? = findPreference(getString(R.string.recycle_bin_key))
|
||||
if (mDatabase.allowRecycleBin) {
|
||||
recycleBinPref?.isChecked = mDatabase.isRecycleBinEnabled
|
||||
// TODO Recycle Bin
|
||||
recycleBinPref?.isEnabled = false
|
||||
val recycleBinEnablePref: SwitchPreference? = findPreference(getString(R.string.recycle_bin_enable_key))
|
||||
recycleBinEnablePref?.apply {
|
||||
isChecked = mDatabase.isRecycleBinEnabled
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val recycleBinEnabled = newValue as Boolean
|
||||
mDatabase.isRecycleBinEnabled = recycleBinEnabled
|
||||
if (recycleBinEnabled) {
|
||||
mDatabase.ensureRecycleBinExists(resources)
|
||||
} else {
|
||||
mDatabase.removeRecycleBin()
|
||||
}
|
||||
refreshRecycleBinGroup()
|
||||
// Save the database
|
||||
// TODO manual save
|
||||
(context as SettingsActivity?)?.progressDialogThread?.startDatabaseSave(true)
|
||||
true
|
||||
}
|
||||
}
|
||||
// Recycle Bin group
|
||||
refreshRecycleBinGroup()
|
||||
} else {
|
||||
dbRecycleBinPrefCategory?.isVisible = false
|
||||
}
|
||||
|
||||
// History
|
||||
findPreference<PreferenceCategory>(getString(R.string.database_category_history_key))
|
||||
?.isVisible = mDatabase.manageHistory == true
|
||||
|
||||
@@ -481,6 +500,18 @@ class NestedSettingsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshRecycleBinGroup() {
|
||||
recycleBinGroupPref?.apply {
|
||||
if (mDatabase.isRecycleBinEnabled) {
|
||||
summary = mDatabase.recycleBin?.title
|
||||
isEnabled = true
|
||||
} else {
|
||||
summary = null
|
||||
isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCreateDatabaseSecurityPreference(rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.preferences_database_security, rootKey)
|
||||
|
||||
|
||||
10
app/src/main/res/menu/recycle_bin.xml
Normal file
10
app/src/main/res/menu/recycle_bin.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/menu_empty_recycle_bin"
|
||||
android:icon="@drawable/ic_content_delete_white_24dp"
|
||||
android:title="@string/menu_empty_recycle_bin"
|
||||
android:orderInCategory="35"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
@@ -220,7 +220,7 @@
|
||||
<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>
|
||||
<string name="recycle_bin_summary">Déplace les groupes et les entrées dans la « Corbeille » avant suppression</string>
|
||||
<string name="recycle_bin_summary">Déplace les groupes et les entrées dans le groupe \"Corbeille\" avant suppression</string>
|
||||
<string name="monospace_font_fields_enable_title">Police de champ</string>
|
||||
<string name="monospace_font_fields_enable_summary">Changer la police utilisée dans les champs pour une meilleure visibilité des caractères</string>
|
||||
<string name="allow_copy_password_title">Confiance dans le presse-papier</string>
|
||||
|
||||
@@ -160,7 +160,8 @@
|
||||
<string name="database_data_compression_key" translatable="false">database_data_compression_key</string>
|
||||
|
||||
<string name="database_category_recycle_bin_key" translatable="false">database_category_recycle_bin_key</string>
|
||||
<string name="recycle_bin_key" translatable="false">recycle_bin_key</string>
|
||||
<string name="recycle_bin_enable_key" translatable="false">recycle_bin_enable_key</string>
|
||||
<string name="recycle_bin_group_key" translatable="false">recycle_bin_group_key</string>
|
||||
|
||||
<string name="database_category_history_key" translatable="false">database_category_history_key</string>
|
||||
<string name="max_history_items_key" translatable="false">max_history_items_key</string>
|
||||
|
||||
@@ -183,6 +183,7 @@
|
||||
<string name="menu_url">Go to URL</string>
|
||||
<string name="menu_file_selection_read_only">Write-protected</string>
|
||||
<string name="menu_open_file_read_and_write">Modifiable</string>
|
||||
<string name="menu_empty_recycle_bin">Empty Recycle Bin</string>
|
||||
<string name="minus">Minus</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="no_results">No search results</string>
|
||||
@@ -242,6 +243,7 @@
|
||||
<string name="warning_unmounted">Mount the SD card to create or load a database.</string>
|
||||
<string name="warning_empty_password">Do you really want no password unlocking protection?</string>
|
||||
<string name="warning_no_encryption_key">Are you sure you do not want to use any encryption key?</string>
|
||||
<string name="warning_permanently_delete_nodes">Are you sure you want to permanently delete the selected nodes?</string>
|
||||
<string name="version_label">Version %1$s</string>
|
||||
<string name="build_label">Build %1$s</string>
|
||||
<string name="configure_biometric">Biometric prompt is supported but not set up.</string>
|
||||
@@ -304,7 +306,8 @@
|
||||
<string name="database_data_compression_title">Data compression</string>
|
||||
<string name="database_data_compression_summary">Data compression reduces the size of the database.</string>
|
||||
<string name="recycle_bin_title">Use recycle bin</string>
|
||||
<string name="recycle_bin_summary">Moves groups and entries to \"Recycle bin\" before deleting</string>
|
||||
<string name="recycle_bin_summary">Moves groups and entries to \"Recycle bin\" group before deleting</string>
|
||||
<string name="recycle_bin_group_title">Recycle bin group</string>
|
||||
<string name="max_history_items_title">Max. history items</string>
|
||||
<string name="max_history_items_summary">Limit number of history items per entry</string>
|
||||
<string name="max_history_size_title">Max. history size</string>
|
||||
|
||||
@@ -74,11 +74,15 @@
|
||||
android:title="@string/recycle_bin">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="@string/recycle_bin_key"
|
||||
android:key="@string/recycle_bin_enable_key"
|
||||
android:persistent="false"
|
||||
android:title="@string/recycle_bin_title"
|
||||
android:summary="@string/recycle_bin_summary"
|
||||
android:checked="false"/>
|
||||
<Preference
|
||||
android:key="@string/recycle_bin_group_key"
|
||||
android:persistent="false"
|
||||
android:title="@string/recycle_bin_group_title"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user