Select entry colors

This commit is contained in:
J-Jamet 2022-01-12 14:19:04 +01:00
parent 6547f0ffad
commit d4818c5567
19 changed files with 593 additions and 54 deletions

View file

@ -74,6 +74,7 @@ import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.view.*
import com.kunzisoft.keepass.viewmodels.ColorPickerViewModel
import com.kunzisoft.keepass.viewmodels.EntryEditViewModel
import org.joda.time.DateTime
import java.util.*
@ -103,6 +104,8 @@ class EntryEditActivity : DatabaseLockActivity(),
private var mEntryLoaded: Boolean = false
private var mTemplatesSelectorAdapter: TemplatesSelectorAdapter? = null
private val mColorPickerViewModel: ColorPickerViewModel by viewModels()
private var mAllowCustomFields = false
private var mAllowOTP = false
@ -243,6 +246,14 @@ class EntryEditActivity : DatabaseLockActivity(),
IconPickerActivity.launch(this@EntryEditActivity, iconImage, mIconSelectionActivityResultLauncher)
}
mEntryEditViewModel.requestColorSelection.observe(this) { color ->
ColorPickerDialogFragment().show(supportFragmentManager, "ColorPickerFragment")
}
mColorPickerViewModel.colorPicked.observe(this) { color ->
mEntryEditViewModel.selectColor(color)
}
mEntryEditViewModel.requestDateTimeSelection.observe(this) { dateInstant ->
if (dateInstant.type == DateInstant.Type.TIME) {
// Launch the time picker

View file

@ -0,0 +1,73 @@
package com.kunzisoft.keepass.activities.dialogs
import android.app.Dialog
import android.graphics.Color
import android.os.Bundle
import android.widget.CompoundButton
import androidx.annotation.ColorInt
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
import com.kunzisoft.androidclearchroma.view.ChromaColorView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.viewmodels.ColorPickerViewModel
class ColorPickerDialogFragment : DatabaseDialogFragment() {
private val mColorPickerViewModel: ColorPickerViewModel by activityViewModels()
private lateinit var enableSwitchView: CompoundButton
private lateinit var chromaColorView: ChromaColorView
private var mDefaultColor = Color.WHITE
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
val root = activity.layoutInflater.inflate(R.layout.fragment_color_picker, null)
enableSwitchView = root.findViewById(R.id.switch_element)
chromaColorView = root.findViewById(R.id.chroma_color_view)
var activated = false
arguments?.apply {
if (containsKey(ARG_INITIAL_COLOR)) {
mDefaultColor = getInt(ARG_INITIAL_COLOR)
}
if (containsKey(ARG_ACTIVATED)) {
activated = getBoolean(ARG_ACTIVATED)
}
}
enableSwitchView.isChecked = activated
val builder = AlertDialog.Builder(activity)
builder.setView(root)
.setPositiveButton(android.R.string.ok) { _, _ ->
val color: Int? = if (enableSwitchView.isChecked)
chromaColorView.currentColor
else
null
mColorPickerViewModel.pickColor(color)
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
// Do nothing
}
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
companion object {
private const val ARG_INITIAL_COLOR = "ARG_INITIAL_COLOR"
private const val ARG_ACTIVATED = "ARG_ACTIVATED"
fun newInstance(
@ColorInt initialColor: Int?,
): ColorPickerDialogFragment {
val colorPickerDialogFragment = ColorPickerDialogFragment()
val args = Bundle()
args.putInt(ARG_INITIAL_COLOR, initialColor ?: Color.WHITE)
args.putBoolean(ARG_ACTIVATED, initialColor != null)
return colorPickerDialogFragment
}
}
}

View file

@ -99,6 +99,12 @@ class EntryEditFragment: DatabaseFragment() {
setOnIconClickListener {
mEntryEditViewModel.requestIconSelection(templateView.getIcon())
}
setOnBackgroundColorClickListener {
mEntryEditViewModel.requestBackgroundColorSelection(templateView.getBackgroundColor())
}
setOnForegroundColorClickListener {
mEntryEditViewModel.requestForegroundColorSelection(templateView.getForegroundColor())
}
setOnCustomEditionActionClickListener { field ->
mEntryEditViewModel.requestCustomFieldEdition(field)
}
@ -147,6 +153,14 @@ class EntryEditFragment: DatabaseFragment() {
templateView.setIcon(iconImage)
}
mEntryEditViewModel.onBackgroundColorSelected.observe(this) { color ->
templateView.setBackgroundColor(color)
}
mEntryEditViewModel.onForegroundColorSelected.observe(this) { color ->
templateView.setForegroundColor(color)
}
mEntryEditViewModel.onPasswordSelected.observe(viewLifecycleOwner) { passwordField ->
templateView.setPasswordField(passwordField)
}

View file

@ -21,6 +21,7 @@ package com.kunzisoft.keepass.adapters
import android.content.Context
import android.graphics.Color
import android.graphics.PorterDuff
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
@ -31,6 +32,7 @@ import android.widget.TextView
import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SortedList
import androidx.recyclerview.widget.SortedListAdapterCallback
@ -39,7 +41,9 @@ 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.node.*
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeVersionedInterface
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.otp.OtpType
@ -377,6 +381,25 @@ class NodesAdapter (private val context: Context,
val entry = subNode as Entry
database.startManageEntry(entry)
// Assign colors
val backgroundColor = entry.backgroundColor
if (backgroundColor != null) {
holder.backgroundView?.setColorFilter(backgroundColor, PorterDuff.Mode.SRC_ATOP)
holder.backgroundView?.isVisible = true
} else {
holder.backgroundView?.isVisible = false
}
val foregroundColor = entry.foregroundColor
if (foregroundColor != null) {
holder.foregroundView?.setColorFilter(foregroundColor, PorterDuff.Mode.SRC_ATOP)
holder.icon.apply {
database.iconDrawableFactory.assignDatabaseIcon(this, subNode.icon, foregroundColor)
}
holder.foregroundView?.isVisible = true
} else {
holder.foregroundView?.isVisible = false
}
holder.text.text = entry.getVisualTitle()
// Add subText with username
holder.subText?.apply {
@ -510,6 +533,8 @@ class NodesAdapter (private val context: Context,
var container: View = itemView.findViewById(R.id.node_container)
var imageIdentifier: ImageView? = itemView.findViewById(R.id.node_image_identifier)
var icon: ImageView = itemView.findViewById(R.id.node_icon)
var backgroundView: ImageView? = itemView.findViewById(R.id.background_view)
var foregroundView: ImageView? = itemView.findViewById(R.id.foreground_view)
var text: TextView = itemView.findViewById(R.id.node_text)
var subText: TextView? = itemView.findViewById(R.id.node_subtext)
var meta: TextView = itemView.findViewById(R.id.node_meta)

View file

@ -19,8 +19,10 @@
*/
package com.kunzisoft.keepass.database.element
import android.graphics.Color
import android.os.Parcel
import android.os.Parcelable
import com.kunzisoft.androidclearchroma.ChromaUtil
import com.kunzisoft.keepass.database.element.binary.AttachmentPool
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
import com.kunzisoft.keepass.database.element.database.DatabaseVersioned
@ -238,6 +240,42 @@ class Entry : Node, EntryVersionedInterface<Group> {
entryKDBX?.notes = value
}
var backgroundColor: Int?
get() {
var colorInt: Int? = null
entryKDBX?.backgroundColor?.let {
try {
colorInt = Color.parseColor(it)
} catch (e: Exception) {}
}
return colorInt
}
set(value) {
entryKDBX?.backgroundColor = if (value == null) {
""
} else {
ChromaUtil.getFormattedColorString(value, false)
}
}
var foregroundColor: Int?
get() {
var colorInt: Int? = null
entryKDBX?.foregroundColor?.let {
try {
colorInt = Color.parseColor(it)
} catch (e: Exception) {}
}
return colorInt
}
set(value) {
entryKDBX?.foregroundColor = if (value == null) {
""
} else {
ChromaUtil.getFormattedColorString(value, false)
}
}
private fun isTan(): Boolean {
return title == PMS_TAN_ENTRY && username.isNotEmpty()
}
@ -419,6 +457,8 @@ class Entry : Node, EntryVersionedInterface<Group> {
entryInfo.expiryTime = expiryTime
entryInfo.url = url
entryInfo.notes = notes
entryInfo.backgroundColor = backgroundColor
entryInfo.foregroundColor = foregroundColor
entryInfo.customFields = getExtraFields().toMutableList()
// Add otpElement to generate token
entryInfo.otpModel = getOtpElement()?.otpModel
@ -453,6 +493,8 @@ class Entry : Node, EntryVersionedInterface<Group> {
expiryTime = newEntryInfo.expiryTime
url = newEntryInfo.url
notes = newEntryInfo.notes
backgroundColor = newEntryInfo.backgroundColor
foregroundColor = newEntryInfo.foregroundColor
addExtraFields(newEntryInfo.customFields)
database?.attachmentPool?.let { binaryPool ->
newEntryInfo.attachments.forEach { attachment ->

View file

@ -40,6 +40,8 @@ class EntryInfo : NodeInfo {
var password: String = ""
var url: String = ""
var notes: String = ""
var backgroundColor: Int? = null
var foregroundColor: Int? = null
var customFields: MutableList<Field> = mutableListOf()
var attachments: MutableList<Attachment> = mutableListOf()
var otpModel: OtpModel? = null
@ -53,6 +55,10 @@ class EntryInfo : NodeInfo {
password = parcel.readString() ?: password
url = parcel.readString() ?: url
notes = parcel.readString() ?: notes
val readBgColor = parcel.readInt()
backgroundColor = if (readBgColor == -1) null else readBgColor
val readFgColor = parcel.readInt()
foregroundColor = if (readFgColor == -1) null else readFgColor
parcel.readList(customFields, Field::class.java.classLoader)
parcel.readList(attachments, Attachment::class.java.classLoader)
otpModel = parcel.readParcelable(OtpModel::class.java.classLoader) ?: otpModel
@ -70,6 +76,8 @@ class EntryInfo : NodeInfo {
parcel.writeString(password)
parcel.writeString(url)
parcel.writeString(notes)
parcel.writeInt(backgroundColor ?: -1)
parcel.writeInt(foregroundColor ?: -1)
parcel.writeList(customFields)
parcel.writeList(attachments)
parcel.writeParcelable(otpModel, flags)
@ -196,6 +204,8 @@ class EntryInfo : NodeInfo {
if (password != other.password) return false
if (url != other.url) return false
if (notes != other.notes) return false
if (backgroundColor != other.backgroundColor) return false
if (foregroundColor != other.foregroundColor) return false
if (customFields != other.customFields) return false
if (attachments != other.attachments) return false
if (otpModel != other.otpModel) return false
@ -211,6 +221,8 @@ class EntryInfo : NodeInfo {
result = 31 * result + password.hashCode()
result = 31 * result + url.hashCode()
result = 31 * result + notes.hashCode()
result = 31 * result + backgroundColor.hashCode()
result = 31 * result + foregroundColor.hashCode()
result = 31 * result + customFields.hashCode()
result = 31 * result + attachments.hashCode()
result = 31 * result + (otpModel?.hashCode() ?: 0)

View file

@ -46,6 +46,8 @@ abstract class TemplateAbstractView<
protected var headerContainerView: ViewGroup
protected var entryIconView: ImageView
protected var backgroundColorButton: ImageView
protected var foregroundColorButton: ImageView
private var titleContainerView: ViewGroup
protected var templateContainerView: ViewGroup
private var customFieldsContainerView: SectionView
@ -57,6 +59,8 @@ abstract class TemplateAbstractView<
headerContainerView = findViewById(R.id.template_header_container)
entryIconView = findViewById(R.id.template_icon_button)
backgroundColorButton = findViewById(R.id.template_background_color_button)
foregroundColorButton = findViewById(R.id.template_foreground_color_button)
titleContainerView = findViewById(R.id.template_title_container)
templateContainerView = findViewById(R.id.template_fields_container)
// To fix card view margin below Marshmallow

View file

@ -54,6 +54,30 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
populateIconMethod?.invoke(entryIconView, iconImage)
}
fun setOnBackgroundColorClickListener(onClickListener: OnClickListener) {
backgroundColorButton.setOnClickListener(onClickListener)
}
fun getBackgroundColor(): Int? {
return mEntryInfo?.backgroundColor
}
fun setBackgroundColor(color: Int?) {
mEntryInfo?.backgroundColor = color
}
fun setOnForegroundColorClickListener(onClickListener: OnClickListener) {
foregroundColorButton.setOnClickListener(onClickListener)
}
fun getForegroundColor(): Int? {
return mEntryInfo?.foregroundColor
}
fun setForegroundColor(color: Int?) {
mEntryInfo?.foregroundColor = color
}
override fun preProcessTemplate() {
headerContainerView.isVisible = true
}

View file

@ -0,0 +1,15 @@
package com.kunzisoft.keepass.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class ColorPickerViewModel: ViewModel() {
val colorPicked : LiveData<Int?> get() = _colorPicked
private val _colorPicked = MutableLiveData<Int?>()
fun pickColor(color: Int?) {
_colorPicked.value = color
}
}

View file

@ -14,6 +14,14 @@ abstract class NodeEditViewModel : ViewModel() {
val onIconSelected : LiveData<IconImage> get() = _onIconSelected
private val _onIconSelected = SingleLiveEvent<IconImage>()
private var mColorRequest: ColorRequest = ColorRequest.BACKGROUND
val requestColorSelection : LiveData<Int?> get() = _requestColorSelection
private val _requestColorSelection = SingleLiveEvent<Int?>()
val onBackgroundColorSelected : LiveData<Int?> get() = _onBackgroundColorSelected
private val _onBackgroundColorSelected = SingleLiveEvent<Int?>()
val onForegroundColorSelected : LiveData<Int?> get() = _onForegroundColorSelected
private val _onForegroundColorSelected = SingleLiveEvent<Int?>()
val requestDateTimeSelection : LiveData<DateInstant> get() = _requestDateTimeSelection
private val _requestDateTimeSelection = SingleLiveEvent<DateInstant>()
val onDateSelected : LiveData<DataDate> get() = _onDateSelected
@ -29,6 +37,23 @@ abstract class NodeEditViewModel : ViewModel() {
_onIconSelected.value = iconImage
}
fun requestBackgroundColorSelection(initialColor: Int?) {
mColorRequest = ColorRequest.BACKGROUND
_requestColorSelection.value = initialColor
}
fun requestForegroundColorSelection(initialColor: Int?) {
mColorRequest = ColorRequest.FOREGROUND
_requestColorSelection.value = initialColor
}
fun selectColor(color: Int?) {
when (mColorRequest) {
ColorRequest.BACKGROUND -> _onBackgroundColorSelected.value = color
ColorRequest.FOREGROUND -> _onForegroundColorSelected.value = color
}
}
fun requestDateTimeSelection(dateInstant: DateInstant) {
_requestDateTimeSelection.value = dateInstant
}
@ -40,4 +65,8 @@ abstract class NodeEditViewModel : ViewModel() {
fun selectTime(hours: Int, minutes: Int) {
_onTimeSelected.value = DataTime(hours, minutes)
}
private enum class ColorRequest {
BACKGROUND, FOREGROUND
}
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<path
android:fillColor="#ffffff"
android:strokeWidth="0.99630105"
android:pathData="M 10,4 C 10,4 3.4004241,12.16731 4.0449219,16 4.4765841,18.566843 7.4158222,21 10,21 12.584196,21 15.523434,18.566843 15.955078,16 16.599576,12.16731 10,4 10,4 Z m 4,0 c 0,0 -0.59708,0.7527282 -1.386719,1.8476562 0.462543,0.6601114 0.953468,1.3798579 1.455078,2.1855469 0.803823,1.2911023 1.594188,2.7131219 2.15625,4.1015629 0.562116,1.388441 0.935799,2.740544 0.71875,4.03125 -0.268817,1.598597 -1.257809,3.011777 -2.517578,4.064453 -0.31833,0.265996 -0.657402,0.509805 -1.009765,0.726562 C 13.611687,20.98319 13.807101,21 14,21 16.584196,21 19.523434,18.566843 19.955078,16 20.599576,12.16731 14,4 14,4 Z m -4,2.5 c 0,0 0.497912,0.6283173 1.144531,1.53125 C 9.4508061,10.655343 7.697485,13.933867 8.0449219,16 8.262611,17.29447 9.126046,18.542028 10.253906,19.470703 10.169439,19.477241 10.083657,19.5 10,19.5 8.0238755,19.5 5.7754103,17.638661 5.4453125,15.675781 4.9524592,12.744903 10,6.5 10,6.5 Z" />
</group>
</vector>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<path
android:fillColor="#ffffff"
android:strokeWidth="0.99630105"
android:pathData="M 10,4 C 10,4 3.4004241,12.16731 4.0449219,16 4.4765841,18.566843 7.4158222,21 10,21 12.584196,21 15.523434,18.566843 15.955078,16 16.599576,12.16731 10,4 10,4 Z m 4,0 c 0,0 -0.597156,0.7527282 -1.386719,1.8476562 0.284669,0.4062608 0.575588,0.8441093 0.882813,1.3125 C 13.714676,6.8748215 14,6.5 14,6.5 c 0,0 5.04754,6.244903 4.554688,9.175781 -0.249068,1.481044 -1.591665,2.900275 -3.083985,3.509766 -0.31745,0.376905 -0.666337,0.728573 -1.044922,1.044922 -0.31833,0.265996 -0.657402,0.509805 -1.009765,0.726562 C 13.61168,20.98319 13.807101,21 14,21 16.584196,21 19.523434,18.566843 19.955078,16 20.599576,12.16731 14,4 14,4 Z" />
</group>
</vector>

View file

@ -51,7 +51,7 @@
android:src="@drawable/background_rounded_square"
android:layout_marginRight="6dp"
android:layout_marginEnd="6dp"
android:contentDescription="@string/database"/>
android:contentDescription="@string/content_description_database_color"/>
<TextView
android:id="@+id/database_name"
android:layout_width="wrap_content"

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 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/>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/edit"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAutofill="noExcludeDescendants"
tools:targetApi="o">
<com.kunzisoft.androidclearchroma.view.ChromaColorView
android:id="@+id/chroma_color_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chromaInitialColor="@color/white"
app:chromaColorMode="RGB"
app:chromaIndicatorMode="HEX"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_element"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="@string/enable"
android:background="@drawable/background_button_small"
android:textColor="?attr/textColorInverse"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:minHeight="48dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -38,6 +38,20 @@
app:layout_constraintEnd_toEndOf="parent"
android:background="?android:attr/selectableItemBackground" >
<ImageView
android:id="@+id/background_view"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_margin="4dp"
android:layout_gravity="center"
android:contentDescription="@string/content_description_entry_background_color"
android:src="@drawable/background_rounded_square"
app:layout_constraintBottom_toBottomOf="@+id/node_icon"
app:layout_constraintEnd_toEndOf="@+id/node_icon"
app:layout_constraintStart_toStartOf="@+id/node_icon"
app:layout_constraintTop_toTopOf="@+id/node_icon"
app:tint="@color/white" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/node_icon"
android:layout_width="32dp"
@ -57,41 +71,18 @@
app:layout_constraintLeft_toLeftOf="parent" />
<ImageView
android:id="@+id/background_color"
android:layout_width="11dp"
android:layout_height="11dp"
android:src="@drawable/background_rounded_square"
app:tint="@color/blue"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:id="@+id/foreground_view"
android:layout_width="9dp"
android:layout_height="9dp"
android:layout_marginStart="14dp"
android:layout_marginLeft="14dp"
android:layout_marginBottom="24dp"
android:layout_gravity="center"
android:elevation="6dp"
tools:ignore="UnusedAttribute"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
<ImageView
android:id="@+id/foreground_color"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/background_rounded_square"
android:layout_marginLeft="18dp"
android:layout_marginStart="18dp"
android:layout_marginRight="18dp"
android:layout_marginEnd="18dp"
android:layout_marginBottom="24dp"
android:layout_gravity="center"
android:elevation="8dp"
tools:ignore="UnusedAttribute"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
android:contentDescription="@string/content_description_entry_foreground_color"
android:src="@drawable/background_rounded_square" />
<LinearLayout
android:id="@+id/node_container_info"

View file

@ -17,9 +17,9 @@
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:targetApi="o"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -29,30 +29,56 @@
android:id="@+id/template_header_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/cardViewStyle"
android:visibility="gone">
<LinearLayout
android:orientation="vertical"
style="?attr/cardViewStyle">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_view_padding">
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/card_view_padding">
<!-- Icon -->
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/template_icon_button"
<!-- Icon -->
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/template_icon_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:src="@drawable/ic_blank_32dp"
android:contentDescription="@string/content_description_entry_icon"
android:layout_gravity="center"/>
<!-- Title -->
<FrameLayout
android:id="@+id/template_title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:src="@drawable/ic_blank_32dp"
android:contentDescription="@string/content_description_entry_icon"
android:layout_gravity="center"/>
<!-- Title -->
<FrameLayout
android:id="@+id/template_title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
android:layout_gravity="end">
<ImageView
android:id="@+id/template_background_color_button"
android:layout_width="42dp"
android:layout_height="42dp"
android:padding="12dp"
android:src="@drawable/ic_color_background_white_24dp"
android:contentDescription="@string/content_description_entry_background_color"
style="@style/KeepassDXStyle.ImageButton.Simple" />
<ImageView
android:id="@+id/template_foreground_color_button"
android:layout_width="42dp"
android:layout_height="42dp"
android:padding="12dp"
android:src="@drawable/ic_color_foreground_white_24dp"
android:contentDescription="@string/content_description_entry_background_color"
style="@style/KeepassDXStyle.ImageButton.Simple" />
</LinearLayout>
</FrameLayout>
</androidx.cardview.widget.CardView>
<LinearLayout

View file

@ -58,6 +58,9 @@
<string name="content_description_keyfile_checkbox">Keyfile checkbox</string>
<string name="content_description_repeat_toggle_password_visibility">Repeat toggle password visibility</string>
<string name="content_description_entry_icon">Entry icon</string>
<string name="content_description_database_color">Database color</string>
<string name="content_description_entry_foreground_color">Entry foreground color</string>
<string name="content_description_entry_background_color">Entry background color</string>
<string name="validate">Validate</string>
<string name="discard_changes">Discard changes?</string>
<string name="discard">Discard</string>

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg4830"
version="1.1"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
inkscape:export-filename="/home/joker/Project/Scratcheck/TestExport.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="ic_color_background.svg">
<defs
id="defs4832" />
<sodipodi:namedview
id="base"
pagecolor="#acacac"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="22.627416"
inkscape:cx="10.190215"
inkscape:cy="15.444172"
inkscape:current-layer="g4770"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="1920"
inkscape:window-y="27"
inkscape:window-maximized="1">
<sodipodi:guide
position="0.99999471,22.999999"
orientation="22,0"
id="guide2987"
inkscape:locked="false" />
<sodipodi:guide
position="0.99999471,0.99999888"
orientation="0,22"
id="guide2989"
inkscape:locked="false" />
<sodipodi:guide
position="22.999995,0.99999888"
orientation="-22,0"
id="guide2991"
inkscape:locked="false" />
<sodipodi:guide
position="39,23"
orientation="0,-22"
id="guide2993"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid2989" />
</sodipodi:namedview>
<metadata
id="metadata4835">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-8)">
<g
id="g4770"
transform="matrix(1.7777778,0,0,1.7777778,-205.48441,-31.997877)">
<g
id="Layer_1"
transform="matrix(-0.00397893,0,0,0.00397893,125.58386,23.674135)" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99630105px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 10,4 C 10,4 3.4004241,12.16731 4.0449219,16 4.4765841,18.566843 7.4158222,21 10,21 12.584196,21 15.523434,18.566843 15.955078,16 16.599576,12.16731 10,4 10,4 Z m 4,0 c 0,0 -0.59708,0.7527282 -1.386719,1.8476562 0.462543,0.6601114 0.953468,1.3798579 1.455078,2.1855469 0.803823,1.2911023 1.594188,2.7131219 2.15625,4.1015629 0.562116,1.388441 0.935799,2.740544 0.71875,4.03125 -0.268817,1.598597 -1.257809,3.011777 -2.517578,4.064453 -0.31833,0.265996 -0.657402,0.509805 -1.009765,0.726562 C 13.611687,20.98319 13.807101,21 14,21 16.584196,21 19.523434,18.566843 19.955078,16 20.599576,12.16731 14,4 14,4 Z m -4,2.5 c 0,0 0.497912,0.6283173 1.144531,1.53125 C 9.4508061,10.655343 7.697485,13.933867 8.0449219,16 8.262611,17.29447 9.126046,18.542028 10.253906,19.470703 10.169439,19.477241 10.083657,19.5 10,19.5 8.0238755,19.5 5.7754103,17.638661 5.4453125,15.675781 4.9524592,12.744903 10,6.5 10,6.5 Z"
transform="matrix(0.56249999,0,0,0.56249999,115.58498,22.498806)"
id="path830"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg4830"
version="1.1"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
inkscape:export-filename="/home/joker/Project/Scratcheck/TestExport.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="ic_color_foreground.svg">
<defs
id="defs4832" />
<sodipodi:namedview
id="base"
pagecolor="#acacac"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="22.627416"
inkscape:cx="1.4839624"
inkscape:cy="15.444172"
inkscape:current-layer="g4770"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="1920"
inkscape:window-y="27"
inkscape:window-maximized="1">
<sodipodi:guide
position="0.99999471,22.999999"
orientation="22,0"
id="guide2987"
inkscape:locked="false" />
<sodipodi:guide
position="0.99999471,0.99999888"
orientation="0,22"
id="guide2989"
inkscape:locked="false" />
<sodipodi:guide
position="22.999995,0.99999888"
orientation="-22,0"
id="guide2991"
inkscape:locked="false" />
<sodipodi:guide
position="39,23"
orientation="0,-22"
id="guide2993"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid2989" />
</sodipodi:namedview>
<metadata
id="metadata4835">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-8)">
<g
id="g4770"
transform="matrix(1.7777778,0,0,1.7777778,-205.48441,-31.997877)">
<g
id="Layer_1"
transform="matrix(-0.00397893,0,0,0.00397893,125.58386,23.674135)" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99630105px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 10,4 C 10,4 3.4004241,12.16731 4.0449219,16 4.4765841,18.566843 7.4158222,21 10,21 12.584196,21 15.523434,18.566843 15.955078,16 16.599576,12.16731 10,4 10,4 Z m 4,0 c 0,0 -0.597156,0.7527282 -1.386719,1.8476562 0.284669,0.4062608 0.575588,0.8441093 0.882813,1.3125 C 13.714676,6.8748215 14,6.5 14,6.5 c 0,0 5.04754,6.244903 4.554688,9.175781 -0.249068,1.481044 -1.591665,2.900275 -3.083985,3.509766 -0.31745,0.376905 -0.666337,0.728573 -1.044922,1.044922 -0.31833,0.265996 -0.657402,0.509805 -1.009765,0.726562 C 13.61168,20.98319 13.807101,21 14,21 16.584196,21 19.523434,18.566843 19.955078,16 20.599576,12.16731 14,4 14,4 Z"
transform="matrix(0.56249999,0,0,0.56249999,115.58498,22.498806)"
id="path820"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB