What changed, and why it matters
This commit is a user-interface performance tweak for Electrum's mobile-style QML history screen. It makes scrolling through transaction history smoother by reusing list row objects instead of constantly creating and destroying them, and by disabling a visual press effect that was causing flicker. There is no security-relevant change here.
No security action required. Treat as a normal UI performance improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies two QML files. In History.qml it enables reuseItems and sets a cacheBuffer on the ElListView, and temporarily toggles reuse off/on around model resets to flush the delegate pool. In HistoryItemDelegate.qml it adds ListView.onPooled/onReused handlers to reset local state and suppresses the Material background overlay. The only functional logic change is guarding fiatLabel.updateText() with delegate.pooled to avoid stale/expensive FX computations for off-screen pooled delegates. This is a rendering/performance optimization, not a security fix.
Changed components
electrum/gui/qml/components/History.qmlelectrum/gui/qml/components/controls/HistoryItemDelegate.qmlInspect captured patch +22 / −1
diff --git a/electrum/gui/qml/components/History.qml b/electrum/gui/qml/components/History.qml
index 7b2782b..ff41d8a 100644
--- a/electrum/gui/qml/components/History.qml
+++ b/electrum/gui/qml/components/History.qml
@@ -23,6 +23,10 @@ Pane {
width: parent.width
height: parent.height
boundsBehavior: Flickable.StopAtBounds
+ reuseItems: true
+ property bool dragScrolling: vdragscroll.drag.active
+ // keeps a buffer of delegate items outside the view, this makes normal scrolling (flicking) smoother
+ cacheBuffer: dragScrolling ? 0 : 1000
model: visualModel
@@ -147,14 +151,18 @@ Pane {
Connections {
target: Daemon
function onWalletLoaded() {
+ listview.reuseItems = false // flush the reuseItems delegate instance pool
listview.positionViewAtBeginning()
+ listview.reuseItems = true // re-enable delegate instance reuse
}
}
StackView.onVisibleChanged: {
// refresh model if History becomes visible and the model is dirty.
if (StackView.visible) {
+ listview.reuseItems = false
Daemon.currentWallet.historyModel.initModel(false)
+ listview.reuseItems = true
}
}
}
diff --git a/electrum/gui/qml/components/controls/HistoryItemDelegate.qml b/electrum/gui/qml/components/controls/HistoryItemDelegate.qml
index 3491a2a..769c7e4 100644
--- a/electrum/gui/qml/components/controls/HistoryItemDelegate.qml
+++ b/electrum/gui/qml/components/controls/HistoryItemDelegate.qml
@@ -13,6 +13,17 @@ Item {
// expose delegate model for scroll indicator
property var delegateModel: model
+ // reuseItems is enabled on the parent ListView. If a delegate item goes out of view it is not destroyed but
+ // stored in a pool and re-used when a new delegate is required.
+ property bool pooled: false
+ ListView.onPooled: pooled = true
+ ListView.onReused: {
+ // Variables that are not bound directly to the model have to be updated when the delegate instance is reused.
+ pooled = false
+ valueLabel.updateText()
+ fiatLabel.updateText()
+ }
+
ColumnLayout {
id: delegateLayout
width: parent.width
@@ -21,6 +32,8 @@ Item {
ItemDelegate {
Layout.fillWidth: true
Layout.preferredHeight: txinfo.height
+ // suppress Material press overlay, it flickers on rows during touch scroll
+ background: null
onClicked: {
if (model.lightning) {
@@ -103,7 +116,7 @@ Item {
color: constants.mutedForeground
function updateText() {
- if (!Daemon.fx.enabled) {
+ if (delegate.pooled || !Daemon.fx.enabled) {
text = ''
} else if (Daemon.fx.historicRates && model.timestamp) {
text = Daemon.fx.fiatValueHistoric(model.value, model.timestamp) + ' ' + Daemon.fx.fiatCurrency
Why this scored 14/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.