diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt index d293edb5a..dd7cc9b7a 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt @@ -41,10 +41,7 @@ import com.kunzisoft.keepass.activities.dialogs.* import com.kunzisoft.keepass.activities.dialogs.FileTooBigDialogFragment.Companion.MAX_WARNING_BINARY_FILE import com.kunzisoft.keepass.activities.helpers.SelectFileHelper import com.kunzisoft.keepass.activities.lock.LockingActivity -import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.DateInstant -import com.kunzisoft.keepass.database.element.Entry -import com.kunzisoft.keepass.database.element.Group +import com.kunzisoft.keepass.database.element.* import com.kunzisoft.keepass.database.element.icon.IconImage import com.kunzisoft.keepass.database.element.icon.IconImageStandard import com.kunzisoft.keepass.database.element.node.NodeId @@ -76,7 +73,8 @@ class EntryEditActivity : LockingActivity(), SetOTPDialogFragment.CreateOtpListener, DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener, - FileTooBigDialogFragment.ActionChooseListener { + FileTooBigDialogFragment.ActionChooseListener, + ReplaceFileDialogFragment.ActionChooseListener { private var mDatabase: Database? = null @@ -437,9 +435,22 @@ class EntryEditActivity : LockingActivity(), } } + override fun onValidateReplaceFile(attachmentToUploadUri: Uri?, entryAttachment: EntryAttachment?) { + if (attachmentToUploadUri != null && entryAttachment != null) { + mAttachmentFileBinderManager?.startUploadAttachment(attachmentToUploadUri, entryAttachment) + } + } + private fun buildNewAttachment(attachmentToUploadUri: Uri, fileName: String) { mDatabase?.buildNewAttachment(applicationContext.filesDir, fileName)?.let { entryAttachment -> - mAttachmentFileBinderManager?.startUploadAttachment(attachmentToUploadUri, entryAttachment) + // Ask to replace the current attachment + if ((mDatabase?.allowMultipleAttachments != true && entryEditContentsView?.containsAttachment() == true) || + entryEditContentsView?.containsAttachment(EntryAttachmentState(entryAttachment, StreamDirection.UPLOAD)) == true) { + ReplaceFileDialogFragment.build(attachmentToUploadUri, entryAttachment) + .show(supportFragmentManager, "replacementFileFragment") + } else { + mAttachmentFileBinderManager?.startUploadAttachment(attachmentToUploadUri, entryAttachment) + } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/ReplaceAttachmentDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/ReplaceAttachmentDialogFragment.kt new file mode 100644 index 000000000..06d039a04 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/ReplaceAttachmentDialogFragment.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2019 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 . + * + */ +package com.kunzisoft.keepass.activities.dialogs + +import android.app.Dialog +import android.content.Context +import android.net.Uri +import android.os.Bundle +import android.text.SpannableStringBuilder +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import com.kunzisoft.keepass.R +import com.kunzisoft.keepass.database.element.EntryAttachment + +/** + * Custom Dialog to confirm big file to upload + */ +class ReplaceFileDialogFragment : DialogFragment() { + + private var mActionChooseListener: ActionChooseListener? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + // Verify that the host activity implements the callback interface + try { + mActionChooseListener = context as ActionChooseListener + } catch (e: ClassCastException) { + throw ClassCastException(context.toString() + + " must implement " + ActionChooseListener::class.java.name) + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + activity?.let { activity -> + // Use the Builder class for convenient dialog construction + val builder = AlertDialog.Builder(activity) + builder.setMessage(SpannableStringBuilder().apply { + append(getString(R.string.warning_replace_file)) + append("\n\n") + append(getString(R.string.warning_sure_add_file)) + }) + builder.setPositiveButton(android.R.string.yes) { _, _ -> + mActionChooseListener?.onValidateReplaceFile( + arguments?.getParcelable(KEY_FILE_URI), + arguments?.getParcelable(KEY_ENTRY_ATTACHMENT)) + } + builder.setNegativeButton(android.R.string.no) { _, _ -> + dismiss() + } + // Create the AlertDialog object and return it + return builder.create() + } + return super.onCreateDialog(savedInstanceState) + } + + interface ActionChooseListener { + fun onValidateReplaceFile(attachmentToUploadUri: Uri?, entryAttachment: EntryAttachment?) + } + + companion object { + private const val KEY_FILE_URI = "KEY_FILE_URI" + private const val KEY_ENTRY_ATTACHMENT = "KEY_ENTRY_ATTACHMENT" + + fun build(attachmentToUploadUri: Uri, + entryAttachment: EntryAttachment): ReplaceFileDialogFragment { + val fragment = ReplaceFileDialogFragment() + fragment.arguments = Bundle().apply { + putParcelable(KEY_FILE_URI, attachmentToUploadUri) + putParcelable(KEY_ENTRY_ATTACHMENT, entryAttachment) + } + return fragment + } + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/AnimatedItemsAdapter.kt b/app/src/main/java/com/kunzisoft/keepass/adapters/AnimatedItemsAdapter.kt index a4deb31eb..d1fa9edc8 100644 --- a/app/src/main/java/com/kunzisoft/keepass/adapters/AnimatedItemsAdapter.kt +++ b/app/src/main/java/com/kunzisoft/keepass/adapters/AnimatedItemsAdapter.kt @@ -32,6 +32,14 @@ abstract class AnimatedItemsAdapter(val contex onListSizeChangedListener?.invoke(previousSize, itemsList.size) } + open fun isEmpty(): Boolean { + return itemsList.isEmpty() + } + + open fun contains(item: Item): Boolean { + return itemsList.contains(item) + } + open fun putItem(item: Item) { val previousSize = itemsList.size if (itemsList.contains(item)) { diff --git a/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt b/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt index ef585d882..1827e14af 100644 --- a/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt +++ b/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt @@ -294,6 +294,14 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context, } } + fun containsAttachment(): Boolean { + return !attachmentsAdapter.isEmpty() + } + + fun containsAttachment(attachment: EntryAttachmentState): Boolean { + return attachmentsAdapter.contains(attachment) + } + fun putAttachment(attachment: EntryAttachmentState) { attachmentsContainerView.visibility = View.VISIBLE attachmentsAdapter.putItem(attachment) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 02be54d4a..61a30a133 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -258,6 +258,7 @@ Continue without encryption key? Permanently delete selected nodes? A KeePass database is supposed to contain only small utility files (such as PGP key files).\n\nYour database may get very large and reduce performance with this upload. + Uploading this file will replace the existing one. Add the file anyway? Version %1$s Build %1$s