Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@
## 2024-05-18 - Optimize Regex pattern detection in DictionaryFacilitatorImpl
**Learning:** `DictionaryFacilitatorImpl.isRegexPattern` used chained `String.contains()` and `String.startsWith()` calls, which internally execute full loops over the string (or delegate to regex). Replacing these chained calls with a single manual O(N) iteration reduces overhead and prevents repeatedly traversing the string.
**Action:** Replace chained string detection methods (`contains`, `startsWith`, `endsWith`) with a single manual loop over the string's indices when checking multiple characters in performance hot paths.

## 2024-05-18 - Cache Drawables in RecyclerView Adapters
**Learning:** `ClipboardAdapter` was allocating new `GradientDrawable` and `RippleDrawable` instances inside `onBindViewHolder` hot-paths (`HeaderViewHolder.bind` and `ClipViewHolder.setContent`). Since these methods are called frequently during scrolling, creating UI objects repeatedly causes unnecessary garbage collection pressure and scrolling jank.
**Action:** Always initialize and cache static UI components like backgrounds and drawables in the `ViewHolder`'s `init` block rather than recreating them during `onBindViewHolder`.
Original file line number Diff line number Diff line change
Expand Up @@ -242,26 +242,30 @@ class ClipboardAdapter(
}

inner class HeaderViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) {
fun bind(header: ClipboardDisplayItem.Header) {
init {
textView.apply {
typeface = itemTypeFace
setTextColor(itemTextColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, itemTextSize)
background = createCardBackground(this)
clipToOutline = true

setOnClickListener {
isPinnedFolded = !isPinnedFolded
refresh()
}
}
}

fun bind(header: ClipboardDisplayItem.Header) {
textView.apply {
text = buildString {
append(if (header.isFolded) "â–¶ " else "â–¼ ")
append(context.getString(R.string.clipboard_pinned))
append(" (")
append(header.count)
append(")")
}

setOnClickListener {
isPinnedFolded = !isPinnedFolded
refresh()
}
}
}
}
Expand Down Expand Up @@ -289,6 +293,15 @@ class ClipboardAdapter(
}
selectIconView = view.findViewById(R.id.clipboard_entry_select_icon)
selectedOverlay = view.findViewById(R.id.clipboard_entry_selected_overlay)
selectedOverlay?.background = GradientDrawable().apply {
val colors = Settings.getValues().mColors
val accentColor = colors.get(ColorType.ACTION_KEY_BACKGROUND)
val radiusDp = Settings.getValues().mKeyBorderRadius.takeIf { it >= 0f } ?: 8f
val radiusPx = radiusDp * view.resources.displayMetrics.density
shape = GradientDrawable.RECTANGLE
cornerRadius = radiusPx
setColor(ColorUtils.setAlphaComponent(accentColor, 0x26))
}
pinnedIconView = view.findViewById<ImageView>(R.id.clipboard_entry_pinned_icon).apply {
visibility = View.GONE
if (pinnedIconResId != 0) {
Expand Down Expand Up @@ -325,15 +338,6 @@ class ClipboardAdapter(
selectIconView.alpha = 1.0f
colors.setColor(selectIconView, ColorType.ACTION_KEY_BACKGROUND)
selectedOverlay?.visibility = View.VISIBLE
val accentColor = colors.get(ColorType.ACTION_KEY_BACKGROUND)
val radiusDp = Settings.getValues().mKeyBorderRadius.takeIf { it >= 0f } ?: 8f
val radiusPx = radiusDp * itemView.resources.displayMetrics.density
val overlayDrawable = GradientDrawable().apply {
shape = GradientDrawable.RECTANGLE
cornerRadius = radiusPx
setColor(ColorUtils.setAlphaComponent(accentColor, 0x26))
}
selectedOverlay?.background = overlayDrawable
} else {
selectIconView.setImageResource(R.drawable.ic_check_circle_outline)
selectIconView.alpha = 0.5f
Expand Down
Loading