Browse Source

handle gap limit warning when creating Request.

(using string error code for now, ideally should be properly defined
as an enum)

Also fix animation bug and work around broken ListView header implementation
patch-4
Sander van Grieken 3 years ago
parent
commit
03048d39b6
  1. 164
      electrum/gui/qml/components/Receive.qml
  2. 33
      electrum/gui/qml/qewallet.py

164
electrum/gui/qml/components/Receive.qml

@ -80,14 +80,12 @@ Pane {
Layout.columnSpan: 2 Layout.columnSpan: 2
text: qsTr('Create Request') text: qsTr('Create Request')
onClicked: { onClicked: {
var a = parseFloat(amount.text) createRequest()
Daemon.currentWallet.create_invoice(a, message.text, expires.currentValue)
} }
} }
} }
Frame { Frame {
clip: true
verticalPadding: 0 verticalPadding: 0
horizontalPadding: 0 horizontalPadding: 0
@ -103,18 +101,15 @@ Pane {
color: Qt.darker(Material.background, 1.25) color: Qt.darker(Material.background, 1.25)
} }
ListView { ColumnLayout {
spacing: 0
anchors.fill: parent anchors.fill: parent
model: Daemon.currentWallet.requestModel Item {
headerPositioning: ListView.OverlayHeader Layout.preferredHeight: hitem.height
Layout.preferredWidth: parent.width
header: Item {
z: 1
height: hitem.height
width: ListView.view.width
Rectangle { Rectangle {
anchors.fill: hitem anchors.fill: parent
color: Qt.lighter(Material.background, 1.25) color: Qt.lighter(Material.background, 1.25)
} }
RowLayout { RowLayout {
@ -127,76 +122,107 @@ Pane {
} }
} }
delegate: Item { ListView {
z: -1 Layout.fillHeight: true
height: item.height Layout.fillWidth: true
width: ListView.view.width clip: true
GridLayout {
id: item model: Daemon.currentWallet.requestModel
columns: 5
Image { delegate: ItemDelegate {
Layout.rowSpan: 2 id: root
Layout.preferredWidth: 32 height: item.height
Layout.preferredHeight: 32 width: ListView.view.width
source: model.type == 0 ? "../../icons/bitcoin.png" : "../../icons/lightning.png"
} onClicked: console.log('Request ' + index + ' clicked')
Label {
Layout.fillWidth: true GridLayout {
Layout.columnSpan: 2 id: item
text: model.message
font.pixelSize: constants.fontSizeLarge anchors {
} left: parent.left
right: parent.right
Label { leftMargin: constants.paddingSmall
text: qsTr('Amount: ') rightMargin: constants.paddingSmall
font.pixelSize: constants.fontSizeSmall }
}
Label { columns: 5
text: model.amount
font.pixelSize: constants.fontSizeSmall Image {
} Layout.rowSpan: 2
Layout.preferredWidth: 32
Label { Layout.preferredHeight: 32
text: qsTr('Timestamp: ') source: model.type == 0 ? "../../icons/bitcoin.png" : "../../icons/lightning.png"
font.pixelSize: constants.fontSizeSmall }
} Label {
Label { Layout.fillWidth: true
text: model.timestamp Layout.columnSpan: 2
font.pixelSize: constants.fontSizeSmall text: model.message
} font.pixelSize: constants.fontSizeLarge
}
Label {
text: qsTr('Status: ') Label {
font.pixelSize: constants.fontSizeSmall text: qsTr('Amount: ')
} font.pixelSize: constants.fontSizeSmall
Label { }
text: model.status Label {
font.pixelSize: constants.fontSizeSmall text: model.amount
font.pixelSize: constants.fontSizeSmall
}
Label {
text: qsTr('Timestamp: ')
font.pixelSize: constants.fontSizeSmall
}
Label {
text: model.timestamp
font.pixelSize: constants.fontSizeSmall
}
Label {
text: qsTr('Status: ')
font.pixelSize: constants.fontSizeSmall
}
Label {
text: model.status
font.pixelSize: constants.fontSizeSmall
}
} }
} }
add: Transition {
NumberAnimation { properties: 'y'; from: -50; duration: 300 }
NumberAnimation { properties: 'opacity'; from: 0; to: 1.0; duration: 700 }
}
addDisplaced: Transition {
NumberAnimation { properties: 'y'; duration: 100 }
NumberAnimation { properties: 'opacity'; to: 1.0; duration: 700 * (1-from) }
}
} }
add: Transition {
NumberAnimation { properties: 'y'; from: -50; duration: 300 }
NumberAnimation { properties: 'opacity'; from: 0; to: 1.0; duration: 700 }
}
addDisplaced: Transition {
NumberAnimation { properties: 'y'; duration: 100 }
}
} }
} }
function createRequest(ignoreGaplimit = false) {
var a = parseFloat(amount.text)
Daemon.currentWallet.create_invoice(a, message.text, expires.currentValue, false, ignoreGaplimit)
}
Connections { Connections {
target: Daemon.currentWallet target: Daemon.currentWallet
function onRequestCreateSuccess() { function onRequestCreateSuccess() {
message.text = '' message.text = ''
amount.text = '' amount.text = ''
} }
function onRequestCreateError(error) { function onRequestCreateError(code, error) {
console.log(error) if (code == 'gaplimit') {
var dialog = app.messageDialog.createObject(app, {'text': error}) var dialog = app.messageDialog.createObject(app, {'text': error, 'yesno': true})
dialog.yesClicked.connect(function() {
createRequest(true)
})
} else {
console.log(error)
var dialog = app.messageDialog.createObject(app, {'text': error})
}
dialog.open() dialog.open()
} }
} }

