Compare commits

..

27 Commits

Author SHA1 Message Date
J-Jamet
b4f2a1eb89 Merge branch 'release/3.0.1' 2021-09-15 13:24:53 +02:00
J-Jamet
e9fc9cbc2a Capture cast exception 2021-09-15 12:21:44 +02:00
J-Jamet
b809180a1b Small changes 2021-09-15 11:25:15 +02:00
J-Jamet
ecc75df3a1 Fix search actions #1091 #1092 2021-09-15 11:16:32 +02:00
J-Jamet
d1b6863143 Update CHANGELOG 2021-09-15 10:36:41 +02:00
J-Jamet
faf27143aa Fix timeout reset #1107 2021-09-15 10:33:37 +02:00
J-Jamet
aee58a4475 Fix exception after group name change and save #1112 2021-09-15 09:48:48 +02:00
J-Jamet
c5e07f643f Fix Magikeyboard URL auto action #1100 2021-09-14 20:40:22 +02:00
J-Jamet
818f5820d5 Update CHANGELOG 2021-09-14 20:13:35 +02:00
J-Jamet
77c6e28876 Fix max lines #1073 2021-09-14 20:06:49 +02:00
J-Jamet
fb7f66012d Upgrade to 3.0.1 2021-09-14 19:35:30 +02:00
J-Jamet
0f7f7bbe6c Min height to 48dp 2021-09-14 19:30:50 +02:00
J-Jamet
8dedb8deb4 Fix text dimension 2021-09-14 19:10:48 +02:00
J-Jamet
d284db4d3c Merge tag '3.0.0' into develop
3.0.0
2021-09-07 18:43:40 +02:00
J-Jamet
82450c0ae8 Merge branch 'release/3.0.0' 2021-09-07 18:43:31 +02:00
J-Jamet
8dd6c33901 Fix add entry education hint with default templates 2021-09-07 14:00:02 +02:00
J-Jamet
f920d40db5 Fix autofill popup window application id #1046 2021-09-07 13:45:35 +02:00
J-Jamet
19be6c1acc Upgrade to 3.0.0 2021-09-07 13:17:34 +02:00
J-Jamet
7d9d8ad0e4 Manage magikeyboard in landscape 2021-09-07 13:09:24 +02:00
J-Jamet
85f8237d5f Merge branch 'fullscreen' of git://github.com/chenxiaolong/KeePassDX into chenxiaolong-fullscreen 2021-09-07 12:41:24 +02:00
J-Jamet
c542894734 Small change in progress dialog 2021-09-07 12:18:21 +02:00
J-Jamet
d348987077 Remove unused code 2021-09-07 11:21:28 +02:00
J-Jamet
3718610595 Copy OTP Token from list to provide suitable alternative to #553 2021-09-07 10:44:34 +02:00
J-Jamet
9c36ec0623 Fix datetime font size 2021-09-07 10:29:08 +02:00
J-Jamet
c6917b5d74 Update CHANGELOG 2021-09-07 10:16:38 +02:00
Andrew Gunnerson
4eaa179789 magikeyboard: Don't force full screen EditTexts on large screen devices
Per [1], Android defaults to showing EditTexts in full screen mode when
the device is in landscape orientation. This makes sense for phones,
but not so much for larger screen devices, like tablets.

This commit updates MagiKeyboard to not use full screen mode on large
screen devices. The condition for disabling full screen mode is the same
as in the AOSP keyboard and should match what other OEM keyboards do as
well.

[1] https://developer.android.com/reference/android/inputmethodservice/InputMethodService#fullscreen-mode
2021-09-06 13:01:56 -04:00
J-Jamet
9008cd4549 Remove max lines in TextFieldView #1073 #1076 2021-09-06 12:18:17 +02:00
26 changed files with 219 additions and 104 deletions

View File

