Browse Source

qml: also show coins in Addresses page, and add a few filter options. Additionally, long press

now activates multi-select mode, and add action to (un)freeze selection.
master
Sander van Grieken 2 years ago
parent
commit
cf91d2e5cc
  1. 252
      electrum/gui/qml/components/Addresses.qml
  2. 6
      electrum/gui/qml/components/controls/AddressDelegate.qml
  3. 97
      electrum/gui/qml/components/controls/CoinDelegate.qml
  4. 195
      electrum/gui/qml/qeaddresslistmodel.py
  5. 5
      electrum/gui/qml/qemodelfilter.py
  6. 22
      electrum/gui/qml/qewallet.py

252
electrum/gui/qml/components/Addresses.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
@ -14,34 +15,246 @@ Pane {
padding: 0 padding: 0
ColumnLayout { ColumnLayout {
id: layout
anchors.fill: parent anchors.fill: parent
spacing: 0
ElListView { ColumnLayout {
id: listview id: layout
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
clip: true Pane {
model: Daemon.currentWallet.addressModel id: filtersPane
currentIndex: -1 Layout.fillWidth: true
GridLayout {
columns: 3
width: parent.width
section.property: 'type' CheckBox {
section.criteria: ViewSection.FullString id: showUsed
section.delegate: sectionDelegate text: qsTr('Show Used')
enabled: listview.filterModel.showAddressesCoins != 2
onCheckedChanged: listview.filterModel.showUsed = checked
Component.onCompleted: checked = listview.filterModel.showUsed
}
delegate: AddressDelegate { RowLayout {
onClicked: { Layout.columnSpan: 2
var page = app.stack.push(Qt.resolvedUrl('AddressDetails.qml'), {'address': model.address}) Layout.fillWidth: true
page.addressDetailsChanged.connect(function() { Layout.alignment: Qt.AlignRight
// update listmodel when details change Label {
listview.model.updateAddress(model.address) text: qsTr('Show')
}) }
ElComboBox {
id: showCoinsAddresses
textRole: 'text'
valueRole: 'value'
model: ListModel {
id: showCoinsAddressesModel
Component.onCompleted: {
// we need to fill the model like this, as ListElement can't evaluate script
showCoinsAddressesModel.append({'text': qsTr('Addresses'), 'value': 1})
showCoinsAddressesModel.append({'text': qsTr('Coins'), 'value': 2})
showCoinsAddressesModel.append({'text': qsTr('Both'), 'value': 3})
showCoinsAddresses.currentIndex = 0
for (let i=0; i < showCoinsAddressesModel.count; i++) {
if (showCoinsAddressesModel.get(i).value == listview.filterModel.showAddressesCoins) {
showCoinsAddresses.currentIndex = i
break
}
}
}
}
onCurrentValueChanged: {
if (activeFocus && currentValue) {
listview.filterModel.showAddressesCoins = currentValue
}
}
}
}
RowLayout {
Layout.columnSpan: 3
Layout.fillWidth: true
TextField {
id: searchEdit
Layout.fillWidth: true
placeholderText: qsTr('text search')
onTextChanged: listview.filterModel.filterText = text
}
Image {
source: Qt.resolvedUrl('../../icons/zoom.png')
sourceSize.width: constants.iconSizeMedium
sourceSize.height: constants.iconSizeMedium
}
}
} }
} }
ScrollIndicator.vertical: ScrollIndicator { } Frame {
id: channelsFrame
Layout.fillWidth: true
Layout.fillHeight: true
verticalPadding: 0
horizontalPadding: 0
background: PaneInsetBackground {}
ElListView {
id: listview
anchors.fill: parent
clip: true
property QtObject backingModel: Daemon.currentWallet.addressCoinModel
property QtObject filterModel: Daemon.currentWallet.addressCoinModel.filterModel
property bool selectMode: false
property bool freeze: true
model: visualModel
currentIndex: -1
section.property: 'type'
section.criteria: ViewSection.FullString
section.delegate: sectionDelegate
function getSelectedItems() {
var items = []
for (let i = 0; i < selectedGroup.count; i++) {
let modelitem = selectedGroup.get(i).model
if (modelitem.outpoint)
items.push(modelitem.outpoint)
else
items.push(modelitem.address)
}
return items
}
DelegateModel {
id: visualModel
model: listview.filterModel
groups: [
DelegateModelGroup {
id: selectedGroup;
name: 'selected'
onCountChanged: {
if (count == 0)
listview.selectMode = false
}
}
]
delegate: Loader {
id: loader
width: parent.width
sourceComponent: model.outpoint ? _coinDelegate : _addressDelegate
function toggle() {
loader.DelegateModel.inSelected = !loader.DelegateModel.inSelected
}
Component {
id: _addressDelegate
AddressDelegate {
id: addressDelegate
width: parent.width
property bool selected: loader.DelegateModel.inSelected
highlighted: selected
onClicked: {
if (!listview.selectMode) {
var page = app.stack.push(Qt.resolvedUrl('AddressDetails.qml'), {
address: model.address
})
page.addressDetailsChanged.connect(function() {
// update listmodel when details change
listview.backingModel.updateAddress(model.address)
})
} else {
loader.toggle()
}
}
onPressAndHold: {
loader.toggle()
if (!listview.selectMode && selectedGroup.count > 0)
listview.selectMode = true
}
}
}
Component {
id: _coinDelegate
Pane {
height: coinDelegate.height
padding: 0
background: Rectangle {
color: Qt.darker(constants.darkerBackground, 1.10)
}
CoinDelegate {
id: coinDelegate
width: parent.width
property bool selected: loader.DelegateModel.inSelected
highlighted: selected
onClicked: {
if (!listview.selectMode) {
var page = app.stack.push(Qt.resolvedUrl('TxDetails.qml'), {
txid: model.txid
})
} else {
loader.toggle()
}
}
onPressAndHold: {
loader.toggle()
if (!listview.selectMode && selectedGroup.count > 0)
listview.selectMode = true
}
}
}
}
}
}
add: Transition {
NumberAnimation { properties: "opacity"; from: 0.0; to: 1.0; duration: 300
easing.type: Easing.OutQuad
}
}
onSelectModeChanged: {
if (selectMode) {
listview.freeze = !selectedGroup.get(0).model.held
}
}
ScrollIndicator.vertical: ScrollIndicator { }
}
}
}
ButtonContainer {
Layout.fillWidth: true
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
text: listview.freeze ? qsTr('Freeze') : qsTr('Unfreeze')
icon.source: '../../icons/seal.png'
visible: listview.selectMode
onClicked: {
var items = listview.getSelectedItems()
listview.backingModel.setFrozenForItems(listview.freeze, items)
selectedGroup.remove(0, selectedGroup.count)
}
}
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
text: qsTr('Pay from...')
icon.source: '../../icons/tab_send.png'
visible: listview.selectMode
enabled: false // TODO
onClicked: {
//
}
}
} }
} }
@ -52,7 +265,6 @@ Pane {
id: root id: root
width: ListView.view.width width: ListView.view.width
height: childrenRect.height height: childrenRect.height
required property string section required property string section
property string section_label: section == 'receive' property string section_label: section == 'receive'
? qsTr('receive addresses') ? qsTr('receive addresses')
@ -74,6 +286,6 @@ Pane {
} }
Component.onCompleted: { Component.onCompleted: {
Daemon.currentWallet.addressModel.initModel() Daemon.currentWallet.addressCoinModel.initModel()
} }
} }

