frontend improvements, refactor qeinvoicelistmodel
This commit is contained in:
@@ -39,7 +39,7 @@ Pane {
|
||||
BtcField {
|
||||
id: amount
|
||||
fiatfield: amountFiat
|
||||
Layout.preferredWidth: parent.width /2
|
||||
Layout.preferredWidth: parent.width /3
|
||||
}
|
||||
|
||||
Label {
|
||||
@@ -55,7 +55,7 @@ Pane {
|
||||
id: amountFiat
|
||||
btcfield: amount
|
||||
visible: Daemon.fx.enabled
|
||||
Layout.preferredWidth: parent.width /2
|
||||
Layout.preferredWidth: parent.width /3
|
||||
}
|
||||
|
||||
Label {
|
||||
|
||||
@@ -164,10 +164,12 @@ Dialog {
|
||||
|
||||
Label {
|
||||
text: qsTr('Address')
|
||||
visible: !modelItem.is_lightning
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 3
|
||||
visible: !modelItem.is_lightning
|
||||
font.family: FixedFont
|
||||
font.pixelSize: constants.fontSizeLarge
|
||||
wrapMode: Text.WrapAnywhere
|
||||
@@ -175,6 +177,7 @@ Dialog {
|
||||
}
|
||||
ToolButton {
|
||||
icon.source: '../../icons/copy_bw.png'
|
||||
visible: !modelItem.is_lightning
|
||||
onClicked: {
|
||||
AppController.textToClipboard(modelItem.address)
|
||||
}
|
||||
@@ -203,8 +206,10 @@ Dialog {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
_bip21uri = bitcoin.create_uri(modelItem.address, modelItem.amount, modelItem.message, modelItem.timestamp, modelItem.expiration - modelItem.timestamp)
|
||||
qr.source = 'image://qrgen/' + _bip21uri
|
||||
if (!modelItem.is_lightning) {
|
||||
_bip21uri = bitcoin.create_bip21_uri(modelItem.address, modelItem.amount, modelItem.message, modelItem.timestamp, modelItem.expiration - modelItem.timestamp)
|
||||
qr.source = 'image://qrgen/' + _bip21uri
|
||||
}
|
||||
}
|
||||
|
||||
Bitcoin {
|
||||
|
||||
@@ -74,7 +74,7 @@ Pane {
|
||||
BtcField {
|
||||
id: amount
|
||||
fiatfield: amountFiat
|
||||
Layout.preferredWidth: parent.width /2
|
||||
Layout.preferredWidth: parent.width /3
|
||||
}
|
||||
|
||||
Label {
|
||||
@@ -91,7 +91,7 @@ Pane {
|
||||
id: amountFiat
|
||||
btcfield: amount
|
||||
visible: Daemon.fx.enabled
|
||||
Layout.preferredWidth: parent.width /2
|
||||
Layout.preferredWidth: parent.width /3
|
||||
}
|
||||
|
||||
Label {
|
||||
@@ -123,6 +123,7 @@ Pane {
|
||||
Button {
|
||||
text: qsTr('Save')
|
||||
enabled: invoice.invoiceType != Invoice.Invalid
|
||||
icon.source: '../../icons/save.png'
|
||||
onClicked: {
|
||||
Daemon.currentWallet.create_invoice(recipient.text, amount.text, message.text)
|
||||
}
|
||||
@@ -131,6 +132,7 @@ Pane {
|
||||
Button {
|
||||
text: qsTr('Pay now')
|
||||
enabled: invoice.invoiceType != Invoice.Invalid // TODO && has funds
|
||||
icon.source: '../../icons/confirmed.png'
|
||||
onClicked: {
|
||||
var f_amount = parseFloat(amount.text)
|
||||
if (isNaN(f_amount))
|
||||
@@ -193,7 +195,7 @@ Pane {
|
||||
model: Daemon.currentWallet.invoiceModel
|
||||
delegate: InvoiceDelegate {
|
||||
onClicked: {
|
||||
var dialog = confirmInvoiceDialog.createObject(app, {'invoice' : invoice, 'invoice_key': model.key})
|
||||
var dialog = invoiceDialog.createObject(app, {'invoice' : invoice, 'invoice_key': model.key})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
@@ -227,7 +229,7 @@ Pane {
|
||||
}
|
||||
|
||||
Component {
|
||||
id: confirmInvoiceDialog
|
||||
id: invoiceDialog
|
||||
InvoiceDialog {
|
||||
onDoPay: {
|
||||
if (invoice.invoiceType == Invoice.OnchainInvoice) {
|
||||
@@ -285,7 +287,7 @@ Pane {
|
||||
if (invoiceType == Invoice.OnchainOnlyAddress)
|
||||
recipient.text = invoice.recipient
|
||||
else {
|
||||
var dialog = confirmInvoiceDialog.createObject(rootItem, {'invoice': invoice})
|
||||
var dialog = invoiceDialog.createObject(rootItem, {'invoice': invoice})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ TextField {
|
||||
inputMethodHints: Qt.ImhPreferNumbers
|
||||
onTextChanged: {
|
||||
if (amountFiat.activeFocus)
|
||||
btcfield.text = text == '' ? '' : Config.satsToUnits(Daemon.fx.satoshiValue(amountFiat.text))
|
||||
btcfield.text = text == ''
|
||||
? ''
|
||||
: Config.satsToUnits(Daemon.fx.satoshiValue(amountFiat.text))
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -36,6 +36,18 @@ ItemDelegate {
|
||||
source: model.is_lightning
|
||||
? "../../../icons/lightning.png"
|
||||
: "../../../icons/bitcoin.png"
|
||||
|
||||
Image {
|
||||
visible: model.onchain_fallback
|
||||
z: -1
|
||||
source: "../../../icons/bitcoin.png"
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: parent.width /2
|
||||
height: parent.height /2
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
@@ -55,13 +67,13 @@ ItemDelegate {
|
||||
|
||||
Label {
|
||||
id: amount
|
||||
text: model.amount == 0 ? '' : Config.formatSats(model.amount)
|
||||
text: model.amount.isEmpty ? '' : Config.formatSats(model.amount)
|
||||
font.pixelSize: constants.fontSizeMedium
|
||||
font.family: FixedFont
|
||||
}
|
||||
|
||||
Label {
|
||||
text: model.amount == 0 ? '' : Config.baseUnit
|
||||
text: model.amount.isEmpty ? '' : Config.baseUnit
|
||||
font.pixelSize: constants.fontSizeMedium
|
||||
color: Material.accentColor
|
||||
}
|
||||
@@ -95,14 +107,14 @@ ItemDelegate {
|
||||
id: fiatValue
|
||||
visible: Daemon.fx.enabled
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: model.amount == 0 ? '' : Daemon.fx.fiatValue(model.amount, false)
|
||||
text: model.amount.isEmpty ? '' : Daemon.fx.fiatValue(model.amount, false)
|
||||
font.family: FixedFont
|
||||
font.pixelSize: constants.fontSizeSmall
|
||||
}
|
||||
Label {
|
||||
visible: Daemon.fx.enabled
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: model.amount == 0 ? '' : Daemon.fx.fiatCurrency
|
||||
text: model.amount.isEmpty ? '' : Daemon.fx.fiatCurrency
|
||||
font.pixelSize: constants.fontSizeSmall
|
||||
color: Material.accentColor
|
||||
}
|
||||
@@ -119,16 +131,16 @@ ItemDelegate {
|
||||
Connections {
|
||||
target: Config
|
||||
function onBaseUnitChanged() {
|
||||
amount.text = model.amount == 0 ? '' : Config.formatSats(model.amount)
|
||||
amount.text = model.amount.isEmpty ? '' : Config.formatSats(model.amount)
|
||||
}
|
||||
function onThousandsSeparatorChanged() {
|
||||
amount.text = model.amount == 0 ? '' : Config.formatSats(model.amount)
|
||||
amount.text = model.amount.isEmpty ? '' : Config.formatSats(model.amount)
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: Daemon.fx
|
||||
function onQuotesUpdated() {
|
||||
fiatValue.text = model.amount == 0 ? '' : Daemon.fx.fiatValue(model.amount, false)
|
||||
fiatValue.text = model.amount.isEmpty ? '' : Daemon.fx.fiatValue(model.amount, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ class QEBitcoin(QObject):
|
||||
return { 'error': str(e) }
|
||||
|
||||
@pyqtSlot(str, QEAmount, str, int, int, result=str)
|
||||
def create_uri(self, address, satoshis, message, timestamp, expiry):
|
||||
def create_bip21_uri(self, address, satoshis, message, timestamp, expiry):
|
||||
extra_params = {}
|
||||
if expiry:
|
||||
extra_params['time'] = str(timestamp)
|
||||
|
||||
@@ -18,7 +18,8 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
self.init_model()
|
||||
|
||||
# define listmodel rolemap
|
||||
_ROLE_NAMES=('key','is_lightning','timestamp','date','message','amount','status','status_str','address','expiration','type')
|
||||
_ROLE_NAMES=('key', 'is_lightning', 'timestamp', 'date', 'message', 'amount',
|
||||
'status', 'status_str', 'address', 'expiration', 'type', 'onchain_fallback')
|
||||
_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_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
|
||||
@@ -96,6 +97,19 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
return
|
||||
i = i + 1
|
||||
|
||||
def invoice_to_model(self, invoice: Invoice):
|
||||
item = self.get_invoice_as_dict(invoice)
|
||||
item['key'] = invoice.get_id()
|
||||
item['is_lightning'] = invoice.is_lightning()
|
||||
if invoice.is_lightning() and 'address' not in item:
|
||||
item['address'] = ''
|
||||
item['date'] = format_time(item['timestamp'])
|
||||
item['amount'] = QEAmount(from_invoice=invoice)
|
||||
item['onchain_fallback'] = invoice.is_lightning() and invoice._lnaddr.get_fallback_address()
|
||||
item['type'] = 'invoice'
|
||||
|
||||
return item
|
||||
|
||||
@abstractmethod
|
||||
def get_invoice_for_key(self, key: str):
|
||||
raise Exception('provide impl')
|
||||
@@ -105,55 +119,52 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
raise Exception('provide impl')
|
||||
|
||||
@abstractmethod
|
||||
def invoice_to_model(self, invoice: Invoice):
|
||||
def get_invoice_as_dict(self, invoice: Invoice):
|
||||
raise Exception('provide impl')
|
||||
|
||||
|
||||
class QEInvoiceListModel(QEAbstractInvoiceListModel):
|
||||
def __init__(self, wallet, parent=None):
|
||||
super().__init__(wallet, parent)
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def get_invoice_list(self):
|
||||
return self.wallet.get_unpaid_invoices()
|
||||
|
||||
def invoice_to_model(self, invoice: Invoice):
|
||||
item = self.wallet.export_invoice(invoice)
|
||||
item['is_lightning'] = invoice.is_lightning()
|
||||
item['date'] = format_time(item['timestamp'])
|
||||
item['amount'] = QEAmount(amount_sat=invoice.get_amount_sat())
|
||||
item['key'] = invoice.get_id()
|
||||
|
||||
item = super().invoice_to_model(invoice)
|
||||
item['type'] = 'invoice'
|
||||
|
||||
return item
|
||||
|
||||
def get_invoice_list(self):
|
||||
return self.wallet.get_unpaid_invoices()
|
||||
|
||||
def get_invoice_for_key(self, key: str):
|
||||
return self.wallet.get_invoice(key)
|
||||
|
||||
def get_invoice_as_dict(self, invoice: Invoice):
|
||||
return self.wallet.export_invoice(invoice)
|
||||
|
||||
class QERequestListModel(QEAbstractInvoiceListModel):
|
||||
def __init__(self, wallet, parent=None):
|
||||
super().__init__(wallet, parent)
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def get_invoice_list(self):
|
||||
return self.wallet.get_unpaid_requests()
|
||||
|
||||
def invoice_to_model(self, req: Invoice):
|
||||
item = self.wallet.export_request(req)
|
||||
item['key'] = req.get_rhash() if req.is_lightning() else req.get_address()
|
||||
item['is_lightning'] = req.is_lightning()
|
||||
item['date'] = format_time(item['timestamp'])
|
||||
item['amount'] = QEAmount(amount_sat=req.get_amount_sat())
|
||||
|
||||
item = super().invoice_to_model(req)
|
||||
item['type'] = 'request'
|
||||
|
||||
return item
|
||||
|
||||
def get_invoice_list(self):
|
||||
return self.wallet.get_unpaid_requests()
|
||||
|
||||
def get_invoice_for_key(self, key: str):
|
||||
return self.wallet.get_request(key)
|
||||
|
||||
def get_invoice_as_dict(self, req: Invoice):
|
||||
return self.wallet.export_request(req)
|
||||
|
||||
@pyqtSlot(str, int)
|
||||
def updateRequest(self, key, status):
|
||||
self.updateInvoice(key, status)
|
||||
|
||||
@@ -15,11 +15,18 @@ from electrum.util import profiler
|
||||
class QEAmount(QObject):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def __init__(self, *, amount_sat: int = 0, amount_msat: int = 0, is_max: bool = False, parent=None):
|
||||
def __init__(self, *, amount_sat: int = 0, amount_msat: int = 0, is_max: bool = False, from_invoice = None, parent=None):
|
||||
super().__init__(parent)
|
||||
self._amount_sat = amount_sat
|
||||
self._amount_msat = amount_msat
|
||||
self._is_max = is_max
|
||||
if from_invoice:
|
||||
inv_amt = from_invoice.get_amount_msat()
|
||||
if inv_amt == '!':
|
||||
self._is_max = True
|
||||
elif inv_amt is not None:
|
||||
self._amount_msat = inv_amt
|
||||
self._amount_sat = from_invoice.get_amount_sat()
|
||||
|
||||
valueChanged = pyqtSignal()
|
||||
|
||||
@@ -43,6 +50,10 @@ class QEAmount(QObject):
|
||||
def isMax(self):
|
||||
return self._is_max
|
||||
|
||||
@pyqtProperty(bool, notify=valueChanged)
|
||||
def isEmpty(self):
|
||||
return not(self._is_max or self._amount_sat or self._amount_msat)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, QEAmount):
|
||||
return self._amount_sat == other._amount_sat and self._amount_msat == other._amount_msat and self._is_max == other._is_max
|
||||
@@ -60,4 +71,4 @@ class QEAmount(QObject):
|
||||
return '%s(sats=%d, msats=%d)' % (s, self._amount_sat, self._amount_msat)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<QEAmount max={self._is_max} sats={self._amount_sat} msats={self._amount_msat}>"
|
||||
return f"<QEAmount max={self._is_max} sats={self._amount_sat} msats={self._amount_msat} empty={self.isEmpty}>"
|
||||
|
||||
Reference in New Issue
Block a user