@@ -1,3 +1,12 @@
KeePassDX(3.0.1)
* Fix text size and smallest margin #1085
* Fix number of lines during an edition #1073
* Fix Magikeyboard URL auto action #1100
* Fix exception after group name change and save #1112
* Fix timeout reset #1107
* Fix search actions #1091 #1092
* Small changes #1106 #1085
KeePassDX(3.0.0) KeePassDX(3.0.0)
* Add / Manage dynamic templates #191 * Add / Manage dynamic templates #191
* Manually select RecycleBin group and Templates group #191 * Manually select RecycleBin group and Templates group #191
@@ -5,7 +14,7 @@ KeePassDX(3.0.0)
* Fix timeout in dialogs #716 * Fix timeout in dialogs #716
* Check URI permissions #626 * Check URI permissions #626
* Better autofill implementation #943 #946 #984 #1070 (Thx @uduerholz) * Better autofill implementation #943 #946 #984 #1070 (Thx @uduerholz)
* Improvements #680 #1035 #1043 #942 #1021 #1027 * Improvements #680 #1035 #1043 #942 #1021 #1027 #1046 #1082 #1083 (Thx @chenxiaolong)
KeePassDX(2.10.5) KeePassDX(2.10.5)
* Increase the saving speed of database #1028 * Increase the saving speed of database #1028

View File

