mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Show OTP Token in entry list
This commit is contained in:
@@ -26,6 +26,7 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -148,6 +149,7 @@ class NodeAdapter (private val context: Context,
|
||||
if (oldItem is Entry && newItem is Entry) {
|
||||
typeContentTheSame = oldItem.getVisualTitle() == newItem.getVisualTitle()
|
||||
&& oldItem.username == newItem.username
|
||||
&& oldItem.getOtpElement() == newItem.getOtpElement()
|
||||
&& oldItem.containsAttachment() == newItem.containsAttachment()
|
||||
} else if (oldItem is Group && newItem is Group) {
|
||||
typeContentTheSame = oldItem.numberOfChildEntries == newItem.numberOfChildEntries
|
||||
@@ -357,6 +359,25 @@ class NodeAdapter (private val context: Context,
|
||||
}
|
||||
}
|
||||
|
||||
val otpElement = entry.getOtpElement()
|
||||
holder.otpContainer?.removeCallbacks(holder.otpRunnable)
|
||||
holder.otpRunnable = null
|
||||
if (otpElement != null && otpElement.token.isNotEmpty()) {
|
||||
holder.otpProgress?.apply {
|
||||
max = otpElement.period
|
||||
progress = otpElement.secondsRemaining
|
||||
}
|
||||
holder.otpToken?.text = otpElement.token
|
||||
holder.otpRunnable = Runnable {
|
||||
holder.otpProgress?.progress = otpElement.secondsRemaining
|
||||
holder.otpToken?.text = otpElement.token
|
||||
holder.otpContainer?.postDelayed(holder.otpRunnable, 200)
|
||||
}
|
||||
holder.otpContainer?.post(holder.otpRunnable)
|
||||
holder.otpContainer?.visibility = View.VISIBLE
|
||||
} else {
|
||||
holder.otpContainer?.visibility = View.GONE
|
||||
}
|
||||
holder.attachmentIcon?.visibility =
|
||||
if (entry.containsAttachment()) View.VISIBLE else View.GONE
|
||||
|
||||
@@ -413,6 +434,10 @@ class NodeAdapter (private val context: Context,
|
||||
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)
|
||||
var otpContainer: ViewGroup? = itemView.findViewById(R.id.node_otp_container)
|
||||
var otpProgress: ProgressBar? = itemView.findViewById(R.id.node_otp_progress)
|
||||
var otpToken: TextView? = itemView.findViewById(R.id.node_otp_token)
|
||||
var otpRunnable: Runnable? = null
|
||||
var numberChildren: TextView? = itemView.findViewById(R.id.node_child_numbers)
|
||||
var attachmentIcon: ImageView? = itemView.findViewById(R.id.node_attachment_icon)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class OtpModel() : Parcelable {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as OtpElement
|
||||
other as OtpModel
|
||||
|
||||
if (type != other.type) return false
|
||||
// Token type is important only if it's a TOTP
|
||||
|
||||
@@ -185,6 +185,19 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) {
|
||||
return secondsRemaining == otpModel.period
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is OtpElement) return false
|
||||
|
||||
if (otpModel != other.otpModel) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return otpModel.hashCode()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MIN_HOTP_COUNTER = 0
|
||||
const val MAX_HOTP_COUNTER = Long.MAX_VALUE
|
||||
|
||||
5
app/src/main/res/color/entry_info_color.xml
Normal file
5
app/src/main/res/color/entry_info_color.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_selected="true" android:color="@color/white"/>
|
||||
<item android:color="?attr/colorAccent"/>
|
||||
</selector>
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromDegrees="270"
|
||||
android:toDegrees="270">
|
||||
<shape
|
||||
android:shape="ring"
|
||||
android:innerRadiusRatio="2.5"
|
||||
android:thickness="2dp"
|
||||
android:useLevel="true">
|
||||
<solid android:color="?attr/colorAccent" />
|
||||
</shape>
|
||||
</rotate>
|
||||
@@ -7,6 +7,6 @@
|
||||
android:innerRadiusRatio="2.5"
|
||||
android:thickness="2dp"
|
||||
android:useLevel="true">
|
||||
<solid android:color="@color/orange" />
|
||||
<solid android:color="@color/entry_info_color" />
|
||||
</shape>
|
||||
</rotate>
|
||||
@@ -25,15 +25,20 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.Selectable.Item">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:minHeight="56dp"
|
||||
android:maxHeight="72dp"
|
||||
app:layout_constraintWidth_percent="@dimen/content_percent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:background="?android:attr/selectableItemBackground" >
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/node_icon"
|
||||
android:layout_width="32dp"
|
||||
@@ -44,67 +49,116 @@
|
||||
android:layout_marginStart="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginRight="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginEnd="@dimen/image_list_margin_vertical"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/ic_blank_32dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/node_container_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:layout_marginLeft="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginStart="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginRight="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginEnd="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginLeft="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/node_icon"
|
||||
app:layout_constraintLeft_toRightOf="@+id/node_icon"
|
||||
app:layout_constraintEnd_toStartOf="@+id/node_attachment_icon"
|
||||
app:layout_constraintRight_toLeftOf="@+id/node_attachment_icon">
|
||||
app:layout_constraintEnd_toStartOf="@+id/node_options"
|
||||
app:layout_constraintRight_toLeftOf="@+id/node_options">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/node_text"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.Title"
|
||||
android:layout_width="wrap_content"
|
||||
tools:text="Node Title"
|
||||
android:maxLines="2"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.Title" />
|
||||
android:maxLines="2"
|
||||
tools:text="Node Title" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/node_subtext"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.SubTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-4dp"
|
||||
tools:text="Node SubTitle"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.SubTitle" />
|
||||
tools:text="Node SubTitle" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/node_meta"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.Meta"
|
||||
android:layout_width="wrap_content"
|
||||
tools:text="7543A7EAB2EA7CFD1394F1615EBEB08C"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.Meta" />
|
||||
tools:text="7543A7EAB2EA7CFD1394F1615EBEB08C" />
|
||||
</LinearLayout>
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/node_attachment_icon"
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/node_options"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginStart="@dimen/image_list_margin_vertical"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:src="@drawable/ic_attach_file_white_24dp"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.Icon"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/node_otp_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:layout_marginRight="18dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/node_attachment_icon"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/node_otp_token"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.Info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
tools:text="5136" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/node_otp_progress"
|
||||
style="@style/KeepassDXStyle.ProgressBar.Circle.NoBackground"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:max="100"
|
||||
android:progress="60" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/node_attachment_icon"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Entry.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:src="@drawable/ic_attach_file_white_24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/node_otp_container" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -25,12 +25,16 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.Selectable.Item">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:minHeight="56dp"
|
||||
android:maxHeight="72dp"
|
||||
app:layout_constraintWidth_percent="@dimen/content_percent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:background="?android:attr/selectableItemBackground" >
|
||||
@@ -66,14 +70,14 @@
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@+id/node_icon"
|
||||
android:layout_toRightOf="@+id/node_icon"
|
||||
android:layout_toStartOf="@+id/node_image_identifier"
|
||||
android:layout_toLeftOf="@+id/node_image_identifier"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="4dp">
|
||||
android:layout_toEndOf="@+id/node_icon"
|
||||
android:layout_toRightOf="@+id/node_icon"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/node_text"
|
||||
@@ -84,25 +88,27 @@
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="2"
|
||||
tools:text="Node Title" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/node_subtext"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Group.SubTitle"
|
||||
android:visibility="gone"
|
||||
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
|
||||
android:id="@+id/node_meta"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Group.Meta"
|
||||
android:layout_width="wrap_content"
|
||||
tools:text="7543A7EAB2EA7CFD1394F1615EBEB08C"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
style="@style/KeepassDXStyle.TextAppearance.Group.Meta" />
|
||||
tools:text="7543A7EAB2EA7CFD1394F1615EBEB08C" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
|
||||
@@ -354,6 +354,7 @@
|
||||
<style name="KeepassDXStyle.TextAppearance.Entry.Title" parent="KeepassDXStyle.TextAppearance">
|
||||
<item name="android:textColor">@color/entry_title_color</item>
|
||||
<item name="android:tint">@color/entry_title_color</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.Entry.SubTitle" parent="KeepassDXStyle.TextAppearance.Small">
|
||||
@@ -365,6 +366,12 @@
|
||||
<item name="android:tint">@color/entry_title_color</item>
|
||||
<item name="android:textSize">11sp</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.Entry.Info" parent="KeepassDXStyle.TextAppearance.Small">
|
||||
<item name="android:textColor">@color/entry_info_color</item>
|
||||
<item name="android:tint">@color/entry_info_color</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.TextAppearance.Entry.Icon" parent="KeepassDXStyle.TextAppearance.Small">
|
||||
<item name="tint">@color/entry_subtitle_color</item>
|
||||
</style>
|
||||
@@ -475,6 +482,10 @@
|
||||
</style>
|
||||
|
||||
<!-- Progress bar -->
|
||||
<style name="KeepassDXStyle.ProgressBar.Circle.NoBackground" parent="Widget.AppCompat.ProgressBar.Horizontal">
|
||||
<item name="android:progressDrawable">@drawable/foreground_progress_circle</item>
|
||||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
<style name="KeepassDXStyle.ProgressBar.Circle" parent="Widget.AppCompat.ProgressBar.Horizontal">
|
||||
<item name="android:progressDrawable">@drawable/foreground_progress_circle</item>
|
||||
<item name="android:background">@drawable/background_progress_circle</item>
|
||||
|
||||
Reference in New Issue
Block a user