mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add notes in groups #734
This commit is contained in:
@@ -6,6 +6,7 @@ KeePassDX(2.9.13)
|
||||
* Better UI #876
|
||||
* Fix themes and add Purple Dark #889
|
||||
* Allow OTP with many padding #585
|
||||
* Add notes in groups #734
|
||||
|
||||
KeePassDX(2.9.12)
|
||||
* Fix OTP token type #863
|
||||
|
||||
@@ -57,13 +57,13 @@ 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.SortNodeEnum
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
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.database.search.SearchHelper
|
||||
import com.kunzisoft.keepass.education.GroupActivityEducation
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.model.GroupInfo
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK
|
||||
@@ -750,7 +750,7 @@ class GroupActivity : LockingActivity(),
|
||||
when (node.type) {
|
||||
Type.GROUP -> {
|
||||
mOldGroupToUpdate = node as Group
|
||||
GroupEditDialogFragment.build(mOldGroupToUpdate!!)
|
||||
GroupEditDialogFragment.build(mOldGroupToUpdate!!.getGroupInfo())
|
||||
.show(supportFragmentManager,
|
||||
GroupEditDialogFragment.TAG_CREATE_GROUP)
|
||||
}
|
||||
@@ -1036,19 +1036,17 @@ class GroupActivity : LockingActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun approveEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction?,
|
||||
name: String?,
|
||||
icon: IconImage?) {
|
||||
override fun approveEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction,
|
||||
groupInfo: GroupInfo) {
|
||||
|
||||
if (name != null && name.isNotEmpty() && icon != null) {
|
||||
if (groupInfo.name.isNotEmpty()) {
|
||||
when (action) {
|
||||
GroupEditDialogFragment.EditGroupDialogAction.CREATION -> {
|
||||
// If group creation
|
||||
mCurrentGroup?.let { currentGroup ->
|
||||
// Build the group
|
||||
mDatabase?.createGroup()?.let { newGroup ->
|
||||
newGroup.title = name
|
||||
newGroup.icon = icon
|
||||
newGroup.setGroupInfo(groupInfo)
|
||||
// Not really needed here because added in runnable but safe
|
||||
newGroup.parent = currentGroup
|
||||
|
||||
@@ -1068,9 +1066,7 @@ class GroupActivity : LockingActivity(),
|
||||
// WARNING remove parent and children to keep memory
|
||||
removeParent()
|
||||
removeChildren()
|
||||
|
||||
title = name
|
||||
this.icon = icon // TODO custom icon #96
|
||||
this.setGroupInfo(groupInfo)
|
||||
}
|
||||
}
|
||||
// If group updated save it in the database
|
||||
@@ -1086,9 +1082,8 @@ class GroupActivity : LockingActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancelEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction?,
|
||||
name: String?,
|
||||
icon: IconImage?) {
|
||||
override fun cancelEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction,
|
||||
groupInfo: GroupInfo) {
|
||||
// Do nothing here
|
||||
}
|
||||
|
||||
|
||||
@@ -23,34 +23,35 @@ import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION
|
||||
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.Group
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.model.GroupInfo
|
||||
|
||||
class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconPickerListener {
|
||||
|
||||
private var mDatabase: Database? = null
|
||||
|
||||
private var editGroupListener: EditGroupListener? = null
|
||||
private var mEditGroupListener: EditGroupListener? = null
|
||||
|
||||
private var editGroupDialogAction: EditGroupDialogAction? = null
|
||||
private var nameGroup: String? = null
|
||||
private var iconGroup: IconImage? = null
|
||||
private var mEditGroupDialogAction = EditGroupDialogAction.NONE
|
||||
private var mGroupInfo = GroupInfo()
|
||||
|
||||
private var nameTextLayoutView: TextInputLayout? = null
|
||||
private var nameTextView: TextView? = null
|
||||
private var iconButtonView: ImageView? = null
|
||||
private var iconColor: Int = 0
|
||||
private var nameTextLayoutView: TextInputLayout? = null
|
||||
private var nameTextView: TextView? = null
|
||||
private var notesTextLayoutView: TextInputLayout? = null
|
||||
private var notesTextView: TextView? = null
|
||||
|
||||
enum class EditGroupDialogAction {
|
||||
CREATION, UPDATE, NONE;
|
||||
@@ -67,7 +68,7 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
// Verify that the host activity implements the callback interface
|
||||
try {
|
||||
// Instantiate the NoticeDialogListener so we can send events to the host
|
||||
editGroupListener = context as EditGroupListener
|
||||
mEditGroupListener = context as EditGroupListener
|
||||
} catch (e: ClassCastException) {
|
||||
// The activity doesn't implement the interface, throw exception
|
||||
throw ClassCastException(context.toString()
|
||||
@@ -76,16 +77,18 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
editGroupListener = null
|
||||
mEditGroupListener = null
|
||||
super.onDetach()
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
val root = activity.layoutInflater.inflate(R.layout.fragment_group_edit, null)
|
||||
iconButtonView = root?.findViewById(R.id.group_edit_icon_button)
|
||||
nameTextLayoutView = root?.findViewById(R.id.group_edit_name_container)
|
||||
nameTextView = root?.findViewById(R.id.group_edit_name)
|
||||
iconButtonView = root?.findViewById(R.id.group_edit_icon_button)
|
||||
notesTextLayoutView = root?.findViewById(R.id.group_edit_note_container)
|
||||
notesTextView = root?.findViewById(R.id.group_edit_note)
|
||||
|
||||
// Retrieve the textColor to tint the icon
|
||||
val ta = activity.theme.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
|
||||
@@ -94,43 +97,40 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
|
||||
// Init elements
|
||||
mDatabase = Database.getInstance()
|
||||
editGroupDialogAction = EditGroupDialogAction.NONE
|
||||
nameGroup = ""
|
||||
iconGroup = mDatabase?.iconFactory?.folderIcon
|
||||
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(KEY_ACTION_ID)
|
||||
&& savedInstanceState.containsKey(KEY_NAME)
|
||||
&& savedInstanceState.containsKey(KEY_ICON)) {
|
||||
editGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID))
|
||||
nameGroup = savedInstanceState.getString(KEY_NAME)
|
||||
iconGroup = savedInstanceState.getParcelable(KEY_ICON)
|
||||
|
||||
&& savedInstanceState.containsKey(KEY_GROUP_INFO)) {
|
||||
mEditGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID))
|
||||
mGroupInfo = savedInstanceState.getParcelable(KEY_GROUP_INFO) ?: mGroupInfo
|
||||
} else {
|
||||
arguments?.apply {
|
||||
if (containsKey(KEY_ACTION_ID))
|
||||
editGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(getInt(KEY_ACTION_ID))
|
||||
|
||||
if (containsKey(KEY_NAME) && containsKey(KEY_ICON)) {
|
||||
nameGroup = getString(KEY_NAME)
|
||||
iconGroup = getParcelable(KEY_ICON)
|
||||
mEditGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(getInt(KEY_ACTION_ID))
|
||||
if (containsKey(KEY_GROUP_INFO)) {
|
||||
mGroupInfo = getParcelable(KEY_GROUP_INFO) ?: mGroupInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate the name
|
||||
nameTextView?.text = nameGroup
|
||||
// populate the icon
|
||||
assignIconView()
|
||||
// populate the name
|
||||
nameTextView?.text = mGroupInfo.name
|
||||
// populate the note
|
||||
notesTextLayoutView?.visibility = if (mGroupInfo.notes == null) View.GONE else View.VISIBLE
|
||||
mGroupInfo.notes?.let {
|
||||
notesTextView?.text = it
|
||||
}
|
||||
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
builder.setView(root)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
editGroupListener?.cancelEditGroup(
|
||||
editGroupDialogAction,
|
||||
nameTextView?.text?.toString(),
|
||||
iconGroup)
|
||||
retrieveGroupInfo()
|
||||
mEditGroupListener?.cancelEditGroup(
|
||||
mEditGroupDialogAction,
|
||||
mGroupInfo)
|
||||
}
|
||||
|
||||
iconButtonView?.setOnClickListener { _ ->
|
||||
@@ -150,32 +150,40 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
if (d != null) {
|
||||
val positiveButton = d.getButton(Dialog.BUTTON_POSITIVE) as Button
|
||||
positiveButton.setOnClickListener {
|
||||
retrieveGroupInfo()
|
||||
if (isValid()) {
|
||||
editGroupListener?.approveEditGroup(
|
||||
editGroupDialogAction,
|
||||
nameTextView?.text?.toString(),
|
||||
iconGroup)
|
||||
mEditGroupListener?.approveEditGroup(
|
||||
mEditGroupDialogAction,
|
||||
mGroupInfo)
|
||||
d.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun retrieveGroupInfo() {
|
||||
mGroupInfo.name = nameTextView?.text?.toString() ?: ""
|
||||
// Only if there
|
||||
val newNotes = notesTextView?.text?.toString()
|
||||
if (newNotes != null && newNotes.isNotEmpty()) {
|
||||
mGroupInfo.notes = newNotes
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignIconView() {
|
||||
if (mDatabase?.drawFactory != null && iconGroup != null) {
|
||||
iconButtonView?.assignDatabaseIcon(mDatabase?.drawFactory!!, iconGroup!!, iconColor)
|
||||
if (mDatabase?.drawFactory != null) {
|
||||
iconButtonView?.assignDatabaseIcon(mDatabase?.drawFactory!!, mGroupInfo.icon, iconColor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun iconPicked(bundle: Bundle) {
|
||||
iconGroup = IconPickerDialogFragment.getIconStandardFromBundle(bundle)
|
||||
mGroupInfo.icon = IconPickerDialogFragment.getIconStandardFromBundle(bundle) ?: mGroupInfo.icon
|
||||
assignIconView()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putInt(KEY_ACTION_ID, editGroupDialogAction!!.ordinal)
|
||||
outState.putString(KEY_NAME, nameGroup)
|
||||
outState.putParcelable(KEY_ICON, iconGroup)
|
||||
outState.putInt(KEY_ACTION_ID, mEditGroupDialogAction.ordinal)
|
||||
outState.putParcelable(KEY_GROUP_INFO, mGroupInfo)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
@@ -188,17 +196,17 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
}
|
||||
|
||||
interface EditGroupListener {
|
||||
fun approveEditGroup(action: EditGroupDialogAction?, name: String?, icon: IconImage?)
|
||||
fun cancelEditGroup(action: EditGroupDialogAction?, name: String?, icon: IconImage?)
|
||||
fun approveEditGroup(action: EditGroupDialogAction,
|
||||
groupInfo: GroupInfo)
|
||||
fun cancelEditGroup(action: EditGroupDialogAction,
|
||||
groupInfo: GroupInfo)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG_CREATE_GROUP = "TAG_CREATE_GROUP"
|
||||
|
||||
const val KEY_NAME = "KEY_NAME"
|
||||
const val KEY_ICON = "KEY_ICON"
|
||||
const val KEY_ACTION_ID = "KEY_ACTION_ID"
|
||||
const val KEY_GROUP_INFO = "KEY_GROUP_INFO"
|
||||
|
||||
fun build(): GroupEditDialogFragment {
|
||||
val bundle = Bundle()
|
||||
@@ -208,11 +216,10 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
return fragment
|
||||
}
|
||||
|
||||
fun build(group: Group): GroupEditDialogFragment {
|
||||
fun build(groupInfo: GroupInfo): GroupEditDialogFragment {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_NAME, group.title)
|
||||
bundle.putParcelable(KEY_ICON, group.icon)
|
||||
bundle.putInt(KEY_ACTION_ID, UPDATE.ordinal)
|
||||
bundle.putParcelable(KEY_GROUP_INFO, groupInfo)
|
||||
val fragment = GroupEditDialogFragment()
|
||||
fragment.arguments = bundle
|
||||
return fragment
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||
import com.kunzisoft.keepass.database.element.node.*
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.GroupInfo
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
@@ -232,6 +233,14 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
|
||||
override val isCurrentlyExpires: Boolean
|
||||
get() = groupKDB?.isCurrentlyExpires ?: groupKDBX?.isCurrentlyExpires ?: false
|
||||
|
||||
var notes: String?
|
||||
get() = groupKDBX?.notes
|
||||
set(value) {
|
||||
value?.let {
|
||||
groupKDBX?.notes = it
|
||||
}
|
||||
}
|
||||
|
||||
override fun getChildGroups(): List<Group> {
|
||||
return groupKDB?.getChildGroups()?.map {
|
||||
Group(it)
|
||||
@@ -391,6 +400,26 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
|
||||
return groupKDBX?.containsCustomData() ?: false
|
||||
}
|
||||
|
||||
/*
|
||||
------------
|
||||
Converter
|
||||
------------
|
||||
*/
|
||||
|
||||
fun getGroupInfo(): GroupInfo {
|
||||
val groupInfo = GroupInfo()
|
||||
groupInfo.name = title
|
||||
groupInfo.icon = icon
|
||||
groupInfo.notes = notes
|
||||
return groupInfo
|
||||
}
|
||||
|
||||
fun setGroupInfo(groupInfo: GroupInfo) {
|
||||
title = groupInfo.name
|
||||
icon = groupInfo.icon
|
||||
notes = groupInfo.notes
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
39
app/src/main/java/com/kunzisoft/keepass/model/GroupInfo.kt
Normal file
39
app/src/main/java/com/kunzisoft/keepass/model/GroupInfo.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.kunzisoft.keepass.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||
|
||||
class GroupInfo() : Parcelable {
|
||||
|
||||
var name: String = ""
|
||||
var icon: IconImage = IconImageStandard()
|
||||
var notes: String? = null
|
||||
|
||||
constructor(parcel: Parcel) : this() {
|
||||
name = parcel.readString() ?: name
|
||||
icon = parcel.readParcelable(IconImage::class.java.classLoader) ?: icon
|
||||
notes = parcel.readString()
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(name)
|
||||
parcel.writeParcelable(icon, flags)
|
||||
parcel.writeString(notes)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<GroupInfo> {
|
||||
override fun createFromParcel(parcel: Parcel): GroupInfo {
|
||||
return GroupInfo(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<GroupInfo?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,5 +48,19 @@
|
||||
android:singleLine="true"
|
||||
android:hint="@string/hint_group_name"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/group_edit_note_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/group_edit_note"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:inputType="text"
|
||||
android:maxLines="5"
|
||||
android:hint="@string/entry_notes"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
* Scroll and better UI in entry edition screen #876
|
||||
* Better UI #876
|
||||
* Fix themes and add Purple Dark #889
|
||||
* Allow OTP with many padding #585
|
||||
* Allow OTP with many padding #585
|
||||
* Add notes in groups #734
|
||||
@@ -4,4 +4,5 @@
|
||||
* Défilement et amélioration de l'UI dans l'écran d'édition #876
|
||||
* Meilleure interface utilisateur #876
|
||||
* Correction des thèmes et ajout de Pourpre Sombre #889
|
||||
* Autoriser l'OTP avec de nombreux rembourrages #585
|
||||
* Autoriser l'OTP avec de nombreux rembourrages #585
|
||||
* Ajout des notes dans les groupes #734
|
||||
Reference in New Issue
Block a user