Highlight rows after collapsing logs

This commit is contained in:
ajp_anton
2026-07-27 21:57:32 +00:00
parent f97dad8fb2
commit 125ba99af9
@@ -1,5 +1,10 @@
package se.ajpanton.notificationlog package se.ajpanton.notificationlog
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.graphics.Color
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Paint import android.graphics.Paint
import android.os.Bundle import android.os.Bundle
@@ -26,6 +31,7 @@ import se.ajpanton.notificationlog.capture.NotificationCaptureService
import java.text.DateFormat import java.text.DateFormat
import java.util.Date import java.util.Date
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.core.content.ContextCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.doOnPreDraw import androidx.core.view.doOnPreDraw
@@ -124,10 +130,18 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
val contents = fieldValue(LogField.CONTENTS, row.entry, settings) val contents = fieldValue(LogField.CONTENTS, row.entry, settings)
val hasContents = LogField.CONTENTS in settings.visibleFields && !contents.isNullOrEmpty() val hasContents = LogField.CONTENTS in settings.visibleFields && !contents.isNullOrEmpty()
val toggleExpanded = { val toggleExpanded = {
val collapseAnchor = if (expanded) captureCollapseAnchor(this@apply) else null val collapsing = expanded
val collapseAnchor = if (collapsing) captureCollapseAnchor(this@apply) else null
if (!expandedIds.add(row.entry.id)) expandedIds.remove(row.entry.id) if (!expandedIds.add(row.entry.id)) expandedIds.remove(row.entry.id)
renderExpanded(row.entry.id in expandedIds) renderExpanded(row.entry.id in expandedIds)
collapseAnchor?.let(::restoreCollapseAnchor) if (collapsing) {
val highlight = { highlightCollapsedRow(this@apply) }
if (collapseAnchor != null) {
restoreCollapseAnchor(collapseAnchor, highlight)
} else {
this@apply.doOnPreDraw { highlight() }
}
}
Unit Unit
} }
val metadataCell = metadataCell(metadata, expanded, toggleExpanded, row.entry.id).apply { val metadataCell = metadataCell(metadata, expanded, toggleExpanded, row.entry.id).apply {
@@ -355,7 +369,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
} }
private fun restoreCollapseAnchor(anchor: CollapseAnchor) { private fun restoreCollapseAnchor(anchor: CollapseAnchor, afterRestore: () -> Unit) {
val currentBinding = binding ?: return val currentBinding = binding ?: return
val scroll = currentBinding.logScroll val scroll = currentBinding.logScroll
val rows = currentBinding.logRows val rows = currentBinding.logRows
@@ -368,6 +382,30 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
val maximum = (scroll.getChildAt(0).height - scroll.height).coerceAtLeast(0) val maximum = (scroll.getChildAt(0).height - scroll.height).coerceAtLeast(0)
scroll.scrollTo(0, target.coerceIn(0, maximum)) scroll.scrollTo(0, target.coerceIn(0, maximum))
afterRestore()
}
}
private fun highlightCollapsedRow(row: View) {
if (!row.isAttachedToWindow) return
val baseColor = ContextCompat.getColor(row.context, R.color.primary)
val startColor = Color.argb(
COLLAPSE_HIGHLIGHT_ALPHA,
Color.red(baseColor),
Color.green(baseColor),
Color.blue(baseColor),
)
val endColor = Color.argb(0, Color.red(baseColor), Color.green(baseColor), Color.blue(baseColor))
row.setBackgroundColor(startColor)
ValueAnimator.ofObject(ArgbEvaluator(), startColor, endColor).apply {
duration = COLLAPSE_HIGHLIGHT_DURATION_MILLIS
addUpdateListener { row.setBackgroundColor(it.animatedValue as Int) }
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
row.background = null
}
})
start()
} }
} }
@@ -406,5 +444,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
const val ROW_SEPARATOR_MARGIN_DP = 4 const val ROW_SEPARATOR_MARGIN_DP = 4
const val METADATA_INDENT_DP = 8 const val METADATA_INDENT_DP = 8
const val MAXIMUM_METADATA_COLUMN_FRACTION = 0.45f const val MAXIMUM_METADATA_COLUMN_FRACTION = 0.45f
const val COLLAPSE_HIGHLIGHT_ALPHA = 52
const val COLLAPSE_HIGHLIGHT_DURATION_MILLIS = 450L
} }
} }