6
electrum/gui/qml/components/controls/AddressDelegate.qml

@ -27,9 +27,9 @@ ItemDelegate {
Label { Label {
id: indexLabel id: indexLabel
font.bold: true font.bold: true
text: model.iaddr < 10 text: model.addridx < 10
? '#' + ('0'+model.iaddr).slice(-2) ? '#' + ('0'+model.addridx).slice(-2)
: '#' + model.iaddr : '#' + model.addridx
Layout.fillWidth: true Layout.fillWidth: true
} }
Label { Label {

97
electrum/gui/qml/components/controls/CoinDelegate.qml

@ -0,0 +1,97 @@
import QtQuick 2.6
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls.Material 2.0
import org.electrum 1.0
ItemDelegate {
id: delegate
width: ListView.view.width
height: delegateLayout.height
highlighted: ListView.isCurrentItem
font.pixelSize: constants.fontSizeMedium // set default font size for child controls
ColumnLayout {
id: delegateLayout
width: parent.width
spacing: 0
GridLayout {
columns: 3
Layout.topMargin: constants.paddingSmall
Layout.leftMargin: constants.paddingLarge + 2*constants.paddingLarge
Layout.rightMargin: constants.paddingLarge
Rectangle {
id: useIndicator
Layout.rowSpan: 2
Layout.preferredWidth: constants.iconSizeSmall
Layout.preferredHeight: constants.iconSizeSmall
Layout.alignment: Qt.AlignTop
color: model.held
? constants.colorAddressFrozen
: constants.colorAddressUsedWithBalance
}
RowLayout {
Layout.fillWidth: true
Label {
font.family: FixedFont
text: model.outpoint
elide: Text.ElideMiddle
Layout.preferredWidth: implicitWidth + constants.paddingMedium
}
Label {
Layout.fillWidth: true
visible: model.short_id
font.family: FixedFont
font.pixelSize: constants.fontSizeSmall
text: '[' + model.short_id + ']'
}
Item {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
visible: !model.short_id
Image {
source: Qt.resolvedUrl('../../../icons/unconfirmed.png')
sourceSize.width: constants.iconSizeSmall
sourceSize.height: constants.iconSizeSmall
}
}
}
RowLayout {
Label {
font.family: FixedFont
text: Config.formatSats(model.amount, false)
visible: model.amount.satsInt != 0
}
Label {
color: Material.accentColor
text: Config.baseUnit
visible: model.amount.satsInt != 0
}
}
Label {
id: labelLabel
Layout.fillWidth: true
Layout.columnSpan: 2
visible: model.label
font.pixelSize: constants.fontSizeMedium
text: model.label
elide: Text.ElideRight
maximumLineCount: 2
wrapMode: Text.WordWrap
}
}
Item {
Layout.preferredWidth: 1
Layout.preferredHeight: constants.paddingSmall
}
}
}

195
electrum/gui/qml/qeaddresslistmodel.py

@ -1,7 +1,6 @@
import itertools from typing import TYPE_CHECKING, List
from typing import TYPE_CHECKING
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot, QSortFilterProxyModel, pyqtSignal, pyqtProperty
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.logging import get_logger from electrum.logging import get_logger
@ -11,38 +10,126 @@ from .qetypes import QEAmount
if TYPE_CHECKING: if TYPE_CHECKING:
from electrum.wallet import Abstract_Wallet from electrum.wallet import Abstract_Wallet
from electrum.transaction import PartialTxInput
class QEAddressListModel(QAbstractListModel): class QEAddressCoinFilterProxyModel(QSortFilterProxyModel):
_logger = get_logger(__name__)
def __init__(self, parent_model, parent=None):
super().__init__(parent)
self._filter_text = None
self._show_coins = True
self._show_addresses = True
self._show_used = False
self._parent_model = parent_model
self.setSourceModel(parent_model)
countChanged = pyqtSignal()
@pyqtProperty(int, notify=countChanged)
def count(self):
return self.rowCount(QModelIndex())
def filterAcceptsRow(self, s_row, s_parent):
parent_model = self.sourceModel()
addridx = parent_model.data(parent_model.index(s_row, 0, s_parent), parent_model._ROLE_RMAP['addridx'])
if addridx is None: # coin
if not self._show_coins:
return False
else:
if not self._show_addresses:
return False
balance = parent_model.data(parent_model.index(s_row, 0, s_parent), parent_model._ROLE_RMAP['balance'])
numtx = parent_model.data(parent_model.index(s_row, 0, s_parent), parent_model._ROLE_RMAP['numtx'])
if balance.isEmpty and numtx and not self._show_used:
return False
if self._filter_text:
label = parent_model.data(parent_model.index(s_row, 0, s_parent), parent_model._ROLE_RMAP['label'])
address = parent_model.data(parent_model.index(s_row, 0, s_parent), parent_model._ROLE_RMAP['address'])
for item in [label, address]:
if self._filter_text in str(item):
return True
return False
return True
showAddressesCoinsChanged = pyqtSignal()
@pyqtProperty(int, notify=showAddressesCoinsChanged)
def showAddressesCoins(self) -> int:
result = 0
if self._show_addresses:
result += 1
if self._show_coins:
result += 2
return result
@showAddressesCoins.setter
def showAddressesCoins(self, show_addresses_coins: int):
show_addresses = show_addresses_coins in [1, 3]
show_coins = show_addresses_coins in [2, 3]
if self._show_addresses != show_addresses or self._show_coins != show_coins:
self._show_addresses = show_addresses
self._show_coins = show_coins
self.invalidateFilter()
self.showAddressesCoinsChanged.emit()
showUsedChanged = pyqtSignal()
@pyqtProperty(bool, notify=showUsedChanged)
def showUsed(self) -> bool:
return self._show_used
@showUsed.setter
def showUsed(self, show_used: bool):
if self._show_used != show_used:
self._show_used = show_used
self.invalidateFilter()
self.showUsedChanged.emit()
filterTextChanged = pyqtSignal()
@pyqtProperty(str, notify=filterTextChanged)
def filterText(self) -> str:
return self._filter_text
@filterText.setter
def filterText(self, filter_text: str):
if self._filter_text != filter_text:
self._filter_text = filter_text
self.invalidateFilter()
self.filterTextChanged.emit()
class QEAddressCoinListModel(QAbstractListModel):
_logger = get_logger(__name__) _logger = get_logger(__name__)
# define listmodel rolemap # define listmodel rolemap
_ROLE_NAMES=('type', 'iaddr', 'address', 'label', 'balance', 'numtx', 'held') _ROLE_NAMES=('type', 'addridx', 'address', 'label', 'balance', 'numtx', 'held', 'height', 'amount', 'outpoint',
'short_outpoint', 'short_id', 'txid')
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES)) _ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + 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))
def __init__(self, wallet: 'Abstract_Wallet', parent=None): def __init__(self, wallet: 'Abstract_Wallet', parent=None):
super().__init__(parent) super().__init__(parent)
self.wallet = wallet self.wallet = wallet
self._receive_addresses = [] self._items = []
self._change_addresses = [] self._filterModel = None
self._dirty = True self._dirty = True
self.initModel() self.initModel()
def rowCount(self, index): def rowCount(self, index):
return len(self._receive_addresses) + len(self._change_addresses) return len(self._items)
def roleNames(self): def roleNames(self):
return self._ROLE_MAP return self._ROLE_MAP
def data(self, index, role): def data(self, index, role):
if index.row() > len(self._receive_addresses) - 1: address = self._items[index.row()]
address = self._change_addresses[index.row() - len(self._receive_addresses)]
else:
address = self._receive_addresses[index.row()]
role_index = role - Qt.UserRole role_index = role - Qt.UserRole
value = address[self._ROLE_NAMES[role_index]] try:
value = address[self._ROLE_NAMES[role_index]]
except KeyError:
return None
if isinstance(value, (bool, list, int, str, QEAmount)) or value is None: if isinstance(value, (bool, list, int, str, QEAmount)) or value is None:
return value return value
if isinstance(value, Satoshis): if isinstance(value, Satoshis):
@ -51,13 +138,14 @@ class QEAddressListModel(QAbstractListModel):
def clear(self): def clear(self):
self.beginResetModel() self.beginResetModel()
self._receive_addresses = [] self._items = []
self._change_addresses = []
self.endResetModel() self.endResetModel()
def addr_to_model(self, address): def addr_to_model(self, addrtype: str, addridx: int, address: str):
c, u, x = self.wallet.get_addr_balance(address) c, u, x = self.wallet.get_addr_balance(address)
item = { item = {
'type': addrtype,
'addridx': addridx,
'address': address, 'address': address,
'numtx': self.wallet.adb.get_address_history_len(address), 'numtx': self.wallet.adb.get_address_history_len(address),
'label': self.wallet.get_label_for_address(address), 'label': self.wallet.get_label_for_address(address),
@ -66,6 +154,27 @@ class QEAddressListModel(QAbstractListModel):
} }
return item return item
def coin_to_model(self, addrtype: str, coin: 'PartialTxInput'):
txid = coin.prevout.txid.hex()
short_id = ''
# check below duplicated from TxInput as we cannot get short_id unambiguously
if coin.block_txpos is not None and coin.block_txpos >= 0:
short_id = str(coin.short_id)
item = {
'type': addrtype,
'amount': QEAmount(amount_sat=coin.value_sats()),
'address': coin.address,
'height': coin.block_height,
'outpoint': coin.prevout.to_str(),
'short_outpoint': coin.prevout.short_name(),
'short_id': short_id,
'txid': txid,
'label': self.wallet.get_label_for_txid(txid) or '',
'held': self.wallet.is_frozen_coin(coin),
'coin': coin
}
return item
@pyqtSlot() @pyqtSlot()
def setDirty(self): def setDirty(self):
self._dirty = True self._dirty = True
@ -80,36 +189,70 @@ class QEAddressListModel(QAbstractListModel):
c_addresses = self.wallet.get_change_addresses() if self.wallet.wallet_type != 'imported' else [] c_addresses = self.wallet.get_change_addresses() if self.wallet.wallet_type != 'imported' else []
n_addresses = len(r_addresses) + len(c_addresses) n_addresses = len(r_addresses) + len(c_addresses)
def insert_row(atype, alist, address, iaddr): def insert_address(atype, address, addridx):
item = self.addr_to_model(address) item = self.addr_to_model(atype, addridx, address)
item['type'] = atype self._items.append(item)
item['iaddr'] = iaddr
alist.append(item) utxos = self.wallet.get_utxos([address])
utxos.sort(key=lambda x: x.block_height)
for i, coin in enumerate(utxos):
self._items.append(self.coin_to_model(atype, coin))
self.clear() self.clear()
self.beginInsertRows(QModelIndex(), 0, n_addresses - 1) self.beginInsertRows(QModelIndex(), 0, n_addresses - 1)
if self.wallet.wallet_type != 'imported': if self.wallet.wallet_type != 'imported':
for i, address in enumerate(r_addresses): for i, address in enumerate(r_addresses):
insert_row('receive', self._receive_addresses, address, i) insert_address('receive', address, i)
for i, address in enumerate(c_addresses): for i, address in enumerate(c_addresses):
insert_row('change', self._change_addresses, address, i) insert_address('change', address, i)
else: else:
for i, address in enumerate(r_addresses): for i, address in enumerate(r_addresses):
insert_row('imported', self._receive_addresses, address, i) insert_address('imported', address, i)
self.endInsertRows() self.endInsertRows()
self._dirty = False self._dirty = False
@pyqtSlot(str) @pyqtSlot(str)
def updateAddress(self, address): def updateAddress(self, address):
for i, a in enumerate(itertools.chain(self._receive_addresses, self._change_addresses)): for i, a in enumerate(self._items):
if a['address'] == address: if a['address'] == address:
self.do_update(i, a) self.do_update(i, a)
return return
def updateCoin(self, outpoint):
for i, a in enumerate(self._items):
if a.get('outpoint') == outpoint:
self.do_update(i, a)
return
def do_update(self, modelindex, modelitem): def do_update(self, modelindex, modelitem):
mi = self.createIndex(modelindex, 0) mi = self.createIndex(modelindex, 0)
self._logger.debug(repr(modelitem)) self._logger.debug(repr(modelitem))
modelitem.update(self.addr_to_model(modelitem['address'])) if modelitem.get('outpoint'):
modelitem.update(self.coin_to_model(modelitem['type'], modelitem['coin']))
else:
modelitem.update(self.addr_to_model(modelitem['type'], modelitem['addridx'], modelitem['address']))
self._logger.debug(repr(modelitem)) self._logger.debug(repr(modelitem))
self.dataChanged.emit(mi, mi, self._ROLE_KEYS) self.dataChanged.emit(mi, mi, self._ROLE_KEYS)
filterModelChanged = pyqtSignal()
@pyqtProperty(QEAddressCoinFilterProxyModel, notify=filterModelChanged)
def filterModel(self):
if self._filterModel is None:
self._filterModel = QEAddressCoinFilterProxyModel(self)
return self._filterModel
@pyqtSlot(bool, list)
def setFrozenForItems(self, freeze: bool, items: List[str]):
self._logger.debug(f'set frozen to {freeze} for {items!r}')
coins = list(filter(lambda x: ':' in x, items))
if len(coins):
self.wallet.set_frozen_state_of_coins(coins, freeze)
for coin in coins:
self.updateCoin(coin)
addresses = list(filter(lambda x: ':' not in x, items))
if len(addresses):
self.wallet.set_frozen_state_of_addresses(addresses, freeze)
for address in addresses:
self.updateAddress(address)