33
electrum/gui/qml/qewallet.py

@ -34,7 +34,7 @@ class QEWallet(QObject):
dataChanged = pyqtSignal() # dummy to silence warnings dataChanged = pyqtSignal() # dummy to silence warnings
requestCreateSuccess = pyqtSignal() requestCreateSuccess = pyqtSignal()
requestCreateError = pyqtSignal([str], arguments=['error']) requestCreateError = pyqtSignal([str,str], arguments=['code','error'])
requestStatus = pyqtSignal() requestStatus = pyqtSignal()
def on_request_status(self, event, *args): def on_request_status(self, event, *args):
@ -122,12 +122,12 @@ class QEWallet(QObject):
tx = self.wallet.make_unsigned_transaction(coins=coins,outputs=outputs) tx = self.wallet.make_unsigned_transaction(coins=coins,outputs=outputs)
return True return True
def create_bitcoin_request(self, amount: int, message: str, expiration: int) -> Optional[str]: def create_bitcoin_request(self, amount: int, message: str, expiration: int, ignore_gap: bool) -> Optional[str]:
addr = self.wallet.get_unused_address() addr = self.wallet.get_unused_address()
if addr is None: if addr is None:
# TODO implement if not self.wallet.is_deterministic(): # imported wallet
return # TODO implement
#if not self.wallet.is_deterministic(): # imported wallet return
#msg = [ #msg = [
#_('No more addresses in your wallet.'), ' ', #_('No more addresses in your wallet.'), ' ',
#_('You are using a non-deterministic wallet, which cannot create new addresses.'), ' ', #_('You are using a non-deterministic wallet, which cannot create new addresses.'), ' ',
@ -137,16 +137,18 @@ class QEWallet(QObject):
#if not self.question(''.join(msg)): #if not self.question(''.join(msg)):
#return #return
#addr = self.wallet.get_receiving_address() #addr = self.wallet.get_receiving_address()
#else: # deterministic wallet else: # deterministic wallet
#if not self.question(_("Warning: The next address will not be recovered automatically if you restore your wallet from seed; you may need to add it manually.\n\nThis occurs because you have too many unused addresses in your wallet. To avoid this situation, use the existing addresses first.\n\nCreate anyway?")): if not ignore_gap:
#return self.requestCreateError.emit('gaplimit',_("Warning: The next address will not be recovered automatically if you restore your wallet from seed; you may need to add it manually.\n\nThis occurs because you have too many unused addresses in your wallet. To avoid this situation, use the existing addresses first.\n\nCreate anyway?"))
#addr = self.wallet.create_new_address(False) return
addr = self.wallet.create_new_address(False)
req = self.wallet.make_payment_request(addr, amount, message, expiration) req = self.wallet.make_payment_request(addr, amount, message, expiration)
try: try:
self.wallet.add_payment_request(req) self.wallet.add_payment_request(req)
except Exception as e: except Exception as e:
self.logger.exception('Error adding payment request') self.logger.exception('Error adding payment request')
self.requestCreateError.emit(_('Error adding payment request') + ':\n' + repr(e)) self.requestCreateError.emit('fatal',_('Error adding payment request') + ':\n' + repr(e))
else: else:
# TODO: check this flow. Only if alias is defined in config. OpenAlias? # TODO: check this flow. Only if alias is defined in config. OpenAlias?
pass pass
@ -155,24 +157,25 @@ class QEWallet(QObject):
return addr return addr
@pyqtSlot(int, 'QString', int) @pyqtSlot(int, 'QString', int)
def create_invoice(self, amount: int, message: str, expiration: int, is_lightning: bool = False): @pyqtSlot(int, 'QString', int, bool)
@pyqtSlot(int, 'QString', int, bool, bool)
def create_invoice(self, amount: int, message: str, expiration: int, is_lightning: bool = False, ignore_gap: bool = False):
expiry = expiration #TODO: self.config.get('request_expiry', PR_DEFAULT_EXPIRATION_WHEN_CREATING) expiry = expiration #TODO: self.config.get('request_expiry', PR_DEFAULT_EXPIRATION_WHEN_CREATING)
try: try:
if is_lightning: if is_lightning:
if not self.wallet.lnworker.channels: if not self.wallet.lnworker.channels:
#self.show_error(_("You need to open a Lightning channel first.")) self.requestCreateError.emit('fatal',_("You need to open a Lightning channel first."))
self.requestCreateError.emit(_("You need to open a Lightning channel first."))
return return
# TODO maybe show a warning if amount exceeds lnworker.num_sats_can_receive (as in kivy) # TODO maybe show a warning if amount exceeds lnworker.num_sats_can_receive (as in kivy)
key = self.wallet.lnworker.add_request(amount, message, expiry) key = self.wallet.lnworker.add_request(amount, message, expiry)
else: else:
key = self.create_bitcoin_request(amount, message, expiry) key = self.create_bitcoin_request(amount, message, expiry, ignore_gap)
if not key: if not key:
return return
#self.address_list.update() #self.address_list.update()
self._addressModel.init_model() self._addressModel.init_model()
except InvoiceError as e: except InvoiceError as e:
self.requestCreateError.emit(_('Error creating payment request') + ':\n' + str(e)) self.requestCreateError.emit('fatal',_('Error creating payment request') + ':\n' + str(e))
return return
assert key is not None assert key is not None

Loading…
Cancel
Save