mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Start using ViewModel for internal database action
This commit is contained in:
@@ -101,10 +101,9 @@ dependencies {
|
|||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||||
implementation 'androidx.biometric:biometric:1.0.1'
|
implementation 'androidx.biometric:biometric:1.0.1'
|
||||||
implementation 'androidx.core:core-ktx:1.2.0'
|
// Lifecycle - LiveData - ViewModel - Coroutines
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
|
implementation "androidx.core:core-ktx:1.2.0"
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
|
implementation 'androidx.fragment:fragment-ktx:1.2.4'
|
||||||
// TODO #538 implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
|
|
||||||
// To upgrade with style
|
// To upgrade with style
|
||||||
implementation 'com.google.android.material:material:1.0.0'
|
implementation 'com.google.android.material:material:1.0.0'
|
||||||
// Database
|
// Database
|
||||||
|
|||||||
@@ -32,9 +32,11 @@ import android.util.Log
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||||
@@ -56,6 +58,7 @@ import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Compa
|
|||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
import com.kunzisoft.keepass.utils.*
|
import com.kunzisoft.keepass.utils.*
|
||||||
import com.kunzisoft.keepass.view.asError
|
import com.kunzisoft.keepass.view.asError
|
||||||
|
import com.kunzisoft.keepass.viewmodels.DatabaseFilesViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_file_selection.*
|
import kotlinx.android.synthetic.main.activity_file_selection.*
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
@@ -68,6 +71,8 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
private var createDatabaseButtonView: View? = null
|
private var createDatabaseButtonView: View? = null
|
||||||
private var openDatabaseButtonView: View? = null
|
private var openDatabaseButtonView: View? = null
|
||||||
|
|
||||||
|
private val databaseFilesViewModel: DatabaseFilesViewModel by viewModels()
|
||||||
|
|
||||||
// Adapter to manage database history list
|
// Adapter to manage database history list
|
||||||
private var mAdapterDatabaseHistory: FileDatabaseHistoryAdapter? = null
|
private var mAdapterDatabaseHistory: FileDatabaseHistoryAdapter? = null
|
||||||
|
|
||||||
@@ -118,25 +123,21 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
// Construct adapter with listeners
|
// Construct adapter with listeners
|
||||||
mAdapterDatabaseHistory = FileDatabaseHistoryAdapter(this)
|
mAdapterDatabaseHistory = FileDatabaseHistoryAdapter(this)
|
||||||
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryOpenListener { fileDatabaseHistoryEntityToOpen ->
|
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryOpenListener { fileDatabaseHistoryEntityToOpen ->
|
||||||
UriUtil.parse(fileDatabaseHistoryEntityToOpen.databaseUri)?.let { databaseFileUri ->
|
fileDatabaseHistoryEntityToOpen.databaseUri?.let { databaseFileUri ->
|
||||||
launchPasswordActivity(
|
launchPasswordActivity(
|
||||||
databaseFileUri,
|
databaseFileUri,
|
||||||
UriUtil.parse(fileDatabaseHistoryEntityToOpen.keyFileUri))
|
fileDatabaseHistoryEntityToOpen.keyFileUri
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryDeleteListener { fileDatabaseHistoryToDelete ->
|
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryDeleteListener { fileDatabaseHistoryToDelete ->
|
||||||
// Remove from app database
|
// Remove from app database
|
||||||
mFileDatabaseHistoryAction?.deleteFileDatabaseHistory(fileDatabaseHistoryToDelete) { fileHistoryDeleted ->
|
databaseFilesViewModel.deleteDatabaseFile(fileDatabaseHistoryToDelete)
|
||||||
// Remove from adapter
|
|
||||||
fileHistoryDeleted?.let { databaseFileHistoryDeleted ->
|
|
||||||
mAdapterDatabaseHistory?.deleteDatabaseFileHistory(databaseFileHistoryDeleted)
|
|
||||||
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
mAdapterDatabaseHistory?.setOnSaveAliasListener { fileDatabaseHistoryWithNewAlias ->
|
mAdapterDatabaseHistory?.setOnSaveAliasListener { fileDatabaseHistoryWithNewAlias ->
|
||||||
mFileDatabaseHistoryAction?.addOrUpdateFileDatabaseHistory(fileDatabaseHistoryWithNewAlias)
|
// Update in app database
|
||||||
|
databaseFilesViewModel.updateDatabaseFile(fileDatabaseHistoryWithNewAlias)
|
||||||
}
|
}
|
||||||
fileDatabaseHistoryRecyclerView.adapter = mAdapterDatabaseHistory
|
fileDatabaseHistoryRecyclerView.adapter = mAdapterDatabaseHistory
|
||||||
|
|
||||||
@@ -159,17 +160,49 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
mDatabaseFileUri = savedInstanceState.getParcelable(EXTRA_DATABASE_URI)
|
mDatabaseFileUri = savedInstanceState.getParcelable(EXTRA_DATABASE_URI)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Observe list of databases
|
||||||
|
databaseFilesViewModel.databaseFilesLoaded.observe(this, Observer { databaseFiles ->
|
||||||
|
when (databaseFiles.databaseFileAction) {
|
||||||
|
DatabaseFilesViewModel.DatabaseFileAction.NONE -> {
|
||||||
|
mAdapterDatabaseHistory?.replaceAllDatabaseFileHistoryList(databaseFiles.databaseFileList)
|
||||||
|
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
DatabaseFilesViewModel.DatabaseFileAction.ADD -> {
|
||||||
|
databaseFiles.databaseFileToActivate?.let { databaseFileToAdd ->
|
||||||
|
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DatabaseFilesViewModel.DatabaseFileAction.UPDATE -> {
|
||||||
|
databaseFiles.databaseFileToActivate?.let { databaseFileToUpdate ->
|
||||||
|
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DatabaseFilesViewModel.DatabaseFileAction.DELETE -> {
|
||||||
|
databaseFiles.databaseFileToActivate?.let { databaseFileToDelete ->
|
||||||
|
mAdapterDatabaseHistory?.deleteDatabaseFileHistory(databaseFileToDelete)
|
||||||
|
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
databaseFilesViewModel.consumeAction()
|
||||||
|
})
|
||||||
|
|
||||||
// Attach the dialog thread to this activity
|
// Attach the dialog thread to this activity
|
||||||
mProgressDialogThread = ProgressDialogThread(this).apply {
|
mProgressDialogThread = ProgressDialogThread(this).apply {
|
||||||
onActionFinish = { actionTask, _ ->
|
onActionFinish = { actionTask, _ ->
|
||||||
when (actionTask) {
|
when (actionTask) {
|
||||||
ACTION_DATABASE_CREATE_TASK -> {
|
ACTION_DATABASE_CREATE_TASK -> {
|
||||||
|
// TODO add Database file
|
||||||
|
// databaseFilesViewModel.addDatabaseFile()
|
||||||
|
databaseFilesViewModel.loadListOfDatabases()
|
||||||
|
runOnUiThread {
|
||||||
GroupActivity.launch(this@FileDatabaseSelectActivity)
|
GroupActivity.launch(this@FileDatabaseSelectActivity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new file by calling the content provider
|
* Create a new file by calling the content provider
|
||||||
@@ -286,21 +319,7 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
} else {
|
} else {
|
||||||
// Construct adapter with listeners
|
// Construct adapter with listeners
|
||||||
if (PreferencesUtil.showRecentFiles(this)) {
|
if (PreferencesUtil.showRecentFiles(this)) {
|
||||||
mFileDatabaseHistoryAction?.getAllFileDatabaseHistories { databaseFileHistoryList ->
|
databaseFilesViewModel.loadListOfDatabases()
|
||||||
databaseFileHistoryList?.let { historyList ->
|
|
||||||
val hideBrokenLocations = PreferencesUtil.hideBrokenLocations(this@FileDatabaseSelectActivity)
|
|
||||||
mAdapterDatabaseHistory?.addDatabaseFileHistoryList(
|
|
||||||
// Show only uri accessible
|
|
||||||
historyList.filter {
|
|
||||||
if (hideBrokenLocations) {
|
|
||||||
FileDatabaseInfo(this@FileDatabaseSelectActivity,
|
|
||||||
it.databaseUri).exists
|
|
||||||
} else
|
|
||||||
true
|
|
||||||
})
|
|
||||||
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mAdapterDatabaseHistory?.clearDatabaseFileHistoryList()
|
mAdapterDatabaseHistory?.clearDatabaseFileHistoryList()
|
||||||
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
||||||
@@ -362,8 +381,7 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data)
|
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
mOpenFileHelper?.onActivityResultCallback(requestCode, resultCode, data
|
mOpenFileHelper?.onActivityResultCallback(requestCode, resultCode, data) { uri ->
|
||||||
) { uri ->
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
launchPasswordActivityWithPath(uri)
|
launchPasswordActivityWithPath(uri)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,12 @@ import android.util.Log
|
|||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
|
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.biometric.BiometricManager
|
import androidx.biometric.BiometricManager
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.dialogs.DuplicateUuidDialog
|
import com.kunzisoft.keepass.activities.dialogs.DuplicateUuidDialog
|
||||||
@@ -48,7 +50,6 @@ import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
|||||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||||
import com.kunzisoft.keepass.activities.selection.SpecialModeActivity
|
import com.kunzisoft.keepass.activities.selection.SpecialModeActivity
|
||||||
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
||||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
|
||||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||||
import com.kunzisoft.keepass.biometric.AdvancedUnlockedManager
|
import com.kunzisoft.keepass.biometric.AdvancedUnlockedManager
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDialogThread
|
import com.kunzisoft.keepass.database.action.ProgressDialogThread
|
||||||
@@ -60,7 +61,7 @@ import com.kunzisoft.keepass.model.SearchInfo
|
|||||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
|
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
|
||||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.CIPHER_ENTITY_KEY
|
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.CIPHER_ENTITY_KEY
|
||||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
|
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
|
||||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.KEY_FILE_KEY
|
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.KEY_FILE_URI_KEY
|
||||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.MASTER_PASSWORD_KEY
|
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.MASTER_PASSWORD_KEY
|
||||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.READ_ONLY_KEY
|
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.READ_ONLY_KEY
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
@@ -68,6 +69,7 @@ import com.kunzisoft.keepass.utils.*
|
|||||||
import com.kunzisoft.keepass.view.AdvancedUnlockInfoView
|
import com.kunzisoft.keepass.view.AdvancedUnlockInfoView
|
||||||
import com.kunzisoft.keepass.view.KeyFileSelectionView
|
import com.kunzisoft.keepass.view.KeyFileSelectionView
|
||||||
import com.kunzisoft.keepass.view.asError
|
import com.kunzisoft.keepass.view.asError
|
||||||
|
import com.kunzisoft.keepass.viewmodels.DatabaseFileViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_password.*
|
import kotlinx.android.synthetic.main.activity_password.*
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
@@ -86,6 +88,8 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
private var infoContainerView: ViewGroup? = null
|
private var infoContainerView: ViewGroup? = null
|
||||||
private var enableButtonOnCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
|
private var enableButtonOnCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
|
||||||
|
|
||||||
|
private val databaseFilesViewModel: DatabaseFileViewModel by viewModels()
|
||||||
|
|
||||||
private var mDatabaseFileUri: Uri? = null
|
private var mDatabaseFileUri: Uri? = null
|
||||||
private var mDatabaseKeyFileUri: Uri? = null
|
private var mDatabaseKeyFileUri: Uri? = null
|
||||||
|
|
||||||
@@ -133,6 +137,7 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
|
|
||||||
mPermissionAsked = savedInstanceState?.getBoolean(KEY_PERMISSION_ASKED) ?: mPermissionAsked
|
mPermissionAsked = savedInstanceState?.getBoolean(KEY_PERMISSION_ASKED) ?: mPermissionAsked
|
||||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrPreference(this, savedInstanceState)
|
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrPreference(this, savedInstanceState)
|
||||||
|
mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this)
|
||||||
|
|
||||||
mOpenFileHelper = OpenFileHelper(this@PasswordActivity)
|
mOpenFileHelper = OpenFileHelper(this@PasswordActivity)
|
||||||
keyFileSelectionView?.apply {
|
keyFileSelectionView?.apply {
|
||||||
@@ -163,11 +168,33 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
if (savedInstanceState?.containsKey(KEY_KEYFILE) == true) {
|
if (savedInstanceState?.containsKey(KEY_KEYFILE) == true) {
|
||||||
mDatabaseKeyFileUri = UriUtil.parse(savedInstanceState.getString(KEY_KEYFILE))
|
mDatabaseKeyFileUri = UriUtil.parse(savedInstanceState.getString(KEY_KEYFILE))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedInstanceState?.containsKey(ALLOW_AUTO_OPEN_BIOMETRIC_PROMPT) == true) {
|
if (savedInstanceState?.containsKey(ALLOW_AUTO_OPEN_BIOMETRIC_PROMPT) == true) {
|
||||||
mAllowAutoOpenBiometricPrompt = savedInstanceState.getBoolean(ALLOW_AUTO_OPEN_BIOMETRIC_PROMPT)
|
mAllowAutoOpenBiometricPrompt = savedInstanceState.getBoolean(ALLOW_AUTO_OPEN_BIOMETRIC_PROMPT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Observe database file change
|
||||||
|
databaseFilesViewModel.databaseFileLoaded.observe(this, Observer { databaseFile ->
|
||||||
|
// Force read only if the file does not exists
|
||||||
|
mForceReadOnly = databaseFile?.let {
|
||||||
|
!it.databaseFileExists
|
||||||
|
} ?: true
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
|
||||||
|
// Post init uri with KeyFile only if needed
|
||||||
|
val keyFileUri =
|
||||||
|
if (mRememberKeyFile
|
||||||
|
&& (mDatabaseKeyFileUri == null || mDatabaseKeyFileUri.toString().isEmpty())) {
|
||||||
|
databaseFile?.keyFileUri
|
||||||
|
} else {
|
||||||
|
mDatabaseKeyFileUri
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define title
|
||||||
|
filenameView?.text = databaseFile?.databaseAlias ?: ""
|
||||||
|
|
||||||
|
onDatabaseFileLoaded(databaseFile?.databaseUri, keyFileUri)
|
||||||
|
})
|
||||||
|
|
||||||
mProgressDialogThread = ProgressDialogThread(this).apply {
|
mProgressDialogThread = ProgressDialogThread(this).apply {
|
||||||
onActionFinish = { actionTask, result ->
|
onActionFinish = { actionTask, result ->
|
||||||
when (actionTask) {
|
when (actionTask) {
|
||||||
@@ -205,7 +232,7 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
result.data?.let { resultData ->
|
result.data?.let { resultData ->
|
||||||
databaseUri = resultData.getParcelable(DATABASE_URI_KEY)
|
databaseUri = resultData.getParcelable(DATABASE_URI_KEY)
|
||||||
masterPassword = resultData.getString(MASTER_PASSWORD_KEY)
|
masterPassword = resultData.getString(MASTER_PASSWORD_KEY)
|
||||||
keyFileUri = resultData.getParcelable(KEY_FILE_KEY)
|
keyFileUri = resultData.getParcelable(KEY_FILE_URI_KEY)
|
||||||
readOnly = resultData.getBoolean(READ_ONLY_KEY)
|
readOnly = resultData.getBoolean(READ_ONLY_KEY)
|
||||||
cipherEntity = resultData.getParcelable(CIPHER_ENTITY_KEY)
|
cipherEntity = resultData.getParcelable(CIPHER_ENTITY_KEY)
|
||||||
}
|
}
|
||||||
@@ -364,45 +391,15 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
else
|
else
|
||||||
mAllowAutoOpenBiometricPrompt
|
mAllowAutoOpenBiometricPrompt
|
||||||
|
|
||||||
initUriFromIntent()
|
mDatabaseFileUri?.let { databaseFileUri ->
|
||||||
|
databaseFilesViewModel.loadDatabaseFile(databaseFileUri)
|
||||||
|
}
|
||||||
|
|
||||||
checkPermission()
|
checkPermission()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initUriFromIntent() {
|
private fun onDatabaseFileLoaded(databaseFileUri: Uri?, keyFileUri: Uri?) {
|
||||||
/*
|
|
||||||
// "canXrite" doesn't work with Google Drive, don't really know why?
|
|
||||||
mForceReadOnly = mDatabaseFileUri?.let {
|
|
||||||
!FileDatabaseInfo(this, it).canWrite
|
|
||||||
} ?: false
|
|
||||||
*/
|
|
||||||
mForceReadOnly = mDatabaseFileUri?.let {
|
|
||||||
!FileDatabaseInfo(this, it).exists
|
|
||||||
} ?: true
|
|
||||||
|
|
||||||
// Post init uri with KeyFile if needed
|
|
||||||
if (mRememberKeyFile && (mDatabaseKeyFileUri == null || mDatabaseKeyFileUri.toString().isEmpty())) {
|
|
||||||
// Retrieve KeyFile in a thread
|
|
||||||
mDatabaseFileUri?.let { databaseUri ->
|
|
||||||
FileDatabaseHistoryAction.getInstance(applicationContext)
|
|
||||||
.getKeyFileUriByDatabaseUri(databaseUri) {
|
|
||||||
onPostInitUri(databaseUri, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onPostInitUri(mDatabaseFileUri, mDatabaseKeyFileUri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onPostInitUri(databaseFileUri: Uri?, keyFileUri: Uri?) {
|
|
||||||
// Define title
|
|
||||||
databaseFileUri?.let {
|
|
||||||
FileDatabaseInfo(this, it).retrieveDatabaseTitle { title ->
|
|
||||||
filenameView?.text = title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define Key File text
|
// Define Key File text
|
||||||
if (mRememberKeyFile) {
|
if (mRememberKeyFile) {
|
||||||
populateKeyFileTextView(keyFileUri)
|
populateKeyFileTextView(keyFileUri)
|
||||||
|
|||||||
@@ -31,19 +31,17 @@ import android.widget.ImageView
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.ViewSwitcher
|
import android.widget.ViewSwitcher
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryEntity
|
import com.kunzisoft.keepass.model.DatabaseFile
|
||||||
import com.kunzisoft.keepass.utils.FileDatabaseInfo
|
|
||||||
import com.kunzisoft.keepass.utils.UriUtil
|
|
||||||
|
|
||||||
class FileDatabaseHistoryAdapter(private val context: Context)
|
class FileDatabaseHistoryAdapter(context: Context)
|
||||||
: RecyclerView.Adapter<FileDatabaseHistoryAdapter.FileDatabaseHistoryViewHolder>() {
|
: RecyclerView.Adapter<FileDatabaseHistoryAdapter.FileDatabaseHistoryViewHolder>() {
|
||||||
|
|
||||||
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||||
private var fileItemOpenListener: ((FileDatabaseHistoryEntity)->Unit)? = null
|
private var fileItemOpenListener: ((DatabaseFile)->Unit)? = null
|
||||||
private var fileSelectClearListener: ((FileDatabaseHistoryEntity)->Boolean)? = null
|
private var fileSelectClearListener: ((DatabaseFile)->Boolean)? = null
|
||||||
private var saveAliasListener: ((FileDatabaseHistoryEntity)->Unit)? = null
|
private var saveAliasListener: ((DatabaseFile)->Unit)? = null
|
||||||
|
|
||||||
private val listDatabaseFiles = ArrayList<FileDatabaseHistoryEntity>()
|
private val listDatabaseFiles = ArrayList<DatabaseFile>()
|
||||||
|
|
||||||
private var mExpandedPosition = -1
|
private var mExpandedPosition = -1
|
||||||
private var mPreviousExpandedPosition = -1
|
private var mPreviousExpandedPosition = -1
|
||||||
@@ -69,29 +67,28 @@ class FileDatabaseHistoryAdapter(private val context: Context)
|
|||||||
|
|
||||||
override fun onBindViewHolder(holder: FileDatabaseHistoryViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: FileDatabaseHistoryViewHolder, position: Int) {
|
||||||
// Get info from position
|
// Get info from position
|
||||||
val fileHistoryEntity = listDatabaseFiles[position]
|
val databaseFile = listDatabaseFiles[position]
|
||||||
val fileDatabaseInfo = FileDatabaseInfo(context, fileHistoryEntity.databaseUri)
|
|
||||||
|
|
||||||
// Click item to open file
|
// Click item to open file
|
||||||
if (fileItemOpenListener != null)
|
if (fileItemOpenListener != null)
|
||||||
holder.fileContainer.setOnClickListener {
|
holder.fileContainer.setOnClickListener {
|
||||||
fileItemOpenListener?.invoke(fileHistoryEntity)
|
fileItemOpenListener?.invoke(databaseFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// File alias
|
// File alias
|
||||||
holder.fileAlias.text = fileDatabaseInfo.retrieveDatabaseAlias(fileHistoryEntity.databaseAlias)
|
holder.fileAlias.text = databaseFile.databaseAlias
|
||||||
|
|
||||||
// File path
|
// File path
|
||||||
holder.filePath.text = UriUtil.decode(fileDatabaseInfo.fileUri?.toString())
|
holder.filePath.text = databaseFile.databaseDecodedPath
|
||||||
|
|
||||||
if (fileDatabaseInfo.exists) {
|
if (databaseFile.databaseFileExists) {
|
||||||
holder.fileInformation.clearColorFilter()
|
holder.fileInformation.clearColorFilter()
|
||||||
} else {
|
} else {
|
||||||
holder.fileInformation.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY)
|
holder.fileInformation.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modification
|
// Modification
|
||||||
fileDatabaseInfo.getModificationString()?.let {
|
databaseFile.databaseLastModified?.let {
|
||||||
holder.fileModification.text = it
|
holder.fileModification.text = it
|
||||||
holder.fileModification.visibility = View.VISIBLE
|
holder.fileModification.visibility = View.VISIBLE
|
||||||
} ?: run {
|
} ?: run {
|
||||||
@@ -99,7 +96,7 @@ class FileDatabaseHistoryAdapter(private val context: Context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size
|
// Size
|
||||||
fileDatabaseInfo.getSizeString()?.let {
|
databaseFile.databaseSize?.let {
|
||||||
holder.fileSize.text = it
|
holder.fileSize.text = it
|
||||||
holder.fileSize.visibility = View.VISIBLE
|
holder.fileSize.visibility = View.VISIBLE
|
||||||
} ?: run {
|
} ?: run {
|
||||||
@@ -114,8 +111,8 @@ class FileDatabaseHistoryAdapter(private val context: Context)
|
|||||||
// Save alias modification
|
// Save alias modification
|
||||||
holder.fileAliasCloseButton.setOnClickListener {
|
holder.fileAliasCloseButton.setOnClickListener {
|
||||||
// Change the alias
|
// Change the alias
|
||||||
fileHistoryEntity.databaseAlias = holder.fileAliasEdit.text.toString()
|
databaseFile.databaseAlias = holder.fileAliasEdit.text.toString()
|
||||||
saveAliasListener?.invoke(fileHistoryEntity)
|
saveAliasListener?.invoke(databaseFile)
|
||||||
|
|
||||||
// Finish save mode
|
// Finish save mode
|
||||||
holder.fileMainSwitcher.showPrevious()
|
holder.fileMainSwitcher.showPrevious()
|
||||||
@@ -130,7 +127,7 @@ class FileDatabaseHistoryAdapter(private val context: Context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
holder.fileDeleteButton.setOnClickListener {
|
holder.fileDeleteButton.setOnClickListener {
|
||||||
fileSelectClearListener?.invoke(fileHistoryEntity)
|
fileSelectClearListener?.invoke(databaseFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
@@ -160,24 +157,24 @@ class FileDatabaseHistoryAdapter(private val context: Context)
|
|||||||
listDatabaseFiles.clear()
|
listDatabaseFiles.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addDatabaseFileHistoryList(listFileDatabaseHistoryToAdd: List<FileDatabaseHistoryEntity>) {
|
fun replaceAllDatabaseFileHistoryList(listFileDatabaseHistoryToAdd: List<DatabaseFile>) {
|
||||||
listDatabaseFiles.clear()
|
listDatabaseFiles.clear()
|
||||||
listDatabaseFiles.addAll(listFileDatabaseHistoryToAdd)
|
listDatabaseFiles.addAll(listFileDatabaseHistoryToAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteDatabaseFileHistory(fileDatabaseHistoryToDelete: FileDatabaseHistoryEntity) {
|
fun deleteDatabaseFileHistory(fileDatabaseHistoryToDelete: DatabaseFile) {
|
||||||
listDatabaseFiles.remove(fileDatabaseHistoryToDelete)
|
listDatabaseFiles.remove(fileDatabaseHistoryToDelete)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOnFileDatabaseHistoryOpenListener(listener : ((FileDatabaseHistoryEntity)->Unit)?) {
|
fun setOnFileDatabaseHistoryOpenListener(listener : ((DatabaseFile)->Unit)?) {
|
||||||
this.fileItemOpenListener = listener
|
this.fileItemOpenListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOnFileDatabaseHistoryDeleteListener(listener : ((FileDatabaseHistoryEntity)->Boolean)?) {
|
fun setOnFileDatabaseHistoryDeleteListener(listener : ((DatabaseFile)->Boolean)?) {
|
||||||
this.fileSelectClearListener = listener
|
this.fileSelectClearListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOnSaveAliasListener(listener : ((FileDatabaseHistoryEntity)->Unit)?) {
|
fun setOnSaveAliasListener(listener : ((DatabaseFile)->Unit)?) {
|
||||||
this.saveAliasListener = listener
|
this.saveAliasListener = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ class FileDatabaseHistoryAction(applicationContext: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addOrUpdateDatabaseUri(databaseUri: Uri, keyFileUri: Uri? = null) {
|
fun addOrUpdateDatabaseUri(databaseUri: Uri, keyFileUri: Uri? = null) {
|
||||||
|
// TODO in Thread
|
||||||
addOrUpdateFileDatabaseHistory(FileDatabaseHistoryEntity(
|
addOrUpdateFileDatabaseHistory(FileDatabaseHistoryEntity(
|
||||||
databaseUri.toString(),
|
databaseUri.toString(),
|
||||||
"",
|
"",
|
||||||
@@ -79,7 +80,9 @@ class FileDatabaseHistoryAction(applicationContext: Context) {
|
|||||||
), true)
|
), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addOrUpdateFileDatabaseHistory(fileDatabaseHistory: FileDatabaseHistoryEntity, unmodifiedAlias: Boolean = false) {
|
fun addOrUpdateFileDatabaseHistory(fileDatabaseHistory: FileDatabaseHistoryEntity,
|
||||||
|
unmodifiedAlias: Boolean = false,
|
||||||
|
fileHistoryUpdatedResult: ((FileDatabaseHistoryEntity?) -> Unit)? = null) {
|
||||||
IOActionTask(
|
IOActionTask(
|
||||||
{
|
{
|
||||||
val fileDatabaseHistoryRetrieve = databaseFileHistoryDao.getByDatabaseUri(fileDatabaseHistory.databaseUri)
|
val fileDatabaseHistoryRetrieve = databaseFileHistoryDao.getByDatabaseUri(fileDatabaseHistory.databaseUri)
|
||||||
@@ -93,6 +96,10 @@ class FileDatabaseHistoryAction(applicationContext: Context) {
|
|||||||
} else {
|
} else {
|
||||||
databaseFileHistoryDao.update(fileDatabaseHistory)
|
databaseFileHistoryDao.update(fileDatabaseHistory)
|
||||||
}
|
}
|
||||||
|
fileDatabaseHistoryRetrieve
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fileHistoryUpdatedResult?.invoke(it)
|
||||||
}
|
}
|
||||||
).execute()
|
).execute()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class CreateDatabaseRunnable(context: Context,
|
|||||||
super.onFinishRun()
|
super.onFinishRun()
|
||||||
|
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
|
// TODO in Thread
|
||||||
// Add database to recent files
|
// Add database to recent files
|
||||||
if (PreferencesUtil.rememberDatabaseLocations(context)) {
|
if (PreferencesUtil.rememberDatabaseLocations(context)) {
|
||||||
FileDatabaseHistoryAction.getInstance(context.applicationContext)
|
FileDatabaseHistoryAction.getInstance(context.applicationContext)
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ class ProgressDialogThread(private val activity: FragmentActivity) {
|
|||||||
putBoolean(DatabaseTaskNotificationService.MASTER_PASSWORD_CHECKED_KEY, masterPasswordChecked)
|
putBoolean(DatabaseTaskNotificationService.MASTER_PASSWORD_CHECKED_KEY, masterPasswordChecked)
|
||||||
putString(DatabaseTaskNotificationService.MASTER_PASSWORD_KEY, masterPassword)
|
putString(DatabaseTaskNotificationService.MASTER_PASSWORD_KEY, masterPassword)
|
||||||
putBoolean(DatabaseTaskNotificationService.KEY_FILE_CHECKED_KEY, keyFileChecked)
|
putBoolean(DatabaseTaskNotificationService.KEY_FILE_CHECKED_KEY, keyFileChecked)
|
||||||
putParcelable(DatabaseTaskNotificationService.KEY_FILE_KEY, keyFile)
|
putParcelable(DatabaseTaskNotificationService.KEY_FILE_URI_KEY, keyFile)
|
||||||
}
|
}
|
||||||
, ACTION_DATABASE_CREATE_TASK)
|
, ACTION_DATABASE_CREATE_TASK)
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ class ProgressDialogThread(private val activity: FragmentActivity) {
|
|||||||
start(Bundle().apply {
|
start(Bundle().apply {
|
||||||
putParcelable(DatabaseTaskNotificationService.DATABASE_URI_KEY, databaseUri)
|
putParcelable(DatabaseTaskNotificationService.DATABASE_URI_KEY, databaseUri)
|
||||||
putString(DatabaseTaskNotificationService.MASTER_PASSWORD_KEY, masterPassword)
|
putString(DatabaseTaskNotificationService.MASTER_PASSWORD_KEY, masterPassword)
|
||||||
putParcelable(DatabaseTaskNotificationService.KEY_FILE_KEY, keyFile)
|
putParcelable(DatabaseTaskNotificationService.KEY_FILE_URI_KEY, keyFile)
|
||||||
putBoolean(DatabaseTaskNotificationService.READ_ONLY_KEY, readOnly)
|
putBoolean(DatabaseTaskNotificationService.READ_ONLY_KEY, readOnly)
|
||||||
putParcelable(DatabaseTaskNotificationService.CIPHER_ENTITY_KEY, cipherEntity)
|
putParcelable(DatabaseTaskNotificationService.CIPHER_ENTITY_KEY, cipherEntity)
|
||||||
putBoolean(DatabaseTaskNotificationService.FIX_DUPLICATE_UUID_KEY, fixDuplicateUuid)
|
putBoolean(DatabaseTaskNotificationService.FIX_DUPLICATE_UUID_KEY, fixDuplicateUuid)
|
||||||
@@ -274,7 +274,7 @@ class ProgressDialogThread(private val activity: FragmentActivity) {
|
|||||||
putBoolean(DatabaseTaskNotificationService.MASTER_PASSWORD_CHECKED_KEY, masterPasswordChecked)
|
putBoolean(DatabaseTaskNotificationService.MASTER_PASSWORD_CHECKED_KEY, masterPasswordChecked)
|
||||||
putString(DatabaseTaskNotificationService.MASTER_PASSWORD_KEY, masterPassword)
|
putString(DatabaseTaskNotificationService.MASTER_PASSWORD_KEY, masterPassword)
|
||||||
putBoolean(DatabaseTaskNotificationService.KEY_FILE_CHECKED_KEY, keyFileChecked)
|
putBoolean(DatabaseTaskNotificationService.KEY_FILE_CHECKED_KEY, keyFileChecked)
|
||||||
putParcelable(DatabaseTaskNotificationService.KEY_FILE_KEY, keyFile)
|
putParcelable(DatabaseTaskNotificationService.KEY_FILE_URI_KEY, keyFile)
|
||||||
}
|
}
|
||||||
, ACTION_DATABASE_ASSIGN_PASSWORD_TASK)
|
, ACTION_DATABASE_ASSIGN_PASSWORD_TASK)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.kunzisoft.keepass.model
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
data class DatabaseFile(var databaseUri: Uri? = null,
|
||||||
|
var keyFileUri: Uri? = null,
|
||||||
|
var databaseDecodedPath: String? = null,
|
||||||
|
var databaseAlias: String? = null,
|
||||||
|
var databaseFileExists: Boolean = false,
|
||||||
|
var databaseLastModified: String? = null,
|
||||||
|
var databaseSize: String? = null) {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is DatabaseFile) return false
|
||||||
|
|
||||||
|
if (databaseUri == null) return false
|
||||||
|
if (databaseUri != other.databaseUri) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return databaseUri?.hashCode() ?: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -295,7 +295,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
intent?.removeExtra(MASTER_PASSWORD_CHECKED_KEY)
|
intent?.removeExtra(MASTER_PASSWORD_CHECKED_KEY)
|
||||||
intent?.removeExtra(MASTER_PASSWORD_KEY)
|
intent?.removeExtra(MASTER_PASSWORD_KEY)
|
||||||
intent?.removeExtra(KEY_FILE_CHECKED_KEY)
|
intent?.removeExtra(KEY_FILE_CHECKED_KEY)
|
||||||
intent?.removeExtra(KEY_FILE_KEY)
|
intent?.removeExtra(KEY_FILE_URI_KEY)
|
||||||
intent?.removeExtra(READ_ONLY_KEY)
|
intent?.removeExtra(READ_ONLY_KEY)
|
||||||
intent?.removeExtra(CIPHER_ENTITY_KEY)
|
intent?.removeExtra(CIPHER_ENTITY_KEY)
|
||||||
intent?.removeExtra(FIX_DUPLICATE_UUID_KEY)
|
intent?.removeExtra(FIX_DUPLICATE_UUID_KEY)
|
||||||
@@ -380,10 +380,10 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
&& intent.hasExtra(MASTER_PASSWORD_CHECKED_KEY)
|
&& intent.hasExtra(MASTER_PASSWORD_CHECKED_KEY)
|
||||||
&& intent.hasExtra(MASTER_PASSWORD_KEY)
|
&& intent.hasExtra(MASTER_PASSWORD_KEY)
|
||||||
&& intent.hasExtra(KEY_FILE_CHECKED_KEY)
|
&& intent.hasExtra(KEY_FILE_CHECKED_KEY)
|
||||||
&& intent.hasExtra(KEY_FILE_KEY)
|
&& intent.hasExtra(KEY_FILE_URI_KEY)
|
||||||
) {
|
) {
|
||||||
val databaseUri: Uri? = intent.getParcelableExtra(DATABASE_URI_KEY)
|
val databaseUri: Uri? = intent.getParcelableExtra(DATABASE_URI_KEY)
|
||||||
val keyFileUri: Uri? = intent.getParcelableExtra(KEY_FILE_KEY)
|
val keyFileUri: Uri? = intent.getParcelableExtra(KEY_FILE_URI_KEY)
|
||||||
|
|
||||||
if (databaseUri == null)
|
if (databaseUri == null)
|
||||||
return null
|
return null
|
||||||
@@ -407,14 +407,14 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
|
|
||||||
if (intent.hasExtra(DATABASE_URI_KEY)
|
if (intent.hasExtra(DATABASE_URI_KEY)
|
||||||
&& intent.hasExtra(MASTER_PASSWORD_KEY)
|
&& intent.hasExtra(MASTER_PASSWORD_KEY)
|
||||||
&& intent.hasExtra(KEY_FILE_KEY)
|
&& intent.hasExtra(KEY_FILE_URI_KEY)
|
||||||
&& intent.hasExtra(READ_ONLY_KEY)
|
&& intent.hasExtra(READ_ONLY_KEY)
|
||||||
&& intent.hasExtra(CIPHER_ENTITY_KEY)
|
&& intent.hasExtra(CIPHER_ENTITY_KEY)
|
||||||
&& intent.hasExtra(FIX_DUPLICATE_UUID_KEY)
|
&& intent.hasExtra(FIX_DUPLICATE_UUID_KEY)
|
||||||
) {
|
) {
|
||||||
val databaseUri: Uri? = intent.getParcelableExtra(DATABASE_URI_KEY)
|
val databaseUri: Uri? = intent.getParcelableExtra(DATABASE_URI_KEY)
|
||||||
val masterPassword: String? = intent.getStringExtra(MASTER_PASSWORD_KEY)
|
val masterPassword: String? = intent.getStringExtra(MASTER_PASSWORD_KEY)
|
||||||
val keyFileUri: Uri? = intent.getParcelableExtra(KEY_FILE_KEY)
|
val keyFileUri: Uri? = intent.getParcelableExtra(KEY_FILE_URI_KEY)
|
||||||
val readOnly: Boolean = intent.getBooleanExtra(READ_ONLY_KEY, true)
|
val readOnly: Boolean = intent.getBooleanExtra(READ_ONLY_KEY, true)
|
||||||
val cipherEntity: CipherDatabaseEntity? = intent.getParcelableExtra(CIPHER_ENTITY_KEY)
|
val cipherEntity: CipherDatabaseEntity? = intent.getParcelableExtra(CIPHER_ENTITY_KEY)
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
result.data = Bundle().apply {
|
result.data = Bundle().apply {
|
||||||
putParcelable(DATABASE_URI_KEY, databaseUri)
|
putParcelable(DATABASE_URI_KEY, databaseUri)
|
||||||
putString(MASTER_PASSWORD_KEY, masterPassword)
|
putString(MASTER_PASSWORD_KEY, masterPassword)
|
||||||
putParcelable(KEY_FILE_KEY, keyFileUri)
|
putParcelable(KEY_FILE_URI_KEY, keyFileUri)
|
||||||
putBoolean(READ_ONLY_KEY, readOnly)
|
putBoolean(READ_ONLY_KEY, readOnly)
|
||||||
putParcelable(CIPHER_ENTITY_KEY, cipherEntity)
|
putParcelable(CIPHER_ENTITY_KEY, cipherEntity)
|
||||||
}
|
}
|
||||||
@@ -451,7 +451,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
&& intent.hasExtra(MASTER_PASSWORD_CHECKED_KEY)
|
&& intent.hasExtra(MASTER_PASSWORD_CHECKED_KEY)
|
||||||
&& intent.hasExtra(MASTER_PASSWORD_KEY)
|
&& intent.hasExtra(MASTER_PASSWORD_KEY)
|
||||||
&& intent.hasExtra(KEY_FILE_CHECKED_KEY)
|
&& intent.hasExtra(KEY_FILE_CHECKED_KEY)
|
||||||
&& intent.hasExtra(KEY_FILE_KEY)
|
&& intent.hasExtra(KEY_FILE_URI_KEY)
|
||||||
) {
|
) {
|
||||||
val databaseUri: Uri = intent.getParcelableExtra(DATABASE_URI_KEY) ?: return null
|
val databaseUri: Uri = intent.getParcelableExtra(DATABASE_URI_KEY) ?: return null
|
||||||
AssignPasswordInDatabaseRunnable(this,
|
AssignPasswordInDatabaseRunnable(this,
|
||||||
@@ -460,7 +460,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
intent.getBooleanExtra(MASTER_PASSWORD_CHECKED_KEY, false),
|
intent.getBooleanExtra(MASTER_PASSWORD_CHECKED_KEY, false),
|
||||||
intent.getStringExtra(MASTER_PASSWORD_KEY),
|
intent.getStringExtra(MASTER_PASSWORD_KEY),
|
||||||
intent.getBooleanExtra(KEY_FILE_CHECKED_KEY, false),
|
intent.getBooleanExtra(KEY_FILE_CHECKED_KEY, false),
|
||||||
intent.getParcelableExtra(KEY_FILE_KEY)
|
intent.getParcelableExtra(KEY_FILE_URI_KEY)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@@ -766,7 +766,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
const val MASTER_PASSWORD_CHECKED_KEY = "MASTER_PASSWORD_CHECKED_KEY"
|
const val MASTER_PASSWORD_CHECKED_KEY = "MASTER_PASSWORD_CHECKED_KEY"
|
||||||
const val MASTER_PASSWORD_KEY = "MASTER_PASSWORD_KEY"
|
const val MASTER_PASSWORD_KEY = "MASTER_PASSWORD_KEY"
|
||||||
const val KEY_FILE_CHECKED_KEY = "KEY_FILE_CHECKED_KEY"
|
const val KEY_FILE_CHECKED_KEY = "KEY_FILE_CHECKED_KEY"
|
||||||
const val KEY_FILE_KEY = "KEY_FILE_KEY"
|
const val KEY_FILE_URI_KEY = "KEY_FILE_KEY"
|
||||||
const val READ_ONLY_KEY = "READ_ONLY_KEY"
|
const val READ_ONLY_KEY = "READ_ONLY_KEY"
|
||||||
const val CIPHER_ENTITY_KEY = "CIPHER_ENTITY_KEY"
|
const val CIPHER_ENTITY_KEY = "CIPHER_ENTITY_KEY"
|
||||||
const val FIX_DUPLICATE_UUID_KEY = "FIX_DUPLICATE_UUID_KEY"
|
const val FIX_DUPLICATE_UUID_KEY = "FIX_DUPLICATE_UUID_KEY"
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.kunzisoft.keepass.viewmodels
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.kunzisoft.keepass.app.App
|
||||||
|
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||||
|
import com.kunzisoft.keepass.app.database.IOActionTask
|
||||||
|
import com.kunzisoft.keepass.model.DatabaseFile
|
||||||
|
import com.kunzisoft.keepass.utils.UriUtil
|
||||||
|
|
||||||
|
class DatabaseFileViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
|
private var mFileDatabaseHistoryAction: FileDatabaseHistoryAction? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(application.applicationContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
val databaseFileLoaded: MutableLiveData<DatabaseFile> by lazy {
|
||||||
|
MutableLiveData<DatabaseFile>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadDatabaseFile(databaseUri: Uri) {
|
||||||
|
mFileDatabaseHistoryAction?.getFileDatabaseHistory(databaseUri) { fileDatabaseHistoryEntity ->
|
||||||
|
IOActionTask (
|
||||||
|
{
|
||||||
|
val fileDatabaseInfo = FileDatabaseInfo(
|
||||||
|
getApplication<App>().applicationContext,
|
||||||
|
databaseUri
|
||||||
|
)
|
||||||
|
DatabaseFile(
|
||||||
|
databaseUri,
|
||||||
|
UriUtil.parse(fileDatabaseHistoryEntity?.keyFileUri),
|
||||||
|
UriUtil.decode(fileDatabaseHistoryEntity?.databaseUri),
|
||||||
|
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias ?: ""),
|
||||||
|
fileDatabaseInfo.exists,
|
||||||
|
fileDatabaseInfo.getModificationString(),
|
||||||
|
fileDatabaseInfo.getSizeString()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
databaseFileLoaded.value = it ?: DatabaseFile(databaseUri)
|
||||||
|
}
|
||||||
|
).execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
package com.kunzisoft.keepass.viewmodels
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.*
|
||||||
|
import com.kunzisoft.keepass.app.App
|
||||||
|
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||||
|
import com.kunzisoft.keepass.app.database.IOActionTask
|
||||||
|
import com.kunzisoft.keepass.model.DatabaseFile
|
||||||
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.utils.UriUtil
|
||||||
|
|
||||||
|
class DatabaseFilesViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
|
private var mFileDatabaseHistoryAction: FileDatabaseHistoryAction? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(application.applicationContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
val databaseFilesLoaded: MutableLiveData<DatabaseFileData> by lazy {
|
||||||
|
MutableLiveData<DatabaseFileData>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadListOfDatabases() {
|
||||||
|
val databaseFileListLoaded = ArrayList<DatabaseFile>()
|
||||||
|
|
||||||
|
mFileDatabaseHistoryAction?.getAllFileDatabaseHistories { databaseFileHistoryList ->
|
||||||
|
databaseFileHistoryList?.let { historyList ->
|
||||||
|
IOActionTask({
|
||||||
|
val context = getApplication<App>().applicationContext
|
||||||
|
val hideBrokenLocations = PreferencesUtil.hideBrokenLocations(context)
|
||||||
|
// Show only uri accessible
|
||||||
|
historyList.forEach { fileDatabaseHistoryEntity ->
|
||||||
|
val fileDatabaseInfo = FileDatabaseInfo(context, fileDatabaseHistoryEntity.databaseUri)
|
||||||
|
if (hideBrokenLocations && fileDatabaseInfo.exists
|
||||||
|
|| !hideBrokenLocations) {
|
||||||
|
databaseFileListLoaded.add(
|
||||||
|
DatabaseFile(
|
||||||
|
UriUtil.parse(fileDatabaseHistoryEntity.databaseUri),
|
||||||
|
UriUtil.parse(fileDatabaseHistoryEntity.keyFileUri),
|
||||||
|
UriUtil.decode(fileDatabaseHistoryEntity.databaseUri),
|
||||||
|
fileDatabaseInfo.retrieveDatabaseAlias(fileDatabaseHistoryEntity.databaseAlias),
|
||||||
|
fileDatabaseInfo.exists,
|
||||||
|
fileDatabaseInfo.getModificationString(),
|
||||||
|
fileDatabaseInfo.getSizeString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
var newValue = databaseFilesLoaded.value
|
||||||
|
if (newValue == null) {
|
||||||
|
newValue = DatabaseFileData()
|
||||||
|
}
|
||||||
|
newValue.apply {
|
||||||
|
databaseFileAction = DatabaseFileAction.NONE
|
||||||
|
databaseFileToActivate = null
|
||||||
|
databaseFileList.apply {
|
||||||
|
clear()
|
||||||
|
addAll(databaseFileListLoaded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
databaseFilesLoaded.value = newValue
|
||||||
|
}).execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addDatabaseFile(databaseFileToAdd: DatabaseFile) {
|
||||||
|
addOrUpdateDatabaseFile(databaseFileToAdd, DatabaseFileAction.ADD)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDatabaseFile(databaseFileToUpdate: DatabaseFile) {
|
||||||
|
addOrUpdateDatabaseFile(databaseFileToUpdate, DatabaseFileAction.UPDATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addOrUpdateDatabaseFile(databaseFileToAddOrUpdate: DatabaseFile,
|
||||||
|
databaseFileAction: DatabaseFileAction) {
|
||||||
|
|
||||||
|
databaseFileToAddOrUpdate.databaseUri?.let { databaseUri ->
|
||||||
|
mFileDatabaseHistoryAction?.getFileDatabaseHistory(databaseUri) { fileDatabaseHistoryToAddOrUpdate ->
|
||||||
|
fileDatabaseHistoryToAddOrUpdate?.let {
|
||||||
|
mFileDatabaseHistoryAction?.addOrUpdateFileDatabaseHistory(fileDatabaseHistoryToAddOrUpdate) { fileHistoryAddedOrUpdated ->
|
||||||
|
fileHistoryAddedOrUpdated?.let {
|
||||||
|
IOActionTask (
|
||||||
|
{
|
||||||
|
val newValue = databaseFilesLoaded.value
|
||||||
|
newValue?.apply {
|
||||||
|
val fileDatabaseInfo = FileDatabaseInfo(getApplication<App>().applicationContext,
|
||||||
|
fileHistoryAddedOrUpdated.databaseUri)
|
||||||
|
this.databaseFileAction = databaseFileAction
|
||||||
|
val databaseFileToActivate =
|
||||||
|
DatabaseFile(
|
||||||
|
UriUtil.parse(fileHistoryAddedOrUpdated.databaseUri),
|
||||||
|
UriUtil.parse(fileHistoryAddedOrUpdated.keyFileUri),
|
||||||
|
UriUtil.decode(fileHistoryAddedOrUpdated.databaseUri),
|
||||||
|
fileDatabaseInfo.retrieveDatabaseAlias(fileHistoryAddedOrUpdated.databaseAlias),
|
||||||
|
fileDatabaseInfo.exists,
|
||||||
|
fileDatabaseInfo.getModificationString(),
|
||||||
|
fileDatabaseInfo.getSizeString()
|
||||||
|
)
|
||||||
|
when (databaseFileAction) {
|
||||||
|
DatabaseFileAction.ADD -> {
|
||||||
|
databaseFileList.add(databaseFileToActivate)
|
||||||
|
}
|
||||||
|
DatabaseFileAction.UPDATE -> {
|
||||||
|
databaseFileList
|
||||||
|
.find { it.databaseUri == databaseFileToActivate.databaseUri }
|
||||||
|
?.apply {
|
||||||
|
keyFileUri = databaseFileToActivate.keyFileUri
|
||||||
|
databaseAlias = databaseFileToActivate.databaseAlias
|
||||||
|
databaseFileExists = databaseFileToActivate.databaseFileExists
|
||||||
|
databaseLastModified = databaseFileToActivate.databaseLastModified
|
||||||
|
databaseSize = databaseFileToActivate.databaseSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
this.databaseFileToActivate = databaseFileToActivate
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ databaseFileAddedOrUpdated ->
|
||||||
|
databaseFileAddedOrUpdated?.let {
|
||||||
|
databaseFilesLoaded.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteDatabaseFile(databaseFileToDelete: DatabaseFile) {
|
||||||
|
|
||||||
|
databaseFileToDelete.databaseUri?.let { databaseUri ->
|
||||||
|
mFileDatabaseHistoryAction?.getFileDatabaseHistory(databaseUri) { fileDatabaseHistoryToDelete ->
|
||||||
|
fileDatabaseHistoryToDelete?.let {
|
||||||
|
mFileDatabaseHistoryAction?.deleteFileDatabaseHistory(fileDatabaseHistoryToDelete) { fileHistoryDeleted ->
|
||||||
|
fileHistoryDeleted?.let { _ ->
|
||||||
|
IOActionTask (
|
||||||
|
{
|
||||||
|
val newValue = databaseFilesLoaded.value
|
||||||
|
newValue?.apply {
|
||||||
|
databaseFileAction = DatabaseFileAction.DELETE
|
||||||
|
databaseFileToActivate =
|
||||||
|
DatabaseFile(
|
||||||
|
UriUtil.parse(fileHistoryDeleted.databaseUri),
|
||||||
|
UriUtil.parse(fileHistoryDeleted.keyFileUri),
|
||||||
|
UriUtil.decode(fileHistoryDeleted.databaseUri),
|
||||||
|
databaseFileToDelete.databaseAlias
|
||||||
|
)
|
||||||
|
databaseFileList.remove(databaseFileToDelete)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ databaseFileDeleted ->
|
||||||
|
databaseFileDeleted?.let {
|
||||||
|
databaseFilesLoaded.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun consumeAction() {
|
||||||
|
databaseFilesLoaded.value?.apply {
|
||||||
|
databaseFileAction = DatabaseFileAction.NONE
|
||||||
|
databaseFileToActivate = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseFileData {
|
||||||
|
val databaseFileList = ArrayList<DatabaseFile>()
|
||||||
|
|
||||||
|
var databaseFileToActivate: DatabaseFile? = null
|
||||||
|
var databaseFileAction: DatabaseFileAction = DatabaseFileAction.NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class DatabaseFileAction {
|
||||||
|
NONE, ADD, UPDATE, DELETE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,14 +17,14 @@
|
|||||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.utils
|
package com.kunzisoft.keepass.viewmodels
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.format.Formatter
|
import android.text.format.Formatter
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.utils.UriUtil
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -58,18 +58,6 @@ class FileDatabaseInfo : Serializable {
|
|||||||
}
|
}
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var canRead: Boolean = false
|
|
||||||
get() {
|
|
||||||
return documentFile?.canRead() ?: field
|
|
||||||
}
|
|
||||||
private set
|
|
||||||
|
|
||||||
var canWrite: Boolean = false
|
|
||||||
get() {
|
|
||||||
return documentFile?.canWrite() ?: field
|
|
||||||
}
|
|
||||||
private set
|
|
||||||
|
|
||||||
fun getModificationString(): String? {
|
fun getModificationString(): String? {
|
||||||
return documentFile?.lastModified()?.let {
|
return documentFile?.lastModified()?.let {
|
||||||
DateFormat.getDateTimeInstance()
|
DateFormat.getDateTimeInstance()
|
||||||
@@ -83,21 +71,11 @@ class FileDatabaseInfo : Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun retrieveDatabaseAlias(alias: String): String {
|
fun retrieveDatabaseAlias(alias: String): String? {
|
||||||
return when {
|
return when {
|
||||||
alias.isNotEmpty() -> alias
|
alias.isNotEmpty() -> alias
|
||||||
PreferencesUtil.isFullFilePathEnable(context) -> fileUri?.path ?: ""
|
PreferencesUtil.isFullFilePathEnable(context) -> fileUri?.path
|
||||||
else -> if (exists) documentFile?.name ?: "" else fileUri?.path ?: ""
|
else -> if (exists) documentFile?.name else fileUri?.path
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun retrieveDatabaseTitle(titleCallback: (String)->Unit) {
|
|
||||||
fileUri?.let { fileUri ->
|
|
||||||
FileDatabaseHistoryAction.getInstance(context.applicationContext)
|
|
||||||
.getFileDatabaseHistory(fileUri) { fileDatabaseHistoryEntity ->
|
|
||||||
titleCallback.invoke(retrieveDatabaseAlias(fileDatabaseHistoryEntity?.databaseAlias
|
|
||||||
?: ""))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user