mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
First refactoring pass
This commit is contained in:
@@ -25,14 +25,13 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentSender
|
import android.content.IntentSender
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.inputmethod.InlineSuggestionsRequest
|
import android.view.inputmethod.InlineSuggestionsRequest
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||||
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
||||||
|
import com.kunzisoft.keepass.activities.selection.DatabaseActivity
|
||||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||||
import com.kunzisoft.keepass.autofill.AutofillHelper.EXTRA_INLINE_SUGGESTIONS_REQUEST
|
import com.kunzisoft.keepass.autofill.AutofillHelper.EXTRA_INLINE_SUGGESTIONS_REQUEST
|
||||||
import com.kunzisoft.keepass.autofill.KeeAutofillService
|
import com.kunzisoft.keepass.autofill.KeeAutofillService
|
||||||
@@ -44,14 +43,14 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
|
|||||||
import com.kunzisoft.keepass.utils.LOCK_ACTION
|
import com.kunzisoft.keepass.utils.LOCK_ACTION
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
class AutofillLauncherActivity : AppCompatActivity() {
|
class AutofillLauncherActivity : DatabaseActivity() {
|
||||||
|
|
||||||
private var mDatabase: Database? = null
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
super.onDatabaseRetrieved(database)
|
||||||
|
// End activity if database not loaded
|
||||||
|
if (database?.loaded != true) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
// Retrieve selection mode
|
// Retrieve selection mode
|
||||||
EntrySelectionHelper.retrieveSpecialModeFromIntent(intent).let { specialMode ->
|
EntrySelectionHelper.retrieveSpecialModeFromIntent(intent).let { specialMode ->
|
||||||
when (specialMode) {
|
when (specialMode) {
|
||||||
@@ -64,7 +63,7 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
|
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
|
||||||
searchInfo.webDomain = concreteWebDomain
|
searchInfo.webDomain = concreteWebDomain
|
||||||
mDatabase?.let { database ->
|
database?.let { database ->
|
||||||
launchSelection(database, searchInfo)
|
launchSelection(database, searchInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +74,7 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
|||||||
val searchInfo = SearchInfo(registerInfo?.searchInfo)
|
val searchInfo = SearchInfo(registerInfo?.searchInfo)
|
||||||
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
|
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
|
||||||
searchInfo.webDomain = concreteWebDomain
|
searchInfo.webDomain = concreteWebDomain
|
||||||
mDatabase?.let { database ->
|
database?.let { database ->
|
||||||
launchRegistration(database, searchInfo, registerInfo)
|
launchRegistration(database, searchInfo, registerInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,8 +86,6 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun launchSelection(database: Database,
|
private fun launchSelection(database: Database,
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.kunzisoft.keepass.activities
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
|
|
||||||
|
interface DatabaseRetrieval {
|
||||||
|
fun onDatabaseRetrieved(database: Database?)
|
||||||
|
fun onDatabaseActionFinished(database: Database,
|
||||||
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result)
|
||||||
|
}
|
||||||
@@ -35,7 +35,6 @@ import android.widget.ProgressBar
|
|||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import com.google.android.material.appbar.CollapsingToolbarLayout
|
import com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.fragments.EntryFragment
|
import com.kunzisoft.keepass.activities.fragments.EntryFragment
|
||||||
@@ -45,6 +44,7 @@ import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
|||||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||||
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
|
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.Entry
|
import com.kunzisoft.keepass.database.element.Entry
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||||
import com.kunzisoft.keepass.education.EntryActivityEducation
|
import com.kunzisoft.keepass.education.EntryActivityEducation
|
||||||
@@ -57,6 +57,7 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
|
|||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RELOAD_TASK
|
||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
import com.kunzisoft.keepass.utils.*
|
import com.kunzisoft.keepass.utils.*
|
||||||
@@ -79,6 +80,9 @@ class EntryActivity : LockingActivity() {
|
|||||||
|
|
||||||
private val mEntryViewModel: EntryViewModel by viewModels()
|
private val mEntryViewModel: EntryViewModel by viewModels()
|
||||||
|
|
||||||
|
private var mEntryId: NodeId<UUID>? = null
|
||||||
|
private var mHistoryPosition: Int = -1
|
||||||
|
|
||||||
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
|
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
|
||||||
private var mAttachmentsToDownload: HashMap<Int, Attachment> = HashMap()
|
private var mAttachmentsToDownload: HashMap<Int, Attachment> = HashMap()
|
||||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||||
@@ -108,23 +112,18 @@ class EntryActivity : LockingActivity() {
|
|||||||
collapsingToolbarLayout?.title = " "
|
collapsingToolbarLayout?.title = " "
|
||||||
toolbar?.title = " "
|
toolbar?.title = " "
|
||||||
|
|
||||||
// Focus view to reinitialize timeout
|
|
||||||
coordinatorLayout?.resetAppTimeoutWhenViewFocusedOrChanged(this, mDatabase)
|
|
||||||
|
|
||||||
// Retrieve the textColor to tint the icon
|
// Retrieve the textColor to tint the icon
|
||||||
val taIconColor = theme.obtainStyledAttributes(intArrayOf(R.attr.colorAccent))
|
val taIconColor = theme.obtainStyledAttributes(intArrayOf(R.attr.colorAccent))
|
||||||
iconColor = taIconColor.getColor(0, Color.BLACK)
|
iconColor = taIconColor.getColor(0, Color.BLACK)
|
||||||
taIconColor.recycle()
|
taIconColor.recycle()
|
||||||
|
|
||||||
mReadOnly = mDatabase?.isReadOnly != false || mReadOnly
|
|
||||||
|
|
||||||
// Get Entry from UUID
|
// Get Entry from UUID
|
||||||
try {
|
try {
|
||||||
intent.getParcelableExtra<NodeId<UUID>?>(KEY_ENTRY)?.let { entryId ->
|
intent.getParcelableExtra<NodeId<UUID>?>(KEY_ENTRY)?.let { entryId ->
|
||||||
|
mEntryId = entryId
|
||||||
intent.removeExtra(KEY_ENTRY)
|
intent.removeExtra(KEY_ENTRY)
|
||||||
val historyPosition = intent.getIntExtra(KEY_ENTRY_HISTORY_POSITION, -1)
|
mHistoryPosition = intent.getIntExtra(KEY_ENTRY_HISTORY_POSITION, -1)
|
||||||
intent.removeExtra(KEY_ENTRY_HISTORY_POSITION)
|
intent.removeExtra(KEY_ENTRY_HISTORY_POSITION)
|
||||||
mEntryViewModel.loadEntry(entryId, historyPosition)
|
|
||||||
}
|
}
|
||||||
} catch (e: ClassCastException) {
|
} catch (e: ClassCastException) {
|
||||||
Log.e(TAG, "Unable to retrieve the entry key")
|
Log.e(TAG, "Unable to retrieve the entry key")
|
||||||
@@ -152,7 +151,7 @@ class EntryActivity : LockingActivity() {
|
|||||||
|
|
||||||
// Assign title icon
|
// Assign title icon
|
||||||
titleIconView?.let { iconView ->
|
titleIconView?.let { iconView ->
|
||||||
mDatabase?.iconDrawableFactory?.assignDatabaseIcon(iconView, entryInfo.icon, iconColor)
|
mIconDrawableFactory?.assignDatabaseIcon(iconView, entryInfo.icon, iconColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign title text
|
// Assign title text
|
||||||
@@ -209,23 +208,36 @@ class EntryActivity : LockingActivity() {
|
|||||||
historySelected.historyPosition,
|
historySelected.historyPosition,
|
||||||
mReadOnly)
|
mReadOnly)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.onActionFinish = { actionTask, result ->
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
when (actionTask) {
|
super.onDatabaseRetrieved(database)
|
||||||
ACTION_DATABASE_RESTORE_ENTRY_HISTORY,
|
// Focus view to reinitialize timeout
|
||||||
ACTION_DATABASE_DELETE_ENTRY_HISTORY -> {
|
coordinatorLayout?.resetAppTimeoutWhenViewFocusedOrChanged(this, database)
|
||||||
// Close the current activity after an history action
|
mEntryViewModel.setDatabase(database)
|
||||||
if (result.isSuccess)
|
mEntryViewModel.loadEntry(mEntryId, mHistoryPosition)
|
||||||
finish()
|
}
|
||||||
}
|
|
||||||
ACTION_DATABASE_RELOAD_TASK -> {
|
override fun onDatabaseActionFinished(
|
||||||
// Close the current activity
|
database: Database,
|
||||||
this.showActionErrorIfNeeded(result)
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result
|
||||||
|
) {
|
||||||
|
super.onDatabaseActionFinished(database, actionTask, result)
|
||||||
|
when (actionTask) {
|
||||||
|
ACTION_DATABASE_RESTORE_ENTRY_HISTORY,
|
||||||
|
ACTION_DATABASE_DELETE_ENTRY_HISTORY -> {
|
||||||
|
// Close the current activity after an history action
|
||||||
|
if (result.isSuccess)
|
||||||
finish()
|
finish()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
coordinatorLayout?.showActionErrorIfNeeded(result)
|
ACTION_DATABASE_RELOAD_TASK -> {
|
||||||
|
// Close the current activity
|
||||||
|
this.showActionErrorIfNeeded(result)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
coordinatorLayout?.showActionErrorIfNeeded(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -356,25 +368,23 @@ class EntryActivity : LockingActivity() {
|
|||||||
}
|
}
|
||||||
R.id.menu_restore_entry_history -> {
|
R.id.menu_restore_entry_history -> {
|
||||||
mEntryViewModel.getMainEntry()?.let { mainEntry ->
|
mEntryViewModel.getMainEntry()?.let { mainEntry ->
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseRestoreEntryHistory(
|
restoreEntryHistory(
|
||||||
mainEntry,
|
mainEntry,
|
||||||
mEntryViewModel.getEntryHistoryPosition(),
|
mEntryViewModel.getEntryHistoryPosition())
|
||||||
!mReadOnly && mAutoSaveEnable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.menu_delete_entry_history -> {
|
R.id.menu_delete_entry_history -> {
|
||||||
mEntryViewModel.getMainEntry()?.let { mainEntry ->
|
mEntryViewModel.getMainEntry()?.let { mainEntry ->
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseDeleteEntryHistory(
|
deleteEntryHistory(
|
||||||
mainEntry,
|
mainEntry,
|
||||||
mEntryViewModel.getEntryHistoryPosition(),
|
mEntryViewModel.getEntryHistoryPosition())
|
||||||
!mReadOnly && mAutoSaveEnable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.menu_save_database -> {
|
R.id.menu_save_database -> {
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSave(!mReadOnly)
|
saveDatabase()
|
||||||
}
|
}
|
||||||
R.id.menu_reload_database -> {
|
R.id.menu_reload_database -> {
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseReload(false)
|
reloadDatabase()
|
||||||
}
|
}
|
||||||
android.R.id.home -> finish() // close this activity and return to preview activity (if there is any)
|
android.R.id.home -> finish() // close this activity and return to preview activity (if there is any)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
|
|||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
|
||||||
import com.kunzisoft.keepass.services.KeyboardEntryNotificationService
|
import com.kunzisoft.keepass.services.KeyboardEntryNotificationService
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
import com.kunzisoft.keepass.utils.UriUtil
|
import com.kunzisoft.keepass.utils.UriUtil
|
||||||
@@ -95,6 +96,9 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
|
|
||||||
private val mEntryEditViewModel: EntryEditViewModel by viewModels()
|
private val mEntryEditViewModel: EntryEditViewModel by viewModels()
|
||||||
|
|
||||||
|
private var mAllowCustomFields = false
|
||||||
|
private var mAllowOTP = false
|
||||||
|
|
||||||
// To manage attachments
|
// To manage attachments
|
||||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||||
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
|
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
|
||||||
@@ -122,9 +126,6 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
validateButton = findViewById(R.id.entry_edit_validate)
|
validateButton = findViewById(R.id.entry_edit_validate)
|
||||||
loadingView = findViewById(R.id.loading)
|
loadingView = findViewById(R.id.loading)
|
||||||
|
|
||||||
// Focus view to reinitialize timeout
|
|
||||||
coordinatorLayout?.resetAppTimeoutWhenViewFocusedOrChanged(this, mDatabase)
|
|
||||||
|
|
||||||
stopService(Intent(this, ClipboardEntryNotificationService::class.java))
|
stopService(Intent(this, ClipboardEntryNotificationService::class.java))
|
||||||
stopService(Intent(this, KeyboardEntryNotificationService::class.java))
|
stopService(Intent(this, KeyboardEntryNotificationService::class.java))
|
||||||
|
|
||||||
@@ -227,7 +228,7 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
templateSelectorSpinner?.apply {
|
templateSelectorSpinner?.apply {
|
||||||
// Build template selector
|
// Build template selector
|
||||||
if (templates.isNotEmpty()) {
|
if (templates.isNotEmpty()) {
|
||||||
adapter = TemplatesSelectorAdapter(this@EntryEditActivity, mDatabase, templates)
|
adapter = TemplatesSelectorAdapter(this@EntryEditActivity, mIconDrawableFactory, templates)
|
||||||
setSelection(templates.indexOf(defaultTemplate))
|
setSelection(templates.indexOf(defaultTemplate))
|
||||||
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||||
@@ -245,71 +246,74 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
mEntryEditViewModel.onEntrySaved.observe(this) { entrySave ->
|
mEntryEditViewModel.onEntrySaved.observe(this) { entrySave ->
|
||||||
// Open a progress dialog and save entry
|
// Open a progress dialog and save entry
|
||||||
entrySave.parent?.let { parent ->
|
entrySave.parent?.let { parent ->
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseCreateEntry(
|
createEntry(entrySave.newEntry, parent)
|
||||||
entrySave.newEntry,
|
|
||||||
parent,
|
|
||||||
!mReadOnly && mAutoSaveEnable
|
|
||||||
)
|
|
||||||
} ?: run {
|
} ?: run {
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseUpdateEntry(
|
updateEntry(entrySave.oldEntry, entrySave.newEntry)
|
||||||
entrySave.oldEntry,
|
|
||||||
entrySave.newEntry,
|
|
||||||
!mReadOnly && mAutoSaveEnable
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create progress dialog
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
mProgressDatabaseTaskProvider?.onActionFinish = { actionTask, result ->
|
super.onDatabaseRetrieved(database)
|
||||||
when (actionTask) {
|
// Focus view to reinitialize timeout
|
||||||
ACTION_DATABASE_CREATE_ENTRY_TASK,
|
coordinatorLayout?.resetAppTimeoutWhenViewFocusedOrChanged(this, database)
|
||||||
ACTION_DATABASE_UPDATE_ENTRY_TASK -> {
|
mEntryEditViewModel.setDatabase(database)
|
||||||
try {
|
mAllowCustomFields = database?.allowEntryCustomFields() == true
|
||||||
if (result.isSuccess) {
|
mAllowOTP = database?.allowOTP == true
|
||||||
var newNodes: List<Node> = ArrayList()
|
}
|
||||||
result.data?.getBundle(DatabaseTaskNotificationService.NEW_NODES_KEY)?.let { newNodesBundle ->
|
|
||||||
mDatabase?.let { database ->
|
override fun onDatabaseActionFinished(
|
||||||
newNodes = DatabaseTaskNotificationService.getListNodesFromBundle(database, newNodesBundle)
|
database: Database,
|
||||||
}
|
actionTask: String,
|
||||||
}
|
result: ActionRunnable.Result
|
||||||
if (newNodes.size == 1) {
|
) {
|
||||||
(newNodes[0] as? Entry?)?.let { entry ->
|
super.onDatabaseActionFinished(database, actionTask, result)
|
||||||
EntrySelectionHelper.doSpecialAction(intent,
|
when (actionTask) {
|
||||||
{
|
ACTION_DATABASE_CREATE_ENTRY_TASK,
|
||||||
// Finish naturally
|
ACTION_DATABASE_UPDATE_ENTRY_TASK -> {
|
||||||
finishForEntryResult(actionTask, entry)
|
try {
|
||||||
},
|
if (result.isSuccess) {
|
||||||
{
|
var newNodes: List<Node> = ArrayList()
|
||||||
// Nothing when search retrieved
|
result.data?.getBundle(DatabaseTaskNotificationService.NEW_NODES_KEY)?.let { newNodesBundle ->
|
||||||
},
|
newNodes = DatabaseTaskNotificationService.getListNodesFromBundle(database, newNodesBundle)
|
||||||
{
|
}
|
||||||
entryValidatedForSave(actionTask, entry)
|
if (newNodes.size == 1) {
|
||||||
},
|
(newNodes[0] as? Entry?)?.let { entry ->
|
||||||
{
|
EntrySelectionHelper.doSpecialAction(intent,
|
||||||
entryValidatedForKeyboardSelection(actionTask, entry)
|
{
|
||||||
},
|
// Finish naturally
|
||||||
{ _, _ ->
|
finishForEntryResult(actionTask, entry)
|
||||||
entryValidatedForAutofillSelection(entry)
|
},
|
||||||
},
|
{
|
||||||
{
|
// Nothing when search retrieved
|
||||||
entryValidatedForAutofillRegistration(actionTask, entry)
|
},
|
||||||
}
|
{
|
||||||
)
|
entryValidatedForSave(actionTask, entry)
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
entryValidatedForKeyboardSelection(database, actionTask, entry)
|
||||||
|
},
|
||||||
|
{ _, _ ->
|
||||||
|
entryValidatedForAutofillSelection(database, entry)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entryValidatedForAutofillRegistration(actionTask, entry)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Unable to retrieve entry after database action", e)
|
|
||||||
}
|
}
|
||||||
}
|
} catch (e: Exception) {
|
||||||
ACTION_DATABASE_RELOAD_TASK -> {
|
Log.e(TAG, "Unable to retrieve entry after database action", e)
|
||||||
// Close the current activity
|
|
||||||
this.showActionErrorIfNeeded(result)
|
|
||||||
finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
coordinatorLayout?.showActionErrorIfNeeded(result)
|
ACTION_DATABASE_RELOAD_TASK -> {
|
||||||
|
// Close the current activity
|
||||||
|
this.showActionErrorIfNeeded(result)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
coordinatorLayout?.showActionErrorIfNeeded(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun entryValidatedForSave(actionTask: String, entry: Entry) {
|
private fun entryValidatedForSave(actionTask: String, entry: Entry) {
|
||||||
@@ -317,26 +321,22 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
finishForEntryResult(actionTask, entry)
|
finishForEntryResult(actionTask, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun entryValidatedForKeyboardSelection(actionTask: String, entry: Entry) {
|
private fun entryValidatedForKeyboardSelection(database: Database, actionTask: String, entry: Entry) {
|
||||||
// Populate Magikeyboard with entry
|
// Populate Magikeyboard with entry
|
||||||
mDatabase?.let { database ->
|
populateKeyboardAndMoveAppToBackground(this,
|
||||||
populateKeyboardAndMoveAppToBackground(this,
|
entry.getEntryInfo(database),
|
||||||
entry.getEntryInfo(database),
|
intent)
|
||||||
intent)
|
|
||||||
}
|
|
||||||
onValidateSpecialMode()
|
onValidateSpecialMode()
|
||||||
// Don't keep activity history for entry edition
|
// Don't keep activity history for entry edition
|
||||||
finishForEntryResult(actionTask, entry)
|
finishForEntryResult(actionTask, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun entryValidatedForAutofillSelection(entry: Entry) {
|
private fun entryValidatedForAutofillSelection(database: Database, entry: Entry) {
|
||||||
// Build Autofill response with the entry selected
|
// Build Autofill response with the entry selected
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
mDatabase?.let { database ->
|
AutofillHelper.buildResponseAndSetResult(this@EntryEditActivity,
|
||||||
AutofillHelper.buildResponseAndSetResult(this@EntryEditActivity,
|
database,
|
||||||
database,
|
entry.getEntryInfo(database))
|
||||||
entry.getEntryInfo(database))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onValidateSpecialMode()
|
onValidateSpecialMode()
|
||||||
}
|
}
|
||||||
@@ -466,10 +466,8 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
|
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
|
||||||
|
|
||||||
val allowCustomField = mDatabase?.allowEntryCustomFields() == true
|
|
||||||
|
|
||||||
menu?.findItem(R.id.menu_add_field)?.apply {
|
menu?.findItem(R.id.menu_add_field)?.apply {
|
||||||
isEnabled = allowCustomField
|
isEnabled = mAllowCustomFields
|
||||||
isVisible = isEnabled
|
isVisible = isEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,9 +479,8 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
menu?.findItem(R.id.menu_add_otp)?.apply {
|
menu?.findItem(R.id.menu_add_otp)?.apply {
|
||||||
val allowOTP = mDatabase?.allowOTP == true
|
|
||||||
// OTP not compatible below KitKat
|
// OTP not compatible below KitKat
|
||||||
isEnabled = allowOTP
|
isEnabled = mAllowOTP
|
||||||
&& !mEntryEditViewModel.entryIsTemplate()
|
&& !mEntryEditViewModel.entryIsTemplate()
|
||||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
||||||
isVisible = isEnabled
|
isVisible = isEnabled
|
||||||
@@ -513,7 +510,7 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
|
|
||||||
if (!generatePasswordEductionPerformed) {
|
if (!generatePasswordEductionPerformed) {
|
||||||
val addNewFieldView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_field)
|
val addNewFieldView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_field)
|
||||||
val addNewFieldEducationPerformed = mDatabase?.allowEntryCustomFields() == true
|
val addNewFieldEducationPerformed = mAllowCustomFields
|
||||||
&& addNewFieldView != null
|
&& addNewFieldView != null
|
||||||
&& addNewFieldView.isVisible
|
&& addNewFieldView.isVisible
|
||||||
&& entryEditActivityEducation.checkAndPerformedEntryNewFieldEducation(
|
&& entryEditActivityEducation.checkAndPerformedEntryNewFieldEducation(
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import android.widget.Toast
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||||
|
import com.kunzisoft.keepass.activities.selection.DatabaseActivity
|
||||||
|
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.search.SearchHelper
|
import com.kunzisoft.keepass.database.search.SearchHelper
|
||||||
import com.kunzisoft.keepass.magikeyboard.MagikIME
|
import com.kunzisoft.keepass.magikeyboard.MagikIME
|
||||||
@@ -39,14 +41,10 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
|
|||||||
* Activity to search or select entry in database,
|
* Activity to search or select entry in database,
|
||||||
* Commonly used with Magikeyboard
|
* Commonly used with Magikeyboard
|
||||||
*/
|
*/
|
||||||
class EntrySelectionLauncherActivity : AppCompatActivity() {
|
class EntrySelectionLauncherActivity : DatabaseActivity() {
|
||||||
|
|
||||||
private var mDatabase: Database? = null
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
super.onDatabaseRetrieved(database)
|
||||||
var sharedWebDomain: String? = null
|
var sharedWebDomain: String? = null
|
||||||
var otpString: String? = null
|
var otpString: String? = null
|
||||||
|
|
||||||
@@ -72,20 +70,22 @@ class EntrySelectionLauncherActivity : AppCompatActivity() {
|
|||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Build domain search param
|
// Build domain search param
|
||||||
val searchInfo = SearchInfo().apply {
|
val searchInfo = SearchInfo().apply {
|
||||||
this.webDomain = sharedWebDomain
|
this.webDomain = sharedWebDomain
|
||||||
this.otpString = otpString
|
this.otpString = otpString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// End activity if database not loaded
|
||||||
|
if (database?.loaded != true) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
|
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
|
||||||
searchInfo.webDomain = concreteWebDomain
|
searchInfo.webDomain = concreteWebDomain
|
||||||
mDatabase?.let { database ->
|
database?.let { database ->
|
||||||
launch(database, searchInfo)
|
launch(database, searchInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun launch(database: Database,
|
private fun launch(database: Database,
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import com.kunzisoft.keepass.adapters.FileDatabaseHistoryAdapter
|
|||||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||||
import com.kunzisoft.keepass.autofill.AutofillComponent
|
import com.kunzisoft.keepass.autofill.AutofillComponent
|
||||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDatabaseTaskProvider
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
|
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
|
||||||
import com.kunzisoft.keepass.model.MainCredential
|
import com.kunzisoft.keepass.model.MainCredential
|
||||||
@@ -61,6 +60,7 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
|
|||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
|
||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
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 com.kunzisoft.keepass.viewmodels.DatabaseFilesViewModel
|
||||||
@@ -85,15 +85,9 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
|
|
||||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||||
|
|
||||||
private var mProgressDatabaseTaskProvider: ProgressDatabaseTaskProvider? = null
|
|
||||||
|
|
||||||
private var mDatabase: Database? = null
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
|
|
||||||
mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(applicationContext)
|
mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(applicationContext)
|
||||||
|
|
||||||
setContentView(R.layout.activity_file_selection)
|
setContentView(R.layout.activity_file_selection)
|
||||||
@@ -195,36 +189,52 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
mAdapterDatabaseHistory?.setDefaultDatabase(it)
|
mAdapterDatabaseHistory?.setDefaultDatabase(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach the dialog thread to this activity
|
// Construct adapter with listeners
|
||||||
mProgressDatabaseTaskProvider = ProgressDatabaseTaskProvider(this).apply {
|
if (PreferencesUtil.showRecentFiles(this@FileDatabaseSelectActivity)) {
|
||||||
onActionFinish = { actionTask, result ->
|
databaseFilesViewModel.loadListOfDatabases()
|
||||||
when (actionTask) {
|
} else {
|
||||||
ACTION_DATABASE_CREATE_TASK -> {
|
mAdapterDatabaseHistory?.clearDatabaseFileHistoryList()
|
||||||
result.data?.getParcelable<Uri?>(DATABASE_URI_KEY)?.let { databaseUri ->
|
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
||||||
val mainCredential = result.data?.getParcelable(DatabaseTaskNotificationService.MAIN_CREDENTIAL_KEY) ?: MainCredential()
|
}
|
||||||
databaseFilesViewModel.addDatabaseFile(databaseUri, mainCredential.keyFileUri)
|
}
|
||||||
}
|
|
||||||
GroupActivity.launch(this@FileDatabaseSelectActivity,
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
PreferencesUtil.enableReadOnlyDatabase(this@FileDatabaseSelectActivity))
|
super.onDatabaseRetrieved(database)
|
||||||
}
|
if (database?.loaded == true) {
|
||||||
ACTION_DATABASE_LOAD_TASK -> {
|
launchGroupActivity(database)
|
||||||
val database = mDatabase
|
}
|
||||||
if (result.isSuccess
|
}
|
||||||
&& database?.loaded == true) {
|
|
||||||
launchGroupActivity(database)
|
override fun onDatabaseActionFinished(
|
||||||
} else {
|
database: Database,
|
||||||
var resultError = ""
|
actionTask: String,
|
||||||
val resultMessage = result.message
|
result: ActionRunnable.Result
|
||||||
// Show error message
|
) {
|
||||||
if (resultMessage != null && resultMessage.isNotEmpty()) {
|
super.onDatabaseActionFinished(database, actionTask, result)
|
||||||
resultError = "$resultError $resultMessage"
|
when (actionTask) {
|
||||||
}
|
ACTION_DATABASE_CREATE_TASK -> {
|
||||||
Log.e(TAG, resultError)
|
result.data?.getParcelable<Uri?>(DATABASE_URI_KEY)?.let { databaseUri ->
|
||||||
Snackbar.make(coordinatorLayout,
|
val mainCredential = result.data?.getParcelable(DatabaseTaskNotificationService.MAIN_CREDENTIAL_KEY) ?: MainCredential()
|
||||||
resultError,
|
databaseFilesViewModel.addDatabaseFile(databaseUri, mainCredential.keyFileUri)
|
||||||
Snackbar.LENGTH_LONG).asError().show()
|
}
|
||||||
}
|
GroupActivity.launch(this@FileDatabaseSelectActivity,
|
||||||
|
PreferencesUtil.enableReadOnlyDatabase(this@FileDatabaseSelectActivity))
|
||||||
|
}
|
||||||
|
ACTION_DATABASE_LOAD_TASK -> {
|
||||||
|
if (result.isSuccess
|
||||||
|
&& database.loaded) {
|
||||||
|
launchGroupActivity(database)
|
||||||
|
} else {
|
||||||
|
var resultError = ""
|
||||||
|
val resultMessage = result.message
|
||||||
|
// Show error message
|
||||||
|
if (resultMessage != null && resultMessage.isNotEmpty()) {
|
||||||
|
resultError = "$resultError $resultMessage"
|
||||||
}
|
}
|
||||||
|
Log.e(TAG, resultError)
|
||||||
|
Snackbar.make(coordinatorLayout,
|
||||||
|
resultError,
|
||||||
|
Snackbar.LENGTH_LONG).asError().show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,29 +310,6 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
createDatabaseButtonView?.visibility = View.GONE
|
createDatabaseButtonView?.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val database = mDatabase
|
|
||||||
if (database?.loaded == true) {
|
|
||||||
launchGroupActivity(database)
|
|
||||||
} else {
|
|
||||||
// Construct adapter with listeners
|
|
||||||
if (PreferencesUtil.showRecentFiles(this)) {
|
|
||||||
databaseFilesViewModel.loadListOfDatabases()
|
|
||||||
} else {
|
|
||||||
mAdapterDatabaseHistory?.clearDatabaseFileHistoryList()
|
|
||||||
mAdapterDatabaseHistory?.notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register progress task
|
|
||||||
mProgressDatabaseTaskProvider?.registerProgressTask()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
// Unregister progress task
|
|
||||||
mProgressDatabaseTaskProvider?.unregisterProgressTask()
|
|
||||||
|
|
||||||
super.onPause()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
@@ -334,15 +321,10 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onAssignKeyDialogPositiveClick(mainCredential: MainCredential) {
|
override fun onAssignKeyDialogPositiveClick(mainCredential: MainCredential) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mDatabaseFileUri?.let { databaseUri ->
|
mDatabaseFileUri?.let { databaseUri ->
|
||||||
|
|
||||||
// Create the new database
|
// Create the new database
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseCreate(
|
createDatabase(databaseUri, mainCredential)
|
||||||
databaseUri,
|
|
||||||
mainCredential
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
val error = getString(R.string.error_create_database_file)
|
val error = getString(R.string.error_create_database_file)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -67,6 +67,8 @@ class IconPickerActivity : LockingActivity() {
|
|||||||
|
|
||||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||||
|
|
||||||
|
private var mDatabase: Database? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@@ -84,11 +86,6 @@ class IconPickerActivity : LockingActivity() {
|
|||||||
mExternalFileHelper = ExternalFileHelper(this)
|
mExternalFileHelper = ExternalFileHelper(this)
|
||||||
|
|
||||||
uploadButton = findViewById(R.id.icon_picker_upload)
|
uploadButton = findViewById(R.id.icon_picker_upload)
|
||||||
if (mDatabase?.allowCustomIcons == true) {
|
|
||||||
uploadButton.setOpenDocumentClickListener(mExternalFileHelper)
|
|
||||||
} else {
|
|
||||||
uploadButton.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
lockView = findViewById(R.id.lock_button)
|
lockView = findViewById(R.id.lock_button)
|
||||||
lockView?.setOnClickListener {
|
lockView?.setOnClickListener {
|
||||||
@@ -114,9 +111,6 @@ class IconPickerActivity : LockingActivity() {
|
|||||||
mIconImage = savedInstanceState.getParcelable(EXTRA_ICON) ?: mIconImage
|
mIconImage = savedInstanceState.getParcelable(EXTRA_ICON) ?: mIconImage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus view to reinitialize timeout
|
|
||||||
findViewById<ViewGroup>(R.id.icon_picker_container)?.resetAppTimeoutWhenViewFocusedOrChanged(this, mDatabase)
|
|
||||||
|
|
||||||
iconPickerViewModel.standardIconPicked.observe(this) { iconStandard ->
|
iconPickerViewModel.standardIconPicked.observe(this) { iconStandard ->
|
||||||
mIconImage.standard = iconStandard
|
mIconImage.standard = iconStandard
|
||||||
// Remove the custom icon if a standard one is selected
|
// Remove the custom icon if a standard one is selected
|
||||||
@@ -150,6 +144,22 @@ class IconPickerActivity : LockingActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
super.onDatabaseRetrieved(database)
|
||||||
|
|
||||||
|
mDatabase = database
|
||||||
|
|
||||||
|
if (database?.allowCustomIcons == true) {
|
||||||
|
uploadButton.setOpenDocumentClickListener(mExternalFileHelper)
|
||||||
|
} else {
|
||||||
|
uploadButton.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus view to reinitialize timeout
|
||||||
|
findViewById<ViewGroup>(R.id.icon_picker_container)
|
||||||
|
?.resetAppTimeoutWhenViewFocusedOrChanged(this, database)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateIconsSelectedViews() {
|
private fun updateIconsSelectedViews() {
|
||||||
if (mIconsSelected.isEmpty()) {
|
if (mIconsSelected.isEmpty()) {
|
||||||
mCustomIconsSelectionMode = false
|
mCustomIconsSelectionMode = false
|
||||||
|
|||||||
@@ -33,11 +33,15 @@ import com.igreenwood.loupe.Loupe
|
|||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
|
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
class ImageViewerActivity : LockingActivity() {
|
class ImageViewerActivity : LockingActivity() {
|
||||||
|
|
||||||
|
private lateinit var imageView: ImageView
|
||||||
|
private lateinit var progressView: View
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@@ -49,43 +53,8 @@ class ImageViewerActivity : LockingActivity() {
|
|||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
|
||||||
val imageContainerView: ViewGroup = findViewById(R.id.image_viewer_container)
|
val imageContainerView: ViewGroup = findViewById(R.id.image_viewer_container)
|
||||||
val imageView: ImageView = findViewById(R.id.image_viewer_image)
|
imageView = findViewById(R.id.image_viewer_image)
|
||||||
val progressView: View = findViewById(R.id.image_viewer_progress)
|
progressView = findViewById(R.id.image_viewer_progress)
|
||||||
|
|
||||||
// Approximately, to not OOM and allow a zoom
|
|
||||||
val mImagePreviewMaxWidth = max(
|
|
||||||
resources.displayMetrics.widthPixels * 2,
|
|
||||||
resources.displayMetrics.heightPixels * 2
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
|
||||||
progressView.visibility = View.VISIBLE
|
|
||||||
intent.getParcelableExtra<Attachment>(IMAGE_ATTACHMENT_TAG)?.let { attachment ->
|
|
||||||
|
|
||||||
supportActionBar?.title = attachment.name
|
|
||||||
|
|
||||||
val size = attachment.binaryData.getSize()
|
|
||||||
supportActionBar?.subtitle = Formatter.formatFileSize(this, size)
|
|
||||||
|
|
||||||
mDatabase?.let { database ->
|
|
||||||
BinaryDatabaseManager.loadBitmap(
|
|
||||||
database,
|
|
||||||
attachment.binaryData,
|
|
||||||
mImagePreviewMaxWidth
|
|
||||||
) { bitmapLoaded ->
|
|
||||||
if (bitmapLoaded == null) {
|
|
||||||
finish()
|
|
||||||
} else {
|
|
||||||
progressView.visibility = View.GONE
|
|
||||||
imageView.setImageBitmap(bitmapLoaded)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: finish()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Unable to view the binary", e)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
Loupe.create(imageView, imageContainerView) {
|
Loupe.create(imageView, imageContainerView) {
|
||||||
onViewTranslateListener = object : Loupe.OnViewTranslateListener {
|
onViewTranslateListener = object : Loupe.OnViewTranslateListener {
|
||||||
@@ -110,6 +79,45 @@ class ImageViewerActivity : LockingActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
super.onDatabaseRetrieved(database)
|
||||||
|
|
||||||
|
try {
|
||||||
|
progressView.visibility = View.VISIBLE
|
||||||
|
intent.getParcelableExtra<Attachment>(IMAGE_ATTACHMENT_TAG)?.let { attachment ->
|
||||||
|
|
||||||
|
supportActionBar?.title = attachment.name
|
||||||
|
|
||||||
|
val size = attachment.binaryData.getSize()
|
||||||
|
supportActionBar?.subtitle = Formatter.formatFileSize(this, size)
|
||||||
|
|
||||||
|
// Approximately, to not OOM and allow a zoom
|
||||||
|
val mImagePreviewMaxWidth = max(
|
||||||
|
resources.displayMetrics.widthPixels * 2,
|
||||||
|
resources.displayMetrics.heightPixels * 2
|
||||||
|
)
|
||||||
|
|
||||||
|
database?.let { database ->
|
||||||
|
BinaryDatabaseManager.loadBitmap(
|
||||||
|
database,
|
||||||
|
attachment.binaryData,
|
||||||
|
mImagePreviewMaxWidth
|
||||||
|
) { bitmapLoaded ->
|
||||||
|
if (bitmapLoaded == null) {
|
||||||
|
finish()
|
||||||
|
} else {
|
||||||
|
progressView.visibility = View.GONE
|
||||||
|
imageView.setImageBitmap(bitmapLoaded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: finish()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to view the binary", e)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> finish()
|
android.R.id.home -> finish()
|
||||||
|
|||||||
@@ -19,22 +19,20 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.activities
|
package com.kunzisoft.keepass.activities
|
||||||
|
|
||||||
import android.os.Bundle
|
import com.kunzisoft.keepass.activities.selection.DatabaseActivity
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.search.SearchHelper
|
import com.kunzisoft.keepass.database.search.SearchHelper
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity to select entry in database and populate it in Magikeyboard
|
* Activity to select entry in database and populate it in Magikeyboard
|
||||||
*/
|
*/
|
||||||
class MagikeyboardLauncherActivity : AppCompatActivity() {
|
class MagikeyboardLauncherActivity : DatabaseActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
super.onDatabaseRetrieved(database)
|
||||||
val database = Database.getInstance()
|
database?.let {
|
||||||
|
val readOnly = database.isReadOnly
|
||||||
val readOnly = database.isReadOnly
|
SearchHelper.checkAutoSearchInfo(this,
|
||||||
SearchHelper.checkAutoSearchInfo(this,
|
|
||||||
database,
|
database,
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
@@ -49,8 +47,8 @@ class MagikeyboardLauncherActivity : AppCompatActivity() {
|
|||||||
// Pass extra to get entry
|
// Pass extra to get entry
|
||||||
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this)
|
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
finish()
|
finish()
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
|||||||
import com.kunzisoft.keepass.autofill.AutofillComponent
|
import com.kunzisoft.keepass.autofill.AutofillComponent
|
||||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||||
import com.kunzisoft.keepass.biometric.AdvancedUnlockFragment
|
import com.kunzisoft.keepass.biometric.AdvancedUnlockFragment
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDatabaseTaskProvider
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
|
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
|
||||||
import com.kunzisoft.keepass.database.exception.FileNotFoundDatabaseException
|
import com.kunzisoft.keepass.database.exception.FileNotFoundDatabaseException
|
||||||
@@ -63,6 +62,7 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
|
|||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.MAIN_CREDENTIAL_KEY
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.MAIN_CREDENTIAL_KEY
|
||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.READ_ONLY_KEY
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.READ_ONLY_KEY
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
|
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
|
||||||
import com.kunzisoft.keepass.utils.MenuUtil
|
import com.kunzisoft.keepass.utils.MenuUtil
|
||||||
import com.kunzisoft.keepass.utils.UriUtil
|
import com.kunzisoft.keepass.utils.UriUtil
|
||||||
@@ -87,8 +87,6 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
|
|
||||||
private val databaseFileViewModel: DatabaseFileViewModel by viewModels()
|
private val databaseFileViewModel: DatabaseFileViewModel by viewModels()
|
||||||
|
|
||||||
private var mDatabase: Database? = null
|
|
||||||
|
|
||||||
private var mDefaultDatabase: Boolean = false
|
private var mDefaultDatabase: Boolean = false
|
||||||
private var mDatabaseFileUri: Uri? = null
|
private var mDatabaseFileUri: Uri? = null
|
||||||
private var mDatabaseKeyFileUri: Uri? = null
|
private var mDatabaseKeyFileUri: Uri? = null
|
||||||
@@ -109,15 +107,11 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private var mProgressDatabaseTaskProvider: ProgressDatabaseTaskProvider? = null
|
|
||||||
|
|
||||||
private var mAllowAutoOpenBiometricPrompt: Boolean = true
|
private var mAllowAutoOpenBiometricPrompt: Boolean = true
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_password)
|
setContentView(R.layout.activity_password)
|
||||||
|
|
||||||
toolbar = findViewById(R.id.toolbar)
|
toolbar = findViewById(R.id.toolbar)
|
||||||
@@ -208,74 +202,107 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
|
|
||||||
onDatabaseFileLoaded(databaseFile?.databaseUri, keyFileUri)
|
onDatabaseFileLoaded(databaseFile?.databaseUri, keyFileUri)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider = ProgressDatabaseTaskProvider(this).apply {
|
override fun onResume() {
|
||||||
onActionFinish = { actionTask, result ->
|
super.onResume()
|
||||||
when (actionTask) {
|
|
||||||
ACTION_DATABASE_LOAD_TASK -> {
|
|
||||||
// Recheck advanced unlock if error
|
|
||||||
advancedUnlockFragment?.initAdvancedUnlockMode()
|
|
||||||
|
|
||||||
if (result.isSuccess) {
|
mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this@PasswordActivity)
|
||||||
mDatabaseKeyFileUri = null
|
|
||||||
clearCredentialsViews(true)
|
|
||||||
mDatabase?.let { database ->
|
|
||||||
launchGroupActivity(database)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var resultError = ""
|
|
||||||
val resultException = result.exception
|
|
||||||
val resultMessage = result.message
|
|
||||||
|
|
||||||
if (resultException != null) {
|
// Back to previous keyboard is setting activated
|
||||||
resultError = resultException.getLocalizedMessage(resources)
|
if (PreferencesUtil.isKeyboardPreviousDatabaseCredentialsEnable(this@PasswordActivity)) {
|
||||||
|
sendBroadcast(Intent(BACK_PREVIOUS_KEYBOARD_ACTION))
|
||||||
|
}
|
||||||
|
|
||||||
when (resultException) {
|
// Don't allow auto open prompt if lock become when UI visible
|
||||||
is DuplicateUuidDatabaseException -> {
|
mAllowAutoOpenBiometricPrompt = if (LockingActivity.LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK == true)
|
||||||
// Relaunch loading if we need to fix UUID
|
false
|
||||||
showLoadDatabaseDuplicateUuidMessage {
|
else
|
||||||
|
mAllowAutoOpenBiometricPrompt
|
||||||
|
mDatabaseFileUri?.let { databaseFileUri ->
|
||||||
|
databaseFileViewModel.loadDatabaseFile(databaseFileUri)
|
||||||
|
}
|
||||||
|
|
||||||
var databaseUri: Uri? = null
|
checkPermission()
|
||||||
var mainCredential: MainCredential = MainCredential()
|
}
|
||||||
var readOnly = true
|
|
||||||
var cipherEntity: CipherDatabaseEntity? = null
|
|
||||||
|
|
||||||
result.data?.let { resultData ->
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
databaseUri = resultData.getParcelable(DATABASE_URI_KEY)
|
super.onDatabaseRetrieved(database)
|
||||||
mainCredential = resultData.getParcelable(MAIN_CREDENTIAL_KEY) ?: mainCredential
|
if (database?.loaded == true) {
|
||||||
readOnly = resultData.getBoolean(READ_ONLY_KEY)
|
// If the database isn't accessible make sure to clear the password field, if it
|
||||||
cipherEntity = resultData.getParcelable(CIPHER_ENTITY_KEY)
|
// was saved in the instance state
|
||||||
}
|
clearCredentialsViews()
|
||||||
|
launchGroupActivity(database)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
databaseUri?.let { databaseFileUri ->
|
override fun onDatabaseActionFinished(
|
||||||
showProgressDialogAndLoadDatabase(
|
database: Database,
|
||||||
databaseFileUri,
|
actionTask: String,
|
||||||
mainCredential,
|
result: ActionRunnable.Result
|
||||||
readOnly,
|
) {
|
||||||
cipherEntity,
|
super.onDatabaseActionFinished(database, actionTask, result)
|
||||||
true)
|
when (actionTask) {
|
||||||
}
|
ACTION_DATABASE_LOAD_TASK -> {
|
||||||
}
|
// Recheck advanced unlock if error
|
||||||
|
advancedUnlockFragment?.initAdvancedUnlockMode()
|
||||||
|
|
||||||
|
if (result.isSuccess) {
|
||||||
|
mDatabaseKeyFileUri = null
|
||||||
|
clearCredentialsViews(true)
|
||||||
|
launchGroupActivity(database)
|
||||||
|
} else {
|
||||||
|
var resultError = ""
|
||||||
|
val resultException = result.exception
|
||||||
|
val resultMessage = result.message
|
||||||
|
|
||||||
|
if (resultException != null) {
|
||||||
|
resultError = resultException.getLocalizedMessage(resources)
|
||||||
|
|
||||||
|
when (resultException) {
|
||||||
|
is DuplicateUuidDatabaseException -> {
|
||||||
|
// Relaunch loading if we need to fix UUID
|
||||||
|
showLoadDatabaseDuplicateUuidMessage {
|
||||||
|
|
||||||
|
var databaseUri: Uri? = null
|
||||||
|
var mainCredential: MainCredential = MainCredential()
|
||||||
|
var readOnly = true
|
||||||
|
var cipherEntity: CipherDatabaseEntity? = null
|
||||||
|
|
||||||
|
result.data?.let { resultData ->
|
||||||
|
databaseUri = resultData.getParcelable(DATABASE_URI_KEY)
|
||||||
|
mainCredential = resultData.getParcelable(MAIN_CREDENTIAL_KEY) ?: mainCredential
|
||||||
|
readOnly = resultData.getBoolean(READ_ONLY_KEY)
|
||||||
|
cipherEntity = resultData.getParcelable(CIPHER_ENTITY_KEY)
|
||||||
}
|
}
|
||||||
is FileNotFoundDatabaseException -> {
|
|
||||||
// Remove this default database inaccessible
|
databaseUri?.let { databaseFileUri ->
|
||||||
if (mDefaultDatabase) {
|
showProgressDialogAndLoadDatabase(
|
||||||
databaseFileViewModel.removeDefaultDatabase()
|
databaseFileUri,
|
||||||
}
|
mainCredential,
|
||||||
|
readOnly,
|
||||||
|
cipherEntity,
|
||||||
|
true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is FileNotFoundDatabaseException -> {
|
||||||
// Show error message
|
// Remove this default database inaccessible
|
||||||
if (resultMessage != null && resultMessage.isNotEmpty()) {
|
if (mDefaultDatabase) {
|
||||||
resultError = "$resultError $resultMessage"
|
databaseFileViewModel.removeDefaultDatabase()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Log.e(TAG, resultError)
|
|
||||||
Snackbar.make(coordinatorLayout,
|
|
||||||
resultError,
|
|
||||||
Snackbar.LENGTH_LONG).asError().show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show error message
|
||||||
|
if (resultMessage != null && resultMessage.isNotEmpty()) {
|
||||||
|
resultError = "$resultError $resultMessage"
|
||||||
|
}
|
||||||
|
Log.e(TAG, resultError)
|
||||||
|
Snackbar.make(coordinatorLayout,
|
||||||
|
resultError,
|
||||||
|
Snackbar.LENGTH_LONG).asError().show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,41 +386,6 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
val database = mDatabase
|
|
||||||
if (database?.loaded == true) {
|
|
||||||
launchGroupActivity(database)
|
|
||||||
} else {
|
|
||||||
mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this)
|
|
||||||
|
|
||||||
// If the database isn't accessible make sure to clear the password field, if it
|
|
||||||
// was saved in the instance state
|
|
||||||
if (mDatabase?.loaded == true) {
|
|
||||||
clearCredentialsViews()
|
|
||||||
}
|
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.registerProgressTask()
|
|
||||||
|
|
||||||
// Back to previous keyboard is setting activated
|
|
||||||
if (PreferencesUtil.isKeyboardPreviousDatabaseCredentialsEnable(this)) {
|
|
||||||
sendBroadcast(Intent(BACK_PREVIOUS_KEYBOARD_ACTION))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't allow auto open prompt if lock become when UI visible
|
|
||||||
mAllowAutoOpenBiometricPrompt = if (LockingActivity.LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK == true)
|
|
||||||
false
|
|
||||||
else
|
|
||||||
mAllowAutoOpenBiometricPrompt
|
|
||||||
mDatabaseFileUri?.let { databaseFileUri ->
|
|
||||||
databaseFileViewModel.loadDatabaseFile(databaseFileUri)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkPermission()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onDatabaseFileLoaded(databaseFileUri: Uri?, keyFileUri: Uri?) {
|
private fun onDatabaseFileLoaded(databaseFileUri: Uri?, keyFileUri: Uri?) {
|
||||||
// Define Key File text
|
// Define Key File text
|
||||||
if (mRememberKeyFile) {
|
if (mRememberKeyFile) {
|
||||||
@@ -417,8 +409,8 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
} else {
|
} else {
|
||||||
// Init Biometric elements
|
// Init Biometric elements
|
||||||
advancedUnlockFragment?.loadDatabase(databaseFileUri,
|
advancedUnlockFragment?.loadDatabase(databaseFileUri,
|
||||||
mAllowAutoOpenBiometricPrompt
|
mAllowAutoOpenBiometricPrompt)
|
||||||
&& mProgressDatabaseTaskProvider?.isBinded() != true)
|
// TODO && mDatabaseTaskProvider?.isBinded() != true)
|
||||||
}
|
}
|
||||||
|
|
||||||
enableOrNotTheConfirmationButton()
|
enableOrNotTheConfirmationButton()
|
||||||
@@ -468,8 +460,6 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
mProgressDatabaseTaskProvider?.unregisterProgressTask()
|
|
||||||
|
|
||||||
// Reinit locking activity UI variable
|
// Reinit locking activity UI variable
|
||||||
LockingActivity.LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK = null
|
LockingActivity.LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK = null
|
||||||
mAllowAutoOpenBiometricPrompt = true
|
mAllowAutoOpenBiometricPrompt = true
|
||||||
@@ -546,7 +536,7 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
readOnly: Boolean,
|
readOnly: Boolean,
|
||||||
cipherDatabaseEntity: CipherDatabaseEntity?,
|
cipherDatabaseEntity: CipherDatabaseEntity?,
|
||||||
fixDuplicateUUID: Boolean) {
|
fixDuplicateUUID: Boolean) {
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseLoad(
|
loadDatabase(
|
||||||
databaseUri,
|
databaseUri,
|
||||||
mainCredential,
|
mainCredential,
|
||||||
readOnly,
|
readOnly,
|
||||||
@@ -716,7 +706,8 @@ open class PasswordActivity : SpecialModeActivity(), AdvancedUnlockFragment.Buil
|
|||||||
when (resultCode) {
|
when (resultCode) {
|
||||||
LockingActivity.RESULT_EXIT_LOCK -> {
|
LockingActivity.RESULT_EXIT_LOCK -> {
|
||||||
clearCredentialsViews()
|
clearCredentialsViews()
|
||||||
mDatabase?.clearAndClose(this)
|
// TODO Database
|
||||||
|
Database.getInstance().clearAndClose(this)
|
||||||
}
|
}
|
||||||
Activity.RESULT_CANCELED -> {
|
Activity.RESULT_CANCELED -> {
|
||||||
clearCredentialsViews()
|
clearCredentialsViews()
|
||||||
|
|||||||
@@ -57,17 +57,17 @@ open class DeleteNodesDialogFragment : DialogFragment() {
|
|||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
|
||||||
val database = Database.getInstance()
|
|
||||||
|
|
||||||
arguments?.apply {
|
arguments?.apply {
|
||||||
if (containsKey(DatabaseTaskNotificationService.GROUPS_ID_KEY)
|
if (containsKey(DatabaseTaskNotificationService.GROUPS_ID_KEY)
|
||||||
&& containsKey(DatabaseTaskNotificationService.ENTRIES_ID_KEY)) {
|
&& containsKey(DatabaseTaskNotificationService.ENTRIES_ID_KEY)) {
|
||||||
mNodesToDelete = getListNodesFromBundle(database, this)
|
// TODO Database
|
||||||
|
mNodesToDelete = getListNodesFromBundle(Database.getInstance(), this)
|
||||||
}
|
}
|
||||||
} ?: savedInstanceState?.apply {
|
} ?: savedInstanceState?.apply {
|
||||||
if (containsKey(DatabaseTaskNotificationService.GROUPS_ID_KEY)
|
if (containsKey(DatabaseTaskNotificationService.GROUPS_ID_KEY)
|
||||||
&& containsKey(DatabaseTaskNotificationService.ENTRIES_ID_KEY)) {
|
&& containsKey(DatabaseTaskNotificationService.ENTRIES_ID_KEY)) {
|
||||||
mNodesToDelete = getListNodesFromBundle(database, savedInstanceState)
|
// TODO Database
|
||||||
|
mNodesToDelete = getListNodesFromBundle(Database.getInstance(), savedInstanceState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ import org.joda.time.DateTime
|
|||||||
|
|
||||||
class GroupEditDialogFragment : DialogFragment() {
|
class GroupEditDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
private var mDatabase: Database? = null
|
|
||||||
|
|
||||||
private var mEditGroupListener: EditGroupListener? = null
|
private var mEditGroupListener: EditGroupListener? = null
|
||||||
|
|
||||||
private var mEditGroupDialogAction = EditGroupDialogAction.NONE
|
private var mEditGroupDialogAction = EditGroupDialogAction.NONE
|
||||||
@@ -101,9 +99,6 @@ class GroupEditDialogFragment : DialogFragment() {
|
|||||||
iconColor = ta.getColor(0, Color.WHITE)
|
iconColor = ta.getColor(0, Color.WHITE)
|
||||||
ta.recycle()
|
ta.recycle()
|
||||||
|
|
||||||
// Init elements
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
|
|
||||||
if (savedInstanceState != null
|
if (savedInstanceState != null
|
||||||
&& savedInstanceState.containsKey(KEY_ACTION_ID)
|
&& savedInstanceState.containsKey(KEY_ACTION_ID)
|
||||||
&& savedInstanceState.containsKey(KEY_GROUP_INFO)) {
|
&& savedInstanceState.containsKey(KEY_GROUP_INFO)) {
|
||||||
@@ -203,7 +198,8 @@ class GroupEditDialogFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun assignIconView() {
|
private fun assignIconView() {
|
||||||
mDatabase?.iconDrawableFactory?.assignDatabaseIcon(iconButtonView, mGroupInfo.icon, iconColor)
|
// TODO Database
|
||||||
|
Database.getInstance()?.iconDrawableFactory?.assignDatabaseIcon(iconButtonView, mGroupInfo.icon, iconColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setIcon(icon: IconImage) {
|
fun setIcon(icon: IconImage) {
|
||||||
|
|||||||
@@ -1,15 +1,34 @@
|
|||||||
package com.kunzisoft.keepass.activities.fragments
|
package com.kunzisoft.keepass.activities.fragments
|
||||||
|
|
||||||
import android.content.Context
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import com.kunzisoft.keepass.activities.DatabaseRetrieval
|
||||||
|
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
|
||||||
import com.kunzisoft.keepass.activities.stylish.StylishFragment
|
import com.kunzisoft.keepass.activities.stylish.StylishFragment
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
|
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||||
|
|
||||||
abstract class DatabaseFragment : StylishFragment() {
|
abstract class DatabaseFragment : StylishFragment(), DatabaseRetrieval {
|
||||||
|
|
||||||
protected var mDatabase: Database? = null
|
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onViewCreated(view: View,
|
||||||
super.onAttach(context)
|
savedInstanceState: Bundle?) {
|
||||||
mDatabase = Database.getInstance()
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
mDatabaseViewModel.database.observe(viewLifecycleOwner) { database ->
|
||||||
|
view.resetAppTimeoutWhenViewFocusedOrChanged(requireContext(), database)
|
||||||
|
onDatabaseRetrieved(database)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseActionFinished(
|
||||||
|
database: Database,
|
||||||
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result
|
||||||
|
) {
|
||||||
|
// Can be overridden by a subclass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,7 @@ import com.kunzisoft.keepass.activities.dialogs.SetOTPDialogFragment
|
|||||||
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
|
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
|
||||||
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
|
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
||||||
import com.kunzisoft.keepass.model.AttachmentState
|
import com.kunzisoft.keepass.model.AttachmentState
|
||||||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||||
@@ -62,6 +63,8 @@ class EntryEditFragment: DatabaseFragment() {
|
|||||||
private lateinit var attachmentsListView: RecyclerView
|
private lateinit var attachmentsListView: RecyclerView
|
||||||
private var attachmentsAdapter: EntryAttachmentsItemsAdapter? = null
|
private var attachmentsAdapter: EntryAttachmentsItemsAdapter? = null
|
||||||
|
|
||||||
|
private var mAllowMultipleAttachments: Boolean = false
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater,
|
override fun onCreateView(inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?): View? {
|
savedInstanceState: Bundle?): View? {
|
||||||
@@ -89,8 +92,6 @@ class EntryEditFragment: DatabaseFragment() {
|
|||||||
attachmentsContainerView = view.findViewById(R.id.entry_attachments_container)
|
attachmentsContainerView = view.findViewById(R.id.entry_attachments_container)
|
||||||
attachmentsListView = view.findViewById(R.id.entry_attachments_list)
|
attachmentsListView = view.findViewById(R.id.entry_attachments_list)
|
||||||
|
|
||||||
view.resetAppTimeoutWhenViewFocusedOrChanged(requireContext(), mDatabase)
|
|
||||||
|
|
||||||
templateView.apply {
|
templateView.apply {
|
||||||
populateIconMethod = { imageView, icon ->
|
populateIconMethod = { imageView, icon ->
|
||||||
drawFactory?.assignDatabaseIcon(imageView, icon, iconColor)
|
drawFactory?.assignDatabaseIcon(imageView, icon, iconColor)
|
||||||
@@ -109,20 +110,6 @@ class EntryEditFragment: DatabaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attachmentsAdapter = EntryAttachmentsItemsAdapter(requireContext())
|
|
||||||
attachmentsAdapter?.database = mDatabase
|
|
||||||
attachmentsAdapter?.onListSizeChangedListener = { previousSize, newSize ->
|
|
||||||
if (previousSize > 0 && newSize == 0) {
|
|
||||||
attachmentsContainerView.collapse(true)
|
|
||||||
} else if (previousSize == 0 && newSize == 1) {
|
|
||||||
attachmentsContainerView.expand(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attachmentsListView.apply {
|
|
||||||
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
|
||||||
adapter = attachmentsAdapter
|
|
||||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
|
||||||
}
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
val attachments: List<Attachment> =
|
val attachments: List<Attachment> =
|
||||||
savedInstanceState.getParcelableArrayList(ATTACHMENTS_TAG) ?: listOf()
|
savedInstanceState.getParcelableArrayList(ATTACHMENTS_TAG) ?: listOf()
|
||||||
@@ -206,10 +193,12 @@ class EntryEditFragment: DatabaseFragment() {
|
|||||||
mEntryEditViewModel.onBuildNewAttachment.observe(viewLifecycleOwner) {
|
mEntryEditViewModel.onBuildNewAttachment.observe(viewLifecycleOwner) {
|
||||||
val attachmentToUploadUri = it.attachmentToUploadUri
|
val attachmentToUploadUri = it.attachmentToUploadUri
|
||||||
val fileName = it.fileName
|
val fileName = it.fileName
|
||||||
mDatabase?.buildNewBinaryAttachment()?.let { binaryAttachment ->
|
|
||||||
|
// TODO Database
|
||||||
|
Database.getInstance()?.buildNewBinaryAttachment()?.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 ((mDatabase?.allowMultipleAttachments == false
|
if ((!mAllowMultipleAttachments
|
||||||
&& containsAttachment()) ||
|
&& containsAttachment()) ||
|
||||||
containsAttachment(EntryAttachmentState(entryAttachment, StreamDirection.UPLOAD))) {
|
containsAttachment(EntryAttachmentState(entryAttachment, StreamDirection.UPLOAD))) {
|
||||||
ReplaceFileDialogFragment.build(attachmentToUploadUri, entryAttachment)
|
ReplaceFileDialogFragment.build(attachmentToUploadUri, entryAttachment)
|
||||||
@@ -249,16 +238,25 @@ class EntryEditFragment: DatabaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
super.onAttach(context)
|
drawFactory = database?.iconDrawableFactory
|
||||||
|
|
||||||
drawFactory = mDatabase?.iconDrawableFactory
|
mAllowMultipleAttachments = database?.allowMultipleAttachments == true
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetach() {
|
attachmentsAdapter = EntryAttachmentsItemsAdapter(requireContext())
|
||||||
super.onDetach()
|
attachmentsAdapter?.database = database
|
||||||
|
attachmentsAdapter?.onListSizeChangedListener = { previousSize, newSize ->
|
||||||
drawFactory = null
|
if (previousSize > 0 && newSize == 0) {
|
||||||
|
attachmentsContainerView.collapse(true)
|
||||||
|
} else if (previousSize == 0 && newSize == 1) {
|
||||||
|
attachmentsContainerView.expand(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attachmentsListView.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||||
|
adapter = attachmentsAdapter
|
||||||
|
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assignEntryInfo(entryInfo: EntryInfo?) {
|
private fun assignEntryInfo(entryInfo: EntryInfo?) {
|
||||||
@@ -307,7 +305,7 @@ class EntryEditFragment: DatabaseFragment() {
|
|||||||
private fun putAttachment(attachment: EntryAttachmentState,
|
private fun putAttachment(attachment: EntryAttachmentState,
|
||||||
onPreviewLoaded: (() -> Unit)? = null) {
|
onPreviewLoaded: (() -> Unit)? = null) {
|
||||||
// When only one attachment is allowed
|
// When only one attachment is allowed
|
||||||
if (mDatabase?.allowMultipleAttachments == false) {
|
if (mAllowMultipleAttachments) {
|
||||||
clearAttachments()
|
clearAttachments()
|
||||||
}
|
}
|
||||||
attachmentsContainerView.visibility = View.VISIBLE
|
attachmentsContainerView.visibility = View.VISIBLE
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator
|
|||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
|
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
import com.kunzisoft.keepass.database.element.template.TemplateField
|
import com.kunzisoft.keepass.database.element.template.TemplateField
|
||||||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||||
@@ -63,8 +64,6 @@ class EntryFragment: DatabaseFragment() {
|
|||||||
|
|
||||||
context?.let { context ->
|
context?.let { context ->
|
||||||
mClipboardHelper = ClipboardHelper(context)
|
mClipboardHelper = ClipboardHelper(context)
|
||||||
attachmentsAdapter = EntryAttachmentsItemsAdapter(context)
|
|
||||||
attachmentsAdapter?.database = mDatabase
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rootView = view
|
rootView = view
|
||||||
@@ -75,14 +74,6 @@ class EntryFragment: DatabaseFragment() {
|
|||||||
templateView = view.findViewById(R.id.entry_template)
|
templateView = view.findViewById(R.id.entry_template)
|
||||||
loadTemplateSettings()
|
loadTemplateSettings()
|
||||||
|
|
||||||
attachmentsContainerView = view.findViewById(R.id.entry_attachments_container)
|
|
||||||
attachmentsListView = view.findViewById(R.id.entry_attachments_list)
|
|
||||||
attachmentsListView.apply {
|
|
||||||
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
|
||||||
adapter = attachmentsAdapter
|
|
||||||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
|
||||||
}
|
|
||||||
|
|
||||||
creationDateView = view.findViewById(R.id.entry_created)
|
creationDateView = view.findViewById(R.id.entry_created)
|
||||||
modificationDateView = view.findViewById(R.id.entry_modified)
|
modificationDateView = view.findViewById(R.id.entry_modified)
|
||||||
|
|
||||||
@@ -112,6 +103,21 @@ class EntryFragment: DatabaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
context?.let { context ->
|
||||||
|
attachmentsAdapter = EntryAttachmentsItemsAdapter(context)
|
||||||
|
attachmentsAdapter?.database = database
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentsContainerView = requireView().findViewById(R.id.entry_attachments_container)
|
||||||
|
attachmentsListView = requireView().findViewById(R.id.entry_attachments_list)
|
||||||
|
attachmentsListView.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||||
|
adapter = attachmentsAdapter
|
||||||
|
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadTemplateSettings() {
|
private fun loadTemplateSettings() {
|
||||||
context?.let { context ->
|
context?.let { context ->
|
||||||
templateView.setFirstTimeAskAllowCopyProtectedFields(PreferencesUtil.isFirstTimeAskAllowCopyProtectedFields(context))
|
templateView.setFirstTimeAskAllowCopyProtectedFields(PreferencesUtil.isFirstTimeAskAllowCopyProtectedFields(context))
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.activities.fragments
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
|
||||||
|
|
||||||
|
|
||||||
@@ -31,8 +32,8 @@ class IconCustomFragment : IconFragment<IconImageCustom>() {
|
|||||||
return R.layout.fragment_icon_grid
|
return R.layout.fragment_icon_grid
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun defineIconList() {
|
override fun defineIconList(database: Database?) {
|
||||||
mDatabase?.doForEachCustomIcons { customIcon, _ ->
|
database?.doForEachCustomIcons { customIcon, _ ->
|
||||||
iconPickerAdapter.addIcon(customIcon, false)
|
iconPickerAdapter.addIcon(customIcon, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import androidx.fragment.app.activityViewModels
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.adapters.IconPickerAdapter
|
import com.kunzisoft.keepass.adapters.IconPickerAdapter
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageDraw
|
import com.kunzisoft.keepass.database.element.icon.IconImageDraw
|
||||||
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
|
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -47,31 +48,7 @@ abstract class IconFragment<T: IconImageDraw> : DatabaseFragment(),
|
|||||||
|
|
||||||
abstract fun retrieveMainLayoutId(): Int
|
abstract fun retrieveMainLayoutId(): Int
|
||||||
|
|
||||||
abstract fun defineIconList()
|
abstract fun defineIconList(database: Database?)
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
|
||||||
super.onAttach(context)
|
|
||||||
|
|
||||||
// Retrieve the textColor to tint the icon
|
|
||||||
val ta = contextThemed?.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
|
|
||||||
val tintColor = ta?.getColor(0, Color.BLACK) ?: Color.BLACK
|
|
||||||
ta?.recycle()
|
|
||||||
|
|
||||||
iconPickerAdapter = IconPickerAdapter<T>(context, tintColor).apply {
|
|
||||||
iconDrawableFactory = mDatabase?.iconDrawableFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val populateList = launch {
|
|
||||||
iconPickerAdapter.clear()
|
|
||||||
defineIconList()
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
populateList.join()
|
|
||||||
iconPickerAdapter.notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater,
|
override fun onCreateView(inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
@@ -88,6 +65,28 @@ abstract class IconFragment<T: IconImageDraw> : DatabaseFragment(),
|
|||||||
iconPickerAdapter.iconPickerListener = this
|
iconPickerAdapter.iconPickerListener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
// Retrieve the textColor to tint the icon
|
||||||
|
val ta = contextThemed?.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
|
||||||
|
val tintColor = ta?.getColor(0, Color.BLACK) ?: Color.BLACK
|
||||||
|
ta?.recycle()
|
||||||
|
|
||||||
|
iconPickerAdapter = IconPickerAdapter<T>(requireContext(), tintColor).apply {
|
||||||
|
iconDrawableFactory = database?.iconDrawableFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val populateList = launch {
|
||||||
|
iconPickerAdapter.clear()
|
||||||
|
defineIconList(database)
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
populateList.join()
|
||||||
|
iconPickerAdapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onIconDeleteClicked() {
|
fun onIconDeleteClicked() {
|
||||||
iconActionSelectionMode = false
|
iconActionSelectionMode = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.google.android.material.tabs.TabLayout
|
|||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.adapters.IconPickerPagerAdapter
|
import com.kunzisoft.keepass.adapters.IconPickerPagerAdapter
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
|
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
|
||||||
|
|
||||||
class IconPickerFragment : DatabaseFragment() {
|
class IconPickerFragment : DatabaseFragment() {
|
||||||
@@ -28,17 +29,7 @@ class IconPickerFragment : DatabaseFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
viewPager = view.findViewById(R.id.icon_picker_pager)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val tabLayout = view.findViewById<TabLayout>(R.id.icon_picker_tabs)
|
|
||||||
iconPickerPagerAdapter = IconPickerPagerAdapter(this,
|
|
||||||
if (mDatabase?.allowCustomIcons == true) 2 else 1)
|
|
||||||
viewPager.adapter = iconPickerPagerAdapter
|
|
||||||
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
|
|
||||||
tab.text = when (position) {
|
|
||||||
1 -> getString(R.string.icon_section_custom)
|
|
||||||
else -> getString(R.string.icon_section_standard)
|
|
||||||
}
|
|
||||||
}.attach()
|
|
||||||
|
|
||||||
arguments?.apply {
|
arguments?.apply {
|
||||||
if (containsKey(ICON_TAB_ARG)) {
|
if (containsKey(ICON_TAB_ARG)) {
|
||||||
@@ -52,6 +43,20 @@ class IconPickerFragment : DatabaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
viewPager = requireView().findViewById(R.id.icon_picker_pager)
|
||||||
|
val tabLayout = requireView().findViewById<TabLayout>(R.id.icon_picker_tabs)
|
||||||
|
iconPickerPagerAdapter = IconPickerPagerAdapter(this,
|
||||||
|
if (database?.allowCustomIcons == true) 2 else 1)
|
||||||
|
viewPager.adapter = iconPickerPagerAdapter
|
||||||
|
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
|
||||||
|
tab.text = when (position) {
|
||||||
|
1 -> getString(R.string.icon_section_custom)
|
||||||
|
else -> getString(R.string.icon_section_standard)
|
||||||
|
}
|
||||||
|
}.attach()
|
||||||
|
}
|
||||||
|
|
||||||
enum class IconTab {
|
enum class IconTab {
|
||||||
STANDARD, CUSTOM
|
STANDARD, CUSTOM
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
package com.kunzisoft.keepass.activities.fragments
|
package com.kunzisoft.keepass.activities.fragments
|
||||||
|
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||||
|
|
||||||
|
|
||||||
@@ -29,8 +30,8 @@ class IconStandardFragment : IconFragment<IconImageStandard>() {
|
|||||||
return R.layout.fragment_icon_grid
|
return R.layout.fragment_icon_grid
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun defineIconList() {
|
override fun defineIconList(database: Database?) {
|
||||||
mDatabase?.doForEachStandardIcons { standardIcon ->
|
database?.doForEachStandardIcons { standardIcon ->
|
||||||
iconPickerAdapter.addIcon(standardIcon, false)
|
iconPickerAdapter.addIcon(standardIcon, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
@@ -34,11 +35,13 @@ import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
|||||||
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||||
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
||||||
import com.kunzisoft.keepass.adapters.NodeAdapter
|
import com.kunzisoft.keepass.adapters.NodeAdapter
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.Group
|
import com.kunzisoft.keepass.database.element.Group
|
||||||
import com.kunzisoft.keepass.database.element.SortNodeEnum
|
import com.kunzisoft.keepass.database.element.SortNodeEnum
|
||||||
import com.kunzisoft.keepass.database.element.node.Node
|
import com.kunzisoft.keepass.database.element.node.Node
|
||||||
import com.kunzisoft.keepass.database.element.node.Type
|
import com.kunzisoft.keepass.database.element.node.Type
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.viewmodels.GroupViewModel
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListener {
|
class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListener {
|
||||||
@@ -47,10 +50,12 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
private var onScrollListener: OnScrollListener? = null
|
private var onScrollListener: OnScrollListener? = null
|
||||||
|
|
||||||
private var mNodesRecyclerView: RecyclerView? = null
|
private var mNodesRecyclerView: RecyclerView? = null
|
||||||
var mainGroup: Group? = null
|
|
||||||
private set
|
|
||||||
private var mAdapter: NodeAdapter? = null
|
private var mAdapter: NodeAdapter? = null
|
||||||
|
|
||||||
|
private val mGroupViewModel: GroupViewModel by activityViewModels()
|
||||||
|
|
||||||
|
private var mCurrentGroup: Group? = null
|
||||||
|
|
||||||
var nodeActionSelectionMode = false
|
var nodeActionSelectionMode = false
|
||||||
private set
|
private set
|
||||||
var nodeActionPasteMode: PasteMode = PasteMode.UNDEFINED
|
var nodeActionPasteMode: PasteMode = PasteMode.UNDEFINED
|
||||||
@@ -64,6 +69,9 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
private var readOnly: Boolean = false
|
private var readOnly: Boolean = false
|
||||||
private var specialMode: SpecialMode = SpecialMode.DEFAULT
|
private var specialMode: SpecialMode = SpecialMode.DEFAULT
|
||||||
|
|
||||||
|
private var mRecycleBinEnable: Boolean = false
|
||||||
|
private var mRecycleBin: Group? = null
|
||||||
|
|
||||||
val isEmpty: Boolean
|
val isEmpty: Boolean
|
||||||
get() = mAdapter == null || mAdapter?.itemCount?:0 <= 0
|
get() = mAdapter == null || mAdapter?.itemCount?:0 <= 0
|
||||||
|
|
||||||
@@ -99,56 +107,63 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, arguments)
|
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, arguments)
|
||||||
|
}
|
||||||
|
|
||||||
arguments?.let { args ->
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
// Contains all the group in element
|
super.onViewCreated(view, savedInstanceState)
|
||||||
if (args.containsKey(GROUP_KEY)) {
|
|
||||||
mainGroup = args.getParcelable(GROUP_KEY)
|
mGroupViewModel.group.observe(viewLifecycleOwner) {
|
||||||
}
|
mCurrentGroup = it.group
|
||||||
if (args.containsKey(IS_SEARCH)) {
|
isASearchResult = it.group.isVirtual
|
||||||
isASearchResult = args.getBoolean(IS_SEARCH)
|
rebuildList()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
mRecycleBinEnable = database?.isRecycleBinEnabled == true
|
||||||
|
mRecycleBin = database?.recycleBin
|
||||||
|
|
||||||
contextThemed?.let { context ->
|
contextThemed?.let { context ->
|
||||||
mDatabase?.let { database ->
|
database?.let { database ->
|
||||||
mAdapter = NodeAdapter(context, database)
|
mAdapter = NodeAdapter(context, database).apply {
|
||||||
}
|
setOnNodeClickListener(object : NodeAdapter.NodeClickCallback {
|
||||||
mAdapter?.apply {
|
override fun onNodeClick(database: Database, node: Node) {
|
||||||
setOnNodeClickListener(object : NodeAdapter.NodeClickCallback {
|
if (nodeActionSelectionMode) {
|
||||||
override fun onNodeClick(node: Node) {
|
if (listActionNodes.contains(node)) {
|
||||||
if (nodeActionSelectionMode) {
|
// Remove selected item if already selected
|
||||||
if (listActionNodes.contains(node)) {
|
listActionNodes.remove(node)
|
||||||
// Remove selected item if already selected
|
} else {
|
||||||
listActionNodes.remove(node)
|
// Add selected item if not already selected
|
||||||
|
listActionNodes.add(node)
|
||||||
|
}
|
||||||
|
nodeClickListener?.onNodeSelected(database, listActionNodes)
|
||||||
|
setActionNodes(listActionNodes)
|
||||||
|
notifyNodeChanged(node)
|
||||||
} else {
|
} else {
|
||||||
// Add selected item if not already selected
|
nodeClickListener?.onNodeClick(database, node)
|
||||||
listActionNodes.add(node)
|
|
||||||
}
|
}
|
||||||
nodeClickListener?.onNodeSelected(listActionNodes)
|
|
||||||
setActionNodes(listActionNodes)
|
|
||||||
notifyNodeChanged(node)
|
|
||||||
} else {
|
|
||||||
nodeClickListener?.onNodeClick(node)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNodeLongClick(node: Node): Boolean {
|
override fun onNodeLongClick(database: Database, node: Node): Boolean {
|
||||||
if (nodeActionPasteMode == PasteMode.UNDEFINED) {
|
if (nodeActionPasteMode == PasteMode.UNDEFINED) {
|
||||||
// Select the first item after a long click
|
// Select the first item after a long click
|
||||||
if (!listActionNodes.contains(node))
|
if (!listActionNodes.contains(node))
|
||||||
listActionNodes.add(node)
|
listActionNodes.add(node)
|
||||||
|
|
||||||
nodeClickListener?.onNodeSelected(listActionNodes)
|
nodeClickListener?.onNodeSelected(database, listActionNodes)
|
||||||
|
|
||||||
setActionNodes(listActionNodes)
|
setActionNodes(listActionNodes)
|
||||||
notifyNodeChanged(node)
|
notifyNodeChanged(node)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
return true
|
})
|
||||||
}
|
}
|
||||||
})
|
mNodesRecyclerView?.adapter = mAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO notify menu updated?
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
@@ -211,7 +226,7 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
@Throws(IllegalArgumentException::class)
|
@Throws(IllegalArgumentException::class)
|
||||||
fun rebuildList() {
|
fun rebuildList() {
|
||||||
// Add elements to the list
|
// Add elements to the list
|
||||||
mainGroup?.let { mainGroup ->
|
mCurrentGroup?.let { mainGroup ->
|
||||||
mAdapter?.apply {
|
mAdapter?.apply {
|
||||||
// Thrown an exception when sort cannot be performed
|
// Thrown an exception when sort cannot be performed
|
||||||
rebuildList(mainGroup)
|
rebuildList(mainGroup)
|
||||||
@@ -253,7 +268,7 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
R.id.menu_sort -> {
|
R.id.menu_sort -> {
|
||||||
context?.let { context ->
|
context?.let { context ->
|
||||||
val sortDialogFragment: SortDialogFragment =
|
val sortDialogFragment: SortDialogFragment =
|
||||||
if (mDatabase?.isRecycleBinEnabled == true) {
|
if (mRecycleBinEnable) {
|
||||||
SortDialogFragment.getInstance(
|
SortDialogFragment.getInstance(
|
||||||
PreferencesUtil.getListSort(context),
|
PreferencesUtil.getListSort(context),
|
||||||
PreferencesUtil.getAscendingSort(context),
|
PreferencesUtil.getAscendingSort(context),
|
||||||
@@ -275,7 +290,8 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun actionNodesCallback(nodes: List<Node>,
|
fun actionNodesCallback(database: Database,
|
||||||
|
nodes: List<Node>,
|
||||||
menuListener: NodesActionMenuListener?,
|
menuListener: NodesActionMenuListener?,
|
||||||
actionModeCallback: ActionMode.Callback) : ActionMode.Callback {
|
actionModeCallback: ActionMode.Callback) : ActionMode.Callback {
|
||||||
|
|
||||||
@@ -289,49 +305,46 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
|
|
||||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
menu?.clear()
|
menu?.clear()
|
||||||
|
if (nodeActionPasteMode != PasteMode.UNDEFINED) {
|
||||||
|
mode?.menuInflater?.inflate(R.menu.node_paste_menu, menu)
|
||||||
|
} else {
|
||||||
|
nodeActionSelectionMode = true
|
||||||
|
mode?.menuInflater?.inflate(R.menu.node_menu, menu)
|
||||||
|
|
||||||
mDatabase?.let { database ->
|
// Open and Edit for a single item
|
||||||
if (nodeActionPasteMode != PasteMode.UNDEFINED) {
|
if (nodes.size == 1) {
|
||||||
mode?.menuInflater?.inflate(R.menu.node_paste_menu, menu)
|
// Edition
|
||||||
} else {
|
if (readOnly
|
||||||
nodeActionSelectionMode = true
|
|| (mRecycleBinEnable && nodes[0] == mRecycleBin)) {
|
||||||
mode?.menuInflater?.inflate(R.menu.node_menu, menu)
|
|
||||||
|
|
||||||
// Open and Edit for a single item
|
|
||||||
if (nodes.size == 1) {
|
|
||||||
// Edition
|
|
||||||
if (readOnly
|
|
||||||
|| (database.isRecycleBinEnabled && nodes[0] == database.recycleBin)) {
|
|
||||||
menu?.removeItem(R.id.menu_edit)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
menu?.removeItem(R.id.menu_open)
|
|
||||||
menu?.removeItem(R.id.menu_edit)
|
menu?.removeItem(R.id.menu_edit)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// Move
|
menu?.removeItem(R.id.menu_open)
|
||||||
if (readOnly
|
menu?.removeItem(R.id.menu_edit)
|
||||||
|| isASearchResult) {
|
|
||||||
menu?.removeItem(R.id.menu_move)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy (not allowed for group)
|
|
||||||
if (readOnly
|
|
||||||
|| isASearchResult
|
|
||||||
|| nodes.any { it.type == Type.GROUP }) {
|
|
||||||
menu?.removeItem(R.id.menu_copy)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deletion
|
|
||||||
if (readOnly
|
|
||||||
|| (database.isRecycleBinEnabled && nodes.any { it == database.recycleBin })) {
|
|
||||||
menu?.removeItem(R.id.menu_delete)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the number of items selected in title
|
// Move
|
||||||
mode?.title = nodes.size.toString()
|
if (readOnly
|
||||||
|
|| isASearchResult) {
|
||||||
|
menu?.removeItem(R.id.menu_move)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy (not allowed for group)
|
||||||
|
if (readOnly
|
||||||
|
|| isASearchResult
|
||||||
|
|| nodes.any { it.type == Type.GROUP }) {
|
||||||
|
menu?.removeItem(R.id.menu_copy)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion
|
||||||
|
if (readOnly
|
||||||
|
|| (mRecycleBinEnable && nodes.any { it == mRecycleBin })) {
|
||||||
|
menu?.removeItem(R.id.menu_delete)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the number of items selected in title
|
||||||
|
mode?.title = nodes.size.toString()
|
||||||
return actionModeCallback.onPrepareActionMode(mode, menu)
|
return actionModeCallback.onPrepareActionMode(mode, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,25 +352,25 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
if (menuListener == null)
|
if (menuListener == null)
|
||||||
return false
|
return false
|
||||||
return when (item?.itemId) {
|
return when (item?.itemId) {
|
||||||
R.id.menu_open -> menuListener.onOpenMenuClick(nodes[0])
|
R.id.menu_open -> menuListener.onOpenMenuClick(database, nodes[0])
|
||||||
R.id.menu_edit -> menuListener.onEditMenuClick(nodes[0])
|
R.id.menu_edit -> menuListener.onEditMenuClick(database, nodes[0])
|
||||||
R.id.menu_copy -> {
|
R.id.menu_copy -> {
|
||||||
nodeActionPasteMode = PasteMode.PASTE_FROM_COPY
|
nodeActionPasteMode = PasteMode.PASTE_FROM_COPY
|
||||||
mAdapter?.unselectActionNodes()
|
mAdapter?.unselectActionNodes()
|
||||||
val returnValue = menuListener.onCopyMenuClick(nodes)
|
val returnValue = menuListener.onCopyMenuClick(database, nodes)
|
||||||
nodeActionSelectionMode = false
|
nodeActionSelectionMode = false
|
||||||
returnValue
|
returnValue
|
||||||
}
|
}
|
||||||
R.id.menu_move -> {
|
R.id.menu_move -> {
|
||||||
nodeActionPasteMode = PasteMode.PASTE_FROM_MOVE
|
nodeActionPasteMode = PasteMode.PASTE_FROM_MOVE
|
||||||
mAdapter?.unselectActionNodes()
|
mAdapter?.unselectActionNodes()
|
||||||
val returnValue = menuListener.onMoveMenuClick(nodes)
|
val returnValue = menuListener.onMoveMenuClick(database, nodes)
|
||||||
nodeActionSelectionMode = false
|
nodeActionSelectionMode = false
|
||||||
returnValue
|
returnValue
|
||||||
}
|
}
|
||||||
R.id.menu_delete -> menuListener.onDeleteMenuClick(nodes)
|
R.id.menu_delete -> menuListener.onDeleteMenuClick(database, nodes)
|
||||||
R.id.menu_paste -> {
|
R.id.menu_paste -> {
|
||||||
val returnValue = menuListener.onPasteMenuClick(nodeActionPasteMode, nodes)
|
val returnValue = menuListener.onPasteMenuClick(database, nodeActionPasteMode, nodes)
|
||||||
nodeActionPasteMode = PasteMode.UNDEFINED
|
nodeActionPasteMode = PasteMode.UNDEFINED
|
||||||
nodeActionSelectionMode = false
|
nodeActionSelectionMode = false
|
||||||
returnValue
|
returnValue
|
||||||
@@ -435,20 +448,20 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
* Callback listener to redefine to do an action when a node is click
|
* Callback listener to redefine to do an action when a node is click
|
||||||
*/
|
*/
|
||||||
interface NodeClickListener {
|
interface NodeClickListener {
|
||||||
fun onNodeClick(node: Node)
|
fun onNodeClick(database: Database, node: Node)
|
||||||
fun onNodeSelected(nodes: List<Node>): Boolean
|
fun onNodeSelected(database: Database, nodes: List<Node>): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Menu listener to redefine to do an action in menu
|
* Menu listener to redefine to do an action in menu
|
||||||
*/
|
*/
|
||||||
interface NodesActionMenuListener {
|
interface NodesActionMenuListener {
|
||||||
fun onOpenMenuClick(node: Node): Boolean
|
fun onOpenMenuClick(database: Database, node: Node): Boolean
|
||||||
fun onEditMenuClick(node: Node): Boolean
|
fun onEditMenuClick(database: Database, node: Node): Boolean
|
||||||
fun onCopyMenuClick(nodes: List<Node>): Boolean
|
fun onCopyMenuClick(database: Database, nodes: List<Node>): Boolean
|
||||||
fun onMoveMenuClick(nodes: List<Node>): Boolean
|
fun onMoveMenuClick(database: Database, nodes: List<Node>): Boolean
|
||||||
fun onDeleteMenuClick(nodes: List<Node>): Boolean
|
fun onDeleteMenuClick(database: Database, nodes: List<Node>): Boolean
|
||||||
fun onPasteMenuClick(pasteMode: PasteMode?, nodes: List<Node>): Boolean
|
fun onPasteMenuClick(database: Database, pasteMode: PasteMode?, nodes: List<Node>): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class PasteMode {
|
enum class PasteMode {
|
||||||
@@ -467,22 +480,6 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val TAG = ListNodesFragment::class.java.name
|
private val TAG = ListNodesFragment::class.java.name
|
||||||
|
|
||||||
private const val GROUP_KEY = "GROUP_KEY"
|
|
||||||
private const val IS_SEARCH = "IS_SEARCH"
|
|
||||||
|
|
||||||
fun newInstance(group: Group?, readOnly: Boolean, isASearch: Boolean): ListNodesFragment {
|
|
||||||
val bundle = Bundle()
|
|
||||||
if (group != null) {
|
|
||||||
bundle.putParcelable(GROUP_KEY, group)
|
|
||||||
}
|
|
||||||
bundle.putBoolean(IS_SEARCH, isASearch)
|
|
||||||
ReadOnlyHelper.putReadOnlyInBundle(bundle, readOnly)
|
|
||||||
val listNodesFragment = ListNodesFragment()
|
|
||||||
listNodesFragment.arguments = bundle
|
|
||||||
return listNodesFragment
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ object ReadOnlyHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove read only
|
||||||
fun retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState: Bundle?, arguments: Bundle?): Boolean {
|
fun retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState: Bundle?, arguments: Bundle?): Boolean {
|
||||||
var readOnly = READ_ONLY_DEFAULT
|
var readOnly = READ_ONLY_DEFAULT
|
||||||
if (savedInstanceState != null && savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
if (savedInstanceState != null && savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
||||||
|
|||||||
@@ -22,30 +22,43 @@ package com.kunzisoft.keepass.activities.lock
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.activities.dialogs.DeleteNodesDialogFragment
|
||||||
|
import com.kunzisoft.keepass.activities.dialogs.EmptyRecycleBinDialogFragment
|
||||||
|
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment
|
||||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||||
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||||
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
||||||
import com.kunzisoft.keepass.activities.selection.SpecialModeActivity
|
import com.kunzisoft.keepass.activities.selection.SpecialModeActivity
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDatabaseTaskProvider
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.Entry
|
||||||
|
import com.kunzisoft.keepass.database.element.Group
|
||||||
|
import com.kunzisoft.keepass.database.element.node.Node
|
||||||
|
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
||||||
|
import com.kunzisoft.keepass.model.GroupInfo
|
||||||
|
import com.kunzisoft.keepass.model.MainCredential
|
||||||
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
import com.kunzisoft.keepass.utils.*
|
import com.kunzisoft.keepass.utils.*
|
||||||
|
|
||||||
abstract class LockingActivity : SpecialModeActivity() {
|
abstract class LockingActivity : SpecialModeActivity(),
|
||||||
|
PasswordEncodingDialogFragment.Listener,
|
||||||
|
DeleteNodesDialogFragment.DeleteNodeListener {
|
||||||
|
|
||||||
protected var mTimeoutEnable: Boolean = true
|
protected var mTimeoutEnable: Boolean = true
|
||||||
|
|
||||||
private var mLockReceiver: LockReceiver? = null
|
private var mLockReceiver: LockReceiver? = null
|
||||||
private var mExitLock: Boolean = false
|
private var mExitLock: Boolean = false
|
||||||
|
|
||||||
protected var mDatabase: Database? = null
|
private var mDatabase: Database? = null
|
||||||
|
|
||||||
// Force readOnly if Entry Selection mode
|
// Force readOnly if Entry Selection mode
|
||||||
protected var mReadOnly: Boolean
|
protected var mReadOnly: Boolean
|
||||||
@@ -58,23 +71,19 @@ abstract class LockingActivity : SpecialModeActivity() {
|
|||||||
private var mReadOnlyToSave: Boolean = false
|
private var mReadOnlyToSave: Boolean = false
|
||||||
protected var mAutoSaveEnable: Boolean = true
|
protected var mAutoSaveEnable: Boolean = true
|
||||||
|
|
||||||
var mProgressDatabaseTaskProvider: ProgressDatabaseTaskProvider? = null
|
protected var mIconDrawableFactory: IconDrawableFactory? = null
|
||||||
private set
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider = ProgressDatabaseTaskProvider(this)
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
if (savedInstanceState != null
|
if (savedInstanceState != null
|
||||||
&& savedInstanceState.containsKey(TIMEOUT_ENABLE_KEY)) {
|
&& savedInstanceState.containsKey(TIMEOUT_ENABLE_KEY)
|
||||||
|
) {
|
||||||
mTimeoutEnable = savedInstanceState.getBoolean(TIMEOUT_ENABLE_KEY)
|
mTimeoutEnable = savedInstanceState.getBoolean(TIMEOUT_ENABLE_KEY)
|
||||||
} else {
|
} else {
|
||||||
if (intent != null)
|
if (intent != null)
|
||||||
mTimeoutEnable = intent.getBooleanExtra(TIMEOUT_ENABLE_KEY, TIMEOUT_ENABLE_KEY_DEFAULT)
|
mTimeoutEnable =
|
||||||
|
intent.getBooleanExtra(TIMEOUT_ENABLE_KEY, TIMEOUT_ENABLE_KEY_DEFAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTimeoutEnable) {
|
if (mTimeoutEnable) {
|
||||||
@@ -93,19 +102,193 @@ abstract class LockingActivity : SpecialModeActivity() {
|
|||||||
mExitLock = false
|
mExitLock = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onDatabaseRetrieved(database)
|
||||||
if (resultCode == RESULT_EXIT_LOCK) {
|
mDatabase = database
|
||||||
mExitLock = true
|
// End activity if database not loaded
|
||||||
if (mDatabase?.loaded == true) {
|
if (database?.loaded != true) {
|
||||||
lockAndExit()
|
finish()
|
||||||
|
}
|
||||||
|
// check timeout
|
||||||
|
if (mTimeoutEnable) {
|
||||||
|
// After the first creation
|
||||||
|
// or If simply swipe with another application
|
||||||
|
// If the time is out -> close the Activity
|
||||||
|
TimeoutHelper.checkTimeAndLockIfTimeout(this)
|
||||||
|
// If onCreate already record time
|
||||||
|
database?.let { it ->
|
||||||
|
if (!mExitLock)
|
||||||
|
TimeoutHelper.recordTime(this, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force read only if the database is like that
|
||||||
|
mReadOnly = database?.isReadOnly != false || mReadOnly
|
||||||
|
mIconDrawableFactory = database?.iconDrawableFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseActionFinished(
|
||||||
|
database: Database,
|
||||||
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result
|
||||||
|
) {
|
||||||
|
super.onDatabaseActionFinished(database, actionTask, result)
|
||||||
|
when (actionTask) {
|
||||||
|
DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> {
|
||||||
|
// Reload the current activity
|
||||||
|
if (result.isSuccess) {
|
||||||
|
reload(database)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPasswordEncodingValidateListener(databaseUri: Uri?,
|
||||||
|
mainCredential: MainCredential) {
|
||||||
|
assignPasswordValidated(databaseUri, mainCredential)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assignPasswordValidated(databaseUri: Uri?,
|
||||||
|
mainCredential: MainCredential) {
|
||||||
|
if (databaseUri != null) {
|
||||||
|
assignDatabasePassword(databaseUri, mainCredential)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignPassword(mainCredential: MainCredential) {
|
||||||
|
mDatabase?.let { database ->
|
||||||
|
database.fileUri?.let { databaseUri ->
|
||||||
|
// Show the progress dialog now or after dialog confirmation
|
||||||
|
if (database.validatePasswordEncoding(mainCredential)) {
|
||||||
|
assignPasswordValidated(databaseUri, mainCredential)
|
||||||
|
} else {
|
||||||
|
PasswordEncodingDialogFragment.getInstance(databaseUri, mainCredential)
|
||||||
|
.show(supportFragmentManager, "passwordEncodingTag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createEntry(newEntry: Entry,
|
||||||
|
parent: Group) {
|
||||||
|
createDatabaseEntry(newEntry, parent, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateEntry(oldEntry: Entry,
|
||||||
|
entryToUpdate: Entry) {
|
||||||
|
updateDatabaseEntry(oldEntry, entryToUpdate, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyNodes(nodesToCopy: List<Node>,
|
||||||
|
newParent: Group) {
|
||||||
|
copyDatabaseNodes(nodesToCopy, newParent, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveNodes(nodesToMove: List<Node>,
|
||||||
|
newParent: Group) {
|
||||||
|
moveDatabaseNodes(nodesToMove, newParent, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun eachNodeRecyclable(database: Database, nodes: List<Node>): Boolean {
|
||||||
|
return nodes.find { node ->
|
||||||
|
var cannotRecycle = true
|
||||||
|
if (node is Entry) {
|
||||||
|
cannotRecycle = !database.canRecycle(node)
|
||||||
|
} else if (node is Group) {
|
||||||
|
cannotRecycle = !database.canRecycle(node)
|
||||||
|
}
|
||||||
|
cannotRecycle
|
||||||
|
} == null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteNodes(nodes: List<Node>, recycleBin: Boolean = false) {
|
||||||
|
mDatabase?.let { database ->
|
||||||
|
// If recycle bin enabled, ensure it exists
|
||||||
|
if (database.isRecycleBinEnabled) {
|
||||||
|
database.ensureRecycleBinExists(resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If recycle bin enabled and not in recycle bin, move in recycle bin
|
||||||
|
if (eachNodeRecyclable(database, nodes)) {
|
||||||
|
permanentlyDeleteNodes(nodes)
|
||||||
|
}
|
||||||
|
// else open the dialog to confirm deletion
|
||||||
|
else {
|
||||||
|
val deleteNodesDialogFragment: DeleteNodesDialogFragment =
|
||||||
|
if (recycleBin) {
|
||||||
|
EmptyRecycleBinDialogFragment.getInstance(nodes)
|
||||||
|
} else {
|
||||||
|
DeleteNodesDialogFragment.getInstance(nodes)
|
||||||
|
}
|
||||||
|
deleteNodesDialogFragment.show(supportFragmentManager, "deleteNodesDialogFragment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun permanentlyDeleteNodes(nodes: List<Node>) {
|
||||||
|
deleteDatabaseNodes(nodes,!mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createGroup(parent: Group,
|
||||||
|
groupInfo: GroupInfo?) {
|
||||||
|
// Build the group
|
||||||
|
mDatabase?.createGroup()?.let { newGroup ->
|
||||||
|
groupInfo?.let { info ->
|
||||||
|
newGroup.setGroupInfo(info)
|
||||||
|
}
|
||||||
|
// Not really needed here because added in runnable but safe
|
||||||
|
newGroup.parent = parent
|
||||||
|
createDatabaseGroup(newGroup, parent, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateGroup(oldGroup: Group,
|
||||||
|
groupInfo: GroupInfo) {
|
||||||
|
// If group updated save it in the database
|
||||||
|
val updateGroup = Group(oldGroup).let { updateGroup ->
|
||||||
|
updateGroup.apply {
|
||||||
|
// WARNING remove parent and children to keep memory
|
||||||
|
removeParent()
|
||||||
|
removeChildren()
|
||||||
|
this.setGroupInfo(groupInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateDatabaseGroup(oldGroup, updateGroup, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun restoreEntryHistory(mainEntry: Entry,
|
||||||
|
entryHistoryPosition: Int,) {
|
||||||
|
restoreDatabaseEntryHistory(mainEntry, entryHistoryPosition, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteEntryHistory(mainEntry: Entry,
|
||||||
|
entryHistoryPosition: Int,) {
|
||||||
|
deleteDatabaseEntryHistory(mainEntry, entryHistoryPosition, !mReadOnly && mAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
if (resultCode == RESULT_EXIT_LOCK) {
|
||||||
|
mExitLock = true
|
||||||
|
lockAndExit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reload(database: Database) {
|
||||||
|
// Reload the current activity
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
|
||||||
|
database.wasReloaded = false
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
|
if (mDatabase?.wasReloaded == true) {
|
||||||
|
reload(mDatabase!!)
|
||||||
|
}
|
||||||
|
|
||||||
// If in ave or registration mode, don't allow read only
|
// If in ave or registration mode, don't allow read only
|
||||||
if ((mSpecialMode == SpecialMode.SAVE
|
if ((mSpecialMode == SpecialMode.SAVE
|
||||||
|| mSpecialMode == SpecialMode.REGISTRATION)
|
|| mSpecialMode == SpecialMode.REGISTRATION)
|
||||||
@@ -115,36 +298,19 @@ abstract class LockingActivity : SpecialModeActivity() {
|
|||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.registerProgressTask()
|
|
||||||
|
|
||||||
// To refresh when back to normal workflow from selection workflow
|
// To refresh when back to normal workflow from selection workflow
|
||||||
mReadOnlyToSave = ReadOnlyHelper.retrieveReadOnlyFromIntent(intent)
|
mReadOnlyToSave = ReadOnlyHelper.retrieveReadOnlyFromIntent(intent)
|
||||||
mAutoSaveEnable = PreferencesUtil.isAutoSaveDatabaseEnabled(this)
|
mAutoSaveEnable = PreferencesUtil.isAutoSaveDatabaseEnabled(this)
|
||||||
|
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
|
|
||||||
if (mTimeoutEnable) {
|
|
||||||
// End activity if database not loaded
|
|
||||||
// TODO generalize
|
|
||||||
if (mDatabase?.loaded != true) {
|
|
||||||
finish()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// After the first creation
|
|
||||||
// or If simply swipe with another application
|
|
||||||
// If the time is out -> close the Activity
|
|
||||||
TimeoutHelper.checkTimeAndLockIfTimeout(this)
|
|
||||||
// If onCreate already record time
|
|
||||||
mDatabase?.let { database ->
|
|
||||||
if (!mExitLock)
|
|
||||||
TimeoutHelper.recordTime(this, database)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOCKING_ACTIVITY_UI_VISIBLE = true
|
LOCKING_ACTIVITY_UI_VISIBLE = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun checkTimeAndLockIfTimeoutOrResetTimeout(action: (() -> Unit)? = null) {
|
||||||
|
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(this, mDatabase, action)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
outState.putBoolean(TIMEOUT_ENABLE_KEY, mTimeoutEnable)
|
outState.putBoolean(TIMEOUT_ENABLE_KEY, mTimeoutEnable)
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
@@ -153,8 +319,6 @@ abstract class LockingActivity : SpecialModeActivity() {
|
|||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
LOCKING_ACTIVITY_UI_VISIBLE = false
|
LOCKING_ACTIVITY_UI_VISIBLE = false
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.unregisterProgressTask()
|
|
||||||
|
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
|
||||||
if (mTimeoutEnable) {
|
if (mTimeoutEnable) {
|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
package com.kunzisoft.keepass.activities.selection
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import com.kunzisoft.keepass.activities.DatabaseRetrieval
|
||||||
|
import com.kunzisoft.keepass.activities.stylish.StylishActivity
|
||||||
|
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
||||||
|
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.Entry
|
||||||
|
import com.kunzisoft.keepass.database.element.Group
|
||||||
|
import com.kunzisoft.keepass.database.element.node.Node
|
||||||
|
import com.kunzisoft.keepass.model.MainCredential
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
|
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||||
|
|
||||||
|
abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
|
||||||
|
|
||||||
|
private val mDatabaseViewModel: DatabaseViewModel by viewModels()
|
||||||
|
private var mDatabaseTaskProvider: DatabaseTaskProvider? = null
|
||||||
|
private var mDatabase: Database? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
mDatabaseTaskProvider = DatabaseTaskProvider(this)
|
||||||
|
|
||||||
|
mDatabaseTaskProvider?.onDatabaseRetrieved = { database ->
|
||||||
|
onDatabaseRetrieved(database)
|
||||||
|
}
|
||||||
|
mDatabaseTaskProvider?.onActionFinish = { database, actionTask, result ->
|
||||||
|
onDatabaseActionFinished(database, actionTask, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
mDatabaseViewModel.saveDatabase.observe(this) { save ->
|
||||||
|
mDatabaseTaskProvider?.startDatabaseSave(save)
|
||||||
|
}
|
||||||
|
|
||||||
|
mDatabaseViewModel.reloadDatabase.observe(this) { fixDuplicateUuid ->
|
||||||
|
// TODO keepCurrentScreen()
|
||||||
|
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?.startDatabaseSaveName(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
mDatabase = database
|
||||||
|
mDatabaseViewModel.defineDatabase(database)
|
||||||
|
// optional method implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseActionFinished(
|
||||||
|
database: Database,
|
||||||
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result
|
||||||
|
) {
|
||||||
|
// optional method implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDatabase(databaseUri: Uri,
|
||||||
|
mainCredential: MainCredential) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseCreate(databaseUri, mainCredential)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Database functions
|
||||||
|
|
||||||
|
fun loadDatabase(databaseUri: Uri,
|
||||||
|
mainCredential: MainCredential,
|
||||||
|
readOnly: Boolean,
|
||||||
|
cipherEntity: CipherDatabaseEntity?,
|
||||||
|
fixDuplicateUuid: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseLoad(databaseUri, mainCredential, readOnly, cipherEntity, fixDuplicateUuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignDatabasePassword(databaseUri: Uri,
|
||||||
|
mainCredential: MainCredential) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseAssignPassword(databaseUri, mainCredential)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveDatabase() {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseSave(mDatabase?.isReadOnly != true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reloadDatabase() {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseReload(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDatabaseEntry(newEntry: Entry,
|
||||||
|
parent: Group,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseCreateEntry(newEntry, parent, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDatabaseEntry(oldEntry: Entry,
|
||||||
|
entryToUpdate: Entry,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseUpdateEntry(oldEntry, entryToUpdate, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyDatabaseNodes(nodesToCopy: List<Node>,
|
||||||
|
newParent: Group,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseCopyNodes(nodesToCopy, newParent, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveDatabaseNodes(nodesToMove: List<Node>,
|
||||||
|
newParent: Group,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseMoveNodes(nodesToMove, newParent, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteDatabaseNodes(nodesToDelete: List<Node>,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseDeleteNodes(nodesToDelete, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDatabaseGroup(newGroup: Group,
|
||||||
|
parent: Group,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseCreateGroup(newGroup, parent, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDatabaseGroup(oldGroup: Group,
|
||||||
|
groupToUpdate: Group,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseUpdateGroup(oldGroup, groupToUpdate, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun restoreDatabaseEntryHistory(mainEntry: Entry,
|
||||||
|
entryHistoryPosition: Int,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseRestoreEntryHistory(mainEntry, entryHistoryPosition, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteDatabaseEntryHistory(mainEntry: Entry,
|
||||||
|
entryHistoryPosition: Int,
|
||||||
|
save: Boolean) {
|
||||||
|
mDatabaseTaskProvider?.startDatabaseDeleteEntryHistory(mainEntry, entryHistoryPosition, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
mDatabaseTaskProvider?.registerProgressTask()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
mDatabaseTaskProvider?.unregisterProgressTask()
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package com.kunzisoft.keepass.activities.selection
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.room.Database
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||||
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
||||||
@@ -15,7 +16,7 @@ import com.kunzisoft.keepass.view.SpecialModeView
|
|||||||
/**
|
/**
|
||||||
* Activity to manage special mode (ie: selection mode)
|
* Activity to manage special mode (ie: selection mode)
|
||||||
*/
|
*/
|
||||||
abstract class SpecialModeActivity : StylishActivity() {
|
abstract class SpecialModeActivity : DatabaseActivity() {
|
||||||
|
|
||||||
protected var mSpecialMode: SpecialMode = SpecialMode.DEFAULT
|
protected var mSpecialMode: SpecialMode = SpecialMode.DEFAULT
|
||||||
private var mTypeMode: TypeMode = TypeMode.DEFAULT
|
private var mTypeMode: TypeMode = TypeMode.DEFAULT
|
||||||
|
|||||||
@@ -358,10 +358,10 @@ class NodeAdapter (private val context: Context,
|
|||||||
|
|
||||||
// Assign click
|
// Assign click
|
||||||
holder.container.setOnClickListener {
|
holder.container.setOnClickListener {
|
||||||
mNodeClickCallback?.onNodeClick(subNode)
|
mNodeClickCallback?.onNodeClick(database, subNode)
|
||||||
}
|
}
|
||||||
holder.container.setOnLongClickListener {
|
holder.container.setOnLongClickListener {
|
||||||
mNodeClickCallback?.onNodeLongClick(subNode) ?: false
|
mNodeClickCallback?.onNodeLongClick(database, subNode) ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,8 +380,8 @@ class NodeAdapter (private val context: Context,
|
|||||||
* Callback listener to redefine to do an action when a node is click
|
* Callback listener to redefine to do an action when a node is click
|
||||||
*/
|
*/
|
||||||
interface NodeClickCallback {
|
interface NodeClickCallback {
|
||||||
fun onNodeClick(node: Node)
|
fun onNodeClick(database: Database, node: Node)
|
||||||
fun onNodeLongClick(node: Node): Boolean
|
fun onNodeLongClick(database: Database, node: Node): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
class NodeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
class NodeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ import com.kunzisoft.keepass.R
|
|||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.element.template.Template
|
import com.kunzisoft.keepass.database.element.template.Template
|
||||||
import com.kunzisoft.keepass.database.element.template.TemplateField
|
import com.kunzisoft.keepass.database.element.template.TemplateField
|
||||||
|
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
||||||
|
|
||||||
|
|
||||||
class TemplatesSelectorAdapter(private val context: Context,
|
class TemplatesSelectorAdapter(private val context: Context,
|
||||||
private val database: Database?,
|
private val iconDrawableFactory: IconDrawableFactory?,
|
||||||
private var templates: List<Template>): BaseAdapter() {
|
private var templates: List<Template>): BaseAdapter() {
|
||||||
|
|
||||||
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||||
@@ -43,7 +44,7 @@ class TemplatesSelectorAdapter(private val context: Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
holder.icon?.let { icon ->
|
holder.icon?.let { icon ->
|
||||||
database?.iconDrawableFactory?.assignDatabaseIcon(icon, template.icon, mIconColor)
|
iconDrawableFactory?.assignDatabaseIcon(icon, template.icon, mIconColor)
|
||||||
}
|
}
|
||||||
holder.name?.text = TemplateField.getLocalizedName(context, template.title)
|
holder.name?.text = TemplateField.getLocalizedName(context, template.title)
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class App : MultiDexApplication() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onTerminate() {
|
override fun onTerminate() {
|
||||||
Database.getInstance().clearAndClose(this)
|
// TODO Database.getInstance().clearAndClose(this)
|
||||||
super.onTerminate()
|
super.onTerminate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,13 +56,9 @@ class KeeAutofillService : AutofillService() {
|
|||||||
var autofillInlineSuggestionsEnabled: Boolean = false
|
var autofillInlineSuggestionsEnabled: Boolean = false
|
||||||
private var mLock = AtomicBoolean()
|
private var mLock = AtomicBoolean()
|
||||||
|
|
||||||
private var mDatabase: Database? = null
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
|
|
||||||
getPreferences()
|
getPreferences()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +98,8 @@ class KeeAutofillService : AutofillService() {
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
mDatabase?.let { database ->
|
// TODO database
|
||||||
|
Database.getInstance()?.let { database ->
|
||||||
launchSelection(database,
|
launchSelection(database,
|
||||||
searchInfo,
|
searchInfo,
|
||||||
parseResult,
|
parseResult,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Co
|
|||||||
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
||||||
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
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.Database
|
||||||
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.database.CompressionAlgorithm
|
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
|
||||||
@@ -83,9 +84,12 @@ import kotlinx.coroutines.launch
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
|
class DatabaseTaskProvider(private val activity: FragmentActivity) {
|
||||||
|
|
||||||
var onActionFinish: ((actionTask: String,
|
var onDatabaseRetrieved: ((database: Database?) -> Unit)? = null
|
||||||
|
|
||||||
|
var onActionFinish: ((database: Database,
|
||||||
|
actionTask: String,
|
||||||
result: ActionRunnable.Result) -> Unit)? = null
|
result: ActionRunnable.Result) -> Unit)? = null
|
||||||
|
|
||||||
private var intentDatabaseTask = Intent(activity.applicationContext, DatabaseTaskNotificationService::class.java)
|
private var intentDatabaseTask = Intent(activity.applicationContext, DatabaseTaskNotificationService::class.java)
|
||||||
@@ -99,16 +103,16 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
|
|||||||
private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null
|
private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null
|
||||||
|
|
||||||
private val actionTaskListener = object: DatabaseTaskNotificationService.ActionTaskListener {
|
private val actionTaskListener = object: DatabaseTaskNotificationService.ActionTaskListener {
|
||||||
override fun onStartAction(titleId: Int?, messageId: Int?, warningId: Int?) {
|
override fun onStartAction(database: Database, titleId: Int?, messageId: Int?, warningId: Int?) {
|
||||||
startDialog(titleId, messageId, warningId)
|
startDialog(titleId, messageId, warningId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUpdateAction(titleId: Int?, messageId: Int?, warningId: Int?) {
|
override fun onUpdateAction(database: Database, titleId: Int?, messageId: Int?, warningId: Int?) {
|
||||||
updateDialog(titleId, messageId, warningId)
|
updateDialog(titleId, messageId, warningId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStopAction(actionTask: String, result: ActionRunnable.Result) {
|
override fun onStopAction(database: Database, actionTask: String, result: ActionRunnable.Result) {
|
||||||
onActionFinish?.invoke(actionTask, result)
|
onActionFinish?.invoke(database, actionTask, result)
|
||||||
// Remove the progress task
|
// Remove the progress task
|
||||||
stopDialog()
|
stopDialog()
|
||||||
}
|
}
|
||||||
@@ -144,6 +148,12 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var databaseListener = object: DatabaseTaskNotificationService.DatabaseListener {
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
onDatabaseRetrieved?.invoke(database)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun startDialog(titleId: Int? = null,
|
private fun startDialog(titleId: Int? = null,
|
||||||
messageId: Int? = null,
|
messageId: Int? = null,
|
||||||
warningId: Int? = null) {
|
warningId: Int? = null) {
|
||||||
@@ -187,16 +197,19 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
|
|||||||
serviceConnection = object : ServiceConnection {
|
serviceConnection = object : ServiceConnection {
|
||||||
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
|
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
|
||||||
mBinder = (serviceBinder as DatabaseTaskNotificationService.ActionTaskBinder?)?.apply {
|
mBinder = (serviceBinder as DatabaseTaskNotificationService.ActionTaskBinder?)?.apply {
|
||||||
addActionTaskListener(actionTaskListener)
|
addDatabaseListener(databaseListener)
|
||||||
addDatabaseFileInfoListener(databaseInfoListener)
|
addDatabaseFileInfoListener(databaseInfoListener)
|
||||||
getService().checkAction()
|
addActionTaskListener(actionTaskListener)
|
||||||
|
getService().checkDatabase()
|
||||||
getService().checkDatabaseInfo()
|
getService().checkDatabaseInfo()
|
||||||
|
getService().checkAction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceDisconnected(name: ComponentName?) {
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
mBinder?.removeDatabaseFileInfoListener(databaseInfoListener)
|
|
||||||
mBinder?.removeActionTaskListener(actionTaskListener)
|
mBinder?.removeActionTaskListener(actionTaskListener)
|
||||||
|
mBinder?.removeDatabaseFileInfoListener(databaseInfoListener)
|
||||||
|
mBinder?.removeDatabaseListener(databaseListener)
|
||||||
mBinder = null
|
mBinder = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,8 +270,9 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
|
|||||||
fun unregisterProgressTask() {
|
fun unregisterProgressTask() {
|
||||||
stopDialog()
|
stopDialog()
|
||||||
|
|
||||||
mBinder?.removeDatabaseFileInfoListener(databaseInfoListener)
|
|
||||||
mBinder?.removeActionTaskListener(actionTaskListener)
|
mBinder?.removeActionTaskListener(actionTaskListener)
|
||||||
|
mBinder?.removeDatabaseFileInfoListener(databaseInfoListener)
|
||||||
|
mBinder?.removeDatabaseListener(databaseListener)
|
||||||
mBinder = null
|
mBinder = null
|
||||||
|
|
||||||
unBindService()
|
unBindService()
|
||||||
@@ -639,6 +653,6 @@ class ProgressDatabaseTaskProvider(private val activity: FragmentActivity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = ProgressDatabaseTaskProvider::class.java.name
|
private val TAG = DatabaseTaskProvider::class.java.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,6 +111,7 @@ class MagikIME : InputMethodService(), KeyboardView.OnKeyboardActionListener {
|
|||||||
|
|
||||||
// Remove entry info if the database is not loaded
|
// Remove entry info if the database is not loaded
|
||||||
// or if entry info timestamp is before database loaded timestamp
|
// or if entry info timestamp is before database loaded timestamp
|
||||||
|
// TODO Database
|
||||||
val database = Database.getInstance()
|
val database = Database.getInstance()
|
||||||
val databaseTime = database.loadTimestamp
|
val databaseTime = database.loadTimestamp
|
||||||
val entryTime = entryInfoTimestamp
|
val entryTime = entryInfoTimestamp
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ class AttachmentFileNotificationService: LockNotificationService() {
|
|||||||
|
|
||||||
private val mainScope = CoroutineScope(Dispatchers.Main)
|
private val mainScope = CoroutineScope(Dispatchers.Main)
|
||||||
|
|
||||||
private var mDatabase: Database? = Database.getInstance()
|
|
||||||
|
|
||||||
override fun retrieveChannelId(): String {
|
override fun retrieveChannelId(): String {
|
||||||
return CHANNEL_ATTACHMENT_ID
|
return CHANNEL_ATTACHMENT_ID
|
||||||
}
|
}
|
||||||
@@ -289,7 +287,8 @@ class AttachmentFileNotificationService: LockNotificationService() {
|
|||||||
// Add action to the list on start
|
// Add action to the list on start
|
||||||
attachmentNotificationList.add(attachmentNotification)
|
attachmentNotificationList.add(attachmentNotification)
|
||||||
|
|
||||||
mDatabase?.let { database ->
|
// TODO Database
|
||||||
|
Database.getInstance()?.let { database ->
|
||||||
mainScope.launch {
|
mainScope.launch {
|
||||||
AttachmentFileAction(attachmentNotification,
|
AttachmentFileAction(attachmentNotification,
|
||||||
database,
|
database,
|
||||||
|
|||||||
@@ -58,12 +58,12 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
|
|
||||||
private val mainScope = CoroutineScope(Dispatchers.Main)
|
private val mainScope = CoroutineScope(Dispatchers.Main)
|
||||||
|
|
||||||
|
private var mDatabaseListeners = LinkedList<DatabaseListener>()
|
||||||
|
private var mDatabaseInfoListeners = LinkedList<DatabaseInfoListener>()
|
||||||
private var mActionTaskBinder = ActionTaskBinder()
|
private var mActionTaskBinder = ActionTaskBinder()
|
||||||
private var mActionTaskListeners = LinkedList<ActionTaskListener>()
|
private var mActionTaskListeners = LinkedList<ActionTaskListener>()
|
||||||
private var mActionRunning = false
|
private var mActionRunning = false
|
||||||
|
|
||||||
private var mDatabaseInfoListeners = LinkedList<DatabaseInfoListener>()
|
|
||||||
|
|
||||||
private var mIconId: Int = R.drawable.notification_ic_database_load
|
private var mIconId: Int = R.drawable.notification_ic_database_load
|
||||||
private var mTitleId: Int = R.string.database_opened
|
private var mTitleId: Int = R.string.database_opened
|
||||||
private var mMessageId: Int? = null
|
private var mMessageId: Int? = null
|
||||||
@@ -81,13 +81,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
|
|
||||||
fun getService(): DatabaseTaskNotificationService = this@DatabaseTaskNotificationService
|
fun getService(): DatabaseTaskNotificationService = this@DatabaseTaskNotificationService
|
||||||
|
|
||||||
fun addActionTaskListener(actionTaskListener: ActionTaskListener) {
|
fun addDatabaseListener(databaseListener: DatabaseListener) {
|
||||||
if (!mActionTaskListeners.contains(actionTaskListener))
|
if (!mDatabaseListeners.contains(databaseListener))
|
||||||
mActionTaskListeners.add(actionTaskListener)
|
mDatabaseListeners.add(databaseListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeActionTaskListener(actionTaskListener: ActionTaskListener) {
|
fun removeDatabaseListener(databaseListener: DatabaseListener) {
|
||||||
mActionTaskListeners.remove(actionTaskListener)
|
mDatabaseListeners.remove(databaseListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addDatabaseFileInfoListener(databaseInfoListener: DatabaseInfoListener) {
|
fun addDatabaseFileInfoListener(databaseInfoListener: DatabaseInfoListener) {
|
||||||
@@ -98,12 +98,19 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
fun removeDatabaseFileInfoListener(databaseInfoListener: DatabaseInfoListener) {
|
fun removeDatabaseFileInfoListener(databaseInfoListener: DatabaseInfoListener) {
|
||||||
mDatabaseInfoListeners.remove(databaseInfoListener)
|
mDatabaseInfoListeners.remove(databaseInfoListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addActionTaskListener(actionTaskListener: ActionTaskListener) {
|
||||||
|
if (!mActionTaskListeners.contains(actionTaskListener))
|
||||||
|
mActionTaskListeners.add(actionTaskListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeActionTaskListener(actionTaskListener: ActionTaskListener) {
|
||||||
|
mActionTaskListeners.remove(actionTaskListener)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ActionTaskListener {
|
interface DatabaseListener {
|
||||||
fun onStartAction(titleId: Int?, messageId: Int?, warningId: Int?)
|
fun onDatabaseRetrieved(database: Database?)
|
||||||
fun onUpdateAction(titleId: Int?, messageId: Int?, warningId: Int?)
|
|
||||||
fun onStopAction(actionTask: String, result: ActionRunnable.Result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DatabaseInfoListener {
|
interface DatabaseInfoListener {
|
||||||
@@ -111,14 +118,15 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
newDatabaseInfo: SnapFileDatabaseInfo)
|
newDatabaseInfo: SnapFileDatabaseInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
interface ActionTaskListener {
|
||||||
* Force to call [ActionTaskListener.onStartAction] if the action is still running
|
fun onStartAction(database: Database, titleId: Int?, messageId: Int?, warningId: Int?)
|
||||||
*/
|
fun onUpdateAction(database: Database, titleId: Int?, messageId: Int?, warningId: Int?)
|
||||||
fun checkAction() {
|
fun onStopAction(database: Database, actionTask: String, result: ActionRunnable.Result)
|
||||||
if (mActionRunning) {
|
}
|
||||||
mActionTaskListeners.forEach { actionTaskListener ->
|
|
||||||
actionTaskListener.onStartAction(mTitleId, mMessageId, mWarningId)
|
fun checkDatabase() {
|
||||||
}
|
mDatabaseListeners.forEach { databaseListener ->
|
||||||
|
databaseListener.onDatabaseRetrieved(mDatabase)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +183,17 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force to call [ActionTaskListener.onStartAction] if the action is still running
|
||||||
|
*/
|
||||||
|
fun checkAction() {
|
||||||
|
if (mActionRunning) {
|
||||||
|
mActionTaskListeners.forEach { actionTaskListener ->
|
||||||
|
actionTaskListener.onStartAction(mDatabase, mTitleId, mMessageId, mWarningId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent): IBinder? {
|
override fun onBind(intent: Intent): IBinder? {
|
||||||
super.onBind(intent)
|
super.onBind(intent)
|
||||||
return mActionTaskBinder
|
return mActionTaskBinder
|
||||||
@@ -184,6 +203,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
super.onStartCommand(intent, flags, startId)
|
super.onStartCommand(intent, flags, startId)
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
mDatabase = Database.getInstance()
|
||||||
|
mDatabaseListeners.forEach { listener ->
|
||||||
|
listener.onDatabaseRetrieved(mDatabase)
|
||||||
|
}
|
||||||
|
|
||||||
// Create the notification
|
// Create the notification
|
||||||
buildMessage(intent)
|
buildMessage(intent)
|
||||||
@@ -243,7 +265,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
})
|
})
|
||||||
|
|
||||||
mActionTaskListeners.forEach { actionTaskListener ->
|
mActionTaskListeners.forEach { actionTaskListener ->
|
||||||
actionTaskListener.onStartAction(mTitleId, mMessageId, mWarningId)
|
actionTaskListener.onStartAction(mDatabase, mTitleId, mMessageId, mWarningId)
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -253,7 +275,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
{ result ->
|
{ result ->
|
||||||
try {
|
try {
|
||||||
mActionTaskListeners.forEach { actionTaskListener ->
|
mActionTaskListeners.forEach { actionTaskListener ->
|
||||||
actionTaskListener.onStopAction(intentAction!!, result)
|
actionTaskListener.onStopAction(mDatabase, intentAction!!, result)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Save the database info before performing action
|
// Save the database info before performing action
|
||||||
@@ -443,7 +465,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
|||||||
override fun updateMessage(resId: Int) {
|
override fun updateMessage(resId: Int) {
|
||||||
mMessageId = resId
|
mMessageId = resId
|
||||||
mActionTaskListeners.forEach { actionTaskListener ->
|
mActionTaskListeners.forEach { actionTaskListener ->
|
||||||
actionTaskListener.onUpdateAction(mTitleId, mMessageId, mWarningId)
|
actionTaskListener.onUpdateAction(mDatabase, mTitleId, mMessageId, mWarningId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,42 @@
|
|||||||
package com.kunzisoft.keepass.settings
|
package com.kunzisoft.keepass.settings
|
||||||
|
|
||||||
import android.content.Context
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.kunzisoft.keepass.activities.DatabaseRetrieval
|
||||||
|
import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
|
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||||
|
|
||||||
abstract class DatabasePreferenceFragment : PreferenceFragmentCompat() {
|
abstract class DatabasePreferenceFragment : PreferenceFragmentCompat(), DatabaseRetrieval {
|
||||||
|
|
||||||
protected var mDatabase: Database? = null
|
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onViewCreated(view: View,
|
||||||
super.onAttach(context)
|
savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
mDatabaseViewModel.database.observe(viewLifecycleOwner) { database ->
|
||||||
|
view.resetAppTimeoutWhenViewFocusedOrChanged(requireContext(), database)
|
||||||
|
onDatabaseRetrieved(database)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseActionFinished(
|
||||||
|
database: Database,
|
||||||
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result
|
||||||
|
) {
|
||||||
|
// Can be overridden by a subclass
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun saveDatabase(save: Boolean) {
|
||||||
|
mDatabaseViewModel.saveDatabase(save)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun reloadDatabase() {
|
||||||
|
mDatabaseViewModel.reloadDatabase(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,11 +23,14 @@ import android.content.Context
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
|
||||||
class MainPreferenceFragment : DatabasePreferenceFragment() {
|
class MainPreferenceFragment : DatabasePreferenceFragment() {
|
||||||
|
|
||||||
private var mCallback: Callback? = null
|
private var mCallback: Callback? = null
|
||||||
|
|
||||||
|
private var mDatabaseLoaded: Boolean = false
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
|
|
||||||
@@ -43,6 +46,10 @@ class MainPreferenceFragment : DatabasePreferenceFragment() {
|
|||||||
super.onDetach()
|
super.onDetach()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
mDatabaseLoaded = database?.loaded == true
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||||
|
|
||||||
@@ -80,7 +87,8 @@ class MainPreferenceFragment : DatabasePreferenceFragment() {
|
|||||||
mCallback?.onNestedPreferenceSelected(NestedSettingsFragment.Screen.DATABASE)
|
mCallback?.onNestedPreferenceSelected(NestedSettingsFragment.Screen.DATABASE)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
if (mDatabase?.loaded != true) {
|
// TODO Check
|
||||||
|
if (mDatabaseLoaded) {
|
||||||
isEnabled = false
|
isEnabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ import com.kunzisoft.keepass.activities.stylish.Stylish
|
|||||||
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
|
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
|
||||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||||
import com.kunzisoft.keepass.biometric.AdvancedUnlockManager
|
import com.kunzisoft.keepass.biometric.AdvancedUnlockManager
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.education.Education
|
import com.kunzisoft.keepass.education.Education
|
||||||
|
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
||||||
import com.kunzisoft.keepass.icons.IconPackChooser
|
import com.kunzisoft.keepass.icons.IconPackChooser
|
||||||
import com.kunzisoft.keepass.settings.preference.IconPackListPreference
|
import com.kunzisoft.keepass.settings.preference.IconPackListPreference
|
||||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.DurationDialogFragmentCompat
|
import com.kunzisoft.keepass.settings.preferencedialogfragment.DurationDialogFragmentCompat
|
||||||
@@ -54,6 +56,12 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
|
|
||||||
private var deleteKeysAlertDialog: AlertDialog? = null
|
private var deleteKeysAlertDialog: AlertDialog? = null
|
||||||
|
|
||||||
|
private var mIconDrawableFactory: IconDrawableFactory? = null
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
this.mIconDrawableFactory = database?.iconDrawableFactory
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
|
||||||
// Load the preferences from an XML resource
|
// Load the preferences from an XML resource
|
||||||
@@ -426,8 +434,9 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (iconPackEnabled) {
|
if (iconPackEnabled) {
|
||||||
mDatabase?.let {
|
// TODO Check
|
||||||
IconPackChooser.setSelectedIconPack(it.iconDrawableFactory, iconPackId)
|
mIconDrawableFactory?.let {
|
||||||
|
IconPackChooser.setSelectedIconPack(it, iconPackId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iconPackEnabled
|
iconPackEnabled
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceCategory
|
import androidx.preference.PreferenceCategory
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
@@ -33,6 +34,7 @@ import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
|
|||||||
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||||
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
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.Database
|
||||||
import com.kunzisoft.keepass.database.element.Group
|
import com.kunzisoft.keepass.database.element.Group
|
||||||
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
|
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
|
||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
||||||
@@ -40,9 +42,11 @@ import com.kunzisoft.keepass.settings.preference.*
|
|||||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.*
|
import com.kunzisoft.keepass.settings.preferencedialogfragment.*
|
||||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
import com.kunzisoft.keepass.utils.MenuUtil
|
import com.kunzisoft.keepass.utils.MenuUtil
|
||||||
|
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||||
|
|
||||||
class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
|
class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
|
||||||
|
|
||||||
|
private var mDatabase: Database? = null
|
||||||
private var mDatabaseReadOnly: Boolean = false
|
private var mDatabaseReadOnly: Boolean = false
|
||||||
private var mDatabaseAutoSaveEnabled: Boolean = true
|
private var mDatabaseAutoSaveEnabled: Boolean = true
|
||||||
|
|
||||||
@@ -61,6 +65,10 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
|
|||||||
private var mMemoryPref: InputKdfSizePreference? = null
|
private var mMemoryPref: InputKdfSizePreference? = null
|
||||||
private var mParallelismPref: InputKdfNumberPreference? = null
|
private var mParallelismPref: InputKdfNumberPreference? = null
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
mDatabase = database
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreateScreenPreference(screen: Screen, savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
@@ -161,8 +169,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
|
|||||||
database.enableRecycleBin(recycleBinEnabled, resources)
|
database.enableRecycleBin(recycleBinEnabled, resources)
|
||||||
refreshRecycleBinGroup()
|
refreshRecycleBinGroup()
|
||||||
// Save the database if not in readonly mode
|
// Save the database if not in readonly mode
|
||||||
(context as SettingsActivity?)?.
|
saveDatabase(mDatabaseAutoSaveEnabled)
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSave(mDatabaseAutoSaveEnabled)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@@ -195,8 +202,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
|
|||||||
database.enableTemplates(templatesEnabled, resources)
|
database.enableTemplates(templatesEnabled, resources)
|
||||||
refreshTemplatesGroup()
|
refreshTemplatesGroup()
|
||||||
// Save the database if not in readonly mode
|
// Save the database if not in readonly mode
|
||||||
(context as SettingsActivity?)?.
|
saveDatabase(mDatabaseAutoSaveEnabled)
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSave(mDatabaseAutoSaveEnabled)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@@ -621,25 +627,20 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
|
||||||
val settingActivity = activity as SettingsActivity?
|
|
||||||
|
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.menu_save_database -> {
|
R.id.menu_save_database -> {
|
||||||
settingActivity?.mProgressDatabaseTaskProvider?.startDatabaseSave(!mDatabaseReadOnly)
|
saveDatabase(!mDatabaseReadOnly)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.menu_reload_database -> {
|
R.id.menu_reload_database -> {
|
||||||
settingActivity?.apply {
|
reloadDatabase()
|
||||||
keepCurrentScreen()
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseReload(false)
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
// Check the time lock before launching settings
|
// Check the time lock before launching settings
|
||||||
settingActivity?.let {
|
// TODO activity menu
|
||||||
|
(activity as SettingsActivity?)?.let {
|
||||||
MenuUtil.onDefaultMenuOptionsItemSelected(it, item, mDatabaseReadOnly, true)
|
MenuUtil.onDefaultMenuOptionsItemSelected(it, item, mDatabaseReadOnly, true)
|
||||||
}
|
}
|
||||||
super.onOptionsItemSelected(item)
|
super.onOptionsItemSelected(item)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.kunzisoft.keepass.activities.dialogs.UnderDevelopmentFeatureDialogFra
|
|||||||
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
|
|
||||||
|
// TODO Move database fragment in sub class
|
||||||
abstract class NestedSettingsFragment : DatabasePreferenceFragment() {
|
abstract class NestedSettingsFragment : DatabasePreferenceFragment() {
|
||||||
|
|
||||||
enum class Screen {
|
enum class Screen {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ package com.kunzisoft.keepass.settings
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.backup.BackupManager
|
import android.app.backup.BackupManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
@@ -33,7 +32,6 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
|
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
|
||||||
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment
|
|
||||||
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||||
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
|
||||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||||
@@ -41,6 +39,7 @@ import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrCha
|
|||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.model.MainCredential
|
import com.kunzisoft.keepass.model.MainCredential
|
||||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
|
||||||
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
@@ -49,8 +48,7 @@ import java.util.*
|
|||||||
open class SettingsActivity
|
open class SettingsActivity
|
||||||
: LockingActivity(),
|
: LockingActivity(),
|
||||||
MainPreferenceFragment.Callback,
|
MainPreferenceFragment.Callback,
|
||||||
AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
|
AssignMasterKeyDialogFragment.AssignPasswordDialogListener {
|
||||||
PasswordEncodingDialogFragment.Listener {
|
|
||||||
|
|
||||||
private var backupManager: BackupManager? = null
|
private var backupManager: BackupManager? = null
|
||||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||||
@@ -60,14 +58,6 @@ open class SettingsActivity
|
|||||||
private var toolbar: Toolbar? = null
|
private var toolbar: Toolbar? = null
|
||||||
private var lockView: View? = null
|
private var lockView: View? = null
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the main fragment to show in first
|
|
||||||
* @return The main fragment
|
|
||||||
*/
|
|
||||||
protected open fun retrieveMainFragment(): Fragment {
|
|
||||||
return MainPreferenceFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@@ -90,9 +80,6 @@ open class SettingsActivity
|
|||||||
lockAndExit()
|
lockAndExit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus view to reinitialize timeout
|
|
||||||
coordinatorLayout?.resetAppTimeoutWhenViewFocusedOrChanged(this, mDatabase)
|
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
supportFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
.add(R.id.fragment_container, retrieveMainFragment())
|
.add(R.id.fragment_container, retrieveMainFragment())
|
||||||
@@ -103,29 +90,6 @@ open class SettingsActivity
|
|||||||
|
|
||||||
backupManager = BackupManager(this)
|
backupManager = BackupManager(this)
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.onActionFinish = { actionTask, result ->
|
|
||||||
when (actionTask) {
|
|
||||||
DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> {
|
|
||||||
// Reload the current activity
|
|
||||||
if (result.isSuccess) {
|
|
||||||
startActivity(intent)
|
|
||||||
finish()
|
|
||||||
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
|
|
||||||
} else {
|
|
||||||
this.showActionErrorIfNeeded(result)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
// Call result in fragment
|
|
||||||
(supportFragmentManager
|
|
||||||
.findFragmentByTag(TAG_NESTED) as NestedSettingsFragment?)
|
|
||||||
?.onProgressDialogThreadResult(actionTask, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
coordinatorLayout?.showActionErrorIfNeeded(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// To reload the current screen
|
// To reload the current screen
|
||||||
if (intent.extras?.containsKey(FRAGMENT_ARG) == true) {
|
if (intent.extras?.containsKey(FRAGMENT_ARG) == true) {
|
||||||
intent.extras?.getString(FRAGMENT_ARG)?.let { fragmentScreenName ->
|
intent.extras?.getString(FRAGMENT_ARG)?.let { fragmentScreenName ->
|
||||||
@@ -136,6 +100,49 @@ open class SettingsActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the main fragment to show in first
|
||||||
|
* @return The main fragment
|
||||||
|
*/
|
||||||
|
protected open fun retrieveMainFragment(): Fragment {
|
||||||
|
return MainPreferenceFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
super.onDatabaseRetrieved(database)
|
||||||
|
|
||||||
|
// Focus view to reinitialize timeout
|
||||||
|
coordinatorLayout?.resetAppTimeoutWhenViewFocusedOrChanged(this, database)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseActionFinished(
|
||||||
|
database: Database,
|
||||||
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result
|
||||||
|
) {
|
||||||
|
super.onDatabaseActionFinished(database, actionTask, result)
|
||||||
|
when (actionTask) {
|
||||||
|
DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> {
|
||||||
|
// Reload the current activity
|
||||||
|
if (result.isSuccess) {
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
|
||||||
|
} else {
|
||||||
|
this.showActionErrorIfNeeded(result)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// Call result in fragment
|
||||||
|
(supportFragmentManager
|
||||||
|
.findFragmentByTag(TAG_NESTED) as NestedSettingsFragment?)
|
||||||
|
?.onProgressDialogThreadResult(actionTask, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
coordinatorLayout?.showActionErrorIfNeeded(result)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> onBackPressed()
|
android.R.id.home -> onBackPressed()
|
||||||
@@ -149,31 +156,8 @@ open class SettingsActivity
|
|||||||
super.onStop()
|
super.onStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPasswordEncodingValidateListener(databaseUri: Uri?,
|
|
||||||
mainCredential: MainCredential) {
|
|
||||||
databaseUri?.let {
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseAssignPassword(
|
|
||||||
databaseUri,
|
|
||||||
mainCredential
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAssignKeyDialogPositiveClick(mainCredential: MainCredential) {
|
override fun onAssignKeyDialogPositiveClick(mainCredential: MainCredential) {
|
||||||
mDatabase?.let { database ->
|
assignPassword(mainCredential)
|
||||||
database.fileUri?.let { databaseUri ->
|
|
||||||
// Show the progress dialog now or after dialog confirmation
|
|
||||||
if (database.validatePasswordEncoding(mainCredential)) {
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseAssignPassword(
|
|
||||||
databaseUri,
|
|
||||||
mainCredential
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
PasswordEncodingDialogFragment.getInstance(databaseUri, mainCredential)
|
|
||||||
.show(supportFragmentManager, "passwordEncodingTag")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential) {}
|
override fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential) {}
|
||||||
@@ -243,7 +227,7 @@ open class SettingsActivity
|
|||||||
|
|
||||||
override fun onNestedPreferenceSelected(key: NestedSettingsFragment.Screen, reload: Boolean) {
|
override fun onNestedPreferenceSelected(key: NestedSettingsFragment.Screen, reload: Boolean) {
|
||||||
if (mTimeoutEnable)
|
if (mTimeoutEnable)
|
||||||
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(this, mDatabase) {
|
checkTimeAndLockIfTimeoutOrResetTimeout {
|
||||||
replaceFragment(key, reload)
|
replaceFragment(key, reload)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class IconPackListPreference @JvmOverloads constructor(context: Context,
|
|||||||
|
|
||||||
setEntries(entries.toTypedArray())
|
setEntries(entries.toTypedArray())
|
||||||
entryValues = values.toTypedArray()
|
entryValues = values.toTypedArray()
|
||||||
|
// TODO database
|
||||||
IconPackChooser.getSelectedIconPack(context, Database.getInstance().iconDrawableFactory)?.let { selectedIconPack ->
|
IconPackChooser.getSelectedIconPack(context, Database.getInstance().iconDrawableFactory)?.let { selectedIconPack ->
|
||||||
setDefaultValue(selectedIconPack.id)
|
setDefaultValue(selectedIconPack.id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.kunzisoft.androidclearchroma.colormode.ColorMode
|
|||||||
import com.kunzisoft.androidclearchroma.fragment.ChromaColorFragment
|
import com.kunzisoft.androidclearchroma.fragment.ChromaColorFragment
|
||||||
import com.kunzisoft.androidclearchroma.fragment.ChromaColorFragment.*
|
import com.kunzisoft.androidclearchroma.fragment.ChromaColorFragment.*
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
|
||||||
class DatabaseColorPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
|
class DatabaseColorPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmentCompat() {
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ class DatabaseColorPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialog
|
|||||||
}
|
}
|
||||||
val oldColor = database.customColor
|
val oldColor = database.customColor
|
||||||
database.customColor = newColor
|
database.customColor = newColor
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveColor(oldColor, newColor, mDatabaseAutoSaveEnable)
|
saveColor(oldColor, newColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDialogClosed(true)
|
onDialogClosed(true)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class DatabaseDataCompressionPreferenceDialogFragmentCompat
|
|||||||
database.compressionAlgorithm = newCompression
|
database.compressionAlgorithm = newCompression
|
||||||
|
|
||||||
if (oldCompression != null && newCompression != null)
|
if (oldCompression != null && newCompression != null)
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveCompression(oldCompression, newCompression, mDatabaseAutoSaveEnable)
|
saveCompression(oldCompression, newCompression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class DatabaseDefaultUsernamePreferenceDialogFragmentCompat : DatabaseSavePrefer
|
|||||||
val newDefaultUsername = inputText
|
val newDefaultUsername = inputText
|
||||||
val oldDefaultUsername = database.defaultUsername
|
val oldDefaultUsername = database.defaultUsername
|
||||||
database.defaultUsername = newDefaultUsername
|
database.defaultUsername = newDefaultUsername
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveDefaultUsername(oldDefaultUsername, newDefaultUsername, mDatabaseAutoSaveEnable)
|
saveDefaultUsername(oldDefaultUsername, newDefaultUsername)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class DatabaseDescriptionPreferenceDialogFragmentCompat : DatabaseSavePreference
|
|||||||
val newDescription = inputText
|
val newDescription = inputText
|
||||||
val oldDescription = database.description
|
val oldDescription = database.description
|
||||||
database.description = newDescription
|
database.description = newDescription
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveDescription(oldDescription, newDescription, mDatabaseAutoSaveEnable)
|
saveDescription(oldDescription, newDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat
|
|||||||
database.encryptionAlgorithm = newAlgorithm
|
database.encryptionAlgorithm = newAlgorithm
|
||||||
|
|
||||||
if (oldAlgorithm != null && newAlgorithm != null)
|
if (oldAlgorithm != null && newAlgorithm != null)
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveEncryption(oldAlgorithm, newAlgorithm, mDatabaseAutoSaveEnable)
|
saveEncryption(oldAlgorithm, newAlgorithm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class DatabaseKeyDerivationPreferenceDialogFragmentCompat
|
|||||||
val oldKdfEngine = database.kdfEngine
|
val oldKdfEngine = database.kdfEngine
|
||||||
if (newKdfEngine != null && oldKdfEngine != null) {
|
if (newKdfEngine != null && oldKdfEngine != null) {
|
||||||
database.kdfEngine = newKdfEngine
|
database.kdfEngine = newKdfEngine
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveKeyDerivation(oldKdfEngine, newKdfEngine, mDatabaseAutoSaveEnable)
|
saveKeyDerivation(oldKdfEngine, newKdfEngine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class DatabaseNamePreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogF
|
|||||||
val newName = inputText
|
val newName = inputText
|
||||||
val oldName = database.name
|
val oldName = database.name
|
||||||
database.name = newName
|
database.name = newName
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveName(oldName, newName, mDatabaseAutoSaveEnable)
|
saveName(oldName, newName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,11 +62,7 @@ class DatabaseRecycleBinGroupPreferenceDialogFragmentCompat
|
|||||||
val oldGroup = database.recycleBin
|
val oldGroup = database.recycleBin
|
||||||
val newGroup = mGroupRecycleBin
|
val newGroup = mGroupRecycleBin
|
||||||
database.setRecycleBin(newGroup)
|
database.setRecycleBin(newGroup)
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveRecycleBin(
|
saveRecycleBin(oldGroup, newGroup)
|
||||||
oldGroup,
|
|
||||||
newGroup,
|
|
||||||
mDatabaseAutoSaveEnable
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class DatabaseRemoveUnlinkedDataPreferenceDialogFragmentCompat : DatabaseSavePre
|
|||||||
override fun onDialogClosed(positiveResult: Boolean) {
|
override fun onDialogClosed(positiveResult: Boolean) {
|
||||||
mDatabase?.let { _ ->
|
mDatabase?.let { _ ->
|
||||||
if (positiveResult) {
|
if (positiveResult) {
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseRemoveUnlinkedData(mDatabaseAutoSaveEnable)
|
removeUnlinkedData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,28 +20,123 @@
|
|||||||
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDatabaseTaskProvider
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import com.kunzisoft.keepass.activities.DatabaseRetrieval
|
||||||
|
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
||||||
|
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.Group
|
||||||
|
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
import com.kunzisoft.keepass.settings.SettingsActivity
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
|
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||||
|
|
||||||
abstract class DatabaseSavePreferenceDialogFragmentCompat : InputPreferenceDialogFragmentCompat() {
|
abstract class DatabaseSavePreferenceDialogFragmentCompat
|
||||||
|
: InputPreferenceDialogFragmentCompat(), DatabaseRetrieval {
|
||||||
|
|
||||||
protected var mDatabaseAutoSaveEnable = true
|
private var mDatabaseAutoSaveEnable = true
|
||||||
protected var mProgressDatabaseTaskProvider: ProgressDatabaseTaskProvider? = null
|
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
|
||||||
|
protected var mDatabase: Database? = null
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
// Attach dialog thread to start action
|
|
||||||
if (context is SettingsActivity) {
|
|
||||||
mProgressDatabaseTaskProvider = context.mProgressDatabaseTaskProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
this.mDatabaseAutoSaveEnable = PreferencesUtil.isAutoSaveDatabaseEnabled(context)
|
this.mDatabaseAutoSaveEnable = PreferencesUtil.isAutoSaveDatabaseEnabled(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetach() {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
mProgressDatabaseTaskProvider = null
|
super.onViewCreated(view, savedInstanceState)
|
||||||
super.onDetach()
|
|
||||||
|
mDatabaseViewModel.database.observe(viewLifecycleOwner) { database ->
|
||||||
|
onDatabaseRetrieved(database)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseRetrieved(database: Database?) {
|
||||||
|
this.mDatabase = database
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDatabaseActionFinished(
|
||||||
|
database: Database,
|
||||||
|
actionTask: String,
|
||||||
|
result: ActionRunnable.Result
|
||||||
|
) {
|
||||||
|
// Optional
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun saveColor(oldColor: String,
|
||||||
|
newColor: String) {
|
||||||
|
mDatabaseViewModel.saveColor(oldColor, newColor, mDatabaseAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun saveCompression(oldCompression: CompressionAlgorithm,
|
||||||
|
newCompression: CompressionAlgorithm) {
|
||||||
|
mDatabaseViewModel.saveCompression(oldCompression, newCompression, 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 saveEncryption(oldEncryption: EncryptionAlgorithm,
|
||||||
|
newEncryptionAlgorithm: EncryptionAlgorithm) {
|
||||||
|
mDatabaseViewModel.saveEncryption(oldEncryption, newEncryptionAlgorithm, 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 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 saveMaxHistoryItems(oldNumber: Int,
|
||||||
|
newNumber: Int) {
|
||||||
|
mDatabaseViewModel.saveMaxHistoryItems(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 saveParallelism(oldNumber: Long,
|
||||||
|
newNumber: Long) {
|
||||||
|
mDatabaseViewModel.saveParallelism(oldNumber, newNumber, mDatabaseAutoSaveEnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun saveIterations(oldNumber: Long,
|
||||||
|
newNumber: Long) {
|
||||||
|
mDatabaseViewModel.saveIterations(oldNumber, newNumber, mDatabaseAutoSaveEnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -62,11 +62,7 @@ class DatabaseTemplatesGroupPreferenceDialogFragmentCompat
|
|||||||
val oldGroup = database.templatesGroup
|
val oldGroup = database.templatesGroup
|
||||||
val newGroup = mGroupTemplates
|
val newGroup = mGroupTemplates
|
||||||
database.setTemplatesGroup(newGroup)
|
database.setTemplatesGroup(newGroup)
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveTemplatesGroup(
|
saveTemplatesGroup(oldGroup, newGroup)
|
||||||
oldGroup,
|
|
||||||
newGroup,
|
|
||||||
mDatabaseAutoSaveEnable
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
@@ -30,7 +29,6 @@ import androidx.annotation.StringRes
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.preference.PreferenceDialogFragmentCompat
|
import androidx.preference.PreferenceDialogFragmentCompat
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
|
||||||
|
|
||||||
abstract class InputPreferenceDialogFragmentCompat : PreferenceDialogFragmentCompat() {
|
abstract class InputPreferenceDialogFragmentCompat : PreferenceDialogFragmentCompat() {
|
||||||
|
|
||||||
@@ -41,14 +39,6 @@ abstract class InputPreferenceDialogFragmentCompat : PreferenceDialogFragmentCom
|
|||||||
|
|
||||||
private var mOnInputTextEditorActionListener: TextView.OnEditorActionListener? = null
|
private var mOnInputTextEditorActionListener: TextView.OnEditorActionListener? = null
|
||||||
|
|
||||||
protected var mDatabase: Database? = null
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
mDatabase = Database.getInstance()
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputText: String
|
var inputText: String
|
||||||
get() = this.inputTextView?.text?.toString() ?: ""
|
get() = this.inputTextView?.text?.toString() ?: ""
|
||||||
set(inputText) {
|
set(inputText) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class MaxHistoryItemsPreferenceDialogFragmentCompat : DatabaseSavePreferenceDial
|
|||||||
// Remove all history items
|
// Remove all history items
|
||||||
database.removeOldestHistoryForEachEntry()
|
database.removeOldestHistoryForEachEntry()
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveMaxHistoryItems(oldMaxHistoryItems, maxHistoryItems, mDatabaseAutoSaveEnable)
|
saveMaxHistoryItems(oldMaxHistoryItems, maxHistoryItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class MaxHistorySizePreferenceDialogFragmentCompat : DatabaseSavePreferenceDialo
|
|||||||
val oldMaxHistorySize = database.historyMaxSize
|
val oldMaxHistorySize = database.historyMaxSize
|
||||||
database.historyMaxSize = numberOfBytes
|
database.historyMaxSize = numberOfBytes
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveMaxHistorySize(oldMaxHistorySize, numberOfBytes, mDatabaseAutoSaveEnable)
|
saveMaxHistorySize(oldMaxHistorySize, numberOfBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class MemoryUsagePreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFr
|
|||||||
val oldMemoryUsage = database.memoryUsage
|
val oldMemoryUsage = database.memoryUsage
|
||||||
database.memoryUsage = numberOfBytes
|
database.memoryUsage = numberOfBytes
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveMemoryUsage(oldMemoryUsage, numberOfBytes, mDatabaseAutoSaveEnable)
|
saveMemoryUsage(oldMemoryUsage, numberOfBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ class ParallelismPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFr
|
|||||||
val oldParallelism = database.parallelism
|
val oldParallelism = database.parallelism
|
||||||
database.parallelism = parallelism
|
database.parallelism = parallelism
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveParallelism(
|
saveParallelism(oldParallelism, parallelism)
|
||||||
oldParallelism,
|
|
||||||
parallelism,
|
|
||||||
mDatabaseAutoSaveEnable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class RoundsPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFragmen
|
|||||||
database.numberKeyEncryptionRounds = Long.MAX_VALUE
|
database.numberKeyEncryptionRounds = Long.MAX_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
mProgressDatabaseTaskProvider?.startDatabaseSaveIterations(oldRounds, rounds, mDatabaseAutoSaveEnable)
|
saveIterations(oldRounds, rounds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,5 +138,5 @@ fun Context.closeDatabase() {
|
|||||||
cancelAll()
|
cancelAll()
|
||||||
}
|
}
|
||||||
// Clear data
|
// Clear data
|
||||||
Database.getInstance().clearAndClose(this)
|
// TODO Database.getInstance().clearAndClose(this)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
package com.kunzisoft.keepass.viewmodels
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
||||||
|
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.Group
|
||||||
|
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
|
||||||
|
|
||||||
|
class DatabaseViewModel: ViewModel() {
|
||||||
|
|
||||||
|
val database : LiveData<Database?> get() = _database
|
||||||
|
private val _database = SingleLiveEvent<Database?>()
|
||||||
|
|
||||||
|
val saveDatabase : LiveData<Boolean> get() = _saveDatabase
|
||||||
|
private val _saveDatabase = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
val reloadDatabase : LiveData<Boolean> get() = _reloadDatabase
|
||||||
|
private val _reloadDatabase = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
val saveName : LiveData<SuperString> get() = _saveName
|
||||||
|
private val _saveName = SingleLiveEvent<SuperString>()
|
||||||
|
|
||||||
|
val saveDescription : LiveData<SuperString> get() = _saveDescription
|
||||||
|
private val _saveDescription = SingleLiveEvent<SuperString>()
|
||||||
|
|
||||||
|
val saveDefaultUsername : LiveData<SuperString> get() = _saveDefaultUsername
|
||||||
|
private val _saveDefaultUsername = SingleLiveEvent<SuperString>()
|
||||||
|
|
||||||
|
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: Database?) {
|
||||||
|
this._database.value = database
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveDatabase(save: Boolean) {
|
||||||
|
_saveDatabase.value = save
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reloadDatabase(fixDuplicateUuid: Boolean) {
|
||||||
|
_reloadDatabase.value = fixDuplicateUuid
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveName(oldValue: String,
|
||||||
|
newValue: String,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveName.value = SuperString(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveDescription(oldValue: String,
|
||||||
|
newValue: String,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveDescription.value = SuperString(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveDefaultUsername(oldValue: String,
|
||||||
|
newValue: String,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveDefaultUsername.value = SuperString(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveColor(oldValue: String,
|
||||||
|
newValue: String,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveColor.value = SuperString(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveCompression(oldValue: CompressionAlgorithm,
|
||||||
|
newValue: CompressionAlgorithm,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveCompression.value = SuperCompression(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeUnlinkedData(save: Boolean) {
|
||||||
|
_removeUnlinkData.value = save
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveRecycleBin(oldValue: Group?,
|
||||||
|
newValue: Group?,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveRecycleBin.value = SuperGroup(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveTemplatesGroup(oldValue: Group?,
|
||||||
|
newValue: Group?,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveTemplatesGroup.value = SuperGroup(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveMaxHistoryItems(oldValue: Int,
|
||||||
|
newValue: Int,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveMaxHistoryItems.value = SuperInt(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveMaxHistorySize(oldValue: Long,
|
||||||
|
newValue: Long,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveMaxHistorySize.value = SuperLong(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun saveEncryption(oldValue: EncryptionAlgorithm,
|
||||||
|
newValue: EncryptionAlgorithm,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveEncryption.value = SuperEncryption(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveKeyDerivation(oldValue: KdfEngine,
|
||||||
|
newValue: KdfEngine,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveKeyDerivation.value = SuperKeyDerivation(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveIterations(oldValue: Long,
|
||||||
|
newValue: Long,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveIterations.value = SuperLong(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveMemoryUsage(oldValue: Long,
|
||||||
|
newValue: Long,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveMemoryUsage.value = SuperLong(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveParallelism(oldValue: Long,
|
||||||
|
newValue: Long,
|
||||||
|
save: Boolean) {
|
||||||
|
_saveParallelism.value = SuperLong(oldValue, newValue, save)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,10 +19,9 @@ import java.util.*
|
|||||||
|
|
||||||
class EntryEditViewModel: ViewModel() {
|
class EntryEditViewModel: ViewModel() {
|
||||||
|
|
||||||
private val mDatabase: Database? = Database.getInstance()
|
private var mDatabase: Database? = null
|
||||||
|
private var mParent: Group? = null
|
||||||
private var mParent : Group? = null
|
private var mEntry: Entry? = null
|
||||||
private var mEntry : Entry? = null
|
|
||||||
private var mIsTemplate: Boolean = false
|
private var mIsTemplate: Boolean = false
|
||||||
|
|
||||||
private val mTempAttachments = mutableListOf<EntryAttachmentState>()
|
private val mTempAttachments = mutableListOf<EntryAttachmentState>()
|
||||||
@@ -80,6 +79,10 @@ class EntryEditViewModel: ViewModel() {
|
|||||||
val onBinaryPreviewLoaded : LiveData<AttachmentPosition> get() = _onBinaryPreviewLoaded
|
val onBinaryPreviewLoaded : LiveData<AttachmentPosition> get() = _onBinaryPreviewLoaded
|
||||||
private val _onBinaryPreviewLoaded = SingleLiveEvent<AttachmentPosition>()
|
private val _onBinaryPreviewLoaded = SingleLiveEvent<AttachmentPosition>()
|
||||||
|
|
||||||
|
fun setDatabase(database: Database?) {
|
||||||
|
this.mDatabase = database
|
||||||
|
}
|
||||||
|
|
||||||
fun initializeEntryToUpdate(entryId: NodeId<UUID>,
|
fun initializeEntryToUpdate(entryId: NodeId<UUID>,
|
||||||
registerInfo: RegisterInfo?,
|
registerInfo: RegisterInfo?,
|
||||||
searchInfo: SearchInfo?) {
|
searchInfo: SearchInfo?) {
|
||||||
@@ -166,7 +169,7 @@ class EntryEditViewModel: ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set default username
|
// Set default username
|
||||||
username = mDatabase.defaultUsername
|
username = mDatabase?.defaultUsername ?: ""
|
||||||
// Warning only the entry recognize is parent, parent don't yet recognize the new entry
|
// Warning only the entry recognize is parent, parent don't yet recognize the new entry
|
||||||
// Useful to recognize child state (ie: entry is a template)
|
// Useful to recognize child state (ie: entry is a template)
|
||||||
parent = parentGroup
|
parent = parentGroup
|
||||||
@@ -246,7 +249,7 @@ class EntryEditViewModel: ViewModel() {
|
|||||||
val tempAttachment = tempAttachmentState.attachment
|
val tempAttachment = tempAttachmentState.attachment
|
||||||
mDatabase?.attachmentPool?.let { binaryPool ->
|
mDatabase?.attachmentPool?.let { binaryPool ->
|
||||||
if (!newEntry.getAttachments(binaryPool).contains(tempAttachment)) {
|
if (!newEntry.getAttachments(binaryPool).contains(tempAttachment)) {
|
||||||
mDatabase.removeAttachmentIfNotUsed(tempAttachment)
|
mDatabase?.removeAttachmentIfNotUsed(tempAttachment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ import java.util.*
|
|||||||
|
|
||||||
class EntryViewModel: ViewModel() {
|
class EntryViewModel: ViewModel() {
|
||||||
|
|
||||||
private val mDatabase: Database? = Database.getInstance()
|
private var mDatabase: Database? = null
|
||||||
|
|
||||||
private var mEntryTemplate: Template? = null
|
private var mEntryTemplate: Template? = null
|
||||||
private var mEntry: Entry? = null
|
private var mEntry: Entry? = null
|
||||||
private var mLastEntryVersion: Entry? = null
|
private var mLastEntryVersion: Entry? = null
|
||||||
@@ -48,59 +47,69 @@ class EntryViewModel: ViewModel() {
|
|||||||
val historySelected : LiveData<EntryHistory> get() = _historySelected
|
val historySelected : LiveData<EntryHistory> get() = _historySelected
|
||||||
private val _historySelected = SingleLiveEvent<EntryHistory>()
|
private val _historySelected = SingleLiveEvent<EntryHistory>()
|
||||||
|
|
||||||
fun loadEntry(entryId: NodeId<UUID>, historyPosition: Int) {
|
fun setDatabase(database: Database?) {
|
||||||
IOActionTask(
|
mDatabase = database
|
||||||
{
|
}
|
||||||
// Manage current version and history
|
|
||||||
mLastEntryVersion = mDatabase?.getEntryById(entryId)
|
|
||||||
|
|
||||||
mEntry = if (historyPosition > -1) {
|
fun loadEntry(entryId: NodeId<UUID>?, historyPosition: Int) {
|
||||||
mLastEntryVersion?.getHistory()?.get(historyPosition)
|
if (entryId != null) {
|
||||||
} else {
|
IOActionTask(
|
||||||
mLastEntryVersion
|
{
|
||||||
}
|
// Manage current version and history
|
||||||
|
mLastEntryVersion = mDatabase?.getEntryById(entryId)
|
||||||
|
|
||||||
mEntryTemplate = mEntry?.let {
|
mEntry = if (historyPosition > -1) {
|
||||||
mDatabase?.getTemplate(it)
|
mLastEntryVersion?.getHistory()?.get(historyPosition)
|
||||||
} ?: Template.STANDARD
|
} else {
|
||||||
|
mLastEntryVersion
|
||||||
|
}
|
||||||
|
|
||||||
mHistoryPosition = historyPosition
|
mEntryTemplate = mEntry?.let {
|
||||||
|
mDatabase?.getTemplate(it)
|
||||||
|
} ?: Template.STANDARD
|
||||||
|
|
||||||
// To simplify template field visibility
|
mHistoryPosition = historyPosition
|
||||||
mEntry?.let { entry ->
|
|
||||||
// Add mLastEntryVersion to check the parent and define the template state
|
|
||||||
mDatabase?.decodeEntryWithTemplateConfiguration(entry, mLastEntryVersion)?.let {
|
|
||||||
// To update current modification time
|
|
||||||
it.touch(modified = false, touchParents = false)
|
|
||||||
|
|
||||||
// Build history info
|
// To simplify template field visibility
|
||||||
val entryInfoHistory = it.getHistory().map { entryHistory ->
|
mEntry?.let { entry ->
|
||||||
entryHistory.getEntryInfo(mDatabase)
|
// Add mLastEntryVersion to check the parent and define the template state
|
||||||
}
|
mDatabase?.decodeEntryWithTemplateConfiguration(entry, mLastEntryVersion)
|
||||||
|
?.let {
|
||||||
|
// To update current modification time
|
||||||
|
it.touch(modified = false, touchParents = false)
|
||||||
|
|
||||||
EntryInfoHistory(
|
// Build history info
|
||||||
mEntryTemplate ?: Template.STANDARD,
|
val entryInfoHistory = it.getHistory().map { entryHistory ->
|
||||||
it.getEntryInfo(mDatabase),
|
entryHistory.getEntryInfo(mDatabase)
|
||||||
entryInfoHistory
|
}
|
||||||
)
|
|
||||||
|
EntryInfoHistory(
|
||||||
|
mEntryTemplate ?: Template.STANDARD,
|
||||||
|
it.getEntryInfo(mDatabase),
|
||||||
|
entryInfoHistory
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ entryInfoHistory ->
|
||||||
|
if (entryInfoHistory != null) {
|
||||||
|
_template.value = entryInfoHistory.template
|
||||||
|
_entryInfo.value = entryInfoHistory.entryInfo
|
||||||
|
_entryIsHistory.value = mHistoryPosition != -1
|
||||||
|
_entryHistory.value = entryInfoHistory.entryHistory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
).execute()
|
||||||
{ entryInfoHistory ->
|
} else {
|
||||||
if (entryInfoHistory != null) {
|
mEntryTemplate = null
|
||||||
_template.value = entryInfoHistory.template
|
mEntry = null
|
||||||
_entryInfo.value = entryInfoHistory.entryInfo
|
mLastEntryVersion = null
|
||||||
_entryIsHistory.value = mHistoryPosition != -1
|
mHistoryPosition = -1
|
||||||
_entryHistory.value = entryInfoHistory.entryHistory
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
).execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateEntry() {
|
fun updateEntry() {
|
||||||
mEntry?.nodeId?.let { nodeId ->
|
loadEntry(mEntry?.nodeId, mHistoryPosition)
|
||||||
loadEntry(nodeId, mHistoryPosition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Remove
|
// TODO Remove
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.kunzisoft.keepass.viewmodels
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.kunzisoft.keepass.app.database.IOActionTask
|
||||||
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.Group
|
||||||
|
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||||
|
|
||||||
|
|
||||||
|
class GroupViewModel: ViewModel() {
|
||||||
|
|
||||||
|
private var mDatabase: Database? = null
|
||||||
|
|
||||||
|
val group : LiveData<SuperGroup> get() = _group
|
||||||
|
private val _group = MutableLiveData<SuperGroup>()
|
||||||
|
|
||||||
|
val onGroupSelected : LiveData<SuperGroup> get() = _onGroupSelected
|
||||||
|
private val _onGroupSelected = SingleLiveEvent<SuperGroup>()
|
||||||
|
|
||||||
|
fun setDatabase(database: Database?) {
|
||||||
|
this.mDatabase = database
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadGroup(groupId: NodeId<*>?) {
|
||||||
|
IOActionTask(
|
||||||
|
{
|
||||||
|
if (groupId != null) {
|
||||||
|
mDatabase?.getGroupById(groupId)
|
||||||
|
} else {
|
||||||
|
mDatabase?.rootGroup
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ group ->
|
||||||
|
if (group != null) {
|
||||||
|
_group.value = SuperGroup(group, mDatabase?.recycleBin == group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadGroup(group: Group) {
|
||||||
|
_group.value = SuperGroup(group, mDatabase?.recycleBin == group)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadGroupFromSearch(searchQuery: String,
|
||||||
|
omitBackup: Boolean) {
|
||||||
|
IOActionTask(
|
||||||
|
{
|
||||||
|
mDatabase?.createVirtualGroupFromSearch(searchQuery, omitBackup)
|
||||||
|
},
|
||||||
|
{ group ->
|
||||||
|
if (group != null) {
|
||||||
|
_group.value = SuperGroup(group, mDatabase?.recycleBin == group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun selectGroup(group: Group) {
|
||||||
|
_onGroupSelected.value = SuperGroup(group, mDatabase?.recycleBin == group)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SuperGroup(val group: Group, val isRecycleBin: Boolean)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = GroupViewModel::class.java.name
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user