5
electrum/gui/qml/qemodelfilter.py

@ -1,7 +1,8 @@
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QSortFilterProxyModel, QModelIndex from PyQt5.QtCore import pyqtSignal, pyqtProperty, QSortFilterProxyModel, QModelIndex, pyqtSlot
from electrum.logging import get_logger from electrum.logging import get_logger
class QEFilterProxyModel(QSortFilterProxyModel): class QEFilterProxyModel(QSortFilterProxyModel):
_logger = get_logger(__name__) _logger = get_logger(__name__)
@ -18,8 +19,10 @@ class QEFilterProxyModel(QSortFilterProxyModel):
def isCustomFilter(self): def isCustomFilter(self):
return self._filter_value is not None return self._filter_value is not None
@pyqtSlot(str)
def setFilterValue(self, filter_value): def setFilterValue(self, filter_value):
self._filter_value = filter_value self._filter_value = filter_value
self.invalidate()
def filterAcceptsRow(self, s_row, s_parent): def filterAcceptsRow(self, s_row, s_parent):
if not self.isCustomFilter: if not self.isCustomFilter:

22
electrum/gui/qml/qewallet.py

@ -19,7 +19,7 @@ from electrum.wallet import Multisig_Wallet
from electrum.crypto import pw_decode_with_version_and_mac from electrum.crypto import pw_decode_with_version_and_mac
from .auth import AuthMixin, auth_protect from .auth import AuthMixin, auth_protect
from .qeaddresslistmodel import QEAddressListModel from .qeaddresslistmodel import QEAddressCoinListModel
from .qechannellistmodel import QEChannelListModel from .qechannellistmodel import QEChannelListModel
from .qeinvoicelistmodel import QEInvoiceListModel, QERequestListModel from .qeinvoicelistmodel import QEInvoiceListModel, QERequestListModel
from .qetransactionlistmodel import QETransactionListModel from .qetransactionlistmodel import QETransactionListModel
@ -91,7 +91,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
self._synchronizing_progress = '' self._synchronizing_progress = ''
self._historyModel = None self._historyModel = None
self._addressModel = None self._addressCoinModel = None
self._requestModel = None self._requestModel = None
self._invoiceModel = None self._invoiceModel = None
self._channelModel = None self._channelModel = None
@ -184,7 +184,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
if wallet == self.wallet: if wallet == self.wallet:
self._logger.info(f'new transaction {tx.txid()}') self._logger.info(f'new transaction {tx.txid()}')
self.add_tx_notification(tx) self.add_tx_notification(tx)
self.addressModel.setDirty() self.addressCoinModel.setDirty()
self.historyModel.setDirty() # assuming wallet.is_up_to_date triggers after self.historyModel.setDirty() # assuming wallet.is_up_to_date triggers after
self.balanceChanged.emit() self.balanceChanged.emit()
@ -198,7 +198,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
def on_event_removed_transaction(self, wallet, tx): def on_event_removed_transaction(self, wallet, tx):
if wallet == self.wallet: if wallet == self.wallet:
self._logger.info(f'removed transaction {tx.txid()}') self._logger.info(f'removed transaction {tx.txid()}')
self.addressModel.setDirty() self.addressCoinModel.setDirty()
self.historyModel.initModel(True) # setDirty()? self.historyModel.initModel(True) # setDirty()?
self.balanceChanged.emit() self.balanceChanged.emit()
@ -295,12 +295,12 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
self._historyModel = QETransactionListModel(self.wallet) self._historyModel = QETransactionListModel(self.wallet)
return self._historyModel return self._historyModel
addressModelChanged = pyqtSignal() addressCoinModelChanged = pyqtSignal()
@pyqtProperty(QEAddressListModel, notify=addressModelChanged) @pyqtProperty(QEAddressCoinListModel, notify=addressCoinModelChanged)
def addressModel(self): def addressCoinModel(self):
if self._addressModel is None: if self._addressCoinModel is None:
self._addressModel = QEAddressListModel(self.wallet) self._addressCoinModel = QEAddressCoinListModel(self.wallet)
return self._addressModel return self._addressCoinModel
requestModelChanged = pyqtSignal() requestModelChanged = pyqtSignal()
@pyqtProperty(QERequestListModel, notify=requestModelChanged) @pyqtProperty(QERequestListModel, notify=requestModelChanged)
@ -658,7 +658,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
assert key is not None assert key is not None
self._logger.debug(f'created request with key {key} addr {addr}') self._logger.debug(f'created request with key {key} addr {addr}')
self.addressModel.setDirty() self.addressCoinModel.setDirty()
self.requestModel.add_invoice(self.wallet.get_request(key)) self.requestModel.add_invoice(self.wallet.get_request(key))
self.requestCreateSuccess.emit(key) self.requestCreateSuccess.emit(key)

Loading…
Cancel
Save