Files
KeePassDX/app/src/main/java/com/kunzisoft/keepass/settings/NestedDatabaseSettingsFragment.kt
2025-12-04 12:35:42 +01:00

840 lines
41 KiB
Kotlin

/*
* Copyright 2019 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
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.toColorInt
import androidx.core.view.MenuProvider
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.TwoStatePreference
import com.kunzisoft.androidclearchroma.ChromaUtil
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
import com.kunzisoft.keepass.settings.preference.DialogColorPreference
import com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference
import com.kunzisoft.keepass.settings.preference.InputKdfNumberPreference
import com.kunzisoft.keepass.settings.preference.InputKdfSizePreference
import com.kunzisoft.keepass.settings.preference.InputNumberPreference
import com.kunzisoft.keepass.settings.preference.InputTextPreference
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseColorPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseDataCompressionPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseDefaultUsernamePreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseDescriptionPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseKeyDerivationPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseMaxHistoryItemsPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseMaxHistorySizePreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseMemoryUsagePreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseNamePreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseParallelismPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseRecycleBinGroupPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseRemoveUnlinkedDataPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseRoundsPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseTemplatesGroupPreferenceDialogFragmentCompat
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.getSerializableCompat
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
import com.kunzisoft.keepass.viewmodels.SettingsViewModel
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
import kotlinx.coroutines.launch
class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetrieval {
private val mSettingsViewModel: SettingsViewModel by activityViewModels()
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private val mUserVerificationViewModel: UserVerificationViewModel by activityViewModels()
private val mDatabase: ContextualDatabase?
get() = mDatabaseViewModel.database
private var mDatabaseReadOnly: Boolean = false
private var mMergeDataAllowed: Boolean = false
private var mDatabaseAutoSaveEnabled: Boolean = true
private var mScreen: Screen? = null
private var dbNamePref: InputTextPreference? = null
private var dbDescriptionPref: InputTextPreference? = null
private var dbDefaultUsernamePref: InputTextPreference? = null
private var dbCustomColorPref: DialogColorPreference? = null
private var dbDataCompressionPref: 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
private var mKeyDerivationPref: DialogListExplanationPreference? = null
private var mRoundPref: InputKdfNumberPreference? = null
private var mMemoryPref: InputKdfSizePreference? = null
private var mParallelismPref: InputKdfNumberPreference? = null
private val menuProvider: MenuProvider = object: MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.database, menu)
if (mDatabaseReadOnly) {
menu.findItem(R.id.menu_save_database)?.isVisible = false
menu.findItem(R.id.menu_merge_database)?.isVisible = false
}
if (!mMergeDataAllowed) {
menu.findItem(R.id.menu_merge_database)?.isVisible = false
}
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.menu_save_database -> {
saveDatabase(!mDatabaseReadOnly)
true
}
R.id.menu_merge_database -> {
mergeDatabase(!mDatabaseReadOnly)
true
}
R.id.menu_reload_database -> {
reloadDatabase()
true
}
R.id.menu_app_settings -> {
// Check the time lock before launching settings
// TODO activity menu
(activity as SettingsActivity?)?.let {
SettingsActivity.launch(it, true)
}
true
}
else -> {
false
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
mDatabaseViewModel.actionState.collect { uiState ->
when (uiState) {
is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> {
onDatabaseActionFinished(
uiState.database,
uiState.actionTask,
uiState.result
)
}
else -> {}
}
}
}
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
mDatabaseViewModel.databaseState.collect { database ->
database?.let {
onDatabaseRetrieved(database)
}
}
}
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
mUserVerificationViewModel.userVerificationState.collect { state ->
when (state) {
is UserVerificationViewModel.UVState.Loading -> {}
is UserVerificationViewModel.UVState.OnUserVerificationCanceled -> {
mSettingsViewModel.showError(state.error)
mUserVerificationViewModel.onUserVerificationReceived()
}
is UserVerificationViewModel.UVState.OnUserVerificationSucceeded -> {
val data = state.dataToVerify
when (data.actionType) {
UserVerificationActionType.EDIT_DATABASE_SETTING -> {
val database = data.database
val preferenceKey = data.preferenceKey
if (database != null && preferenceKey != null) {
// Main Preferences
when (preferenceKey) {
// Master Key
getString(R.string.settings_database_change_credentials_key) -> {
SetMainCredentialDialogFragment
.getInstance(database.allowNoMasterKey)
.show(parentFragmentManager, "passwordDialog")
}
else -> {}
}
// TODO Settings in compose
@Suppress("DEPRECATION")
mSettingsViewModel.dialogFragment?.let { dialogFragment ->
dialogFragment.setTargetFragment(
this@NestedDatabaseSettingsFragment, 0
)
dialogFragment.show(parentFragmentManager, TAG_PREF_FRAGMENT)
}
mSettingsViewModel.dialogFragment = null
}
}
else -> {}
}
mUserVerificationViewModel.onUserVerificationReceived()
}
}
}
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.addMenuProvider(menuProvider, viewLifecycleOwner)
viewLifecycleOwner.lifecycleScope.launch {
mDatabaseViewModel.databaseState.collect { database ->
view.resetAppTimeoutWhenViewTouchedOrFocused(
context = requireContext(),
databaseLoaded = database?.loaded
)
}
}
}
override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) {
mScreen = screen
val database = mDatabase
// Load the preferences from an XML resource
when (screen) {
Screen.DATABASE -> {
setPreferencesFromResource(R.xml.preferences_database, rootKey)
if (database?.loaded == true)
onCreateDatabasePreference(database)
}
Screen.DATABASE_SECURITY -> {
setPreferencesFromResource(R.xml.preferences_database_security, rootKey)
if (database?.loaded == true)
onCreateDatabaseSecurityPreference(database)
}
Screen.DATABASE_MASTER_KEY -> {
setPreferencesFromResource(R.xml.preferences_database_master_key, rootKey)
if (database?.loaded == true)
onCreateDatabaseMasterKeyPreference(database)
}
else -> {
}
}
}
private fun saveDatabase(save: Boolean) {
mDatabaseViewModel.saveDatabase(save)
}
private fun mergeDatabase(save: Boolean) {
mDatabaseViewModel.mergeDatabase(save)
}
private fun reloadDatabase() {
mDatabaseViewModel.reloadDatabase(false)
}
override fun onDatabaseRetrieved(database: ContextualDatabase) {
mDatabaseReadOnly = database.isReadOnly
mMergeDataAllowed = database.isMergeDataAllowed()
if (database.loaded) {
when (mScreen) {
Screen.DATABASE -> {
onCreateDatabasePreference(database)
}
Screen.DATABASE_SECURITY -> {
onCreateDatabaseSecurityPreference(database)
}
Screen.DATABASE_MASTER_KEY -> {
onCreateDatabaseMasterKeyPreference(database)
}
else -> {
}
}
} else {
Log.e(javaClass.name, "Database isn't ready")
}
}
private fun onCreateDatabasePreference(database: ContextualDatabase) {
val dbGeneralPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_general_key))
// Database name
dbNamePref = findPreference(getString(R.string.database_name_key))
dbNamePref?.let { namePreference ->
if (database.allowName) {
namePreference.summary = database.name
} else {
dbGeneralPrefCategory?.removePreference(namePreference)
}
}
// Database description
dbDescriptionPref = findPreference(getString(R.string.database_description_key))
dbDescriptionPref?.let { descriptionPreference ->
if (database.allowDescription) {
dbDescriptionPref?.summary = database.description
} else {
dbGeneralPrefCategory?.removePreference(descriptionPreference)
}
}
// Database default username
dbDefaultUsernamePref = findPreference(getString(R.string.database_default_username_key))
dbDefaultUsernamePref?.summary = database.defaultUsername
// Database custom color
dbCustomColorPref = findPreference(getString(R.string.database_custom_color_key))
dbCustomColorPref?.apply {
val customColor = database.customColor
if (customColor != null) {
color = customColor
summary = ChromaUtil.getFormattedColorString(customColor, false)
} else{
color = DialogColorPreference.DISABLE_COLOR
summary = ""
}
}
// Version
findPreference<Preference>(getString(R.string.database_version_key))
?.summary = database.version
val dbCompressionPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_data_key))
// Database compression
dbDataCompressionPref = findPreference(getString(R.string.database_data_compression_key))
if (database.allowDataCompression) {
dbDataCompressionPref?.summary = (database.compressionAlgorithm
?: CompressionAlgorithm.NONE).getLocalizedName(resources)
} else {
dbCompressionPrefCategory?.isVisible = false
}
val dbRecycleBinPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_recycle_bin_key))
recycleBinGroupPref = findPreference(getString(R.string.recycle_bin_group_key))
// Recycle bin
if (database.allowConfigurableRecycleBin) {
val recycleBinEnablePref: TwoStatePreference? = findPreference(getString(R.string.recycle_bin_enable_key))
recycleBinEnablePref?.apply {
isChecked = database.isRecycleBinEnabled
isEnabled = if (!mDatabaseReadOnly) {
setOnPreferenceChangeListener { _, newValue ->
val recycleBinEnabled = newValue as Boolean
database.enableRecycleBin(recycleBinEnabled, resources.getString(R.string.recycle_bin))
refreshRecycleBinGroup(database)
// Save the database if not in readonly mode
saveDatabase(mDatabaseAutoSaveEnabled)
true
}
true
} else {
false
}
}
// Change the recycle bin group
recycleBinGroupPref?.setOnPreferenceClickListener {
true
}
// Recycle Bin group
refreshRecycleBinGroup(database)
} else {
recycleBinGroupPref?.onPreferenceClickListener = null
dbRecycleBinPrefCategory?.isVisible = false
}
// Templates
val templatesGroupPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_templates_key))
templatesGroupPref = findPreference(getString(R.string.templates_group_uuid_key))
if (database.allowTemplatesGroup) {
val templatesEnablePref: TwoStatePreference? = findPreference(getString(R.string.templates_group_enable_key))
templatesEnablePref?.apply {
isChecked = database.isTemplatesEnabled
isEnabled = if (!mDatabaseReadOnly) {
setOnPreferenceChangeListener { _, newValue ->
val templatesEnabled = newValue as Boolean
database.enableTemplates(templatesEnabled,
resources.getString(R.string.templates)
)
refreshTemplatesGroup(database)
// Save the database if not in readonly mode
saveDatabase(mDatabaseAutoSaveEnabled)
true
}
true
} else {
false
}
}
// Refresh templates group
refreshTemplatesGroup(database)
} else {
templatesGroupPrefCategory?.isVisible = false
}
// History
findPreference<PreferenceCategory>(getString(R.string.database_category_history_key))
?.isVisible = database.manageHistory == true
// Max history items
dbMaxHistoryItemsPref = findPreference<InputNumberPreference>(getString(R.string.max_history_items_key))?.apply {
summary = database.historyMaxItems.toString()
}
// Max history size
dbMaxHistorySizePref = findPreference<InputNumberPreference>(getString(R.string.max_history_size_key))?.apply {
summary = database.historyMaxSize.toString()
}
}
private fun refreshRecycleBinGroup(database: ContextualDatabase?) {
recycleBinGroupPref?.apply {
if (database?.isRecycleBinEnabled == true) {
summary = database.recycleBin?.toString()
isEnabled = true
} else {
summary = null
isEnabled = false
}
}
}
private fun refreshTemplatesGroup(database: ContextualDatabase?) {
templatesGroupPref?.apply {
if (database?.isTemplatesEnabled == true) {
summary = database.templatesGroup?.toString()
isEnabled = true
} else {
summary = null
isEnabled = false
}
}
}
private fun onCreateDatabaseSecurityPreference(database: ContextualDatabase) {
// Encryption Algorithm
mEncryptionAlgorithmPref = findPreference<DialogListExplanationPreference>(getString(R.string.encryption_algorithm_key))?.apply {
summary = database.getEncryptionAlgorithmName()
}
// Key derivation function
mKeyDerivationPref = findPreference<DialogListExplanationPreference>(getString(R.string.key_derivation_function_key))?.apply {
summary = database.getKeyDerivationName()
}
// Round encryption
mRoundPref = findPreference<InputKdfNumberPreference>(getString(R.string.transform_rounds_key))?.apply {
summary = database.numberKeyEncryptionRounds.toString()
}
// Memory Usage
mMemoryPref = findPreference<InputKdfSizePreference>(getString(R.string.memory_usage_key))?.apply {
summary = database.memoryUsage.toString()
}
// Parallelism
mParallelismPref = findPreference<InputKdfNumberPreference>(getString(R.string.parallelism_key))?.apply {
summary = database.parallelism.toString()
}
}
private fun onCreateDatabaseMasterKeyPreference(database: ContextualDatabase) {
val changeCredentialKey = getString(R.string.settings_database_change_credentials_key)
findPreference<Preference>(changeCredentialKey)?.apply {
isEnabled = if (!mDatabaseReadOnly) {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
checkUserVerification(
mUserVerificationViewModel,
UserVerificationData(
actionType = UserVerificationActionType.EDIT_DATABASE_SETTING,
database = database,
preferenceKey = changeCredentialKey
)
)
false
}
true
} else {
false
}
}
}
private val colorSelectedListener: ((Int?)-> Unit) = { color ->
if (color != null) {
dbCustomColorPref?.color = color
dbCustomColorPref?.summary = ChromaUtil.getFormattedColorString(color, false)
} else {
dbCustomColorPref?.color = DialogColorPreference.DISABLE_COLOR
dbCustomColorPref?.summary = ""
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = super.onCreateView(inflater, container, savedInstanceState)
try {
// To reassign color listener after orientation change
val chromaDialog = parentFragmentManager.findFragmentByTag(TAG_PREF_FRAGMENT) as DatabaseColorPreferenceDialogFragmentCompat?
chromaDialog?.onColorSelectedListener = colorSelectedListener
} catch (_: Exception) {}
return view
}
// TODO check error
override fun onDatabaseActionFinished(database: ContextualDatabase,
actionTask: String,
result: ActionRunnable.Result) {
result.data?.let { data ->
if (data.containsKey(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
&& data.containsKey(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)) {
when (actionTask) {
/*
--------
Main preferences
--------
*/
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_NAME_TASK -> {
val oldName = data.getString(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)!!
val newName = data.getString(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)!!
val nameToShow =
if (result.isSuccess) {
newName
} else {
database.name = oldName
oldName
}
dbNamePref?.summary = nameToShow
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_DESCRIPTION_TASK -> {
val oldDescription = data.getString(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)!!
val newDescription = data.getString(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)!!
val descriptionToShow =
if (result.isSuccess) {
newDescription
} else {
database.description = oldDescription
oldDescription
}
dbDescriptionPref?.summary = descriptionToShow
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_DEFAULT_USERNAME_TASK -> {
val oldDefaultUsername = data.getString(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)!!
val newDefaultUsername = data.getString(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)!!
val defaultUsernameToShow =
if (result.isSuccess) {
newDefaultUsername
} else {
database.defaultUsername = oldDefaultUsername
oldDefaultUsername
}
dbDefaultUsernamePref?.summary = defaultUsernameToShow
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_COLOR_TASK -> {
val oldColor = data.getString(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)!!
val newColor = data.getString(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)!!
val defaultColorToShow =
if (result.isSuccess) {
newColor
} else {
database.customColor = oldColor.toColorInt()
oldColor
}
dbCustomColorPref?.summary = defaultColorToShow
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_COMPRESSION_TASK -> {
val oldCompression = data.getSerializableCompat<CompressionAlgorithm>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newCompression = data.getSerializableCompat<CompressionAlgorithm>(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val algorithmToShow =
if (result.isSuccess) {
newCompression
} else {
database.compressionAlgorithm = oldCompression
oldCompression
}
dbDataCompressionPref?.summary = algorithmToShow?.getLocalizedName(resources)
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_RECYCLE_BIN_TASK -> {
val oldRecycleBin = data.getParcelableCompat<Group>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newRecycleBin = data.getParcelableCompat<Group>(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val recycleBinToShow =
if (result.isSuccess) {
newRecycleBin
} else {
oldRecycleBin
}
database.setRecycleBin(recycleBinToShow)
refreshRecycleBinGroup(database)
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_TEMPLATES_GROUP_TASK -> {
val oldTemplatesGroup = data.getParcelableCompat<Group>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newTemplatesGroup = data.getParcelableCompat<Group>(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val templatesGroupToShow =
if (result.isSuccess) {
newTemplatesGroup
} else {
oldTemplatesGroup
}
database.setTemplatesGroup(templatesGroupToShow)
refreshTemplatesGroup(database)
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_MAX_HISTORY_ITEMS_TASK -> {
val oldMaxHistoryItems = data.getInt(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newMaxHistoryItems = data.getInt(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val maxHistoryItemsToShow =
if (result.isSuccess) {
newMaxHistoryItems
} else {
database.historyMaxItems = oldMaxHistoryItems
oldMaxHistoryItems
}
dbMaxHistoryItemsPref?.summary = maxHistoryItemsToShow.toString()
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_MAX_HISTORY_SIZE_TASK -> {
val oldMaxHistorySize = data.getLong(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newMaxHistorySize = data.getLong(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val maxHistorySizeToShow =
if (result.isSuccess) {
newMaxHistorySize
} else {
database.historyMaxSize = oldMaxHistorySize
oldMaxHistorySize
}
dbMaxHistorySizePref?.summary = maxHistorySizeToShow.toString()
}
/*
--------
Security
--------
*/
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_ENCRYPTION_TASK -> {
val oldEncryption = data.getSerializableCompat<EncryptionAlgorithm>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newEncryption = data.getSerializableCompat<EncryptionAlgorithm>(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val algorithmToShow =
if (result.isSuccess) {
newEncryption
} else {
database.encryptionAlgorithm = oldEncryption
oldEncryption
}
mEncryptionAlgorithmPref?.summary = algorithmToShow.toString()
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_KEY_DERIVATION_TASK -> {
val oldKeyDerivationEngine = data.getSerializableCompat<KdfEngine>(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newKeyDerivationEngine = data.getSerializableCompat<KdfEngine>(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val kdfEngineToShow =
if (result.isSuccess) {
newKeyDerivationEngine
} else {
database.kdfEngine = oldKeyDerivationEngine
oldKeyDerivationEngine
}
mKeyDerivationPref?.summary = kdfEngineToShow.toString()
mRoundPref?.summary = kdfEngineToShow?.defaultKeyRounds.toString()
// Disable memory and parallelism if not available
mMemoryPref?.summary = kdfEngineToShow?.defaultMemoryUsage.toString()
mParallelismPref?.summary = kdfEngineToShow?.defaultParallelism.toString()
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_ITERATIONS_TASK -> {
val oldIterations = data.getLong(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newIterations = data.getLong(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val roundsToShow =
if (result.isSuccess) {
newIterations
} else {
database.numberKeyEncryptionRounds = oldIterations
oldIterations
}
mRoundPref?.summary = roundsToShow.toString()
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_MEMORY_USAGE_TASK -> {
val oldMemoryUsage = data.getLong(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newMemoryUsage = data.getLong(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val memoryToShow =
if (result.isSuccess) {
newMemoryUsage
} else {
database.memoryUsage = oldMemoryUsage
oldMemoryUsage
}
mMemoryPref?.summary = memoryToShow.toString()
}
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_PARALLELISM_TASK -> {
val oldParallelism = data.getLong(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
val newParallelism = data.getLong(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
val parallelismToShow =
if (result.isSuccess) {
newParallelism
} else {
database.parallelism = oldParallelism
oldParallelism
}
mParallelismPref?.summary = parallelismToShow.toString()
}
}
}
}
}
override fun onDisplayPreferenceDialog(preference: Preference) {
var otherDialogFragment = false
var dialogFragment: DialogFragment? = null
// Main Preferences
when (preference.key) {
getString(R.string.database_name_key) -> {
dialogFragment = DatabaseNamePreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.database_description_key) -> {
dialogFragment = DatabaseDescriptionPreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.database_default_username_key) -> {
dialogFragment = DatabaseDefaultUsernamePreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.database_custom_color_key) -> {
dialogFragment = DatabaseColorPreferenceDialogFragmentCompat.newInstance(preference.key).apply {
onColorSelectedListener = colorSelectedListener
}
}
getString(R.string.database_data_compression_key) -> {
dialogFragment = DatabaseDataCompressionPreferenceDialogFragmentCompat.newInstance(preference.key)
}
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 = DatabaseMaxHistoryItemsPreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.max_history_size_key) -> {
dialogFragment = DatabaseMaxHistorySizePreferenceDialogFragmentCompat.newInstance(preference.key)
}
// Security
getString(R.string.encryption_algorithm_key) -> {
dialogFragment = DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.key_derivation_function_key) -> {
val keyDerivationDialogFragment = DatabaseKeyDerivationPreferenceDialogFragmentCompat.newInstance(preference.key)
// Add other prefs to manage
keyDerivationDialogFragment.setRoundPreference(mRoundPref)
keyDerivationDialogFragment.setMemoryPreference(mMemoryPref)
keyDerivationDialogFragment.setParallelismPreference(mParallelismPref)
dialogFragment = keyDerivationDialogFragment
}
getString(R.string.transform_rounds_key) -> {
dialogFragment = DatabaseRoundsPreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.memory_usage_key) -> {
dialogFragment = DatabaseMemoryUsagePreferenceDialogFragmentCompat.newInstance(preference.key)
}
getString(R.string.parallelism_key) -> {
dialogFragment = DatabaseParallelismPreferenceDialogFragmentCompat.newInstance(preference.key)
}
else -> otherDialogFragment = true
}
if (dialogFragment != null && !mDatabaseReadOnly) {
mSettingsViewModel.dialogFragment = dialogFragment
checkUserVerification(
mUserVerificationViewModel,
UserVerificationData(
actionType = UserVerificationActionType.EDIT_DATABASE_SETTING,
database = mDatabase,
preferenceKey = preference.key
)
)
}
// Could not be handled here. Try with the super method.
else if (otherDialogFragment) {
super.onDisplayPreferenceDialog(preference)
}
}
override fun onResume() {
super.onResume()
context?.let { context ->
mDatabaseAutoSaveEnabled = PreferencesUtil.isAutoSaveDatabaseEnabled(context)
}
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
// To reload group when database settings are modified
when (preference.key) {
getString(R.string.database_name_key),
getString(R.string.database_description_key),
getString(R.string.database_default_username_key),
getString(R.string.database_custom_color_key),
getString(R.string.database_data_compression_key),
getString(R.string.database_data_remove_unlinked_attachments_key),
getString(R.string.recycle_bin_enable_key),
getString(R.string.recycle_bin_group_key),
getString(R.string.templates_group_enable_key),
getString(R.string.templates_group_uuid_key),
getString(R.string.max_history_items_key),
getString(R.string.max_history_size_key) -> {
NestedAppSettingsFragment.DATABASE_PREFERENCE_CHANGED = true
}
}
return super.onPreferenceTreeClick(preference)
}
companion object {
private const val TAG_PREF_FRAGMENT = "TAG_PREF_FRAGMENT"
}
}