Fix entry history

This commit is contained in:
J-Jamet
2021-07-30 23:00:28 +02:00
parent 96ed4c419a
commit 43207b316f
8 changed files with 145 additions and 127 deletions

View File

@@ -81,8 +81,10 @@ class EntryActivity : LockingActivity() {
private val mEntryViewModel: EntryViewModel by viewModels()
private var mEntryId: NodeId<UUID>? = null
private var mMainEntryId: NodeId<UUID>? = null
private var mHistoryPosition: Int = -1
private var mEntryIsHistory: Boolean = false
private var mUrl: String? = null
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
private var mAttachmentsToDownload: HashMap<Int, Attachment> = HashMap()
@@ -122,7 +124,7 @@ class EntryActivity : LockingActivity() {
// Get Entry from UUID
try {
intent.getParcelableExtra<NodeId<UUID>?>(KEY_ENTRY)?.let { entryId ->
mEntryId = entryId
mMainEntryId = entryId
intent.removeExtra(KEY_ENTRY)
mHistoryPosition = intent.getIntExtra(KEY_ENTRY_HISTORY_POSITION, -1)
intent.removeExtra(KEY_ENTRY_HISTORY_POSITION)
@@ -140,6 +142,30 @@ class EntryActivity : LockingActivity() {
lockAndExit()
}
mEntryViewModel.mainEntryId.observe(this) { mainEntryId ->
this.mMainEntryId = mainEntryId
invalidateOptionsMenu()
}
mEntryViewModel.historyPosition.observe(this) { historyPosition ->
this.mHistoryPosition = historyPosition
val entryIsHistory = historyPosition > -1
this.mEntryIsHistory = entryIsHistory
// Assign history dedicated view
historyView?.visibility = if (entryIsHistory) View.VISIBLE else View.GONE
if (entryIsHistory) {
val taColorAccent = theme.obtainStyledAttributes(intArrayOf(R.attr.colorAccent))
collapsingToolbarLayout?.contentScrim = ColorDrawable(taColorAccent.getColor(0, Color.BLACK))
taColorAccent.recycle()
}
invalidateOptionsMenu()
}
mEntryViewModel.url.observe(this) { url ->
this.mUrl = url
invalidateOptionsMenu()
}
mEntryViewModel.entryInfo.observe(this) { entryInfo ->
// Manage entry copy to start notification if allowed (at the first start)
if (savedInstanceState == null) {
@@ -168,18 +194,6 @@ class EntryActivity : LockingActivity() {
loadingView?.hideByFading()
}
mEntryViewModel.entryIsHistory.observe(this) { entryIsHistory ->
// Assign history dedicated view
historyView?.visibility = if (entryIsHistory) View.VISIBLE else View.GONE
if (entryIsHistory) {
val taColorAccent = theme.obtainStyledAttributes(intArrayOf(R.attr.colorAccent))
collapsingToolbarLayout?.contentScrim = ColorDrawable(taColorAccent.getColor(0, Color.BLACK))
taColorAccent.recycle()
}
invalidateOptionsMenu()
}
mEntryViewModel.onOtpElementUpdated.observe(this) { otpElement ->
if (otpElement == null)
entryProgress?.visibility = View.GONE
@@ -219,7 +233,7 @@ class EntryActivity : LockingActivity() {
coordinatorLayout?.resetAppTimeoutWhenViewFocusedOrChanged(this, database)
mEntryViewModel.setDatabase(database)
mEntryViewModel.loadEntry(mEntryId, mHistoryPosition)
mEntryViewModel.loadEntry(mMainEntryId, mHistoryPosition)
// Assign title icon
mIcon?.let { icon ->
@@ -306,16 +320,14 @@ class EntryActivity : LockingActivity() {
inflater.inflate(R.menu.entry, menu)
inflater.inflate(R.menu.database, menu)
if (mEntryViewModel.getEntry()?.url?.isEmpty() != false) {
if (mUrl?.isEmpty() != false) {
menu.findItem(R.id.menu_goto_url)?.isVisible = false
}
val entryIsHistory = mEntryViewModel.getEntryIsHistory()
if (entryIsHistory && !mReadOnly) {
if (mEntryIsHistory && !mReadOnly) {
inflater.inflate(R.menu.entry_history, menu)
}
if (entryIsHistory || mReadOnly) {
if (mEntryIsHistory || mReadOnly) {
menu.findItem(R.id.menu_save_database)?.isVisible = false
menu.findItem(R.id.menu_edit)?.isVisible = false
}
@@ -366,29 +378,29 @@ class EntryActivity : LockingActivity() {
return true
}
R.id.menu_edit -> {
mEntryViewModel.getEntry()?.let { entry ->
EntryEditActivity.launch(this@EntryActivity, entry)
mMainEntryId?.let { entryId ->
EntryEditActivity.launch(this@EntryActivity, entryId)
}
return true
}
R.id.menu_goto_url -> {
mEntryViewModel.getEntry()?.url?.let { url ->
mUrl?.let { url ->
UriUtil.gotoUrl(this, url)
}
return true
}
R.id.menu_restore_entry_history -> {
mEntryViewModel.getMainEntry()?.let { mainEntry ->
mMainEntryId?.let { mainEntryId ->
restoreEntryHistory(
mainEntry,
mEntryViewModel.getEntryHistoryPosition())
mainEntryId,
mHistoryPosition)
}
}
R.id.menu_delete_entry_history -> {
mEntryViewModel.getMainEntry()?.let { mainEntry ->
mMainEntryId?.let { mainEntryId ->
deleteEntryHistory(
mainEntry,
mEntryViewModel.getEntryHistoryPosition())
mainEntryId,
mHistoryPosition)
}
}
R.id.menu_save_database -> {
@@ -405,7 +417,7 @@ class EntryActivity : LockingActivity() {
override fun finish() {
// Transit data in previous Activity after an update
Intent().apply {
putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntryViewModel.getEntry())
putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mMainEntryId)
setResult(EntryEditActivity.UPDATE_ENTRY_RESULT_CODE, this)
}
super.finish()

View File

@@ -661,7 +661,7 @@ class EntryEditActivity : LockingActivity(),
try {
val bundle = Bundle()
val intentEntry = Intent()
bundle.putParcelable(ADD_OR_UPDATE_ENTRY_KEY, entry)
bundle.putParcelable(ADD_OR_UPDATE_ENTRY_KEY, entry.nodeId)
intentEntry.putExtras(bundle)
when (actionTask) {
ACTION_DATABASE_CREATE_ENTRY_TASK -> {
@@ -698,13 +698,13 @@ class EntryEditActivity : LockingActivity(),
* Launch EntryEditActivity to update an existing entry
*
* @param activity from activity
* @param entry Entry to update
* @param entryId Entry to update
*/
fun launch(activity: Activity,
entry: Entry) {
entryId: NodeId<UUID>) {
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
val intent = Intent(activity, EntryEditActivity::class.java)
intent.putExtra(KEY_ENTRY, entry.nodeId)
intent.putExtra(KEY_ENTRY, entryId)
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE)
}
}

View File

@@ -772,7 +772,7 @@ class GroupActivity : LockingActivity(),
.show(supportFragmentManager,
GroupEditDialogFragment.TAG_CREATE_GROUP)
}
Type.ENTRY -> EntryEditActivity.launch(this@GroupActivity, node as Entry)
Type.ENTRY -> EntryEditActivity.launch(this@GroupActivity, (node as Entry).nodeId)
}
return true
}

View File

@@ -39,6 +39,7 @@ import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.SortNodeEnum
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.viewmodels.GroupViewModel
@@ -397,9 +398,9 @@ class ListNodesFragment : DatabaseFragment(), SortDialogFragment.SortSelectionLi
EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE -> {
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE
|| resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE) {
data?.getParcelableExtra<Node>(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY)?.let { changedNode ->
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE)
addNode(changedNode)
data?.getParcelableExtra<NodeId<UUID>>(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY)?.let { changedNodeId ->
// TODO if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE)
// addNode(changedNode)
if (resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE)
mAdapter?.notifyDataSetChanged()
} ?: Log.e(this.javaClass.name, "New node can be retrieve in Activity Result")

View File

@@ -40,6 +40,7 @@ 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.database.element.node.NodeId
import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.model.MainCredential
@@ -48,6 +49,7 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.*
import java.util.*
abstract class LockingActivity : SpecialModeActivity(),
PasswordEncodingDialogFragment.Listener,
@@ -256,14 +258,14 @@ abstract class LockingActivity : SpecialModeActivity(),
updateDatabaseGroup(oldGroup, updateGroup, !mReadOnly && mAutoSaveEnable)
}
fun restoreEntryHistory(mainEntry: Entry,
entryHistoryPosition: Int,) {
restoreDatabaseEntryHistory(mainEntry, entryHistoryPosition, !mReadOnly && mAutoSaveEnable)
fun restoreEntryHistory(mainEntryId: NodeId<UUID>,
entryHistoryPosition: Int) {
restoreDatabaseEntryHistory(mainEntryId, entryHistoryPosition, !mReadOnly && mAutoSaveEnable)
}
fun deleteEntryHistory(mainEntry: Entry,
entryHistoryPosition: Int,) {
deleteDatabaseEntryHistory(mainEntry, entryHistoryPosition, !mReadOnly && mAutoSaveEnable)
fun deleteEntryHistory(mainEntryId: NodeId<UUID>,
entryHistoryPosition: Int) {
deleteDatabaseEntryHistory(mainEntryId, entryHistoryPosition, !mReadOnly && mAutoSaveEnable)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

View File

@@ -11,9 +11,11 @@ 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.database.element.node.NodeId
import com.kunzisoft.keepass.model.MainCredential
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
import java.util.*
abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
@@ -186,16 +188,16 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
mDatabaseTaskProvider?.startDatabaseUpdateGroup(oldGroup, groupToUpdate, save)
}
fun restoreDatabaseEntryHistory(mainEntry: Entry,
fun restoreDatabaseEntryHistory(mainEntryId: NodeId<UUID>,
entryHistoryPosition: Int,
save: Boolean) {
mDatabaseTaskProvider?.startDatabaseRestoreEntryHistory(mainEntry, entryHistoryPosition, save)
mDatabaseTaskProvider?.startDatabaseRestoreEntryHistory(mainEntryId, entryHistoryPosition, save)
}
fun deleteDatabaseEntryHistory(mainEntry: Entry,
fun deleteDatabaseEntryHistory(mainEntryId: NodeId<UUID>,
entryHistoryPosition: Int,
save: Boolean) {
mDatabaseTaskProvider?.startDatabaseDeleteEntryHistory(mainEntry, entryHistoryPosition, save)
mDatabaseTaskProvider?.startDatabaseDeleteEntryHistory(mainEntryId, entryHistoryPosition, save)
}
override fun onResume() {

View File

@@ -447,22 +447,22 @@ class DatabaseTaskProvider(private val activity: FragmentActivity) {
-----------------
*/
fun startDatabaseRestoreEntryHistory(mainEntry: Entry,
fun startDatabaseRestoreEntryHistory(mainEntryId: NodeId<UUID>,
entryHistoryPosition: Int,
save: Boolean) {
start(Bundle().apply {
putParcelable(DatabaseTaskNotificationService.ENTRY_ID_KEY, mainEntry.nodeId)
putParcelable(DatabaseTaskNotificationService.ENTRY_ID_KEY, mainEntryId)
putInt(DatabaseTaskNotificationService.ENTRY_HISTORY_POSITION_KEY, entryHistoryPosition)
putBoolean(DatabaseTaskNotificationService.SAVE_DATABASE_KEY, save)
}
, ACTION_DATABASE_RESTORE_ENTRY_HISTORY)
}
fun startDatabaseDeleteEntryHistory(mainEntry: Entry,
fun startDatabaseDeleteEntryHistory(mainEntryId: NodeId<UUID>,
entryHistoryPosition: Int,
save: Boolean) {
start(Bundle().apply {
putParcelable(DatabaseTaskNotificationService.ENTRY_ID_KEY, mainEntry.nodeId)
putParcelable(DatabaseTaskNotificationService.ENTRY_ID_KEY, mainEntryId)
putInt(DatabaseTaskNotificationService.ENTRY_HISTORY_POSITION_KEY, entryHistoryPosition)
putBoolean(DatabaseTaskNotificationService.SAVE_DATABASE_KEY, save)
}

View File

@@ -1,3 +1,22 @@
/*
* Copyright 2021 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.viewmodels
import androidx.lifecycle.LiveData
@@ -6,7 +25,6 @@ import androidx.lifecycle.ViewModel
import com.kunzisoft.keepass.app.database.IOActionTask
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.node.NodeId
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.element.template.Template
@@ -19,20 +37,22 @@ import java.util.*
class EntryViewModel: ViewModel() {
private var mDatabase: Database? = null
private var mEntryTemplate: Template? = null
private var mEntry: Entry? = null
private var mLastEntryVersion: Entry? = null
private var mHistoryPosition: Int = -1
val template : LiveData<Template> get() = _template
private val _template = MutableLiveData<Template>()
val mainEntryId : LiveData<NodeId<UUID>?> get() = _mainEntryId
private val _mainEntryId = MutableLiveData<NodeId<UUID>?>()
val historyPosition : LiveData<Int> get() = _historyPosition
private val _historyPosition = MutableLiveData<Int>()
val url : LiveData<String?> get() = _url
private val _url = MutableLiveData<String?>()
val entryInfo : LiveData<EntryInfo> get() = _entryInfo
private val _entryInfo = MutableLiveData<EntryInfo>()
val entryIsHistory : LiveData<Boolean> get() = _entryIsHistory
private val _entryIsHistory = MutableLiveData<Boolean>()
val entryHistory : LiveData<List<EntryInfo>> get() = _entryHistory
private val _entryHistory = MutableLiveData<List<EntryInfo>>()
@@ -55,25 +75,30 @@ class EntryViewModel: ViewModel() {
if (entryId != null) {
IOActionTask(
{
mDatabase?.getEntryById(entryId)
},
{ mainEntry ->
// Manage current version and history
mLastEntryVersion = mDatabase?.getEntryById(entryId)
_mainEntryId.value = mainEntry?.nodeId
_historyPosition.value = historyPosition
mEntry = if (historyPosition > -1) {
mLastEntryVersion?.getHistory()?.get(historyPosition)
val currentEntry = if (historyPosition > -1) {
mainEntry?.getHistory()?.get(historyPosition)
} else {
mLastEntryVersion
mainEntry
}
_url.value = currentEntry?.url
mEntryTemplate = mEntry?.let {
IOActionTask(
{
val entryTemplate = currentEntry?.let {
mDatabase?.getTemplate(it)
} ?: Template.STANDARD
mHistoryPosition = historyPosition
// To simplify template field visibility
mEntry?.let { entry ->
// Add mLastEntryVersion to check the parent and define the template state
mDatabase?.decodeEntryWithTemplateConfiguration(entry, mLastEntryVersion)
currentEntry?.let { entry ->
// Add mainEntry to check the parent and define the template state
mDatabase?.decodeEntryWithTemplateConfiguration(entry, mainEntry)
?.let {
// To update current modification time
it.touch(modified = false, touchParents = false)
@@ -84,7 +109,7 @@ class EntryViewModel: ViewModel() {
}
EntryInfoHistory(
mEntryTemplate ?: Template.STANDARD,
entryTemplate,
it.getEntryInfo(mDatabase),
entryInfoHistory
)
@@ -95,41 +120,17 @@ class EntryViewModel: ViewModel() {
if (entryInfoHistory != null) {
_template.value = entryInfoHistory.template
_entryInfo.value = entryInfoHistory.entryInfo
_entryIsHistory.value = mHistoryPosition != -1
_entryHistory.value = entryInfoHistory.entryHistory
}
}
).execute()
} else {
mEntryTemplate = null
mEntry = null
mLastEntryVersion = null
mHistoryPosition = -1
}
).execute()
}
}
fun updateEntry() {
loadEntry(mEntry?.nodeId, mHistoryPosition)
}
// TODO Remove
fun getEntry(): Entry? {
return mEntry
}
// TODO Remove
fun getMainEntry(): Entry? {
return mLastEntryVersion
}
// TODO Remove
fun getEntryHistoryPosition(): Int {
return mHistoryPosition
}
// TODO Remove
fun getEntryIsHistory(): Boolean {
return entryIsHistory.value ?: false
loadEntry(_mainEntryId.value, _historyPosition.value ?: -1)
}
fun onOtpElementUpdated(optElement: OtpElement?) {