add proog generation message and spinner

This commit is contained in:
Sergio Chouhy 2026-06-05 02:06:25 -03:00
parent f4b3554244
commit edf27b82aa
4 changed files with 68 additions and 13 deletions

View File

@ -11,6 +11,7 @@
#include <QUrl>
#include "logos_api.h"
#include "logos_api_client.h"
#include "logos_sdk.h"
namespace {
@ -18,7 +19,12 @@ namespace {
const char SETTINGS_APP[] = "ExecutionZoneWalletUI";
const char CONFIG_PATH_KEY[] = "configPath";
const char STORAGE_PATH_KEY[] = "storagePath";
const char LEZ_MODULE[] = "logos_execution_zone";
const int WALLET_FFI_SUCCESS = 0;
// Proof generation time is unbounded on commodity hardware.
// Timeout(-1) means "wait indefinitely", matching Qt's own convention
// for infinite waits (e.g. QRemoteObjectPendingCall::waitForFinished(-1)).
const Timeout NO_TIMEOUT{-1};
// Convert a decimal amount string to 32-char hex (16 bytes little-endian)
// for transfer_public/transfer_private/transfer_private_owned.
@ -219,7 +225,6 @@ QString LEZWalletBackend::transferPrivate(QString fromHex, QString toHex, QStrin
if (amountHex.isEmpty()) return QStringLiteral("Error: Invalid amount.");
QString keysPayload = toHex.trimmed();
// If "To" is not JSON (e.g. user pasted account id hex), resolve to keys.
if (!keysPayload.startsWith(QLatin1Char('{'))) {
qDebug() << "LEZWalletBackend::transferPrivate: resolving keys via get_private_account_keys";
const QString resolved = getPrivateAccountKeys(keysPayload);
@ -227,14 +232,20 @@ QString LEZWalletBackend::transferPrivate(QString fromHex, QString toHex, QStrin
keysPayload = resolved;
}
return m_logos->logos_execution_zone.transfer_private(fromHex, keysPayload, amountHex);
return m_logosAPI->getClient(LEZ_MODULE)->invokeRemoteMethod(
LEZ_MODULE, "transfer_private",
QVariantList{fromHex.trimmed(), keysPayload, amountHex},
NO_TIMEOUT).toString();
}
QString LEZWalletBackend::transferPrivateOwned(QString fromHex, QString toHex, QString amountStr)
{
const QString amountHex = amountToLe16Hex(amountStr);
if (amountHex.isEmpty()) return QStringLiteral("Error: Invalid amount.");
return m_logos->logos_execution_zone.transfer_private_owned(fromHex, toHex.trimmed(), amountHex);
return m_logosAPI->getClient(LEZ_MODULE)->invokeRemoteMethod(
LEZ_MODULE, "transfer_private_owned",
QVariantList{fromHex.trimmed(), toHex.trimmed(), amountHex},
NO_TIMEOUT).toString();
}
QString LEZWalletBackend::transferShielded(QString fromHex, QString toKeysJson, QString amountStr)
@ -250,21 +261,30 @@ QString LEZWalletBackend::transferShielded(QString fromHex, QString toKeysJson,
keysPayload = resolved;
}
return m_logos->logos_execution_zone.transfer_shielded(fromHex, keysPayload, amountHex);
return m_logosAPI->getClient(LEZ_MODULE)->invokeRemoteMethod(
LEZ_MODULE, "transfer_shielded",
QVariantList{fromHex.trimmed(), keysPayload, amountHex},
NO_TIMEOUT).toString();
}
QString LEZWalletBackend::transferShieldedOwned(QString fromHex, QString toHex, QString amountStr)
{
const QString amountHex = amountToLe16Hex(amountStr);
if (amountHex.isEmpty()) return QStringLiteral("Error: Invalid amount.");
return m_logos->logos_execution_zone.transfer_shielded_owned(fromHex, toHex.trimmed(), amountHex);
return m_logosAPI->getClient(LEZ_MODULE)->invokeRemoteMethod(
LEZ_MODULE, "transfer_shielded_owned",
QVariantList{fromHex.trimmed(), toHex.trimmed(), amountHex},
NO_TIMEOUT).toString();
}
QString LEZWalletBackend::transferDeshielded(QString fromHex, QString toHex, QString amountStr)
{
const QString amountHex = amountToLe16Hex(amountStr);
if (amountHex.isEmpty()) return QStringLiteral("Error: Invalid amount.");
return m_logos->logos_execution_zone.transfer_deshielded(fromHex.trimmed(), toHex.trimmed(), amountHex);
return m_logosAPI->getClient(LEZ_MODULE)->invokeRemoteMethod(
LEZ_MODULE, "transfer_deshielded",
QVariantList{fromHex.trimmed(), toHex.trimmed(), amountHex},
NO_TIMEOUT).toString();
}
bool LEZWalletBackend::createNew(QString configPath, QString storagePath, QString password)

View File

@ -61,7 +61,6 @@ Rectangle {
}
// Parse a transfer result JSON string and write to dashboardView.
// Used by all three transfer handlers below.
function applyTransferResult(dashboardView, raw) {
var msg = raw || ""
var isError = false
@ -168,45 +167,55 @@ Rectangle {
}
onTransferPrivateRequested: (fromId, toKeysJsonOrAddress, amount) => {
if (!backend) return
dashboardView.transferPending = true
logos.watch(backend.transferPrivate(fromId, toKeysJsonOrAddress, amount),
function(raw) { ffiErrors.applyTransferResult(dashboardView, raw) },
function(raw) { dashboardView.transferPending = false; ffiErrors.applyTransferResult(dashboardView, raw) },
function(error) {
dashboardView.transferPending = false
dashboardView.transferResult = qsTr("Error: %1").arg(error)
dashboardView.transferResultIsError = true
})
}
onTransferPrivateOwnedRequested: (fromId, toAccountId, amount) => {
if (!backend) return
dashboardView.transferPending = true
logos.watch(backend.transferPrivateOwned(fromId, toAccountId, amount),
function(raw) { ffiErrors.applyTransferResult(dashboardView, raw) },
function(raw) { dashboardView.transferPending = false; ffiErrors.applyTransferResult(dashboardView, raw) },
function(error) {
dashboardView.transferPending = false
dashboardView.transferResult = qsTr("Error: %1").arg(error)
dashboardView.transferResultIsError = true
})
}
onTransferShieldedRequested: (fromId, toKeysJsonOrAddress, amount) => {
if (!backend) return
dashboardView.transferPending = true
logos.watch(backend.transferShielded(fromId, toKeysJsonOrAddress, amount),
function(raw) { ffiErrors.applyTransferResult(dashboardView, raw) },
function(raw) { dashboardView.transferPending = false; ffiErrors.applyTransferResult(dashboardView, raw) },
function(error) {
dashboardView.transferPending = false
dashboardView.transferResult = qsTr("Error: %1").arg(error)
dashboardView.transferResultIsError = true
})
}
onTransferShieldedOwnedRequested: (fromId, toAccountId, amount) => {
if (!backend) return
dashboardView.transferPending = true
logos.watch(backend.transferShieldedOwned(fromId, toAccountId, amount),
function(raw) { ffiErrors.applyTransferResult(dashboardView, raw) },
function(raw) { dashboardView.transferPending = false; ffiErrors.applyTransferResult(dashboardView, raw) },
function(error) {
dashboardView.transferPending = false
dashboardView.transferResult = qsTr("Error: %1").arg(error)
dashboardView.transferResultIsError = true
})
}
onTransferDeshieldedRequested: (fromId, toAccountId, amount) => {
if (!backend) return
dashboardView.transferPending = true
logos.watch(backend.transferDeshielded(fromId, toAccountId, amount),
function(raw) { ffiErrors.applyTransferResult(dashboardView, raw) },
function(raw) { dashboardView.transferPending = false; ffiErrors.applyTransferResult(dashboardView, raw) },
function(error) {
dashboardView.transferPending = false
dashboardView.transferResult = qsTr("Error: %1").arg(error)
dashboardView.transferResultIsError = true
})

View File

@ -14,6 +14,7 @@ Rectangle {
property var privateAccountModel: null
property string transferResult: ""
property bool transferResultIsError: false
property bool transferPending: false
// --- Public API: output signals (parent connects and calls backend) ---
signal createPublicAccountRequested()
@ -55,6 +56,7 @@ Rectangle {
privateAccountModel: root.privateAccountModel
transferResult: root.transferResult
transferResultIsError: root.transferResultIsError
transferPending: root.transferPending
onTransferPublicRequested: (fromId, toAddress, amount) => root.transferPublicRequested(fromId, toAddress, amount)
onTransferPrivateRequested: (fromId, toKeysJsonOrAddress, amount) => root.transferPrivateRequested(fromId, toKeysJsonOrAddress, amount)

View File

@ -15,6 +15,7 @@ Rectangle {
property var privateAccountModel: null
property string transferResult: ""
property bool transferResultIsError: false
property bool transferPending: false
// --- Public API: signals out (match backend: transfer_public, transfer_private, transfer_private_owned, transfer_shielded, transfer_shielded_owned) ---
signal transferPublicRequested(string fromAccountId, string toAddress, string amount)
@ -40,7 +41,9 @@ Rectangle {
readonly property bool toAddressValid: (toComboPermanent || (showOwnedOption && useOwnedAccountForTo))
? (toFilterCount > 0 && toCombo.currentIndex >= 0)
: (toField && toField.text.trim().length > 0)
readonly property bool sendEnabled: amountField && manualFromField
readonly property bool needsProof: isPrivateTab || isShieldedTab || isDeshieldedTab
readonly property bool sendEnabled: !root.transferPending
&& amountField && manualFromField
&& amountField.text.length > 0 && d.toAddressValid
&& ((fromFilterCount > 0 && fromCombo.currentIndex >= 0)
|| (fromFilterCount === 0 && manualFromField.text.trim().length > 0))
@ -203,9 +206,30 @@ Rectangle {
}
}
// Proof pending indicator
RowLayout {
Layout.fillWidth: true
visible: root.transferPending
spacing: Theme.spacing.small
LogosSpinner {
Layout.preferredWidth: 20
Layout.preferredHeight: 20
running: root.transferPending
}
LogosText {
Layout.fillWidth: true
text: qsTr("Generating proof, please wait…")
font.pixelSize: Theme.typography.secondaryText
color: Theme.palette.textSecondary
}
}
// Result label
RowLayout {
Layout.fillWidth: true
visible: !root.transferPending
LogosText {
id: resultText
Layout.fillWidth: true