@@ -11,8 +11,8 @@ android {
applicationId "com.kunzisoft.keepass" applicationId "com.kunzisoft.keepass"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 30 targetSdkVersion 30
versionCode = 86 versionCode = 88
versionName = "3.0.0_beta03" versionName = "3.0.1"
multiDexEnabled true multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests" testApplicationId = "com.kunzisoft.keepass.tests"

View File

@@ -653,6 +653,8 @@ class GroupActivity : DatabaseLockActivity(),
Log.e(TAG, "Node can't be cast in Entry") Log.e(TAG, "Node can't be cast in Entry")
} }
} }
reloadGroupIfSearch()
} }
private fun entrySelectedForSave(database: Database, entry: Entry, searchInfo: SearchInfo) { private fun entrySelectedForSave(database: Database, entry: Entry, searchInfo: SearchInfo) {
@@ -738,6 +740,12 @@ class GroupActivity : DatabaseLockActivity(),
actionNodeMode?.finish() actionNodeMode?.finish()
} }
private fun reloadGroupIfSearch() {
if (Intent.ACTION_SEARCH == intent.action) {
reloadCurrentGroup()
}
}
override fun onNodeSelected( override fun onNodeSelected(
database: Database, database: Database,
nodes: List<Node> nodes: List<Node>
@@ -793,6 +801,7 @@ class GroupActivity : DatabaseLockActivity(),
(node as Entry).nodeId (node as Entry).nodeId
) )
} }
reloadGroupIfSearch()
return true return true
} }
@@ -847,6 +856,7 @@ class GroupActivity : DatabaseLockActivity(),
): Boolean { ): Boolean {
deleteNodes(nodes) deleteNodes(nodes)
finishNodeAction() finishNodeAction()
reloadGroupIfSearch()
return true return true
} }
@@ -934,9 +944,7 @@ class GroupActivity : DatabaseLockActivity(),
) { ) {
// If no node, show education to add new one // If no node, show education to add new one
val addNodeButtonEducationPerformed = mGroupFragment != null val addNodeButtonEducationPerformed = actionNodeMode == null
&& mGroupFragment!!.isEmpty
&& actionNodeMode == null
&& addNodeButtonView?.addButtonView != null && addNodeButtonView?.addButtonView != null
&& addNodeButtonView!!.isEnable && addNodeButtonView!!.isEnable
&& groupActivityEducation.checkAndPerformedAddNodeButtonEducation( && groupActivityEducation.checkAndPerformedAddNodeButtonEducation(
@@ -1095,7 +1103,7 @@ class GroupActivity : DatabaseLockActivity(),
try { try {
mGroupViewModel.loadGroup(mDatabase, mCurrentGroupState) mGroupViewModel.loadGroup(mDatabase, mCurrentGroupState)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Unable to rebuild the list after deletion", e) Log.e(TAG, "Unable to rebuild the group", e)
} }
} }

View File

@@ -74,9 +74,6 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
private var mRecycleBinEnable: Boolean = false private var mRecycleBinEnable: Boolean = false
private var mRecycleBin: Group? = null private var mRecycleBin: Group? = null
val isEmpty: Boolean
get() = mAdapter == null || mAdapter?.itemCount?:0 <= 0
private var mRecycleViewScrollListener = object : RecyclerView.OnScrollListener() { private var mRecycleViewScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)

View File

@@ -28,6 +28,7 @@ import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@@ -41,9 +42,11 @@ 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.NodeVersionedInterface import com.kunzisoft.keepass.database.element.node.NodeVersionedInterface
import com.kunzisoft.keepass.database.element.node.Type 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.OtpElement
import com.kunzisoft.keepass.otp.OtpType import com.kunzisoft.keepass.otp.OtpType
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.view.setTextSize import com.kunzisoft.keepass.view.setTextSize
import com.kunzisoft.keepass.view.strikeOut import com.kunzisoft.keepass.view.strikeOut
import java.util.* import java.util.*
@@ -64,8 +67,10 @@ class NodeAdapter (private val context: Context,
private var mCalculateViewTypeTextSize = Array(2) { true } // number of view type private var mCalculateViewTypeTextSize = Array(2) { true } // number of view type
private var mTextSizeUnit: Int = TypedValue.COMPLEX_UNIT_PX private var mTextSizeUnit: Int = TypedValue.COMPLEX_UNIT_PX
private var mPrefSizeMultiplier: Float = 0F private var mPrefSizeMultiplier: Float = 0F
private var mSubtextDefaultDimension: Float = 0F private var mTextDefaultDimension: Float = 0F
private var mInfoTextDefaultDimension: Float = 0F private var mSubTextDefaultDimension: Float = 0F
private var mMetaTextDefaultDimension: Float = 0F
private var mOtpTokenTextDefaultDimension: Float = 0F
private var mNumberChildrenTextDefaultDimension: Float = 0F private var mNumberChildrenTextDefaultDimension: Float = 0F
private var mIconDefaultDimension: Float = 0F private var mIconDefaultDimension: Float = 0F
@@ -77,6 +82,7 @@ class NodeAdapter (private val context: Context,
private var mActionNodesList = LinkedList<Node>() private var mActionNodesList = LinkedList<Node>()
private var mNodeClickCallback: NodeClickCallback? = null private var mNodeClickCallback: NodeClickCallback? = null
private var mClipboardHelper = ClipboardHelper(context)
@ColorInt @ColorInt
private val mContentSelectionColor: Int private val mContentSelectionColor: Int
@@ -299,8 +305,10 @@ class NodeAdapter (private val context: Context,
mInflater.inflate(R.layout.item_list_nodes_entry, parent, false) mInflater.inflate(R.layout.item_list_nodes_entry, parent, false)
} }
val nodeViewHolder = NodeViewHolder(view) val nodeViewHolder = NodeViewHolder(view)
mInfoTextDefaultDimension = nodeViewHolder.text.textSize mTextDefaultDimension = nodeViewHolder.text.textSize
mSubtextDefaultDimension = nodeViewHolder.subText.textSize mSubTextDefaultDimension = nodeViewHolder.subText?.textSize ?: mSubTextDefaultDimension
mMetaTextDefaultDimension = nodeViewHolder.meta.textSize
mOtpTokenTextDefaultDimension = nodeViewHolder.otpToken?.textSize ?: mOtpTokenTextDefaultDimension
nodeViewHolder.numberChildren?.let { nodeViewHolder.numberChildren?.let {
mNumberChildrenTextDefaultDimension = it.textSize mNumberChildrenTextDefaultDimension = it.textSize
} }
@@ -311,7 +319,9 @@ class NodeAdapter (private val context: Context,
val subNode = mNodeSortedList.get(position) val subNode = mNodeSortedList.get(position)
// Node selection // Node selection
holder.container.isSelected = mActionNodesList.contains(subNode) holder.container.apply {
isSelected = mActionNodesList.contains(subNode)
}
// Assign image // Assign image
val iconColor = if (holder.container.isSelected) val iconColor = if (holder.container.isSelected)
@@ -333,19 +343,18 @@ class NodeAdapter (private val context: Context,
// Assign text // Assign text
holder.text.apply { holder.text.apply {
text = subNode.title text = subNode.title
setTextSize(mTextSizeUnit, mInfoTextDefaultDimension, mPrefSizeMultiplier) setTextSize(mTextSizeUnit, mTextDefaultDimension, mPrefSizeMultiplier)
strikeOut(subNode.isCurrentlyExpires) strikeOut(subNode.isCurrentlyExpires)
} }
// Add subText with username
holder.subText.apply {
text = ""
strikeOut(subNode.isCurrentlyExpires)
visibility = View.GONE
}
// Add meta text to show UUID // Add meta text to show UUID
holder.meta.apply { holder.meta.apply {
text = subNode.nodeId.toString() if (mShowUUID) {
visibility = if (mShowUUID) View.VISIBLE else View.GONE text = subNode.nodeId.toString()
setTextSize(mTextSizeUnit, mMetaTextDefaultDimension, mPrefSizeMultiplier)
visibility = View.VISIBLE
} else {
visibility = View.GONE
}
} }
// Specific elements for entry // Specific elements for entry
@@ -354,12 +363,16 @@ class NodeAdapter (private val context: Context,
database.startManageEntry(entry) database.startManageEntry(entry)
holder.text.text = entry.getVisualTitle() holder.text.text = entry.getVisualTitle()
holder.subText.apply { // Add subText with username
holder.subText?.apply {
val username = entry.username val username = entry.username
if (mShowUserNames && username.isNotEmpty()) { if (mShowUserNames && username.isNotEmpty()) {
visibility = View.VISIBLE visibility = View.VISIBLE
text = username text = username
setTextSize(mTextSizeUnit, mSubtextDefaultDimension, mPrefSizeMultiplier) setTextSize(mTextSizeUnit, mSubTextDefaultDimension, mPrefSizeMultiplier)
strikeOut(subNode.isCurrentlyExpires)
} else {
visibility = View.GONE
} }
} }
@@ -427,7 +440,21 @@ class NodeAdapter (private val context: Context,
} }
} }
} }
holder?.otpToken?.text = otpElement?.token holder?.otpToken?.apply {
text = otpElement?.token
setTextSize(mTextSizeUnit, mOtpTokenTextDefaultDimension, mPrefSizeMultiplier)
}
holder?.otpContainer?.setOnClickListener {
otpElement?.token?.let { token ->
Toast.makeText(
context,
context.getString(R.string.copy_field,
TemplateField.getLocalizedName(context, TemplateField.LABEL_TOKEN)),
Toast.LENGTH_LONG
).show()
mClipboardHelper.copyToClipboard(token)
}
}
} }
class OtpRunnable(val view: View?): Runnable { class OtpRunnable(val view: View?): Runnable {
@@ -468,7 +495,7 @@ class NodeAdapter (private val context: Context,
var imageIdentifier: ImageView? = itemView.findViewById(R.id.node_image_identifier) var imageIdentifier: ImageView? = itemView.findViewById(R.id.node_image_identifier)
var icon: ImageView = itemView.findViewById(R.id.node_icon) var icon: ImageView = itemView.findViewById(R.id.node_icon)
var text: TextView = itemView.findViewById(R.id.node_text) var text: TextView = itemView.findViewById(R.id.node_text)
var subText: TextView = itemView.findViewById(R.id.node_subtext) var subText: TextView? = itemView.findViewById(R.id.node_subtext)
var meta: TextView = itemView.findViewById(R.id.node_meta) var meta: TextView = itemView.findViewById(R.id.node_meta)
var otpContainer: ViewGroup? = itemView.findViewById(R.id.node_otp_container) var otpContainer: ViewGroup? = itemView.findViewById(R.id.node_otp_container)
var otpProgress: ProgressBar? = itemView.findViewById(R.id.node_otp_progress) var otpProgress: ProgressBar? = itemView.findViewById(R.id.node_otp_progress)

View File

@@ -53,8 +53,10 @@ class StructureParser(private val structure: AssistStructure) {
applicationId = windowNode.title.toString().split("/")[0] applicationId = windowNode.title.toString().split("/")[0]
Log.d(TAG, "Autofill applicationId: $applicationId") Log.d(TAG, "Autofill applicationId: $applicationId")
if (parseViewNode(windowNode.rootViewNode)) if (applicationId?.contains("PopupWindow:") == false) {
break@mainLoop if (parseViewNode(windowNode.rootViewNode))
break@mainLoop
}
} }
// If not explicit username field found, add the field just before password field. // If not explicit username field found, add the field just before password field.
if (usernameId == null && passwordId != null && usernameIdCandidate != null) { if (usernameId == null && passwordId != null && usernameIdCandidate != null) {

View File

@@ -177,16 +177,20 @@ class Group : Node, GroupVersionedInterface<Group, Entry> {
fun addChildrenFrom(group: Group) { fun addChildrenFrom(group: Group) {
group.groupKDB?.getChildEntries()?.forEach { entryToAdd -> group.groupKDB?.getChildEntries()?.forEach { entryToAdd ->
groupKDB?.addChildEntry(entryToAdd) groupKDB?.addChildEntry(entryToAdd)
entryToAdd.parent = groupKDB
} }
group.groupKDB?.getChildGroups()?.forEach { groupToAdd -> group.groupKDB?.getChildGroups()?.forEach { groupToAdd ->
groupKDB?.addChildGroup(groupToAdd) groupKDB?.addChildGroup(groupToAdd)
groupToAdd.parent = groupKDB
} }
group.groupKDBX?.getChildEntries()?.forEach { entryToAdd -> group.groupKDBX?.getChildEntries()?.forEach { entryToAdd ->
groupKDBX?.addChildEntry(entryToAdd) groupKDBX?.addChildEntry(entryToAdd)
entryToAdd.parent = groupKDBX
} }
group.groupKDBX?.getChildGroups()?.forEach { groupToAdd -> group.groupKDBX?.getChildGroups()?.forEach { groupToAdd ->
groupKDBX?.addChildGroup(groupToAdd) groupKDBX?.addChildGroup(groupToAdd)
groupToAdd.parent = groupKDBX
} }
} }

View File

@@ -178,6 +178,11 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
assignKeyboardView() assignKeyboardView()
} }
override fun onEvaluateFullscreenMode(): Boolean {
return resources.getBoolean(R.bool.magikeyboard_allow_fullscreen_mode)
&& super.onEvaluateFullscreenMode()
}
private fun playVibration(keyCode: Int) { private fun playVibration(keyCode: Int) {
when (keyCode) { when (keyCode) {
Keyboard.KEYCODE_DELETE -> {} Keyboard.KEYCODE_DELETE -> {}
@@ -267,7 +272,7 @@ class MagikeyboardService : InputMethodService(), KeyboardView.OnKeyboardActionL
if (entryInfoKey != null) { if (entryInfoKey != null) {
currentInputConnection.commitText(entryInfoKey!!.url, 1) currentInputConnection.commitText(entryInfoKey!!.url, 1)
} }
actionTabAutomatically() actionGoAutomatically()
} }
KEY_FIELDS -> { KEY_FIELDS -> {
if (entryInfoKey != null) { if (entryInfoKey != null) {

View File

@@ -64,11 +64,13 @@ class DurationDialogFragmentCompat : InputPreferenceDialogFragmentCompat() {
private fun durationToDaysHoursMinutesSeconds(duration: Long) { private fun durationToDaysHoursMinutesSeconds(duration: Long) {
if (duration < 0) { if (duration < 0) {
mEnabled = false
mDays = 0 mDays = 0
mHours = 0 mHours = 0
mMinutes = 0 mMinutes = 0
mSeconds = 0 mSeconds = 0
} else { } else {
mEnabled = true
mDays = (duration / (24L * 60L * 60L * 1000L)).toInt() mDays = (duration / (24L * 60L * 60L * 1000L)).toInt()
val daysMilliseconds = mDays * 24L * 60L * 60L * 1000L val daysMilliseconds = mDays * 24L * 60L * 60L * 1000L
mHours = ((duration - daysMilliseconds) / (60L * 60L * 1000L)).toInt() mHours = ((duration - daysMilliseconds) / (60L * 60L * 1000L)).toInt()
@@ -125,10 +127,9 @@ class DurationDialogFragmentCompat : InputPreferenceDialogFragmentCompat() {
} }
} }
mEnabled = isSwitchActivated()
setSwitchAction({ isChecked -> setSwitchAction({ isChecked ->
mEnabled = isChecked mEnabled = isChecked
}, mDays + mHours + mMinutes + mSeconds > 0) }, mEnabled)
assignValuesInViews() assignValuesInViews()
} }

View File

@@ -46,8 +46,6 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
private var mDefault: DateInstant = DateInstant.NEVER_EXPIRES private var mDefault: DateInstant = DateInstant.NEVER_EXPIRES
var setOnDateClickListener: ((DateInstant) -> Unit)? = null
init { init {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater? val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
inflater?.inflate(R.layout.view_date_time, this) inflater?.inflate(R.layout.view_date_time, this)

View File

@@ -275,22 +275,26 @@ abstract class TemplateAbstractView<
templateAttribute: TemplateAttribute, templateAttribute: TemplateAttribute,
entryInfoValue: String, entryInfoValue: String,
showEmptyFields: Boolean) { showEmptyFields: Boolean) {
var fieldView: TEntryFieldView? = findViewWithTag(fieldTag) try {
if (!showEmptyFields && entryInfoValue.isEmpty()) { var fieldView: TEntryFieldView? = findViewWithTag(fieldTag)
fieldView?.isFieldVisible = false if (!showEmptyFields && entryInfoValue.isEmpty()) {
} else if (fieldView == null && entryInfoValue.isNotEmpty()) { fieldView?.isFieldVisible = false
// Add new not referenced view if standard field not in template } else if (fieldView == null && entryInfoValue.isNotEmpty()) {
fieldView = buildViewForNotReferencedField( // Add new not referenced view if standard field not in template
Field(templateAttribute.label, fieldView = buildViewForNotReferencedField(
ProtectedString(templateAttribute.protected, "")), Field(templateAttribute.label,
templateAttribute ProtectedString(templateAttribute.protected, "")),
) as? TEntryFieldView? templateAttribute
fieldView?.let { ) as? TEntryFieldView?
addNotReferencedView(it as View) fieldView?.let {
addNotReferencedView(it as View)
}
} }
fieldView?.value = entryInfoValue
fieldView?.applyFontVisibility(mFontInVisibility)
} catch(e: Exception) {
Log.e(TAG, "Unable to populate entry field view", e)
} }
fieldView?.value = entryInfoValue
fieldView?.applyFontVisibility(mFontInVisibility)
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@@ -299,22 +303,25 @@ abstract class TemplateAbstractView<
expires: Boolean, expires: Boolean,
expiryTime: DateInstant, expiryTime: DateInstant,
showEmptyFields: Boolean) { showEmptyFields: Boolean) {
try {
var fieldView: TDateTimeView? = findViewWithTag(fieldTag) var fieldView: TDateTimeView? = findViewWithTag(fieldTag)
if (!showEmptyFields && !expires) { if (!showEmptyFields && !expires) {
fieldView?.isFieldVisible = false fieldView?.isFieldVisible = false
} else if (fieldView == null && expires) { } else if (fieldView == null && expires) {
fieldView = buildViewForNotReferencedField( fieldView = buildViewForNotReferencedField(
Field(templateAttribute.label, Field(templateAttribute.label,
ProtectedString(templateAttribute.protected, "")), ProtectedString(templateAttribute.protected, "")),
templateAttribute templateAttribute
) as? TDateTimeView? ) as? TDateTimeView?
fieldView?.let { fieldView?.let {
addNotReferencedView(it as View) addNotReferencedView(it as View)
}
} }
fieldView?.activation = expires
fieldView?.dateTime = expiryTime
} catch(e: Exception) {
Log.e(TAG, "Unable to populate date time view", e)
} }
fieldView?.activation = expires
fieldView?.dateTime = expiryTime
} }
/** /**

View File

@@ -53,7 +53,6 @@ class TemplateView @JvmOverloads constructor(context: Context,
label = templateAttribute.alias label = templateAttribute.alias
?: TemplateField.getLocalizedName(context, field.name) ?: TemplateField.getLocalizedName(context, field.name)
setMaxChars(templateAttribute.options.getNumberChars()) setMaxChars(templateAttribute.options.getNumberChars())
setMaxLines(templateAttribute.options.getNumberLines())
// TODO Linkify // TODO Linkify
value = field.protectedValue.stringValue value = field.protectedValue.stringValue
// Here the value is often empty // Here the value is often empty

View File

@@ -187,6 +187,6 @@ class TextEditFieldView @JvmOverloads constructor(context: Context,
companion object { companion object {
const val MAX_CHARS_LIMIT = Integer.MAX_VALUE const val MAX_CHARS_LIMIT = Integer.MAX_VALUE
const val MAX_LINES_LIMIT = 40 const val MAX_LINES_LIMIT = Integer.MAX_VALUE
} }
} }

View File

@@ -214,18 +214,6 @@ class TextFieldView @JvmOverloads constructor(context: Context,
} }
} }
fun setMaxLines(numberLines: Int) {
when {
numberLines <= 0 -> {
valueView.maxLines = MAX_LINES_LIMIT
}
else -> {
val lines = if (numberLines > MAX_LINES_LIMIT) MAX_LINES_LIMIT else numberLines
valueView.maxLines = lines
}
}
}
fun setProtection(protection: Boolean, hiddenProtectedValue: Boolean = false) { fun setProtection(protection: Boolean, hiddenProtectedValue: Boolean = false) {
showButton.isVisible = protection showButton.isVisible = protection
showButton.isSelected = hiddenProtectedValue showButton.isSelected = hiddenProtectedValue
@@ -343,6 +331,5 @@ class TextFieldView @JvmOverloads constructor(context: Context,
companion object { companion object {
const val MAX_CHARS_LIMIT = Integer.MAX_VALUE const val MAX_CHARS_LIMIT = Integer.MAX_VALUE
const val MAX_LINES_LIMIT = 40
} }
} }

View File

@@ -33,6 +33,7 @@
android:layout_marginStart="20dp" android:layout_marginStart="20dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
style="@style/KeepassDXStyle.TextAppearance.Title" style="@style/KeepassDXStyle.TextAppearance.Title"
android:textStyle="bold"
android:textColor="?android:attr/textColor"/> android:textColor="?android:attr/textColor"/>
<TextView <TextView
@@ -62,7 +63,7 @@
app:indicatorColor="?attr/colorAccent" app:indicatorColor="?attr/colorAccent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="20dp"
android:indeterminate="true" android:indeterminate="true"
android:max="100"/> android:max="100"/>

View File

@@ -30,8 +30,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:minHeight="56dp" android:minHeight="48dp"
android:maxHeight="72dp"
app:layout_constraintWidth_percent="@dimen/content_percent" app:layout_constraintWidth_percent="@dimen/content_percent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
@@ -104,10 +103,12 @@
tools:text="7543A7EAB2EA7CFD1394F1615EBEB08C" /> tools:text="7543A7EAB2EA7CFD1394F1615EBEB08C" />
</LinearLayout> </LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:id="@+id/node_options" android:id="@+id/node_options"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="0dp" android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="end"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
android:layout_marginLeft="12dp" android:layout_marginLeft="12dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
@@ -118,9 +119,11 @@
android:id="@+id/node_otp_container" android:id="@+id/node_otp_container"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="16dp" android:layout_marginEnd="12dp"
android:layout_marginRight="16dp" android:layout_marginRight="12dp"
android:padding="4dp"
android:orientation="horizontal" android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/node_attachment_icon" app:layout_constraintBottom_toTopOf="@+id/node_attachment_icon"
app:layout_constraintEnd_toEndOf="parent"> app:layout_constraintEnd_toEndOf="parent">
@@ -162,7 +165,7 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/node_otp_container" /> app:layout_constraintTop_toBottomOf="@+id/node_otp_container" />
</androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -30,8 +30,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:minHeight="56dp" android:minHeight="48dp"
android:maxHeight="72dp"
app:layout_constraintWidth_percent="@dimen/content_percent" app:layout_constraintWidth_percent="@dimen/content_percent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
@@ -89,18 +88,6 @@
android:maxLines="2" android:maxLines="2"
tools:text="Node Title" /> tools:text="Node Title" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/node_subtext"
style="@style/KeepassDXStyle.TextAppearance.Group.SubTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dp"
android:gravity="center_vertical"
android:lines="1"
android:singleLine="true"
android:visibility="gone"
tools:text="Node SubTitle" />
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/node_meta" android:id="@+id/node_meta"
style="@style/KeepassDXStyle.TextAppearance.Group.Meta" style="@style/KeepassDXStyle.TextAppearance.Group.Meta"

View File

@@ -20,7 +20,7 @@
android:focusable="false" android:focusable="false"
android:cursorVisible="false" android:cursorVisible="false"
android:focusableInTouchMode="false" android:focusableInTouchMode="false"
style="@style/KeepassDXStyle.TextAppearance.Large" style="@style/KeepassDXStyle.TextAppearance.TextEntryItem"
tools:text="2020-03-04 05:00" /> tools:text="2020-03-04 05:00" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<resources>
<bool name="magikeyboard_allow_fullscreen_mode">true</bool>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<resources>
<bool name="magikeyboard_allow_fullscreen_mode">false</bool>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<resources>
<bool name="magikeyboard_allow_fullscreen_mode">false</bool>
</resources>

View File

@@ -367,7 +367,7 @@
<string name="clipboard_warning">If automatic deletion of clipboard fails, delete its history manually.</string> <string name="clipboard_warning">If automatic deletion of clipboard fails, delete its history manually.</string>
<string name="lock">Lock</string> <string name="lock">Lock</string>
<string name="lock_database_screen_off_title">Screen lock</string> <string name="lock_database_screen_off_title">Screen lock</string>
<string name="lock_database_screen_off_summary">Lock the database when the screen is off</string> <string name="lock_database_screen_off_summary">Lock the database after a few seconds once the screen is off</string>
<string name="lock_database_back_root_title">Press \'Back\' to lock</string> <string name="lock_database_back_root_title">Press \'Back\' to lock</string>
<string name="lock_database_back_root_summary">Lock the database when the user clicks the back button on the root screen</string> <string name="lock_database_back_root_summary">Lock the database when the user clicks the back button on the root screen</string>
<string name="lock_database_show_button_title">Show lock button</string> <string name="lock_database_show_button_title">Show lock button</string>

View File

@@ -4,4 +4,4 @@
* Fix timeout in dialogs #716 * Fix timeout in dialogs #716
* Check URI permissions #626 * Check URI permissions #626
* Better autofill implementation #943 #946 #984 #1070 (Thx @uduerholz) * Better autofill implementation #943 #946 #984 #1070 (Thx @uduerholz)
* Improvements #680 #1035 #1043 #942 #1021 #1027 * Improvements #680 #1035 #1043 #942 #1021 #1027 #1046 #1082 #1083 (Thx @chenxiaolong)

View File

@@ -0,0 +1,7 @@
* Fix text size and smallest margin #1085
* Fix number of lines during an edition #1073
* Fix Magikeyboard URL auto action #1100
* Fix exception after group name change and save #1112
* Fix timeout reset #1107
* Fix search actions #1091 #1092
* Small changes #1106 #1085

View File

@@ -4,4 +4,4 @@
* Correction du délai d'expiration dans les dialogues #716 * Correction du délai d'expiration dans les dialogues #716
* Vérification des permissions URI #626 * Vérification des permissions URI #626
* Meilleure implémentation du remplissage auto #943 #946 #984 #1070 (Thx @uduerholz) * Meilleure implémentation du remplissage auto #943 #946 #984 #1070 (Thx @uduerholz)
* Améliorations #680 #1035 #1043 #942 #1021 #1027 * Améliorations #680 #1035 #1043 #942 #1021 #1027 #1046 #1082 #1083 (Thx @chenxiaolong)

View File

@@ -0,0 +1,7 @@
* Correction de la taille de texte et plus petites marges #1085
* Correction du nombre de lignes d'édition #1073
* Correction de l'action auto de l'URL Magiclavier #1100
* Correction de l'exception après un changement de nom de groupe et sauvegarde #1112
* Correction de la réinitialisation du délai d'expiration #1107
* Correction des actions de recherche #1091 #1092
* Petits changements #1106 #1085