fix: Database State

This commit is contained in:
J-Jamet
2025-10-09 14:31:03 +02:00
parent 50b1ac388e
commit 755e0ea9a5
10 changed files with 170 additions and 134 deletions

View File

@@ -5,7 +5,9 @@ import android.view.View
import android.view.WindowManager.LayoutParams.FLAG_SECURE import android.view.WindowManager.LayoutParams.FLAG_SECURE
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.database.ContextualDatabase
@@ -18,26 +20,32 @@ import kotlinx.coroutines.launch
abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval { abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels() private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private val mDatabase: ContextualDatabase?
get() = mDatabaseViewModel.database
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
lifecycleScope.launch { lifecycleScope.launch {
// Initialize the parameters repeatOnLifecycle(Lifecycle.State.STARTED) {
mDatabaseViewModel.uiState.collect { uiState -> mDatabaseViewModel.actionState.collect { uiState ->
when (uiState) { when (uiState) {
is DatabaseViewModel.UIState.Loading -> {} is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> {
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> { onDatabaseActionFinished(
resetAppTimeoutOnTouchOrFocus() uiState.database,
onDatabaseRetrieved(uiState.database) uiState.actionTask,
uiState.result
)
}
else -> {}
} }
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> { }
onDatabaseActionFinished( }
uiState.database, }
uiState.actionTask, lifecycleScope.launch {
uiState.result repeatOnLifecycle(Lifecycle.State.RESUMED) {
) mDatabaseViewModel.databaseState.collect { database ->
} onDatabaseRetrieved(database)
else -> {}
} }
} }
} }
@@ -78,7 +86,7 @@ abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
fun resetAppTimeout() { fun resetAppTimeout() {
context?.let { context?.let {
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(it, TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(it,
mDatabaseViewModel.database?.loaded ?: false) mDatabase?.loaded ?: false)
} }
} }
@@ -91,7 +99,7 @@ abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
context?.let { context?.let {
dialog?.window?.decorView?.resetAppTimeoutWhenViewTouchedOrFocused( dialog?.window?.decorView?.resetAppTimeoutWhenViewTouchedOrFocused(
it, it,
mDatabaseViewModel.database?.loaded mDatabase?.loaded
) )
} }
} }

View File

@@ -10,45 +10,50 @@ import androidx.lifecycle.repeatOnLifecycle
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
abstract class DatabaseFragment : Fragment(), DatabaseRetrieval { abstract class DatabaseFragment : Fragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels() protected val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
protected val mDatabase: ContextualDatabase?
get() = mDatabaseViewModel.database
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) { repeatOnLifecycle(Lifecycle.State.STARTED) {
mDatabaseViewModel.uiState.collect { uiState -> mDatabaseViewModel.actionState.collect { uiState ->
when (uiState) { when (uiState) {
is DatabaseViewModel.UIState.Loading -> {} is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> {
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
onDatabaseRetrieved(uiState.database)
}
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
onDatabaseActionFinished( onDatabaseActionFinished(
uiState.database, uiState.database,
uiState.actionTask, uiState.actionTask,
uiState.result uiState.result
) )
} }
else -> {} else -> {}
} }
} }
} }
} }
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
mDatabaseViewModel.databaseState.collect { database ->
onDatabaseRetrieved(database)
}
}
}
} }
protected fun resetAppTimeoutWhenViewFocusedOrChanged(view: View?) { protected fun resetAppTimeoutWhenViewFocusedOrChanged(view: View?) {
context?.let { context?.let {
view?.resetAppTimeoutWhenViewTouchedOrFocused( view?.resetAppTimeoutWhenViewTouchedOrFocused(
context = it, context = it,
databaseLoaded = mDatabaseViewModel.database?.loaded databaseLoaded = mDatabase?.loaded
) )
} }
} }
@@ -60,8 +65,4 @@ abstract class DatabaseFragment : Fragment(), DatabaseRetrieval {
) { ) {
// Can be overridden by a subclass // Can be overridden by a subclass
} }
protected fun buildNewBinaryAttachment(): BinaryData? {
return mDatabaseViewModel.database?.buildNewBinaryAttachment()
}
} }

