mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: Complete refactoring of database action
This commit is contained in:
@@ -217,7 +217,6 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
||||
}
|
||||
|
||||
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
|
||||
super.onDatabaseRetrieved(database)
|
||||
if (database != null) {
|
||||
launchGroupActivityIfLoaded(database)
|
||||
}
|
||||
@@ -228,8 +227,6 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
||||
actionTask: String,
|
||||
result: ActionRunnable.Result
|
||||
) {
|
||||
super.onDatabaseActionFinished(database, actionTask, result)
|
||||
|
||||
if (result.isSuccess) {
|
||||
// Update list
|
||||
when (actionTask) {
|
||||
@@ -392,7 +389,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
|
||||
try {
|
||||
mDatabaseFileUri?.let { databaseUri ->
|
||||
// Create the new database
|
||||
createDatabase(databaseUri, mainCredential)
|
||||
mDatabaseViewModel.createDatabase(databaseUri, mainCredential)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
val error = getString(R.string.error_create_database_file)
|
||||
|
||||
@@ -587,7 +587,7 @@ class MainCredentialActivity : DatabaseModeActivity() {
|
||||
readOnly: Boolean,
|
||||
cipherEncryptDatabase: CipherEncryptDatabase?,
|
||||
fixDuplicateUUID: Boolean) {
|
||||
loadDatabase(
|
||||
mDatabaseViewModel.loadDatabase(
|
||||
databaseUri,
|
||||
mainCredential,
|
||||
readOnly,
|
||||
|
||||
@@ -67,7 +67,7 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
|
||||
}
|
||||
builder.setMessage(stringBuilder)
|
||||
builder.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
actionDatabaseListener?.validateDatabaseChanged()
|
||||
actionDatabaseListener?.onDatabaseChangeValidated()
|
||||
}
|
||||
return builder.create()
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
|
||||
}
|
||||
|
||||
interface ActionDatabaseChangedListener {
|
||||
fun validateDatabaseChanged()
|
||||
fun onDatabaseChangeValidated()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -30,13 +30,17 @@ abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
|
||||
resetAppTimeoutOnTouchOrFocus()
|
||||
onDatabaseRetrieved(uiState.database)
|
||||
}
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
|
||||
onDatabaseActionFinished(
|
||||
uiState.database,
|
||||
uiState.actionTask,
|
||||
uiState.result
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDatabaseViewModel.actionFinished.observe(this) { result ->
|
||||
onDatabaseActionFinished(result.database, result.actionTask, result.result)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -4,7 +4,9 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
|
||||
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
@@ -20,21 +22,26 @@ abstract class DatabaseFragment : Fragment(), DatabaseRetrieval {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
lifecycleScope.launch {
|
||||
// Initialize the parameters
|
||||
mDatabaseViewModel.uiState.collect { uiState ->
|
||||
when (uiState) {
|
||||
is DatabaseViewModel.UIState.Loading -> {}
|
||||
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
|
||||
onDatabaseRetrieved(uiState.database)
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
mDatabaseViewModel.uiState.collect { uiState ->
|
||||
when (uiState) {
|
||||
is DatabaseViewModel.UIState.Loading -> {}
|
||||
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
|
||||
onDatabaseRetrieved(uiState.database)
|
||||
}
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
|
||||
onDatabaseActionFinished(
|
||||
uiState.database,
|
||||
uiState.actionTask,
|
||||
uiState.result
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDatabaseViewModel.actionFinished.observe(viewLifecycleOwner) { result ->
|
||||
onDatabaseActionFinished(result.database, result.actionTask, result.result)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun resetAppTimeoutWhenViewFocusedOrChanged(view: View?) {
|
||||
|
||||
@@ -1,58 +1,120 @@
|
||||
package com.kunzisoft.keepass.activities.legacy
|
||||
|
||||
import android.net.Uri
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Companion.DATABASE_CHANGED_DIALOG_TAG
|
||||
import com.kunzisoft.keepass.activities.stylish.StylishActivity
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.DatabaseTaskProvider
|
||||
import com.kunzisoft.keepass.database.MainCredential
|
||||
import com.kunzisoft.keepass.model.CipherEncryptDatabase
|
||||
import com.kunzisoft.keepass.database.DatabaseTaskProvider.Companion.startDatabaseService
|
||||
import com.kunzisoft.keepass.database.ProgressMessage
|
||||
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.utils.getBinaryDir
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment.Companion.PROGRESS_TASK_DIALOG_TAG
|
||||
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval {
|
||||
|
||||
protected val mDatabaseViewModel: DatabaseViewModel by viewModels()
|
||||
protected var mDatabaseTaskProvider: DatabaseTaskProvider? = null
|
||||
protected var mDatabase: ContextualDatabase? = null
|
||||
protected val mDatabase: ContextualDatabase?
|
||||
get() = mDatabaseViewModel.database
|
||||
|
||||
private var progressTaskDialogFragment: ProgressTaskDialogFragment? = null
|
||||
private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null
|
||||
|
||||
private val mActionDatabaseListener =
|
||||
object : DatabaseChangedDialogFragment.ActionDatabaseChangedListener {
|
||||
override fun onDatabaseChangeValidated() {
|
||||
mDatabaseViewModel.onDatabaseChangeValidated()
|
||||
}
|
||||
}
|
||||
|
||||
private val tempServiceParameters = mutableListOf<Pair<Bundle?, String>>()
|
||||
private val requestPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { _ ->
|
||||
// Whether or not the user has accepted, the service can be started,
|
||||
// There just won't be any notification if it's not allowed.
|
||||
tempServiceParameters.removeFirstOrNull()?.let {
|
||||
startDatabaseService(it.first, it.second)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
mDatabaseViewModel.uiState.collect { uiState ->
|
||||
when (uiState) {
|
||||
is DatabaseViewModel.UIState.Loading -> {}
|
||||
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
|
||||
onDatabaseRetrieved(uiState.database)
|
||||
}
|
||||
|
||||
mDatabaseTaskProvider = DatabaseTaskProvider(this, showDatabaseDialog())
|
||||
is DatabaseViewModel.UIState.OnDatabaseReloaded -> {
|
||||
if (finishActivityIfReloadRequested()) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
mDatabaseTaskProvider?.onDatabaseRetrieved = { database ->
|
||||
val databaseWasReloaded = database?.wasReloaded == true
|
||||
if (databaseWasReloaded && finishActivityIfReloadRequested()) {
|
||||
finish()
|
||||
} else if (mDatabase == null || mDatabase != database || databaseWasReloaded) {
|
||||
database?.wasReloaded = false
|
||||
onDatabaseRetrieved(database)
|
||||
is DatabaseViewModel.UIState.OnDatabaseInfoChanged -> {
|
||||
showDatabaseChangedDialog(
|
||||
uiState.previousDatabaseInfo,
|
||||
uiState.newDatabaseInfo,
|
||||
uiState.readOnlyDatabase
|
||||
)
|
||||
}
|
||||
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionRequested -> {
|
||||
startDatabasePermissionService(
|
||||
uiState.bundle,
|
||||
uiState.actionTask
|
||||
)
|
||||
}
|
||||
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionStarted -> {
|
||||
if (showDatabaseDialog())
|
||||
startDialog(uiState.progressMessage)
|
||||
}
|
||||
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionUpdated -> {
|
||||
if (showDatabaseDialog())
|
||||
updateDialog(uiState.progressMessage)
|
||||
}
|
||||
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionStopped -> {
|
||||
// Remove the progress task
|
||||
stopDialog()
|
||||
}
|
||||
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
|
||||
onDatabaseActionFinished(
|
||||
uiState.database,
|
||||
uiState.actionTask,
|
||||
uiState.result
|
||||
)
|
||||
stopDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mDatabaseTaskProvider?.onActionFinish = { database, actionTask, result ->
|
||||
onDatabaseActionFinished(database, actionTask, result)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun showDatabaseDialog(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
mDatabaseTaskProvider?.destroy()
|
||||
mDatabaseTaskProvider = null
|
||||
mDatabase = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
||||
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
|
||||
mDatabase = database
|
||||
mDatabaseViewModel.defineDatabase(database)
|
||||
// optional method implementation
|
||||
}
|
||||
|
||||
@@ -61,44 +123,100 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval {
|
||||
actionTask: String,
|
||||
result: ActionRunnable.Result
|
||||
) {
|
||||
mDatabaseViewModel.onActionFinished(database, actionTask, result)
|
||||
// optional method implementation
|
||||
}
|
||||
|
||||
fun createDatabase(
|
||||
databaseUri: Uri,
|
||||
mainCredential: MainCredential
|
||||
private fun startDatabasePermissionService(bundle: Bundle?, actionTask: String) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
|
||||
== PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
startDatabaseService(bundle, actionTask)
|
||||
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.POST_NOTIFICATIONS
|
||||
)
|
||||
) {
|
||||
// it's not the first time, so the user deliberately chooses not to display the notification
|
||||
startDatabaseService(bundle, actionTask)
|
||||
} else {
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(R.string.warning_database_notification_permission)
|
||||
.setNegativeButton(R.string.later) { _, _ ->
|
||||
// Refuses the notification, so start the service
|
||||
startDatabaseService(bundle, actionTask)
|
||||
}
|
||||
.setPositiveButton(R.string.ask) { _, _ ->
|
||||
// Save the temp parameters to ask the permission
|
||||
tempServiceParameters.add(Pair(bundle, actionTask))
|
||||
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}.create().show()
|
||||
}
|
||||
} else {
|
||||
startDatabaseService(bundle, actionTask)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDatabaseChangedDialog(
|
||||
previousDatabaseInfo: SnapFileDatabaseInfo,
|
||||
newDatabaseInfo: SnapFileDatabaseInfo,
|
||||
readOnlyDatabase: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider?.startDatabaseCreate(databaseUri, mainCredential)
|
||||
lifecycleScope.launch {
|
||||
if (databaseChangedDialogFragment == null) {
|
||||
databaseChangedDialogFragment = supportFragmentManager
|
||||
.findFragmentByTag(DATABASE_CHANGED_DIALOG_TAG) as DatabaseChangedDialogFragment?
|
||||
databaseChangedDialogFragment?.actionDatabaseListener =
|
||||
mActionDatabaseListener
|
||||
}
|
||||
if (progressTaskDialogFragment == null) {
|
||||
databaseChangedDialogFragment = DatabaseChangedDialogFragment.getInstance(
|
||||
previousDatabaseInfo,
|
||||
newDatabaseInfo,
|
||||
readOnlyDatabase
|
||||
)
|
||||
databaseChangedDialogFragment?.actionDatabaseListener =
|
||||
mActionDatabaseListener
|
||||
databaseChangedDialogFragment?.show(
|
||||
supportFragmentManager,
|
||||
DATABASE_CHANGED_DIALOG_TAG
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDatabase(
|
||||
databaseUri: Uri,
|
||||
mainCredential: MainCredential,
|
||||
readOnly: Boolean,
|
||||
cipherEncryptDatabase: CipherEncryptDatabase?,
|
||||
fixDuplicateUuid: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider?.startDatabaseLoad(
|
||||
databaseUri,
|
||||
mainCredential,
|
||||
readOnly,
|
||||
cipherEncryptDatabase,
|
||||
fixDuplicateUuid
|
||||
)
|
||||
private fun startDialog(progressMessage: ProgressMessage) {
|
||||
lifecycleScope.launch {
|
||||
if (progressTaskDialogFragment == null) {
|
||||
progressTaskDialogFragment = supportFragmentManager
|
||||
.findFragmentByTag(PROGRESS_TASK_DIALOG_TAG) as ProgressTaskDialogFragment?
|
||||
}
|
||||
if (progressTaskDialogFragment == null) {
|
||||
progressTaskDialogFragment = ProgressTaskDialogFragment()
|
||||
progressTaskDialogFragment?.show(
|
||||
supportFragmentManager,
|
||||
PROGRESS_TASK_DIALOG_TAG
|
||||
)
|
||||
}
|
||||
updateDialog(progressMessage)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun closeDatabase() {
|
||||
mDatabase?.clearAndClose(this.getBinaryDir())
|
||||
private fun updateDialog(progressMessage: ProgressMessage) {
|
||||
progressTaskDialogFragment?.apply {
|
||||
updateTitle(progressMessage.titleId)
|
||||
updateMessage(progressMessage.messageId)
|
||||
updateWarning(progressMessage.warningId)
|
||||
setCancellable(progressMessage.cancelable)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mDatabaseTaskProvider?.registerProgressTask()
|
||||
private fun stopDialog() {
|
||||
progressTaskDialogFragment?.dismissAllowingStateLoss()
|
||||
progressTaskDialogFragment = null
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
mDatabaseTaskProvider?.unregisterProgressTask()
|
||||
super.onPause()
|
||||
|
||||
protected open fun showDatabaseDialog(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -87,80 +87,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
deleteDatabaseNodes(nodes)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveDatabase.observe(this) { save ->
|
||||
mDatabaseTaskProvider?.startDatabaseSave(save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.mergeDatabase.observe(this) { save ->
|
||||
mDatabaseTaskProvider?.startDatabaseMerge(save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.reloadDatabase.observe(this) { fixDuplicateUuid ->
|
||||
mDatabaseTaskProvider?.askToStartDatabaseReload(mDatabase?.dataModifiedSinceLastLoading != false) {
|
||||
mDatabaseTaskProvider?.startDatabaseReload(fixDuplicateUuid)
|
||||
}
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveName.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveName(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveDescription.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveDescription(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveDefaultUsername.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveDefaultUsername(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveColor.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveColor(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveCompression.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveCompression(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.removeUnlinkData.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseRemoveUnlinkedData(it)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveRecycleBin.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveRecycleBin(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveTemplatesGroup.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveTemplatesGroup(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveMaxHistoryItems.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveMaxHistoryItems(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveMaxHistorySize.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveMaxHistorySize(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveEncryption.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveEncryption(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveKeyDerivation.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveKeyDerivation(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveIterations.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveIterations(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveMemoryUsage.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveMemoryUsage(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mDatabaseViewModel.saveParallelism.observe(this) {
|
||||
mDatabaseTaskProvider?.startDatabaseSaveParallelism(it.oldValue, it.newValue, it.save)
|
||||
}
|
||||
|
||||
mExitLock = false
|
||||
}
|
||||
|
||||
@@ -169,8 +95,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
}
|
||||
|
||||
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
|
||||
super.onDatabaseRetrieved(database)
|
||||
|
||||
// End activity if database not loaded
|
||||
if (finishActivityIfDatabaseNotLoaded() && (database == null || !database.loaded)) {
|
||||
finish()
|
||||
@@ -186,7 +110,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
if (mTimeoutEnable) {
|
||||
if (mLockReceiver == null) {
|
||||
mLockReceiver = LockReceiver {
|
||||
mDatabase = null
|
||||
closeDatabase(database)
|
||||
mExitLock = true
|
||||
closeOptionsMenu()
|
||||
@@ -227,7 +150,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
actionTask: String,
|
||||
result: ActionRunnable.Result
|
||||
) {
|
||||
super.onDatabaseActionFinished(database, actionTask, result)
|
||||
when (actionTask) {
|
||||
DatabaseTaskNotificationService.ACTION_DATABASE_MERGE_TASK,
|
||||
DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> {
|
||||
@@ -249,24 +171,15 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
databaseUri: Uri?,
|
||||
mainCredential: MainCredential
|
||||
) {
|
||||
assignDatabasePassword(databaseUri, mainCredential)
|
||||
mDatabaseViewModel.assignMainCredential(databaseUri, mainCredential)
|
||||
}
|
||||
|
||||
private fun assignDatabasePassword(
|
||||
databaseUri: Uri?,
|
||||
mainCredential: MainCredential
|
||||
) {
|
||||
if (databaseUri != null) {
|
||||
mDatabaseTaskProvider?.startDatabaseAssignCredential(databaseUri, mainCredential)
|
||||
}
|
||||
}
|
||||
|
||||
fun assignPassword(mainCredential: MainCredential) {
|
||||
fun assignMainCredential(mainCredential: MainCredential) {
|
||||
mDatabase?.let { database ->
|
||||
database.fileUri?.let { databaseUri ->
|
||||
// Show the progress dialog now or after dialog confirmation
|
||||
if (database.isValidCredential(mainCredential.toMasterCredential(contentResolver))) {
|
||||
assignDatabasePassword(databaseUri, mainCredential)
|
||||
mDatabaseViewModel.assignMainCredential(databaseUri, mainCredential)
|
||||
} else {
|
||||
PasswordEncodingDialogFragment.getInstance(databaseUri, mainCredential)
|
||||
.show(supportFragmentManager, "passwordEncodingTag")
|
||||
@@ -276,45 +189,51 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
}
|
||||
|
||||
fun saveDatabase() {
|
||||
mDatabaseTaskProvider?.startDatabaseSave(true)
|
||||
mDatabaseViewModel.saveDatabase(save = true)
|
||||
}
|
||||
|
||||
fun saveDatabaseTo(uri: Uri) {
|
||||
mDatabaseTaskProvider?.startDatabaseSave(true, uri)
|
||||
mDatabaseViewModel.saveDatabase(save = true, saveToUri = uri)
|
||||
}
|
||||
|
||||
fun mergeDatabase() {
|
||||
mDatabaseTaskProvider?.startDatabaseMerge(mAutoSaveEnable)
|
||||
mDatabaseViewModel.mergeDatabase(save = mAutoSaveEnable)
|
||||
}
|
||||
|
||||
fun mergeDatabaseFrom(uri: Uri, mainCredential: MainCredential) {
|
||||
mDatabaseTaskProvider?.startDatabaseMerge(mAutoSaveEnable, uri, mainCredential)
|
||||
mDatabaseViewModel.mergeDatabase(mAutoSaveEnable, uri, mainCredential)
|
||||
}
|
||||
|
||||
fun reloadDatabase() {
|
||||
mDatabaseTaskProvider?.askToStartDatabaseReload(mDatabase?.dataModifiedSinceLastLoading != false) {
|
||||
mDatabaseTaskProvider?.startDatabaseReload(false)
|
||||
}
|
||||
mDatabaseViewModel.reloadDatabase(fixDuplicateUuid = false)
|
||||
}
|
||||
|
||||
fun createEntry(newEntry: Entry,
|
||||
parent: Group) {
|
||||
mDatabaseTaskProvider?.startDatabaseCreateEntry(newEntry, parent, mAutoSaveEnable)
|
||||
fun createEntry(
|
||||
newEntry: Entry,
|
||||
parent: Group
|
||||
) {
|
||||
mDatabaseViewModel.createEntry(newEntry, parent, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
fun updateEntry(oldEntry: Entry,
|
||||
entryToUpdate: Entry) {
|
||||
mDatabaseTaskProvider?.startDatabaseUpdateEntry(oldEntry, entryToUpdate, mAutoSaveEnable)
|
||||
fun updateEntry(
|
||||
oldEntry: Entry,
|
||||
entryToUpdate: Entry
|
||||
) {
|
||||
mDatabaseViewModel.updateEntry(oldEntry, entryToUpdate, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
fun copyNodes(nodesToCopy: List<Node>,
|
||||
newParent: Group) {
|
||||
mDatabaseTaskProvider?.startDatabaseCopyNodes(nodesToCopy, newParent, mAutoSaveEnable)
|
||||
fun copyNodes(
|
||||
nodesToCopy: List<Node>,
|
||||
newParent: Group
|
||||
) {
|
||||
mDatabaseViewModel.copyNodes(nodesToCopy, newParent, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
fun moveNodes(nodesToMove: List<Node>,
|
||||
newParent: Group) {
|
||||
mDatabaseTaskProvider?.startDatabaseMoveNodes(nodesToMove, newParent, mAutoSaveEnable)
|
||||
fun moveNodes(
|
||||
nodesToMove: List<Node>,
|
||||
newParent: Group
|
||||
) {
|
||||
mDatabaseViewModel.moveNodes(nodesToMove, newParent, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
private fun eachNodeRecyclable(database: ContextualDatabase, nodes: List<Node>): Boolean {
|
||||
@@ -330,6 +249,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
}
|
||||
|
||||
fun deleteNodes(nodes: List<Node>, recycleBin: Boolean = false) {
|
||||
// TODO Move in ViewModel
|
||||
mDatabase?.let { database ->
|
||||
// If recycle bin enabled, ensure it exists
|
||||
if (database.isRecycleBinEnabled) {
|
||||
@@ -350,11 +270,14 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
}
|
||||
|
||||
private fun deleteDatabaseNodes(nodes: List<Node>) {
|
||||
mDatabaseTaskProvider?.startDatabaseDeleteNodes(nodes, mAutoSaveEnable)
|
||||
mDatabaseViewModel.deleteNodes(nodes, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
fun createGroup(parent: Group,
|
||||
groupInfo: GroupInfo?) {
|
||||
fun createGroup(
|
||||
parent: Group,
|
||||
groupInfo: GroupInfo?
|
||||
) {
|
||||
// TODO Move in ViewModel
|
||||
// Build the group
|
||||
mDatabase?.createGroup()?.let { newGroup ->
|
||||
groupInfo?.let { info ->
|
||||
@@ -362,12 +285,15 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
}
|
||||
// Not really needed here because added in runnable but safe
|
||||
newGroup.parent = parent
|
||||
mDatabaseTaskProvider?.startDatabaseCreateGroup(newGroup, parent, mAutoSaveEnable)
|
||||
mDatabaseViewModel.createGroup(newGroup, parent, mAutoSaveEnable)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateGroup(oldGroup: Group,
|
||||
groupInfo: GroupInfo) {
|
||||
fun updateGroup(
|
||||
oldGroup: Group,
|
||||
groupInfo: GroupInfo
|
||||
) {
|
||||
// TODO Move in ViewModel
|
||||
// If group updated save it in the database
|
||||
val updateGroup = Group(oldGroup).let { updateGroup ->
|
||||
updateGroup.apply {
|
||||
@@ -377,18 +303,21 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
|
||||
this.setGroupInfo(groupInfo)
|
||||
}
|
||||
}
|
||||
mDatabaseTaskProvider?.startDatabaseUpdateGroup(oldGroup, updateGroup, mAutoSaveEnable)
|
||||
mDatabaseViewModel.updateGroup(oldGroup, updateGroup, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
fun restoreEntryHistory(mainEntryId: NodeId<UUID>,
|
||||
entryHistoryPosition: Int) {
|
||||
mDatabaseTaskProvider
|
||||
?.startDatabaseRestoreEntryHistory(mainEntryId, entryHistoryPosition, mAutoSaveEnable)
|
||||
fun restoreEntryHistory(
|
||||
mainEntryId: NodeId<UUID>,
|
||||
entryHistoryPosition: Int
|
||||
) {
|
||||
mDatabaseViewModel.restoreEntryHistory(mainEntryId, entryHistoryPosition, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
fun deleteEntryHistory(mainEntryId: NodeId<UUID>,
|
||||
entryHistoryPosition: Int) {
|
||||
mDatabaseTaskProvider?.startDatabaseDeleteEntryHistory(mainEntryId, entryHistoryPosition, mAutoSaveEnable)
|
||||
fun deleteEntryHistory(
|
||||
mainEntryId: NodeId<UUID>,
|
||||
entryHistoryPosition: Int
|
||||
) {
|
||||
mDatabaseViewModel.deleteEntryHistory(mainEntryId, entryHistoryPosition, mAutoSaveEnable)
|
||||
}
|
||||
|
||||
private fun checkRegister() {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database
|
||||
|
||||
import android.Manifest
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
@@ -29,23 +28,16 @@ import android.content.Context.BIND_IMPORTANT
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.ServiceConnection
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Companion.DATABASE_CHANGED_DIALOG_TAG
|
||||
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
||||
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
|
||||
import com.kunzisoft.keepass.database.element.Entry
|
||||
@@ -55,7 +47,6 @@ import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
import com.kunzisoft.keepass.model.CipherEncryptDatabase
|
||||
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_CHALLENGE_RESPONDED
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_ASSIGN_CREDENTIAL_TASK
|
||||
@@ -89,13 +80,9 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
|
||||
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
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment.Companion.PROGRESS_TASK_DIALOG_TAG
|
||||
import com.kunzisoft.keepass.utils.DATABASE_START_TASK_ACTION
|
||||
import com.kunzisoft.keepass.utils.DATABASE_STOP_TASK_ACTION
|
||||
import com.kunzisoft.keepass.utils.putParcelableList
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
@@ -103,121 +90,41 @@ import java.util.UUID
|
||||
* Useful to retrieve a database instance and sending tasks commands
|
||||
*/
|
||||
class DatabaseTaskProvider(
|
||||
private var context: Context,
|
||||
private var showDialog: Boolean = true
|
||||
private var context: Context
|
||||
) {
|
||||
|
||||
// To show dialog only if context is an activity
|
||||
private var activity: FragmentActivity? = try {
|
||||
context as? FragmentActivity?
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
var onDatabaseRetrieved: ((database: ContextualDatabase?) -> Unit)? = null
|
||||
|
||||
var onActionFinish: ((
|
||||
database: ContextualDatabase,
|
||||
actionTask: String,
|
||||
result: ActionRunnable.Result
|
||||
) -> Unit)? = null
|
||||
|
||||
private var intentDatabaseTask: Intent = Intent(
|
||||
context.applicationContext,
|
||||
DatabaseTaskNotificationService::class.java
|
||||
)
|
||||
var onStartActionRequested: ((bundle: Bundle?, actionTask: String) -> Unit)? = null
|
||||
var actionTaskListener: DatabaseTaskNotificationService.ActionTaskListener? = null
|
||||
var databaseInfoListener: DatabaseTaskNotificationService.DatabaseInfoListener? = null
|
||||
|
||||
private var databaseTaskBroadcastReceiver: BroadcastReceiver? = null
|
||||
private var mBinder: DatabaseTaskNotificationService.ActionTaskBinder? = null
|
||||
|
||||
private var serviceConnection: ServiceConnection? = null
|
||||
|
||||
private var progressTaskDialogFragment: ProgressTaskDialogFragment? = null
|
||||
private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null
|
||||
private var intentDatabaseTask: Intent = Intent(
|
||||
context.applicationContext,
|
||||
DatabaseTaskNotificationService::class.java
|
||||
)
|
||||
|
||||
fun destroy() {
|
||||
this.activity = null
|
||||
this.onDatabaseRetrieved = null
|
||||
this.onActionFinish = null
|
||||
this.databaseTaskBroadcastReceiver = null
|
||||
this.mBinder = null
|
||||
this.serviceConnection = null
|
||||
this.progressTaskDialogFragment = null
|
||||
this.databaseChangedDialogFragment = null
|
||||
}
|
||||
|
||||
private val actionTaskListener = object : DatabaseTaskNotificationService.ActionTaskListener {
|
||||
override fun onActionStarted(
|
||||
database: ContextualDatabase,
|
||||
progressMessage: ProgressMessage
|
||||
) {
|
||||
if (showDialog)
|
||||
startDialog(progressMessage)
|
||||
}
|
||||
|
||||
override fun onActionUpdated(
|
||||
database: ContextualDatabase,
|
||||
progressMessage: ProgressMessage
|
||||
) {
|
||||
if (showDialog)
|
||||
updateDialog(progressMessage)
|
||||
}
|
||||
|
||||
override fun onActionStopped(
|
||||
database: ContextualDatabase
|
||||
) {
|
||||
// Remove the progress task
|
||||
stopDialog()
|
||||
}
|
||||
|
||||
override fun onActionFinished(
|
||||
database: ContextualDatabase,
|
||||
actionTask: String,
|
||||
result: ActionRunnable.Result
|
||||
) {
|
||||
onActionFinish?.invoke(database, actionTask, result)
|
||||
onActionStopped(database)
|
||||
}
|
||||
}
|
||||
|
||||
private val mActionDatabaseListener =
|
||||
object : DatabaseChangedDialogFragment.ActionDatabaseChangedListener {
|
||||
override fun validateDatabaseChanged() {
|
||||
override fun onDatabaseChangeValidated() {
|
||||
mBinder?.getService()?.saveDatabaseInfo()
|
||||
}
|
||||
}
|
||||
|
||||
private var databaseInfoListener = object :
|
||||
DatabaseTaskNotificationService.DatabaseInfoListener {
|
||||
override fun onDatabaseInfoChanged(
|
||||
previousDatabaseInfo: SnapFileDatabaseInfo,
|
||||
newDatabaseInfo: SnapFileDatabaseInfo,
|
||||
readOnlyDatabase: Boolean
|
||||
) {
|
||||
activity?.let { activity ->
|
||||
activity.lifecycleScope.launch {
|
||||
if (databaseChangedDialogFragment == null) {
|
||||
databaseChangedDialogFragment = activity.supportFragmentManager
|
||||
.findFragmentByTag(DATABASE_CHANGED_DIALOG_TAG) as DatabaseChangedDialogFragment?
|
||||
databaseChangedDialogFragment?.actionDatabaseListener =
|
||||
mActionDatabaseListener
|
||||
}
|
||||
if (progressTaskDialogFragment == null) {
|
||||
databaseChangedDialogFragment = DatabaseChangedDialogFragment.getInstance(
|
||||
previousDatabaseInfo,
|
||||
newDatabaseInfo,
|
||||
readOnlyDatabase
|
||||
)
|
||||
databaseChangedDialogFragment?.actionDatabaseListener =
|
||||
mActionDatabaseListener
|
||||
databaseChangedDialogFragment?.show(
|
||||
activity.supportFragmentManager,
|
||||
DATABASE_CHANGED_DIALOG_TAG
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onDatabaseChangeValidated() {
|
||||
mBinder?.getService()?.saveDatabaseInfo()
|
||||
}
|
||||
|
||||
private var databaseListener = object : DatabaseTaskNotificationService.DatabaseListener {
|
||||
@@ -226,49 +133,16 @@ class DatabaseTaskProvider(
|
||||
}
|
||||
}
|
||||
|
||||
private fun startDialog(progressMessage: ProgressMessage) {
|
||||
activity?.let { activity ->
|
||||
activity.lifecycleScope.launch {
|
||||
if (progressTaskDialogFragment == null) {
|
||||
progressTaskDialogFragment = activity.supportFragmentManager
|
||||
.findFragmentByTag(PROGRESS_TASK_DIALOG_TAG) as ProgressTaskDialogFragment?
|
||||
}
|
||||
if (progressTaskDialogFragment == null) {
|
||||
progressTaskDialogFragment = ProgressTaskDialogFragment()
|
||||
progressTaskDialogFragment?.show(
|
||||
activity.supportFragmentManager,
|
||||
PROGRESS_TASK_DIALOG_TAG
|
||||
)
|
||||
}
|
||||
updateDialog(progressMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDialog(progressMessage: ProgressMessage) {
|
||||
progressTaskDialogFragment?.apply {
|
||||
updateTitle(progressMessage.titleId)
|
||||
updateMessage(progressMessage.messageId)
|
||||
updateWarning(progressMessage.warningId)
|
||||
setCancellable(progressMessage.cancelable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopDialog() {
|
||||
progressTaskDialogFragment?.dismissAllowingStateLoss()
|
||||
progressTaskDialogFragment = null
|
||||
}
|
||||
|
||||
private fun initServiceConnection() {
|
||||
stopDialog()
|
||||
actionTaskListener?.onActionStopped()
|
||||
if (serviceConnection == null) {
|
||||
serviceConnection = object : ServiceConnection {
|
||||
override fun onBindingDied(name: ComponentName?) {
|
||||
stopDialog()
|
||||
actionTaskListener?.onActionStopped()
|
||||
}
|
||||
|
||||
override fun onNullBinding(name: ComponentName?) {
|
||||
stopDialog()
|
||||
actionTaskListener?.onActionStopped()
|
||||
}
|
||||
|
||||
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
|
||||
@@ -291,13 +165,21 @@ class DatabaseTaskProvider(
|
||||
|
||||
private fun addServiceListeners(service: DatabaseTaskNotificationService.ActionTaskBinder?) {
|
||||
service?.addDatabaseListener(databaseListener)
|
||||
service?.addDatabaseFileInfoListener(databaseInfoListener)
|
||||
service?.addActionTaskListener(actionTaskListener)
|
||||
databaseInfoListener?.let { infoListener ->
|
||||
service?.addDatabaseFileInfoListener(infoListener)
|
||||
}
|
||||
actionTaskListener?.let { taskListener ->
|
||||
service?.addActionTaskListener(taskListener)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeServiceListeners(service: DatabaseTaskNotificationService.ActionTaskBinder?) {
|
||||
service?.removeActionTaskListener(actionTaskListener)
|
||||
service?.removeDatabaseFileInfoListener(databaseInfoListener)
|
||||
actionTaskListener?.let { taskListener ->
|
||||
service?.removeActionTaskListener(taskListener)
|
||||
}
|
||||
databaseInfoListener?.let { infoListener ->
|
||||
service?.removeDatabaseFileInfoListener(infoListener)
|
||||
}
|
||||
service?.removeDatabaseListener(databaseListener)
|
||||
}
|
||||
|
||||
@@ -369,58 +251,9 @@ class DatabaseTaskProvider(
|
||||
}
|
||||
}
|
||||
|
||||
private val tempServiceParameters = mutableListOf<Pair<Bundle?, String>>()
|
||||
private val requestPermissionLauncher = activity?.registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { _ ->
|
||||
// Whether or not the user has accepted, the service can be started,
|
||||
// There just won't be any notification if it's not allowed.
|
||||
tempServiceParameters.removeFirstOrNull()?.let {
|
||||
startService(it.first, it.second)
|
||||
}
|
||||
}
|
||||
|
||||
private fun start(bundle: Bundle? = null, actionTask: String) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val contextActivity = activity
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS)
|
||||
== PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
startService(bundle, actionTask)
|
||||
} else if (contextActivity != null && shouldShowRequestPermissionRationale(
|
||||
contextActivity,
|
||||
Manifest.permission.POST_NOTIFICATIONS
|
||||
)
|
||||
) {
|
||||
// it's not the first time, so the user deliberately chooses not to display the notification
|
||||
startService(bundle, actionTask)
|
||||
} else {
|
||||
AlertDialog.Builder(context)
|
||||
.setMessage(R.string.warning_database_notification_permission)
|
||||
.setNegativeButton(R.string.later) { _, _ ->
|
||||
// Refuses the notification, so start the service
|
||||
startService(bundle, actionTask)
|
||||
}
|
||||
.setPositiveButton(R.string.ask) { _, _ ->
|
||||
// Save the temp parameters to ask the permission
|
||||
tempServiceParameters.add(Pair(bundle, actionTask))
|
||||
requestPermissionLauncher?.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}.create().show()
|
||||
}
|
||||
} else {
|
||||
startService(bundle, actionTask)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startService(bundle: Bundle? = null, actionTask: String) {
|
||||
try {
|
||||
if (bundle != null)
|
||||
intentDatabaseTask.putExtras(bundle)
|
||||
intentDatabaseTask.action = actionTask
|
||||
context.startService(intentDatabaseTask)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to perform database action", e)
|
||||
Toast.makeText(context, R.string.error_start_database_action, Toast.LENGTH_LONG).show()
|
||||
onStartActionRequested?.invoke(bundle, actionTask) ?: run {
|
||||
context.startDatabaseService(bundle, actionTask)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -843,5 +676,21 @@ class DatabaseTaskProvider(
|
||||
|
||||
companion object {
|
||||
private val TAG = DatabaseTaskProvider::class.java.name
|
||||
|
||||
fun Context.startDatabaseService(bundle: Bundle? = null, actionTask: String) {
|
||||
try {
|
||||
val intentDatabaseTask = Intent(
|
||||
applicationContext,
|
||||
DatabaseTaskNotificationService::class.java
|
||||
)
|
||||
if (bundle != null)
|
||||
intentDatabaseTask.putExtras(bundle)
|
||||
intentDatabaseTask.action = actionTask
|
||||
startService(intentDatabaseTask)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to perform database action", e)
|
||||
Toast.makeText(this, R.string.error_start_database_action, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ class HardwareKeyActivity: DatabaseModeActivity(){
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
val challengeResponse: ByteArray? = result.data?.getByteArrayExtra(HARDWARE_KEY_RESPONSE_KEY)
|
||||
Log.d(TAG, "Response form challenge")
|
||||
mDatabaseTaskProvider?.startChallengeResponded(challengeResponse ?: ByteArray(0))
|
||||
mDatabaseViewModel.onChallengeResponded(challengeResponse)
|
||||
} else {
|
||||
Log.e(TAG, "Response from challenge error")
|
||||
mDatabaseTaskProvider?.startChallengeResponded(ByteArray(0))
|
||||
mDatabaseViewModel.onChallengeResponded(null)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
@@ -49,13 +49,11 @@ class HardwareKeyActivity: DatabaseModeActivity(){
|
||||
}
|
||||
|
||||
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
|
||||
super.onDatabaseRetrieved(database)
|
||||
|
||||
val hardwareKey = HardwareKey.getHardwareKeyFromString(
|
||||
intent.getStringExtra(DATA_HARDWARE_KEY)
|
||||
)
|
||||
if (isHardwareKeyAvailable(this, hardwareKey, true) {
|
||||
mDatabaseTaskProvider?.startChallengeResponded(ByteArray(0))
|
||||
mDatabaseViewModel.onChallengeResponded(null)
|
||||
}) {
|
||||
when (hardwareKey) {
|
||||
/*
|
||||
|
||||
@@ -176,7 +176,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
||||
progressMessage: ProgressMessage
|
||||
)
|
||||
fun onActionStopped(
|
||||
database: ContextualDatabase
|
||||
database: ContextualDatabase? = null
|
||||
)
|
||||
fun onActionFinished(
|
||||
database: ContextualDatabase,
|
||||
|
||||
@@ -60,6 +60,7 @@ class MainPreferenceFragment : PreferenceFragmentCompat() {
|
||||
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
|
||||
checkDatabaseLoaded(uiState.database?.loaded == true)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,12 @@ package com.kunzisoft.keepass.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
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
|
||||
@@ -40,10 +45,29 @@ 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.*
|
||||
import com.kunzisoft.keepass.database.helper.getLocalizedName
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
||||
import com.kunzisoft.keepass.settings.preference.*
|
||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.*
|
||||
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
|
||||
@@ -131,13 +155,17 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
)
|
||||
onDatabaseRetrieved(uiState.database)
|
||||
}
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
|
||||
onDatabaseActionFinished(
|
||||
uiState.database,
|
||||
uiState.actionTask,
|
||||
uiState.result
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDatabaseViewModel.actionFinished.observe(viewLifecycleOwner) {
|
||||
onDatabaseActionFinished(it.database, it.actionTask, it.result)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
||||
@@ -192,7 +192,7 @@ open class SettingsActivity
|
||||
}
|
||||
|
||||
override fun onAssignKeyDialogPositiveClick(mainCredential: MainCredential) {
|
||||
assignPassword(mainCredential)
|
||||
assignMainCredential(mainCredential)
|
||||
}
|
||||
|
||||
override fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential) {}
|
||||
|
||||
@@ -59,6 +59,14 @@ abstract class DatabaseSavePreferenceDialogFragmentCompat
|
||||
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
|
||||
onDatabaseRetrieved(uiState.database)
|
||||
}
|
||||
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
|
||||
onDatabaseActionFinished(
|
||||
uiState.database,
|
||||
uiState.actionTask,
|
||||
uiState.result
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,8 +89,10 @@ abstract class DatabaseSavePreferenceDialogFragmentCompat
|
||||
// To inherit to save element in database
|
||||
}
|
||||
|
||||
protected fun saveColor(oldColor: Int?,
|
||||
newColor: Int?) {
|
||||
protected fun saveColor(
|
||||
oldColor: Int?,
|
||||
newColor: Int?
|
||||
) {
|
||||
val oldColorString = if (oldColor != null)
|
||||
ChromaUtil.getFormattedColorString(oldColor, false)
|
||||
else
|
||||
@@ -91,77 +101,158 @@ abstract class DatabaseSavePreferenceDialogFragmentCompat
|
||||
ChromaUtil.getFormattedColorString(newColor, false)
|
||||
else
|
||||
""
|
||||
mDatabaseViewModel.saveColor(oldColorString, newColorString, mDatabaseAutoSaveEnable)
|
||||
mDatabaseViewModel.saveColor(
|
||||
oldColorString,
|
||||
newColorString,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveCompression(oldCompression: CompressionAlgorithm,
|
||||
newCompression: CompressionAlgorithm
|
||||
protected fun saveCompression(
|
||||
oldCompression: CompressionAlgorithm,
|
||||
newCompression: CompressionAlgorithm
|
||||
) {
|
||||
mDatabaseViewModel.saveCompression(oldCompression, newCompression, mDatabaseAutoSaveEnable)
|
||||
mDatabaseViewModel.saveCompression(
|
||||
oldCompression,
|
||||
newCompression,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveDefaultUsername(oldUsername: String,
|
||||
newUsername: String) {
|
||||
mDatabaseViewModel.saveDefaultUsername(oldUsername, newUsername, mDatabaseAutoSaveEnable)
|
||||
protected fun saveDefaultUsername(
|
||||
oldUsername: String,
|
||||
newUsername: String
|
||||
) {
|
||||
mDatabaseViewModel.saveDefaultUsername(
|
||||
oldUsername,
|
||||
newUsername,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveDescription(oldDescription: String,
|
||||
newDescription: String) {
|
||||
mDatabaseViewModel.saveDescription(oldDescription, newDescription, mDatabaseAutoSaveEnable)
|
||||
protected fun saveDescription(
|
||||
oldDescription: String,
|
||||
newDescription: String
|
||||
) {
|
||||
mDatabaseViewModel.saveDescription(
|
||||
oldDescription,
|
||||
newDescription,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveEncryption(oldEncryption: EncryptionAlgorithm,
|
||||
newEncryptionAlgorithm: EncryptionAlgorithm) {
|
||||
mDatabaseViewModel.saveEncryption(oldEncryption, newEncryptionAlgorithm, mDatabaseAutoSaveEnable)
|
||||
protected fun saveEncryption(
|
||||
oldEncryption: EncryptionAlgorithm,
|
||||
newEncryptionAlgorithm: EncryptionAlgorithm
|
||||
) {
|
||||
mDatabaseViewModel.saveEncryption(
|
||||
oldEncryption,
|
||||
newEncryptionAlgorithm,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveKeyDerivation(oldKeyDerivation: KdfEngine,
|
||||
newKeyDerivation: KdfEngine) {
|
||||
mDatabaseViewModel.saveKeyDerivation(oldKeyDerivation, newKeyDerivation, mDatabaseAutoSaveEnable)
|
||||
protected fun saveKeyDerivation(
|
||||
oldKeyDerivation: KdfEngine,
|
||||
newKeyDerivation: KdfEngine
|
||||
) {
|
||||
mDatabaseViewModel.saveKeyDerivation(
|
||||
oldKeyDerivation,
|
||||
newKeyDerivation,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveName(oldName: String,
|
||||
newName: String) {
|
||||
mDatabaseViewModel.saveName(oldName, newName, mDatabaseAutoSaveEnable)
|
||||
protected fun saveName(
|
||||
oldName: String,
|
||||
newName: String
|
||||
) {
|
||||
mDatabaseViewModel.saveName(
|
||||
oldName,
|
||||
newName,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveRecycleBin(oldGroup: Group?,
|
||||
newGroup: Group?) {
|
||||
mDatabaseViewModel.saveRecycleBin(oldGroup, newGroup, mDatabaseAutoSaveEnable)
|
||||
protected fun saveRecycleBin(
|
||||
oldGroup: Group?,
|
||||
newGroup: Group?
|
||||
) {
|
||||
mDatabaseViewModel.saveRecycleBin(
|
||||
oldGroup,
|
||||
newGroup,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun removeUnlinkedData() {
|
||||
mDatabaseViewModel.removeUnlinkedData(mDatabaseAutoSaveEnable)
|
||||
}
|
||||
|
||||
protected fun saveTemplatesGroup(oldGroup: Group?,
|
||||
newGroup: Group?) {
|
||||
mDatabaseViewModel.saveTemplatesGroup(oldGroup, newGroup, mDatabaseAutoSaveEnable)
|
||||
protected fun saveTemplatesGroup(
|
||||
oldGroup: Group?,
|
||||
newGroup: Group?
|
||||
) {
|
||||
mDatabaseViewModel.saveTemplatesGroup(
|
||||
oldGroup,
|
||||
newGroup,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveMaxHistoryItems(oldNumber: Int,
|
||||
newNumber: Int) {
|
||||
mDatabaseViewModel.saveMaxHistoryItems(oldNumber, newNumber, mDatabaseAutoSaveEnable)
|
||||
protected fun saveMaxHistoryItems(
|
||||
oldNumber: Int,
|
||||
newNumber: Int
|
||||
) {
|
||||
mDatabaseViewModel.saveMaxHistoryItems(
|
||||
oldNumber,
|
||||
newNumber,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveMaxHistorySize(oldNumber: Long,
|
||||
newNumber: Long) {
|
||||
mDatabaseViewModel.saveMaxHistorySize(oldNumber, newNumber, mDatabaseAutoSaveEnable)
|
||||
protected fun saveMaxHistorySize(
|
||||
oldNumber: Long,
|
||||
newNumber: Long
|
||||
) {
|
||||
mDatabaseViewModel.saveMaxHistorySize(
|
||||
oldNumber,
|
||||
newNumber,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveMemoryUsage(oldNumber: Long,
|
||||
newNumber: Long) {
|
||||
mDatabaseViewModel.saveMemoryUsage(oldNumber, newNumber, mDatabaseAutoSaveEnable)
|
||||
protected fun saveMemoryUsage(
|
||||
oldNumber: Long,
|
||||
newNumber: Long
|
||||
) {
|
||||
mDatabaseViewModel.saveMemoryUsage(
|
||||
oldNumber,
|
||||
newNumber,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveParallelism(oldNumber: Long,
|
||||
newNumber: Long) {
|
||||
mDatabaseViewModel.saveParallelism(oldNumber, newNumber, mDatabaseAutoSaveEnable)
|
||||
protected fun saveParallelism(
|
||||
oldNumber: Long,
|
||||
newNumber: Long
|
||||
) {
|
||||
mDatabaseViewModel.saveParallelism(
|
||||
oldNumber,
|
||||
newNumber,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
protected fun saveIterations(oldNumber: Long,
|
||||
newNumber: Long) {
|
||||
mDatabaseViewModel.saveIterations(oldNumber, newNumber, mDatabaseAutoSaveEnable)
|
||||
protected fun saveIterations(
|
||||
oldNumber: Long,
|
||||
newNumber: Long
|
||||
) {
|
||||
mDatabaseViewModel.saveIterations(
|
||||
oldNumber,
|
||||
newNumber,
|
||||
mDatabaseAutoSaveEnable
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
package com.kunzisoft.keepass.viewmodels
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import android.app.Application
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.DatabaseTaskProvider
|
||||
import com.kunzisoft.keepass.database.MainCredential
|
||||
import com.kunzisoft.keepass.database.ProgressMessage
|
||||
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
||||
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
|
||||
import com.kunzisoft.keepass.database.element.Entry
|
||||
import com.kunzisoft.keepass.database.element.Group
|
||||
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
|
||||
import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.model.CipherEncryptDatabase
|
||||
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.utils.getBinaryDir
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
class DatabaseViewModel: ViewModel() {
|
||||
class DatabaseViewModel(application: Application): AndroidViewModel(application) {
|
||||
|
||||
var database: ContextualDatabase? = null
|
||||
private set
|
||||
@@ -19,174 +32,438 @@ class DatabaseViewModel: ViewModel() {
|
||||
private val mUiState = MutableStateFlow<UIState>(UIState.Loading)
|
||||
val uiState: StateFlow<UIState> = mUiState
|
||||
|
||||
val actionFinished : LiveData<ActionResult> get() = _actionFinished
|
||||
private val _actionFinished = SingleLiveEvent<ActionResult>()
|
||||
private var mDatabaseTaskProvider: DatabaseTaskProvider = DatabaseTaskProvider(
|
||||
context = application
|
||||
)
|
||||
|
||||
val saveDatabase : LiveData<Boolean> get() = _saveDatabase
|
||||
private val _saveDatabase = SingleLiveEvent<Boolean>()
|
||||
init {
|
||||
mDatabaseTaskProvider.onDatabaseRetrieved = { databaseRetrieved ->
|
||||
val databaseWasReloaded = databaseRetrieved?.wasReloaded == true
|
||||
if (databaseWasReloaded) {
|
||||
mUiState.value = UIState.OnDatabaseReloaded
|
||||
}
|
||||
if (database == null || database != databaseRetrieved || databaseWasReloaded) {
|
||||
databaseRetrieved?.wasReloaded = false
|
||||
defineDatabase(databaseRetrieved)
|
||||
}
|
||||
}
|
||||
mDatabaseTaskProvider.onStartActionRequested = { bundle, actionTask ->
|
||||
mUiState.value = UIState.OnDatabaseActionRequested(bundle, actionTask)
|
||||
}
|
||||
mDatabaseTaskProvider.databaseInfoListener = object : DatabaseTaskNotificationService.DatabaseInfoListener {
|
||||
override fun onDatabaseInfoChanged(
|
||||
previousDatabaseInfo: SnapFileDatabaseInfo,
|
||||
newDatabaseInfo: SnapFileDatabaseInfo,
|
||||
readOnlyDatabase: Boolean
|
||||
) {
|
||||
mUiState.value = UIState.OnDatabaseInfoChanged(
|
||||
previousDatabaseInfo,
|
||||
newDatabaseInfo,
|
||||
readOnlyDatabase
|
||||
)
|
||||
}
|
||||
}
|
||||
mDatabaseTaskProvider.actionTaskListener = object : DatabaseTaskNotificationService.ActionTaskListener {
|
||||
override fun onActionStarted(
|
||||
database: ContextualDatabase,
|
||||
progressMessage: ProgressMessage
|
||||
) {
|
||||
mUiState.value = UIState.OnDatabaseActionStarted(database, progressMessage)
|
||||
}
|
||||
|
||||
val mergeDatabase : LiveData<Boolean> get() = _mergeDatabase
|
||||
private val _mergeDatabase = SingleLiveEvent<Boolean>()
|
||||
override fun onActionUpdated(
|
||||
database: ContextualDatabase,
|
||||
progressMessage: ProgressMessage
|
||||
) {
|
||||
mUiState.value = UIState.OnDatabaseActionUpdated(database, progressMessage)
|
||||
}
|
||||
|
||||
val reloadDatabase : LiveData<Boolean> get() = _reloadDatabase
|
||||
private val _reloadDatabase = SingleLiveEvent<Boolean>()
|
||||
override fun onActionStopped(database: ContextualDatabase?) {
|
||||
mUiState.value = UIState.OnDatabaseActionStopped(database)
|
||||
}
|
||||
|
||||
val saveName : LiveData<SuperString> get() = _saveName
|
||||
private val _saveName = SingleLiveEvent<SuperString>()
|
||||
override fun onActionFinished(
|
||||
database: ContextualDatabase,
|
||||
actionTask: String,
|
||||
result: ActionRunnable.Result
|
||||
) {
|
||||
mUiState.value = UIState.OnDatabaseActionFinished(database, actionTask, result)
|
||||
}
|
||||
}
|
||||
|
||||
val saveDescription : LiveData<SuperString> get() = _saveDescription
|
||||
private val _saveDescription = SingleLiveEvent<SuperString>()
|
||||
mDatabaseTaskProvider.registerProgressTask()
|
||||
}
|
||||
|
||||
val saveDefaultUsername : LiveData<SuperString> get() = _saveDefaultUsername
|
||||
private val _saveDefaultUsername = SingleLiveEvent<SuperString>()
|
||||
/*
|
||||
* Main database actions
|
||||
*/
|
||||
|
||||
val saveColor : LiveData<SuperString> get() = _saveColor
|
||||
private val _saveColor = SingleLiveEvent<SuperString>()
|
||||
|
||||
val saveCompression : LiveData<SuperCompression> get() = _saveCompression
|
||||
private val _saveCompression = SingleLiveEvent<SuperCompression>()
|
||||
|
||||
val removeUnlinkData : LiveData<Boolean> get() = _removeUnlinkData
|
||||
private val _removeUnlinkData = SingleLiveEvent<Boolean>()
|
||||
|
||||
val saveRecycleBin : LiveData<SuperGroup> get() = _saveRecycleBin
|
||||
private val _saveRecycleBin = SingleLiveEvent<SuperGroup>()
|
||||
|
||||
val saveTemplatesGroup : LiveData<SuperGroup> get() = _saveTemplatesGroup
|
||||
private val _saveTemplatesGroup = SingleLiveEvent<SuperGroup>()
|
||||
|
||||
val saveMaxHistoryItems : LiveData<SuperInt> get() = _saveMaxHistoryItems
|
||||
private val _saveMaxHistoryItems = SingleLiveEvent<SuperInt>()
|
||||
|
||||
val saveMaxHistorySize : LiveData<SuperLong> get() = _saveMaxHistorySize
|
||||
private val _saveMaxHistorySize = SingleLiveEvent<SuperLong>()
|
||||
|
||||
val saveEncryption : LiveData<SuperEncryption> get() = _saveEncryption
|
||||
private val _saveEncryption = SingleLiveEvent<SuperEncryption>()
|
||||
|
||||
val saveKeyDerivation : LiveData<SuperKeyDerivation> get() = _saveKeyDerivation
|
||||
private val _saveKeyDerivation = SingleLiveEvent<SuperKeyDerivation>()
|
||||
|
||||
val saveIterations : LiveData<SuperLong> get() = _saveIterations
|
||||
private val _saveIterations = SingleLiveEvent<SuperLong>()
|
||||
|
||||
val saveMemoryUsage : LiveData<SuperLong> get() = _saveMemoryUsage
|
||||
private val _saveMemoryUsage = SingleLiveEvent<SuperLong>()
|
||||
|
||||
val saveParallelism : LiveData<SuperLong> get() = _saveParallelism
|
||||
private val _saveParallelism = SingleLiveEvent<SuperLong>()
|
||||
|
||||
|
||||
fun defineDatabase(database: ContextualDatabase?) {
|
||||
private fun defineDatabase(database: ContextualDatabase?) {
|
||||
this.database = database
|
||||
this.mUiState.value = UIState.OnDatabaseRetrieved(database)
|
||||
}
|
||||
|
||||
fun onActionFinished(database: ContextualDatabase,
|
||||
actionTask: String,
|
||||
result: ActionRunnable.Result) {
|
||||
this._actionFinished.value = ActionResult(database, actionTask, result)
|
||||
fun loadDatabase(
|
||||
databaseUri: Uri,
|
||||
mainCredential: MainCredential,
|
||||
readOnly: Boolean,
|
||||
cipherEncryptDatabase: CipherEncryptDatabase?,
|
||||
fixDuplicateUuid: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseLoad(
|
||||
databaseUri,
|
||||
mainCredential,
|
||||
readOnly,
|
||||
cipherEncryptDatabase,
|
||||
fixDuplicateUuid
|
||||
)
|
||||
}
|
||||
|
||||
fun saveDatabase(save: Boolean) {
|
||||
_saveDatabase.value = save
|
||||
fun createDatabase(
|
||||
databaseUri: Uri,
|
||||
mainCredential: MainCredential
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseCreate(databaseUri, mainCredential)
|
||||
}
|
||||
|
||||
fun mergeDatabase(save: Boolean) {
|
||||
_mergeDatabase.value = save
|
||||
fun assignMainCredential(
|
||||
databaseUri: Uri?,
|
||||
mainCredential: MainCredential
|
||||
) {
|
||||
if (databaseUri != null) {
|
||||
mDatabaseTaskProvider.startDatabaseAssignCredential(databaseUri, mainCredential)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveDatabase(save: Boolean, saveToUri: Uri? = null) {
|
||||
mDatabaseTaskProvider.startDatabaseSave(save, saveToUri)
|
||||
}
|
||||
|
||||
fun mergeDatabase(
|
||||
save: Boolean,
|
||||
fromDatabaseUri: Uri? = null,
|
||||
mainCredential: MainCredential? = null
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseMerge(save, fromDatabaseUri, mainCredential)
|
||||
}
|
||||
|
||||
fun reloadDatabase(fixDuplicateUuid: Boolean) {
|
||||
_reloadDatabase.value = fixDuplicateUuid
|
||||
mDatabaseTaskProvider.askToStartDatabaseReload(
|
||||
conditionToAsk = database?.dataModifiedSinceLastLoading != false
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseReload(fixDuplicateUuid)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveName(oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean) {
|
||||
_saveName.value = SuperString(oldValue, newValue, save)
|
||||
fun closeDatabase() {
|
||||
database?.clearAndClose(getApplication<Application>().getBinaryDir())
|
||||
}
|
||||
|
||||
fun saveDescription(oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean) {
|
||||
_saveDescription.value = SuperString(oldValue, newValue, save)
|
||||
fun onDatabaseChangeValidated() {
|
||||
mDatabaseTaskProvider.onDatabaseChangeValidated()
|
||||
}
|
||||
|
||||
fun saveDefaultUsername(oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean) {
|
||||
_saveDefaultUsername.value = SuperString(oldValue, newValue, save)
|
||||
/*
|
||||
* Nodes actions
|
||||
*/
|
||||
|
||||
fun createEntry(
|
||||
newEntry: Entry,
|
||||
parent: Group,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseCreateEntry(
|
||||
newEntry,
|
||||
parent,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveColor(oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean) {
|
||||
_saveColor.value = SuperString(oldValue, newValue, save)
|
||||
fun updateEntry(
|
||||
oldEntry: Entry,
|
||||
entryToUpdate: Entry,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseUpdateEntry(
|
||||
oldEntry,
|
||||
entryToUpdate,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveCompression(oldValue: CompressionAlgorithm,
|
||||
newValue: CompressionAlgorithm,
|
||||
save: Boolean) {
|
||||
_saveCompression.value = SuperCompression(oldValue, newValue, save)
|
||||
fun restoreEntryHistory(
|
||||
mainEntryId: NodeId<UUID>,
|
||||
entryHistoryPosition: Int,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseRestoreEntryHistory(
|
||||
mainEntryId,
|
||||
entryHistoryPosition,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun deleteEntryHistory(
|
||||
mainEntryId: NodeId<UUID>,
|
||||
entryHistoryPosition: Int,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseDeleteEntryHistory(
|
||||
mainEntryId,
|
||||
entryHistoryPosition,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun createGroup(
|
||||
newGroup: Group,
|
||||
parent: Group,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseCreateGroup(
|
||||
newGroup,
|
||||
parent,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun updateGroup(
|
||||
oldGroup: Group,
|
||||
groupToUpdate: Group,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseUpdateGroup(
|
||||
oldGroup,
|
||||
groupToUpdate,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun copyNodes(
|
||||
nodesToCopy: List<Node>,
|
||||
newParent: Group,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseCopyNodes(
|
||||
nodesToCopy,
|
||||
newParent,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun moveNodes(
|
||||
nodesToMove: List<Node>,
|
||||
newParent: Group,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseMoveNodes(
|
||||
nodesToMove,
|
||||
newParent,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun deleteNodes(
|
||||
nodes: List<Node>,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseDeleteNodes(
|
||||
nodes,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* Settings actions
|
||||
*/
|
||||
|
||||
fun saveName(
|
||||
oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveName(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveDescription(
|
||||
oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveDescription(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveDefaultUsername(
|
||||
oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveDefaultUsername(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveColor(
|
||||
oldValue: String,
|
||||
newValue: String,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveColor(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveCompression(
|
||||
oldValue: CompressionAlgorithm,
|
||||
newValue: CompressionAlgorithm,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveCompression(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun removeUnlinkedData(save: Boolean) {
|
||||
_removeUnlinkData.value = save
|
||||
mDatabaseTaskProvider.startDatabaseRemoveUnlinkedData(save)
|
||||
}
|
||||
|
||||
fun saveRecycleBin(oldValue: Group?,
|
||||
newValue: Group?,
|
||||
save: Boolean) {
|
||||
_saveRecycleBin.value = SuperGroup(oldValue, newValue, save)
|
||||
fun saveRecycleBin(
|
||||
oldValue: Group?,
|
||||
newValue: Group?,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveRecycleBin(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveTemplatesGroup(oldValue: Group?,
|
||||
newValue: Group?,
|
||||
save: Boolean) {
|
||||
_saveTemplatesGroup.value = SuperGroup(oldValue, newValue, save)
|
||||
fun saveTemplatesGroup(
|
||||
oldValue: Group?,
|
||||
newValue: Group?,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveTemplatesGroup(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveMaxHistoryItems(oldValue: Int,
|
||||
newValue: Int,
|
||||
save: Boolean) {
|
||||
_saveMaxHistoryItems.value = SuperInt(oldValue, newValue, save)
|
||||
fun saveMaxHistoryItems(
|
||||
oldValue: Int,
|
||||
newValue: Int,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveMaxHistoryItems(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveMaxHistorySize(oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean) {
|
||||
_saveMaxHistorySize.value = SuperLong(oldValue, newValue, save)
|
||||
fun saveMaxHistorySize(
|
||||
oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveMaxHistorySize(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun saveEncryption(oldValue: EncryptionAlgorithm,
|
||||
newValue: EncryptionAlgorithm,
|
||||
save: Boolean) {
|
||||
_saveEncryption.value = SuperEncryption(oldValue, newValue, save)
|
||||
fun saveEncryption(
|
||||
oldValue: EncryptionAlgorithm,
|
||||
newValue: EncryptionAlgorithm,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveEncryption(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveKeyDerivation(oldValue: KdfEngine,
|
||||
newValue: KdfEngine,
|
||||
save: Boolean) {
|
||||
_saveKeyDerivation.value = SuperKeyDerivation(oldValue, newValue, save)
|
||||
fun saveKeyDerivation(
|
||||
oldValue: KdfEngine,
|
||||
newValue: KdfEngine,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveKeyDerivation(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveIterations(oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean) {
|
||||
_saveIterations.value = SuperLong(oldValue, newValue, save)
|
||||
fun saveIterations(
|
||||
oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveIterations(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveMemoryUsage(oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean) {
|
||||
_saveMemoryUsage.value = SuperLong(oldValue, newValue, save)
|
||||
fun saveMemoryUsage(
|
||||
oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveMemoryUsage(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
fun saveParallelism(oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean) {
|
||||
_saveParallelism.value = SuperLong(oldValue, newValue, save)
|
||||
fun saveParallelism(
|
||||
oldValue: Long,
|
||||
newValue: Long,
|
||||
save: Boolean
|
||||
) {
|
||||
mDatabaseTaskProvider.startDatabaseSaveParallelism(
|
||||
oldValue,
|
||||
newValue,
|
||||
save
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware Key
|
||||
*/
|
||||
|
||||
fun onChallengeResponded(challengeResponse: ByteArray?) {
|
||||
mDatabaseTaskProvider.startChallengeResponded(
|
||||
challengeResponse ?: ByteArray(0)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
mDatabaseTaskProvider.unregisterProgressTask()
|
||||
mDatabaseTaskProvider.destroy()
|
||||
}
|
||||
|
||||
sealed class UIState {
|
||||
@@ -194,33 +471,31 @@ class DatabaseViewModel: ViewModel() {
|
||||
data class OnDatabaseRetrieved(
|
||||
val database: ContextualDatabase?
|
||||
): UIState()
|
||||
object OnDatabaseReloaded: UIState()
|
||||
data class OnDatabaseActionRequested(
|
||||
val bundle: Bundle? = null,
|
||||
val actionTask: String
|
||||
): UIState()
|
||||
data class OnDatabaseInfoChanged(
|
||||
val previousDatabaseInfo: SnapFileDatabaseInfo,
|
||||
val newDatabaseInfo: SnapFileDatabaseInfo,
|
||||
val readOnlyDatabase: Boolean
|
||||
): UIState()
|
||||
data class OnDatabaseActionStarted(
|
||||
val database: ContextualDatabase,
|
||||
val progressMessage: ProgressMessage
|
||||
): UIState()
|
||||
data class OnDatabaseActionUpdated(
|
||||
val database: ContextualDatabase,
|
||||
val progressMessage: ProgressMessage
|
||||
): UIState()
|
||||
data class OnDatabaseActionStopped(
|
||||
val database: ContextualDatabase?
|
||||
): UIState()
|
||||
data class OnDatabaseActionFinished(
|
||||
val database: ContextualDatabase,
|
||||
val actionTask: String,
|
||||
val result: ActionRunnable.Result
|
||||
): UIState()
|
||||
}
|
||||
|
||||
data class ActionResult(val database: ContextualDatabase,
|
||||
val actionTask: String,
|
||||
val result: ActionRunnable.Result)
|
||||
data class SuperString(val oldValue: String,
|
||||
val newValue: String,
|
||||
val save: Boolean)
|
||||
data class SuperInt(val oldValue: Int,
|
||||
val newValue: Int,
|
||||
val save: Boolean)
|
||||
data class SuperLong(val oldValue: Long,
|
||||
val newValue: Long,
|
||||
val save: Boolean)
|
||||
data class SuperMerge(val fixDuplicateUuid: Boolean,
|
||||
val save: Boolean)
|
||||
data class SuperCompression(val oldValue: CompressionAlgorithm,
|
||||
val newValue: CompressionAlgorithm,
|
||||
val save: Boolean)
|
||||
data class SuperEncryption(val oldValue: EncryptionAlgorithm,
|
||||
val newValue: EncryptionAlgorithm,
|
||||
val save: Boolean)
|
||||
data class SuperKeyDerivation(val oldValue: KdfEngine,
|
||||
val newValue: KdfEngine,
|
||||
val save: Boolean)
|
||||
data class SuperGroup(val oldValue: Group?,
|
||||
val newValue: Group?,
|
||||
val save: Boolean)
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user