Browse Source

add (today, yesterday, last week, last month, older) sections to history

patch-4
Sander van Grieken 3 years ago
parent
commit
5c7060fffb
  1. 217
      electrum/gui/qml/components/History.qml
  2. 38
      electrum/gui/qml/qetransactionlistmodel.py

217
electrum/gui/qml/components/History.qml

@ -2,6 +2,7 @@ import QtQuick 2.6
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.0
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0 import QtQuick.Controls.Material 2.0
import QtQml.Models 2.2
import org.electrum 1.0 import org.electrum 1.0
@ -15,99 +16,149 @@ Pane {
width: parent.width width: parent.width
height: parent.height height: parent.height
model: Daemon.currentWallet.historyModel model: visualModel
delegate: Item { section.property: 'section'
id: delegate section.criteria: ViewSection.FullString
section.delegate: RowLayout {
width: ListView.view.width width: ListView.view.width
height: delegateLayout.height required property string section
Label {
ColumnLayout { text: section == 'today'
id: delegateLayout ? qsTr('Today')
width: parent.width : section == 'yesterday'
spacing: 0 ? qsTr('Yesterday')
: section == 'lastweek'
Rectangle { ? qsTr('Last week')
visible: index > 0 : section == 'lastmonth'
Layout.fillWidth: true ? qsTr('Last month')
Layout.preferredHeight: constants.paddingSmall : qsTr('Older')
color: Qt.rgba(0,0,0,0.10) Layout.alignment: Qt.AlignHCenter
} Layout.topMargin: constants.paddingLarge
font.pixelSize: constants.fontSizeLarge
color: constants.mutedForeground
}
}
ItemDelegate { DelegateModel {
Layout.fillWidth: true id: visualModel
Layout.preferredHeight: txinfo.height model: Daemon.currentWallet.historyModel
GridLayout { groups: [
id: txinfo DelegateModelGroup { name: 'today'; includeByDefault: false },
columns: 3 DelegateModelGroup { name: 'yesterday'; includeByDefault: false },
DelegateModelGroup { name: 'lastweek'; includeByDefault: false },
x: constants.paddingSmall DelegateModelGroup { name: 'lastmonth'; includeByDefault: false },
width: delegate.width - 2*constants.paddingSmall DelegateModelGroup { name: 'older'; includeByDefault: false }
]
Item { Layout.columnSpan: 3; Layout.preferredWidth: 1; Layout.preferredHeight: 1}
Image { delegate: Item {
readonly property variant tx_icons : [ id: delegate
"../../../gui/icons/unconfirmed.png", width: ListView.view.width
"../../../gui/icons/clock1.png", height: delegateLayout.height
"../../../gui/icons/clock2.png",
"../../../gui/icons/clock3.png", ColumnLayout {
"../../../gui/icons/clock4.png", id: delegateLayout
"../../../gui/icons/clock5.png", width: parent.width
"../../../gui/icons/confirmed.png" spacing: 0
]
ItemDelegate {
Layout.preferredWidth: constants.iconSizeLarge Layout.fillWidth: true
Layout.preferredHeight: constants.iconSizeLarge Layout.preferredHeight: txinfo.height
Layout.alignment: Qt.AlignVCenter
Layout.rowSpan: 2 GridLayout {
source: tx_icons[Math.min(6,model.confirmations)] id: txinfo
columns: 3
x: constants.paddingSmall
width: delegate.width - 2*constants.paddingSmall
Item { Layout.columnSpan: 3; Layout.preferredWidth: 1; Layout.preferredHeight: 1}
Image {
readonly property variant tx_icons : [
"../../../gui/icons/unconfirmed.png",
"../../../gui/icons/clock1.png",
"../../../gui/icons/clock2.png",
"../../../gui/icons/clock3.png",
"../../../gui/icons/clock4.png",
"../../../gui/icons/clock5.png",
"../../../gui/icons/confirmed.png"
]
Layout.preferredWidth: constants.iconSizeLarge
Layout.preferredHeight: constants.iconSizeLarge
Layout.alignment: Qt.AlignVCenter
Layout.rowSpan: 2
source: tx_icons[Math.min(6,model.confirmations)]
}
Label {
font.pixelSize: constants.fontSizeLarge
Layout.fillWidth: true
text: model.label !== '' ? model.label : '<no label>'
color: model.label !== '' ? Material.accentColor : 'gray'
wrapMode: Text.Wrap
maximumLineCount: 2
elide: Text.ElideRight
}
Label {
id: valueLabel
font.family: FixedFont
font.pixelSize: constants.fontSizeMedium
Layout.alignment: Qt.AlignRight
text: Config.formatSats(model.bc_value)
font.bold: true
color: model.incoming ? constants.colorCredit : constants.colorDebit
}
Label {
font.pixelSize: constants.fontSizeSmall
text: model.date
}
Label {
font.pixelSize: constants.fontSizeXSmall
Layout.alignment: Qt.AlignRight
text: model.fee !== undefined ? 'fee: ' + model.fee : ''
}
Item { Layout.columnSpan: 3; Layout.preferredWidth: 1; Layout.preferredHeight: 1 }
} }
}
Label { Rectangle {
font.pixelSize: constants.fontSizeLarge visible: delegate.ListView.section == delegate.ListView.nextSection
Layout.fillWidth: true Layout.fillWidth: true
text: model.label !== '' ? model.label : '<no label>' Layout.preferredHeight: constants.paddingTiny
color: model.label !== '' ? Material.accentColor : 'gray' color: Qt.rgba(0,0,0,0.10)
wrapMode: Text.Wrap
maximumLineCount: 2
elide: Text.ElideRight
}
Label {
id: valueLabel
font.family: FixedFont
font.pixelSize: constants.fontSizeMedium
text: Config.formatSats(model.bc_value)
font.bold: true
color: model.incoming ? constants.colorCredit : constants.colorDebit
}
Label {
font.pixelSize: constants.fontSizeSmall
text: model.date
}
Label {
font.pixelSize: constants.fontSizeXSmall
Layout.alignment: Qt.AlignRight
text: model.fee !== undefined ? 'fee: ' + model.fee : ''
}
Item { Layout.columnSpan: 3; Layout.preferredWidth: 1; Layout.preferredHeight: 1 }
} }
} }
} // as the items in the model are not bindings to QObjects,
// as the items in the model are not bindings to QObjects, // hook up events that might change the appearance
// hook up events that might change the appearance Connections {
Connections { target: Config
target: Config function onBaseUnitChanged() {
function onBaseUnitChanged() { valueLabel.text = Config.formatSats(model.bc_value)
valueLabel.text = Config.formatSats(model.bc_value) }
function onThousandsSeparatorChanged() {
valueLabel.text = Config.formatSats(model.bc_value)
}
} }
function onThousandsSeparatorChanged() {
valueLabel.text = Config.formatSats(model.bc_value) Component.onCompleted: {
if (model.section == 'today') {
delegate.DelegateModel.inToday = true
} else if (model.section == 'yesterday') {
delegate.DelegateModel.inYesterday = true
} else if (model.section == 'lastweek') {
delegate.DelegateModel.inLastweek = true
} else if (model.section == 'lastmonth') {
delegate.DelegateModel.inLastmonth = true
} else if (model.section == 'older') {
delegate.DelegateModel.inOlder = true
}
} }
}
} // delegate } // delegate
}
ScrollIndicator.vertical: ScrollIndicator { } ScrollIndicator.vertical: ScrollIndicator { }

38
electrum/gui/qml/qetransactionlistmodel.py

@ -1,4 +1,4 @@
from datetime import datetime from datetime import datetime, timedelta
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
@ -17,7 +17,7 @@ class QETransactionListModel(QAbstractListModel):
# define listmodel rolemap # define listmodel rolemap
_ROLE_NAMES=('txid','fee_sat','height','confirmations','timestamp','monotonic_timestamp', _ROLE_NAMES=('txid','fee_sat','height','confirmations','timestamp','monotonic_timestamp',
'incoming','bc_value','bc_balance','date','label','txpos_in_block','fee', 'incoming','bc_value','bc_balance','date','label','txpos_in_block','fee',
'inputs','outputs') 'inputs','outputs','section')
_ROLE_KEYS = range(Qt.UserRole + 1, Qt.UserRole + 1 + len(_ROLE_NAMES)) _ROLE_KEYS = range(Qt.UserRole + 1, Qt.UserRole + 1 + len(_ROLE_NAMES))
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES])) _ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS)) _ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
@ -43,14 +43,38 @@ class QETransactionListModel(QAbstractListModel):
self.tx_history = [] self.tx_history = []
self.endResetModel() self.endResetModel()
def tx_to_model(self, tx):
item = tx
for output in item['outputs']:
output['value'] = output['value'].value
# newly arriving txs have no (block) timestamp
# TODO?
if not item['timestamp']:
item['timestamp'] = datetime.timestamp(datetime.now())
txts = datetime.fromtimestamp(item['timestamp'])
today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
if (txts > today):
item['section'] = 'today'
elif (txts > today - timedelta(days=1)):
item['section'] = 'yesterday'
elif (txts > today - timedelta(days=7)):
item['section'] = 'lastweek'
elif (txts > today - timedelta(days=31)):
item['section'] = 'lastmonth'
else:
item['section'] = 'older'
return item
# initial model data # initial model data
def init_model(self): def init_model(self):
history = self.wallet.get_detailed_history(show_addresses = True) history = self.wallet.get_detailed_history(show_addresses = True)
txs = history['transactions'] txs = []
# use primitives for tx in history['transactions']:
for tx in txs: txs.append(self.tx_to_model(tx))
for output in tx['outputs']:
output['value'] = output['value'].value
self.clear() self.clear()
self.beginInsertRows(QModelIndex(), 0, len(txs) - 1) self.beginInsertRows(QModelIndex(), 0, len(txs) - 1)

Loading…
Cancel
Save