View File

@@ -230,7 +230,7 @@ class EntryEditFragment: DatabaseFragment() {
val attachmentToUploadUri = it.attachmentToUploadUri val attachmentToUploadUri = it.attachmentToUploadUri
val fileName = it.fileName val fileName = it.fileName
buildNewBinaryAttachment()?.let { binaryAttachment -> mDatabaseViewModel.buildNewAttachment()?.let { binaryAttachment ->
val entryAttachment = Attachment(fileName, binaryAttachment) val entryAttachment = Attachment(fileName, binaryAttachment)
// Ask to replace the current attachment // Ask to replace the current attachment
if ((!mAllowMultipleAttachments if ((!mAllowMultipleAttachments

View File

@@ -47,7 +47,6 @@ import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.KeyboardUtil.hideKeyboard import com.kunzisoft.keepass.utils.KeyboardUtil.hideKeyboard
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
import com.kunzisoft.keepass.viewmodels.GroupViewModel import com.kunzisoft.keepass.viewmodels.GroupViewModel
import java.util.LinkedList import java.util.LinkedList
@@ -61,7 +60,6 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
private var mLayoutManager: LinearLayoutManager? = null private var mLayoutManager: LinearLayoutManager? = null
private var mAdapter: NodesAdapter? = null private var mAdapter: NodesAdapter? = null
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private val mGroupViewModel: GroupViewModel by activityViewModels() private val mGroupViewModel: GroupViewModel by activityViewModels()
private var mCurrentGroup: Group? = null private var mCurrentGroup: Group? = null
@@ -105,7 +103,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
PreferencesUtil.getListSort(context), PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context), PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context), PreferencesUtil.getGroupsBeforeSort(context),
if (mDatabaseViewModel.database?.isRecycleBinEnabled == true) { if (mDatabase?.isRecycleBinEnabled == true) {
PreferencesUtil.getRecycleBinBottomSort(context) PreferencesUtil.getRecycleBinBottomSort(context)
} else null } else null
) )
@@ -301,8 +299,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
} }
private fun containsRecycleBin(nodes: List<Node>): Boolean { private fun containsRecycleBin(database: ContextualDatabase?, nodes: List<Node>): Boolean {
val database = mDatabaseViewModel.database
return database?.isRecycleBinEnabled == true return database?.isRecycleBinEnabled == true
&& nodes.any { it == database.recycleBin } && nodes.any { it == database.recycleBin }
} }
@@ -331,7 +328,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
// Open and Edit for a single item // Open and Edit for a single item
if (nodes.size == 1) { if (nodes.size == 1) {
// Edition // Edition
if (database.isReadOnly || containsRecycleBin(nodes)) { if (database.isReadOnly || containsRecycleBin(database, nodes)) {
menu?.removeItem(R.id.menu_edit) menu?.removeItem(R.id.menu_edit)
} }
} else { } else {
@@ -351,7 +348,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
// Deletion // Deletion
if (database.isReadOnly || containsRecycleBin(nodes)) { if (database.isReadOnly || containsRecycleBin(database, nodes)) {
menu?.removeItem(R.id.menu_delete) menu?.removeItem(R.id.menu_delete)
} }
} }

View File

@@ -57,20 +57,16 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
lifecycleScope.launch { lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) { repeatOnLifecycle(Lifecycle.State.STARTED) {
mDatabaseViewModel.uiState.collect { uiState -> mDatabaseViewModel.actionState.collect { uiState ->
when (uiState) { when (uiState) {
is DatabaseViewModel.UIState.Loading -> {} is DatabaseViewModel.ActionState.Loading -> {}
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> { is DatabaseViewModel.ActionState.OnDatabaseReloaded -> {
onDatabaseRetrieved(uiState.database)
}
is DatabaseViewModel.UIState.OnDatabaseReloaded -> {
if (finishActivityIfReloadRequested()) { if (finishActivityIfReloadRequested()) {
finish() finish()
} }
} }
is DatabaseViewModel.UIState.OnDatabaseInfoChanged -> { is DatabaseViewModel.ActionState.OnDatabaseInfoChanged -> {
showDatabaseChangedDialog( showDatabaseChangedDialog(
uiState.previousDatabaseInfo, uiState.previousDatabaseInfo,
uiState.newDatabaseInfo, uiState.newDatabaseInfo,
@@ -78,29 +74,29 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval {
) )
} }
is DatabaseViewModel.UIState.OnDatabaseActionRequested -> { is DatabaseViewModel.ActionState.OnDatabaseActionRequested -> {
startDatabasePermissionService( startDatabasePermissionService(
uiState.bundle, uiState.bundle,
uiState.actionTask uiState.actionTask
) )
} }
is DatabaseViewModel.UIState.OnDatabaseActionStarted -> { is DatabaseViewModel.ActionState.OnDatabaseActionStarted -> {
if (showDatabaseDialog()) if (showDatabaseDialog())
startDialog(uiState.progressMessage) startDialog(uiState.progressMessage)
} }
is DatabaseViewModel.UIState.OnDatabaseActionUpdated -> { is DatabaseViewModel.ActionState.OnDatabaseActionUpdated -> {
if (showDatabaseDialog()) if (showDatabaseDialog())
updateDialog(uiState.progressMessage) updateDialog(uiState.progressMessage)
} }
is DatabaseViewModel.UIState.OnDatabaseActionStopped -> { is DatabaseViewModel.ActionState.OnDatabaseActionStopped -> {
// Remove the progress task // Remove the progress task
stopDialog() stopDialog()
} }
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> { is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> {
onDatabaseActionFinished( onDatabaseActionFinished(
uiState.database, uiState.database,
uiState.actionTask, uiState.actionTask,
@@ -112,6 +108,13 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval {
} }
} }
} }
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
mDatabaseViewModel.databaseState.collect { database ->
onDatabaseRetrieved(database)
}
}
}
} }
override fun onDatabaseRetrieved(database: ContextualDatabase?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {

View File

@@ -96,7 +96,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
override fun onDatabaseRetrieved(database: ContextualDatabase?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// End activity if database not loaded // End activity if database not loaded
if (finishActivityIfDatabaseNotLoaded() && (database == null || !database.loaded)) { if (finishActivityIfDatabaseNotLoaded() && (database != null && !database.loaded)) {
finish() finish()
} }

View File

@@ -21,13 +21,15 @@ package com.kunzisoft.keepass.settings
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -36,6 +38,8 @@ class MainPreferenceFragment : PreferenceFragmentCompat() {
private var mCallback: Callback? = null private var mCallback: Callback? = null
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels() private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private val mDatabase: ContextualDatabase?
get() = mDatabaseViewModel.database
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
@@ -51,20 +55,16 @@ class MainPreferenceFragment : PreferenceFragmentCompat() {
mCallback = null mCallback = null
super.onDetach() super.onDetach()
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch { lifecycleScope.launch {
// Initialize the parameters repeatOnLifecycle(Lifecycle.State.RESUMED) {
mDatabaseViewModel.uiState.collect { uiState -> mDatabaseViewModel.databaseState.collect { database ->
when (uiState) { checkDatabaseLoaded(database?.loaded == true)
is DatabaseViewModel.UIState.Loading -> {}
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
checkDatabaseLoaded(uiState.database?.loaded == true)
}
else -> {}
} }
} }
} }
super.onViewCreated(view, savedInstanceState)
} }
private fun checkDatabaseLoaded(isDatabaseLoaded: Boolean) { private fun checkDatabaseLoaded(isDatabaseLoaded: Boolean) {
@@ -128,7 +128,7 @@ class MainPreferenceFragment : PreferenceFragmentCompat() {
} }
} }
checkDatabaseLoaded(mDatabaseViewModel.database?.loaded == true) checkDatabaseLoaded(mDatabase?.loaded == true)
} }
interface Callback { interface Callback {

View File

@@ -31,7 +31,9 @@ import androidx.core.graphics.toColorInt
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import androidx.preference.TwoStatePreference import androidx.preference.TwoStatePreference
@@ -77,6 +79,8 @@ import kotlinx.coroutines.launch
class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetrieval { class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels() private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private val mDatabase: ContextualDatabase?
get() = mDatabaseViewModel.database
private var mDatabaseReadOnly: Boolean = false private var mDatabaseReadOnly: Boolean = false
private var mMergeDataAllowed: Boolean = false private var mMergeDataAllowed: Boolean = false
private var mDatabaseAutoSaveEnabled: Boolean = true private var mDatabaseAutoSaveEnabled: Boolean = true
@@ -139,38 +143,50 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
} }
} }
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 ->
onDatabaseRetrieved(database)
}
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
activity?.addMenuProvider(menuProvider, viewLifecycleOwner) activity?.addMenuProvider(menuProvider, viewLifecycleOwner)
viewLifecycleOwner.lifecycleScope.launch {
lifecycleScope.launch { mDatabaseViewModel.databaseState.collect { database ->
mDatabaseViewModel.uiState.collect { uiState -> view.resetAppTimeoutWhenViewTouchedOrFocused(
when (uiState) { context = requireContext(),
is DatabaseViewModel.UIState.Loading -> {} databaseLoaded = database?.loaded
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> { )
view.resetAppTimeoutWhenViewTouchedOrFocused(
context = requireContext(),
databaseLoaded = uiState.database?.loaded
)
onDatabaseRetrieved(uiState.database)
}
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
onDatabaseActionFinished(
uiState.database,
uiState.actionTask,
uiState.result
)
}
else -> {}
}
} }
} }
} }
override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) { override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) {
mScreen = screen mScreen = screen
val database = mDatabaseViewModel.database val database = mDatabase
// Load the preferences from an XML resource // Load the preferences from an XML resource
when (screen) { when (screen) {
Screen.DATABASE -> { Screen.DATABASE -> {

View File

@@ -42,6 +42,8 @@ abstract class DatabaseSavePreferenceDialogFragmentCompat
private var mDatabaseAutoSaveEnable = true private var mDatabaseAutoSaveEnable = true
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels() private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
protected val mDatabase: ContextualDatabase?
get() = mDatabaseViewModel.database
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
@@ -50,27 +52,30 @@ abstract class DatabaseSavePreferenceDialogFragmentCompat
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
lifecycleScope.launch { lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) { repeatOnLifecycle(Lifecycle.State.STARTED) {
mDatabaseViewModel.uiState.collect { uiState -> mDatabaseViewModel.actionState.collect { uiState ->
when (uiState) { when (uiState) {
is DatabaseViewModel.UIState.Loading -> {} is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> {
is DatabaseViewModel.UIState.OnDatabaseRetrieved -> {
onDatabaseRetrieved(uiState.database)
}
is DatabaseViewModel.UIState.OnDatabaseActionFinished -> {
onDatabaseActionFinished( onDatabaseActionFinished(
uiState.database, uiState.database,
uiState.actionTask, uiState.actionTask,
uiState.result uiState.result
) )
} }
else -> {} else -> {}
} }
} }
} }
} }
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
mDatabaseViewModel.databaseState.collect { database ->
onDatabaseRetrieved(database)
}
}
}
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
@@ -82,7 +87,7 @@ abstract class DatabaseSavePreferenceDialogFragmentCompat
} }
override fun onDialogClosed(positiveResult: Boolean) { override fun onDialogClosed(positiveResult: Boolean) {
onDialogClosed(mDatabaseViewModel.database, positiveResult) onDialogClosed(mDatabase, positiveResult)
} }
open fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) { open fun onDialogClosed(database: ContextualDatabase?, positiveResult: Boolean) {

View File

@@ -12,6 +12,7 @@ import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
import com.kunzisoft.keepass.database.element.Entry import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
@@ -26,11 +27,14 @@ import java.util.UUID
class DatabaseViewModel(application: Application): AndroidViewModel(application) { class DatabaseViewModel(application: Application): AndroidViewModel(application) {
var database: ContextualDatabase? = null private val mDatabaseState = MutableStateFlow<ContextualDatabase?>(null)
private set val databaseState: StateFlow<ContextualDatabase?> = mDatabaseState
private val mUiState = MutableStateFlow<UIState>(UIState.Loading) val database: ContextualDatabase?
val uiState: StateFlow<UIState> = mUiState get() = databaseState.value
private val mActionState = MutableStateFlow<ActionState>(ActionState.Loading)
val actionState: StateFlow<ActionState> = mActionState
private var mDatabaseTaskProvider: DatabaseTaskProvider = DatabaseTaskProvider( private var mDatabaseTaskProvider: DatabaseTaskProvider = DatabaseTaskProvider(
context = application context = application
@@ -40,15 +44,15 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
mDatabaseTaskProvider.onDatabaseRetrieved = { databaseRetrieved -> mDatabaseTaskProvider.onDatabaseRetrieved = { databaseRetrieved ->
val databaseWasReloaded = databaseRetrieved?.wasReloaded == true val databaseWasReloaded = databaseRetrieved?.wasReloaded == true
if (databaseWasReloaded) { if (databaseWasReloaded) {
mUiState.value = UIState.OnDatabaseReloaded mActionState.value = ActionState.OnDatabaseReloaded
} }
if (database == null || database != databaseRetrieved || databaseWasReloaded) { if (database == null || database != databaseRetrieved || databaseWasReloaded) {
databaseRetrieved?.wasReloaded = false databaseRetrieved?.wasReloaded = false
defineDatabase(databaseRetrieved) mDatabaseState.value = databaseRetrieved
} }
} }
mDatabaseTaskProvider.onStartActionRequested = { bundle, actionTask -> mDatabaseTaskProvider.onStartActionRequested = { bundle, actionTask ->
mUiState.value = UIState.OnDatabaseActionRequested(bundle, actionTask) mActionState.value = ActionState.OnDatabaseActionRequested(bundle, actionTask)
} }
mDatabaseTaskProvider.databaseInfoListener = object : DatabaseTaskNotificationService.DatabaseInfoListener { mDatabaseTaskProvider.databaseInfoListener = object : DatabaseTaskNotificationService.DatabaseInfoListener {
override fun onDatabaseInfoChanged( override fun onDatabaseInfoChanged(
@@ -56,7 +60,7 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
newDatabaseInfo: SnapFileDatabaseInfo, newDatabaseInfo: SnapFileDatabaseInfo,
readOnlyDatabase: Boolean readOnlyDatabase: Boolean
) { ) {
mUiState.value = UIState.OnDatabaseInfoChanged( mActionState.value = ActionState.OnDatabaseInfoChanged(
previousDatabaseInfo, previousDatabaseInfo,
newDatabaseInfo, newDatabaseInfo,
readOnlyDatabase readOnlyDatabase
@@ -68,18 +72,18 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
database: ContextualDatabase, database: ContextualDatabase,
progressMessage: ProgressMessage progressMessage: ProgressMessage
) { ) {
mUiState.value = UIState.OnDatabaseActionStarted(database, progressMessage) mActionState.value = ActionState.OnDatabaseActionStarted(database, progressMessage)
} }
override fun onActionUpdated( override fun onActionUpdated(
database: ContextualDatabase, database: ContextualDatabase,
progressMessage: ProgressMessage progressMessage: ProgressMessage
) { ) {
mUiState.value = UIState.OnDatabaseActionUpdated(database, progressMessage) mActionState.value = ActionState.OnDatabaseActionUpdated(database, progressMessage)
} }
override fun onActionStopped(database: ContextualDatabase?) { override fun onActionStopped(database: ContextualDatabase?) {
mUiState.value = UIState.OnDatabaseActionStopped(database) mActionState.value = ActionState.OnDatabaseActionStopped(database)
} }
override fun onActionFinished( override fun onActionFinished(
@@ -87,7 +91,7 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {
mUiState.value = UIState.OnDatabaseActionFinished(database, actionTask, result) mActionState.value = ActionState.OnDatabaseActionFinished(database, actionTask, result)
} }
} }
@@ -98,11 +102,6 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
* Main database actions * Main database actions
*/ */
private fun defineDatabase(database: ContextualDatabase?) {
this.database = database
this.mUiState.value = UIState.OnDatabaseRetrieved(database)
}
fun loadDatabase( fun loadDatabase(
databaseUri: Uri, databaseUri: Uri,
mainCredential: MainCredential, mainCredential: MainCredential,
@@ -156,7 +155,9 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
} }
fun closeDatabase() { fun closeDatabase() {
database?.clearAndClose(getApplication<Application>().getBinaryDir()) database?.clearAndClose(
filesDirectory = getApplication<Application>().getBinaryDir()
)
} }
fun onDatabaseChangeValidated() { fun onDatabaseChangeValidated() {
@@ -273,6 +274,14 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
) )
} }
/*
* Attributes
*/
fun buildNewAttachment(): BinaryData? {
return database?.buildNewBinaryAttachment()
}
/* /*
* Settings actions * Settings actions
*/ */
@@ -466,36 +475,33 @@ class DatabaseViewModel(application: Application): AndroidViewModel(application)
mDatabaseTaskProvider.destroy() mDatabaseTaskProvider.destroy()
} }
sealed class UIState { sealed class ActionState {
object Loading: UIState() object Loading: ActionState()
data class OnDatabaseRetrieved( object OnDatabaseReloaded: ActionState()
val database: ContextualDatabase?
): UIState()
object OnDatabaseReloaded: UIState()
data class OnDatabaseActionRequested( data class OnDatabaseActionRequested(
val bundle: Bundle? = null, val bundle: Bundle? = null,
val actionTask: String val actionTask: String
): UIState() ): ActionState()
data class OnDatabaseInfoChanged( data class OnDatabaseInfoChanged(
val previousDatabaseInfo: SnapFileDatabaseInfo, val previousDatabaseInfo: SnapFileDatabaseInfo,
val newDatabaseInfo: SnapFileDatabaseInfo, val newDatabaseInfo: SnapFileDatabaseInfo,
val readOnlyDatabase: Boolean val readOnlyDatabase: Boolean
): UIState() ): ActionState()
data class OnDatabaseActionStarted( data class OnDatabaseActionStarted(
val database: ContextualDatabase, var database: ContextualDatabase,
val progressMessage: ProgressMessage val progressMessage: ProgressMessage
): UIState() ): ActionState()
data class OnDatabaseActionUpdated( data class OnDatabaseActionUpdated(
val database: ContextualDatabase, var database: ContextualDatabase,
val progressMessage: ProgressMessage val progressMessage: ProgressMessage
): UIState() ): ActionState()
data class OnDatabaseActionStopped( data class OnDatabaseActionStopped(
val database: ContextualDatabase? var database: ContextualDatabase?
): UIState() ): ActionState()
data class OnDatabaseActionFinished( data class OnDatabaseActionFinished(
val database: ContextualDatabase, var database: ContextualDatabase,
val actionTask: String, val actionTask: String,
val result: ActionRunnable.Result val result: ActionRunnable.Result
): UIState() ): ActionState()
} }
} }