Files
pallectrum/electrum/gui/qml/components/OpenChannelDialog.qml
Davide Grilli 64b88fbded Rename Bitcoin to Palladium in UI and codebase
Update all references to "Bitcoin" and "Electrum" in the UI and codebase to "Palladium" and "Pallectrum" respectively. This includes network names, wallet types, error messages, and other user-facing text. Also updates the BIP21 URI scheme from 'bitcoin' to 'palladium'.
2025-11-23 22:09:21 +01:00

331 lines
13 KiB
QML

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.Material
import org.electrum 1.0
import "controls"
ElDialog {
id: root
title: qsTr("Open Lightning Channel")
iconSource: Qt.resolvedUrl('../../icons/lightning.png')
padding: 0
width: parent.width
height: parent.height
ColumnLayout {
anchors.fill: parent
spacing: 0
Flickable {
Layout.preferredWidth: parent.width
Layout.fillHeight: true
leftMargin: constants.paddingLarge
rightMargin: constants.paddingLarge
contentHeight: rootLayout.height
clip:true
interactive: height < contentHeight
GridLayout {
id: rootLayout
width: parent.width
columns: 3
InfoTextArea {
Layout.fillWidth: true
Layout.columnSpan: 3
visible: !Daemon.currentWallet.lightningHasDeterministicNodeId
iconStyle: InfoTextArea.IconStyle.Warn
text: Daemon.currentWallet.seedType == 'segwit'
? [ qsTr('Your channels cannot be recovered from seed, because they were created with an old version of Pallectrum.'), ' ',
qsTr('This means that you must save a backup of your wallet every time you create a new channel.'),
'\n\n',
qsTr('If you want this wallet to have recoverable channels, you must close your existing channels and restore this wallet from seed.')
].join('')
: [ qsTr('Your channels cannot be recovered from seed.'), ' ',
qsTr('This means that you must save a backup of your wallet every time you create a new channel.'),
'\n\n',
qsTr('If you want to have recoverable channels, you must create a new wallet with a Pallectrum seed')
].join('')
}
InfoTextArea {
Layout.fillWidth: true
Layout.columnSpan: 3
visible: Daemon.currentWallet.lightningHasDeterministicNodeId && !Config.useRecoverableChannels
iconStyle: InfoTextArea.IconStyle.Warn
text: [ qsTr('You currently have recoverable channels setting disabled.'),
qsTr('This means your channels cannot be recovered from seed.')
].join(' ')
}
Label {
text: qsTr('Node')
Layout.columnSpan: 3
color: Material.accentColor
}
// gossip
TextArea {
id: node
visible: Config.useGossip
Layout.columnSpan: 2
Layout.fillWidth: true
font.family: FixedFont
wrapMode: Text.Wrap
placeholderText: qsTr('Paste or scan node uri/pubkey')
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
onTextChanged: {
if (activeFocus)
channelopener.connectStr = text
}
onActiveFocusChanged: {
if (!activeFocus)
channelopener.connectStr = text
}
}
RowLayout {
visible: Config.useGossip
spacing: 0
ToolButton {
icon.source: '../../icons/paste.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
onClicked: {
var cliptext = AppController.clipboardToText()
if (!cliptext)
return
if (channelopener.validateConnectString(cliptext)) {
channelopener.connectStr = cliptext
node.text = channelopener.connectStr
} else {
var dialog = app.messageDialog.createObject(app, {
text: qsTr('Invalid node-id or connect string')
})
dialog.open()
}
}
}
ToolButton {
icon.source: '../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: qsTr('Scan a node-id or a connect string')
})
dialog.onFoundText.connect(function(data) {
if (channelopener.validateConnectString(data)) {
channelopener.connectStr = data
node.text = channelopener.connectStr
} else {
var errdialog = app.messageDialog.createObject(app, {
text: qsTr('Invalid node-id or connect string')
})
errdialog.open()
}
dialog.close()
})
dialog.open()
}
}
}
// trampoline
ComboBox {
visible: !Config.useGossip
Layout.columnSpan: 3
Layout.fillWidth: true
model: channelopener.trampolineNodeNames
onCurrentValueChanged: {
if (activeFocus)
channelopener.connectStr = currentValue
}
// preselect a random node
Component.onCompleted: {
if (!Config.useGossip) {
currentIndex = Math.floor(Math.random() * channelopener.trampolineNodeNames.length)
channelopener.connectStr = currentValue
}
}
}
Label {
text: qsTr('Amount')
Layout.columnSpan: 3
color: Material.accentColor
}
BtcField {
id: amountBtc
fiatfield: amountFiat
Layout.preferredWidth: amountFontMetrics.advanceWidth('0') * 14 + leftPadding + rightPadding
onTextAsSatsChanged: {
if (!is_max.checked)
channelopener.amount = amountBtc.textAsSats
}
readOnly: is_max.checked
color: readOnly
? Material.accentColor
: Material.foreground
Connections {
target: channelopener.amount
function onSatsIntChanged() {
if (is_max.checked) // amount updated by max amount estimate
amountBtc.text = Config.formatSatsForEditing(channelopener.amount.satsInt)
}
}
}
RowLayout {
Layout.fillWidth: true
Label {
text: Config.baseUnit
color: Material.accentColor
}
Switch {
id: is_max
text: qsTr('Max')
onCheckedChanged: {
if (activeFocus) {
channelopener.amount.isMax = checked
if (checked) {
channelopener.updateMaxAmount()
}
}
}
}
}
Item { width: 1; height: 1; visible: Daemon.fx.enabled }
FiatField {
id: amountFiat
Layout.preferredWidth: amountFontMetrics.advanceWidth('0') * 14 + leftPadding + rightPadding
btcfield: amountBtc
visible: Daemon.fx.enabled
readOnly: is_max.checked
color: readOnly
? Material.accentColor
: Material.foreground
}
Label {
visible: Daemon.fx.enabled
text: Daemon.fx.fiatCurrency
color: Material.accentColor
Layout.fillWidth: true
}
Item { visible: Daemon.fx.enabled ; height: 1; width: 1 }
InfoTextArea {
id: warning
Layout.topMargin: constants.paddingMedium
Layout.fillWidth: true
Layout.columnSpan: 3
text: channelopener.warning
visible: text
compact: true
}
}
}
FlatButton {
Layout.fillWidth: true
text: qsTr('Open Channel...')
icon.source: '../../icons/confirmed.png'
enabled: channelopener.valid
onClicked: channelopener.openChannel()
}
}
Component {
id: confirmOpenChannelDialog
ConfirmTxDialog {
amountLabelText: qsTr('Channel capacity')
sendButtonText: qsTr('Open Channel')
finalizer: channelopener.finalizer
}
}
ChannelOpener {
id: channelopener
wallet: Daemon.currentWallet
onAuthRequired: (method, authMessage) => {
app.handleAuthRequired(channelopener, method, authMessage)
}
onValidationError: (code, message) => {
if (code == 'invalid_nodeid') {
var dialog = app.messageDialog.createObject(app, {
title: qsTr('Error'),
iconSource: Qt.resolvedUrl('../../icons/warning.png'),
text: message
})
dialog.open()
}
}
onConflictingBackup: (message) => {
var dialog = app.messageDialog.createObject(app, {
text: message,
yesno: true
})
dialog.open()
dialog.accepted.connect(function() {
channelopener.openChannel(true)
})
}
onFinalizerChanged: {
var dialog = confirmOpenChannelDialog.createObject(app, {
satoshis: channelopener.amount
})
dialog.accepted.connect(function() {
dialog.finalizer.signAndSend()
})
dialog.open()
}
onChannelOpening: (peer) => {
console.log('Channel is opening')
app.channelOpenProgressDialog.reset()
app.channelOpenProgressDialog.peer = peer
app.channelOpenProgressDialog.open()
}
onChannelOpenError: (message) => {
app.channelOpenProgressDialog.state = 'failed'
app.channelOpenProgressDialog.error = message
}
onChannelOpenSuccess: (cid, has_onchain_backup, min_depth, tx_complete) => {
var message = qsTr('Channel established.') + ' '
+ qsTr('This channel will be usable after %1 confirmations').arg(min_depth)
if (!tx_complete) {
message = message + '\n\n' + qsTr('Please sign and broadcast the funding transaction.')
channelopener.wallet.historyModel.initModel(true) // local tx doesn't trigger model update
}
app.channelOpenProgressDialog.state = 'success'
app.channelOpenProgressDialog.info = message
if (!has_onchain_backup) {
app.channelOpenProgressDialog.channelBackup = channelopener.channelBackup(cid)
}
// TODO: handle incomplete TX
root.close()
}
}
FontMetrics {
id: amountFontMetrics
font: amountBtc.font
}
}